Live data from Hacker News

Perfecting GLFW for Zig, and finding lurking undefined behavior that went unnot

devlog.hexops.com

21–30 of 60 posts

Re: Perfecting GLFW for Zig, and finding lurking undefined behavior that went unnot

#23

The article discusses some undefined behaviour resulting from shifting an unsigned char left by 24 places. Any idea why the compiler wasn't warning about that? It seems like it would be easy to implement that warning in the compiler. I feel that I'm missing something.

gcc and clang should warn about this: #include void foo() { uint32_t foo = 1; foo According to godbolt, the following warning is emitted for gcc: warning: left shift count >= width of type [-Wshift-count-overflow] And for clang: warning: shift count >= width of type [-Wshift-count-overflow] https://godbolt.org/z/ffccWexMP

The problem in the article is something like this:

    int main() {
        unsigned char foo = 0x80;
        unsigned int x = foo 
and with ubsan enabled it says

    /app/example.c:5:30: runtime error: left shift of 128 by 24 places cannot be represented in type 'int'
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /app/example.c:5:30 in

What's non-obvious is also the rules around arithmetic. Types unsigned char and unsigned int are mentioned in my snippet but the arithmetic - the `<<` operator - performed using the type int.

Re: Perfecting GLFW for Zig, and finding lurking undefined behavior that went unnot

#24

I enabled ubsan on a local build of our code. It found some issues, but good god the build time was atrocious! I doubt it's something you could enable on a CI pipeline.

We run sanitizers nightly, but not as part of presubmit checks. It strikes a good balance between productivity and safety.

Re: Perfecting GLFW for Zig, and finding lurking undefined behavior that went unnot

#25
Yet another example of unnecessary undefined behavior in C as a consequence of needing to run on dead hardware. Bit shifting should clearly be defined to be operating on the underlying bits, with the resulting value being whatever that bit pattern would be on the target architecture.

Re: Perfecting GLFW for Zig, and finding lurking undefined behavior that went unnot

#26
post #15

tl;dr: Glfw is a library used most often by beginners learning graphics programming [but also in production systems]. A bit of code in that library shifts a char value c left by 24 places, yielding a 32-bit int value. If the top bit of the char (c & 0x80) is 1, that shifts it into the sign bit of the int, changing its sign, which is Undefined Behavior, and the compiler is free to do anything, including both what you…

The (not yet merged) PR https://github.com/glfw/glfw/pull/1986 casts to signed long, which only avoids UB (is 64 bits) on 64-bit platforms which aren't Windows.

> Wouldn't it be better to cast to unsigned int or something similar (like uint32_t), since long can still be 32 bits? If the size of long and int is the same, wouldn't the cast as proposed in the PR be semantically identical to the current state?

Re: Perfecting GLFW for Zig, and finding lurking undefined behavior that went unnot

#27
post #15

tl;dr: Glfw is a library used most often by beginners learning graphics programming [but also in production systems]. A bit of code in that library shifts a char value c left by 24 places, yielding a 32-bit int value. If the top bit of the char (c & 0x80) is 1, that shifts it into the sign bit of the int, changing its sign, which is Undefined Behavior, and the compiler is free to do anything, including both what you…

The (not yet merged) PR https://github.com/glfw/glfw/pull/1986 casts to signed long, which only avoids UB (is 64 bits) on 64-bit platforms which aren't Windows. > Wouldn't it be better to cast to unsigned int or something similar (like uint32_t), since long can still be 32 bits? If the size of long and int is the same, wouldn't the cast as proposed in the PR be semantically identical to the current state?

Casting to signed long is demonstrably wrong.

The code in question is (probably) pretty slow, offering plenty of room for improvement beyond just fixing the UB. But it has seemed to work well enough, so far, like most things.

Re: Perfecting GLFW for Zig, and finding lurking undefined behavior that went unnot

#29
post #9

Earlier quoted context omitted.

Is it safe to say that SDL is a strict superset of GLFW?

I think that is a reasonable statement. SDL includes other functionality like image loading, audio, etc. whereas GLFW is primarily focused just with getting a window with a graphics context for OpenGL/Vulkan/etc set up.

SDL’s advantage is that it supports more platforms (like mobile and Switch), and is much more battle-tested with hundreds of games using it, including Valve’s ones. Many people seem to use SDL for only windowing and input and seem okay with it.

Re: Perfecting GLFW for Zig, and finding lurking undefined behavior that went unnot

#30
Seems like a cool project and kudos to the authors attentions to detail.

These lines tickled my Bone of Irony:

> No installing apt packages. No dealing with missing header errors. It should just work out-of-the-box, and for every platform

I think it’s interesting/ironic because at some point the layers of header files were pitched as a way of making things more modular and better. A means of simplifying. Aptitude was meant to do the same thing. Simplify a process that was formerly seen as icky and complicated.

The author could have just as well mentioned just about any other software install/deploy/configure technology. In the end it always seems that yesteryears “it makes things easier” is eventually derided and replaced with a some new simple straightforward mechanism. As whatever the new approach is, scales in time and application, it takes the place of what it derided and becomes the new derided. One big merry go round.

Post reply on HN