3 ms·
Iunno, for this example, isn't this actually UB according to standard C? I don't think it'd be that objectionable to put e.g. a semantic comment saying "yeah no
by remexre 4y ago
Iunno, for this example, isn't this actually UB according to standard C? I don't think it'd be that objectionable to put e.g. a semantic comment saying "yeah no this is actually not UB because we check in ./configure that your compiler is one known to not do bad things," *if* such a thing were standardized across linting tools.
Of course, that's a heckuva if.
- david2ndaccount 4y agoThis is not standard C, this is already in the land of compiler extensions and platform specific code. The behavior is defined by the compiler and no compiler should treat this as UB.
- remexre 4y agoIs the code actually compiled with -fno-strict-aliasing (which IME is rare for userspace code, but I don't work with numerical code very much), or are you saying this is because of the types involved in the cast? I didn't see anything in [0] about a change in pointer semantics from using the vector extensions in the compilation unit? [0]: https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html#Vector-Extensions https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html#Ve...
- zokier 4y ago_m512i is defined as may_alias https://github.com/gcc-mirror/gcc/blob/master/gcc/config/i386/avx512cdintrin.h#L43 https://github.com/gcc-mirror/gcc/blob/master/gcc/config/i38... https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#Common-Type-Attributes https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.ht...
- deathanatos 4y agoIt is using compiler intrinsics, I grant, and taking advantage of IB is yes, well-defined given an implementation (as we have here) … but it seems like it's still C? Here, I'm not 100% certain this code isn't UB: we type-pun a __m512i and a uint64_t … I'm not certain that's not UB. If I'm forced into writing C, I try to avoid doing that at all costs … I'd rather not encounter nasal demons. The warning also seems a bit merited, given that each "increment" is over more than a single object on the underlying array. (But, of course, that is the intent. But I'm just not sure the static analyzer can see it.)
- cpeterso 4y agoPlus, a pointer to __m512i might require different alignment than a pointer to unsigned long. This code received a pointer to unsigned long from somewhere that might have cared about the data it pointed to, so his code should acknowledge that (with type casts or assertions) or make a __m512i or void* pointer part of this function's signature, making the type change part of the contract with the caller.
- aidenn0 4y agoSomeone can perhaps update me for C11, which I'm not up-to-date on, but at least as of C99, while the details of the specification was perhaps unclear on the specifics, the intent was clear that type-punning (of non-character types) without using unions is UB.
- brigade 4y agoIt’s not potentially UB until you access the object through the wrong pointer type; pointer math isn’t type punning. In this case it should be accessed through one of the load intrinsics, which has its behavior defined in the same way memcpy doesn’t invoke UB.
- zokier 4y ago> Here, I'm not 100% certain this code isn't UB: we type-pun a __m512i and a uint64_t … I'm not certain that's not UB I'm 99% certain its not UB in itself, because of https://github.com/gcc-mirror/gcc/blob/master/gcc/config/i386/avx512cdintrin.h#L41-L43 https://github.com/gcc-mirror/gcc/blob/master/gcc/config/i38...
- eklitzke 4y agoThis is not UB. In this case where you're using the wrong pointer type the worst thing that can happen is you can have aliasing issues. For example, if I have an int* and a double*, the C compiler is free to assume that the pointers can never alias each other so it can optimize loads and stores assuming that an update to the int pointer will never affect the double pointer. In general this can cause problems if the pointers actually do alias each other, but if there's no aliasing occurring then nothing bad will happen.
- remexre 4y agoMy understanding was that the UB was defined such that: int i = 0; float f = 1.0f; void* p; if(rand() & 1) p = &i; else p = &f; int j = *(int*)p; assert(i == j); could legally be compiled to a no-op (or a single call to rand() with an ignored result, I suppose), despite there being no "weird" pointer stores, since the ill-typed-at-runtime load "can't happen," so the compiler can reason that (int*)p must equal &i, and hence j = i. EDIT: And, in fact, gcc does this: https://godbolt.org/z/WM33vzzdo https://godbolt.org/z/WM33vzzdo Not sure if that applies to vector loads, and the gcc docs don't specify, though.