Closed laytan closed 2 months ago
Found the issue, bottom line is we hit undefined behaviour.
During the blend of PNG images we have this part of the code: c.r = u8((1.0 - alpha) * bg[0] + f32(c.r) * alpha)
ultimately casting a f32
to u8
, in the case here this resolves to:
c.r = u8((1.0 - 0) * 65535 + f32(255) * 0)
c.r = u8(65535)
which overflows, ok, that can still be as designed, Odin should not have undefined behaviour so should be fine.
But then:
package main
import "core:fmt"
main :: proc() {
oh := f32(65535)
no := u8(oh)
fmt.println(no) // 255 on -o:none, 0 on -o:speed
}
This all took me way way too long to get to the bottom of for it to be so simple
I've also replicated it on Windows and Linux on other optimization levels:
W:\Odin\bug>odin run .
48 [255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0]
W:\Odin\bug>odin run . -o:size
48 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
W:\Odin\bug>odin run . -o:speed
48 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
W:\Odin\bug>odin run . -o:aggressive
48 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
/mnt/w/Odin/bug $ odin run .
48 [255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0]
/mnt/w/Odin/bug $ odin run . -o:size
48 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
/mnt/w/Odin/bug $ odin run . -o:speed
48 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
/mnt/w/Odin/bug $ odin run . -o:aggressive
48 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Fixed via 8fcfd8c506752d3e0d65e4d9ef7856486a65ca5f
Context
While trying to verify #3308 by running all tests with optimisations turned on, I found this test failure that has been there for a while already. I couldn't figure it out in reasonable time there, so I am making this issue.
Reproduced on Linux and Darwin amd64, with
-o:speed
on LLVM 17 and 18.There is even a comment by @Kelimion in the test file mentioning failure https://github.com/odin-lang/Odin/blob/c72a269b7cfd5f955254f9c3ad8e5e63bac7aa2c/tests/core/image/test_core_image.odin#L1494
Steps to Reproduce
odin run tests/core/image -o:speed