Skip to content

Compiler failure when transmuting png.load_from_file() output in a global enumerated array #5133

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
BemusedButBloodthirsty opened this issue May 8, 2025 · 5 comments

Comments

@BemusedButBloodthirsty
Copy link

Context

The program uses core:image/png to load a 64x64 pixel image with the png.load_from_file() procedure.
The bytes buffer IMG.pixels.buf[:] is transmuted to a []u32 slice and added to the global enumerated array's contents.

Odin:    dev-2025-03-nightly:951bef4
OS:      Windows 11 Home Basic (version: 24H2), build 26100.3775
CPU:     AMD Ryzen 5 3600XT 6-Core Processor
RAM:     16305 MiB
Backend: LLVM 18.1.8

Expected Behavior

Should always be able to compile and then print the length of the array (equal to 2) to the console when using odin run .

Current Behavior

Compilation fails most of the time.
Does however rarely manage to compile and successfully print 2?

Failure Information (for bugs)

Steps to Reproduce

  1. Code:
package a_potential_bug

import "core:fmt"
import "core:image/png"

IMG := png.load_from_file("./some_image.png") or_else nil // Tested with 64x64 pixel PNG file. 

Some_Enum :: enum int {
    A,
    B,
}

global_enumerated_array: [Some_Enum][]u32 = {
    .A = transmute([]u32) IMG.pixels.buf[:],
    .B = transmute([]u32) IMG.pixels.buf[:],
    // Note: Also tried using `mem.slice_data_cast()` instead of `transmute()` here but the issue persists. 
}

main :: proc() {
    fmt.println(len(global_enumerated_array))
}
  1. Make sure the current directory contains a some_image.png png image which is 64x64 pixels in resolution (P.S. I did not test other resolutions).
  2. Simply use odin run .

Failure Logs

The console output is usually:
C:WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command odin run ." terminated with exit code: 1..

@Kelimion
Copy link
Member

Kelimion commented May 8, 2025

You may want to retry with odin build. I've checked the compiler's return value and it's always 0. The return value you see is likely from the generated program crashing being forwarded from the compiler running it at the end.

I run it like this, and your code hasn't caused the compiler to crash once.

@echo off
odin build . -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -out:scratch.exe -o:none

IF %ERRORLEVEL% NEQ 0 (
	echo Error %ERRORLEVEL%
) ELSE (
	scratch.exe
)

Rewriting it this way works consistently.

package a_potential_bug

import "core:fmt"
import "core:image/png"
import "core:slice"

@(init)
initialize_array :: proc() {
	img := png.load_from_file(ODIN_ROOT + "/tests/core/assets/PNG/basi0g01.png") or_else nil // Tested with 64x64 pixel PNG file.
	if img == nil {
		return
	}

	global_enumerated_array[.A] = slice.reinterpret([]u32, img.pixels.buf[:])
	global_enumerated_array[.B] = slice.reinterpret([]u32, img.pixels.buf[:])
}

Some_Enum :: enum int {
	A,
	B,
}
global_enumerated_array: [Some_Enum][]u32

main :: proc() {
	fmt.println(len(global_enumerated_array))
}

@BemusedButBloodthirsty
Copy link
Author

Epic, thanks @Kelimion - that solves the problem I've been having. Will keep odin build in mind when I encounter something in the future.

@Kelimion
Copy link
Member

Kelimion commented May 9, 2025

Epic, thanks @Kelimion - that solves the problem I've been having. Will keep odin build in mind when I encounter something in the future.

One trick is to use a build.bat/sh that uses odin build, checks the return value and either prints the return value or runs the executable if there was no error. Another is to keep using odin run and only switch to odin build if you experience a crash or what you suspect might be one, so you can isolate whether it's a compiler problem.

@Kelimion
Copy link
Member

Kelimion commented May 9, 2025

And you may also want to add a @(fini) which deletes those slices, unless you're okay with leaking the allocations on program exit. The OS will clean them up anyway, but if you ever want to run valgrind or the like, that'll become a false positive.

@BemusedButBloodthirsty
Copy link
Author

Noted, thanks for the good advice. The absence of @(fini) in my case shouldn't be a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants