Hacker News new | ask | show | jobs
by pjc50 3 days ago
> Some of which is not actually UB because the implementation defines it

No - if something is UB in the spec, it's UB. The implementation will do something, sure, but what it does is not fixed and may even change based on compiler version and optimization level.

> DWORD-sized memory access is atomic on Windows because Microsoft said it is

Well, Intel said it is. Mind you I don't think there are any 32-bit native architectures where aligned dword access isn't atomic. Unaligned, on the other hand ...

2 comments

"Undefined behavior" in the C standard literally means "behavior which this C standard does not put any requirements on" - it says so in the definitions section of the C standard. Other things can still put requirements on it. MSVC isn't just a C++ compiler - it's a C++ compiler for x64 Windows and therefore follows the rules of C++, x64, and Windows all at once.
> No - if something is UB in the spec, it's UB.

A compiler is still free to ignore the spec and declare that something is not UB. However, this is very much compiler based, not platform based. Windows might guarantee that aligned DWORD-sized memory accesses are atomic, but that doesn't mean Clang when compiling for Windows would respect this - but MSVC might.

No, a compiler obviously cannot do this. nothing is undefined behaviour under a known compiler, version, and settings. UB means you can't know what the code does in general not that you can't know what it does in a very specific case.
UB has 2 very different implications:

1. It means that even if your program happens to work, it can't be portable

2. It means that even if your program happens to work today, it might stop working tomorrow when you add some new code, when you change some compiler flags, or when you do even a minor compiler upgrade

Of course, a compiler can't address 1. However, a compiler can very much address item 2. If Microsoft were to say "in MSVC, we define integer overflow to wrap", then they would guarantee that `INT_MAX + 1` will produce `INT_MIN` regardless of any optimization settings, any compiler upgrades, any other changes to the code. Of course, compiling the exact same program with Clang or GCC might cause it to crash or corrupt memory or anything else - but as long as you stuck with MSVC, your program would have perfectly defined semantics.

This is similar to using compiler extensions or intrinsics - they are not portable and not defined by the standard, maybe even explicitly defined to NOT be supported per the standard (such as variable length arrays in C++ in GCC), but they are nevertheless perfectly safe as long as you stick to your chosen compiler.

Edit to add: the integer overflow example is not just a theoretical possibility - lots of C++ compilers provide the `-fwrapv` flag; when using that flag, signed integer overflow is no longer UB for that program, it is defined just the same as unsigned integer overflow.