c++ - Strict aliasing seems inconsistant -


had couple of bugs strict aliasing , thought try fix of them. having looked in detail @ seems gcc doesn't issue warning, , things impossible implement. @ least understanding every below broken. understanding wrong, there correct way these things, or code have technically break rule , covered system tests?

the bugs code char , unsigned char buffers mixed, e.g. below:

size_t process(char *buf, char *end) {     char *p = buf;     processsome((unsigned char**)&p, (unsigned char*)end);     //gcc decided p not changed processsome , returned 0     return (size_t)(p - buf); } 

changing below seemed fix problem, although still involves cast not sure why works , warning free:

size_t process(char *buf, char *end) {     unsigned char *buf2 = (unsigned char *)buf;     unsigned char *p = buf2;     unsigned char *end2 = (unsigned char*)end;     processsome(&p, end2);     return (size_t)(p - buf2); } 

also there bunch of other places seem work without warnings

//contains unsigned char* of data. possibly network, disk, etc. //the buffer contents 8 byte aligned. const buffer *buffer = foo(); const uint16_t *utf16text = (const uint16_t*)buffer->getdata();//const unsigned char* //... read utf16text. not seem ever warning   //also seems work fine size_t len = calculateworstcaselength(...); buffer *buffer = new buffer(len * 2); uint16_t *utf16 = (uint16_t*)buffer->getdata();//unsigned char* len = dosomeprocessing(utf16, len, ...); buffer->truncate(len * 2); send(buffer); 

and with...

struct hash128 {     unsigned char data[16]; }; ... size_t operator ()(const hash128 &hash) {     return *(size_t*)hash.data;//warning } 

a non char case. doesn't have warning, , if bad, how avoid (both ways seem work)?

int *x = fromsomewhere();//aligned 16 bytes, array of 4 __m128i xmm = _mm_load_si128((__m128*i)x); __m128i xmm2 = *(__m128i*)x; 

looking @ other api's there seems various cases understanding violate rule (have not come across linux/gcc specfic one, sure there 1 somewhere).

  1. cocreateinstance has void** output param requiring explicit pointer cast. direct3d has well.

  2. large_integer union have read/writes different members (e.g. code might use high/low, other might read int64).

  3. i recall cpython implementation quite happily casts pyobject* bunch of other stuff happens have same memory layout @ start.

  4. a lot of hash implementations have seen cast input buffer uint32_t*, perhaps use uint8_t handle 1-3 bytes @ end.

  5. pretty every memory allocator implementation have seen uses char* or unsigned char*, must cast desired type (possibly via returned void*, internally allocate @ least char)

first, pointers char , unsigned char pretty exempted rules regarding string aliasing; allowed convert type of pointer char* or unsigned char*, , @ pointed object array of char or unsigned char. now, regards code:

size_t process(char *buf, char *end) {     char *p = buf;     processsome((unsigned char**)&p, (unsigned char*)end);     //gcc decided p not changed processsome , returned 0     return (size_t)(p - buf); } 

the issue here you're trying @ char* if unsigned char*. that's not guaranteed. given cast visible, g++ being bit obtuse not turning strict aliasing analysis off automatically, technically, covered standard.

in

size_t process(char *buf, char *end) {     unsigned char *buf2 = (unsigned char *)buf;     unsigned char *p = buf2;     unsigned char *end2 = (unsigned char*)end;     processsome(&p, end2);     return (size_t)(p - buf2); } 

on other hand, of conversions involve char* , unsigned char*, both of may alias anything, compiler required make work.

with regards rest, don't return type of buffer->getdata() is, it's hard say. if char*, unsigned char* or void*, code legal (except missing cast in second use of buffer->getdata()). long of casts involve char*, unsigned char* or void* (ignoring const qualifiers), compiler required assume there possible aliasing: when original pointer has 1 of these types, have been created means of cast pointer target type, , language guarantees can convert pointer 1 of these types, , original type, , recover same value. (of course, if char* wasn't uint16_t, may end alignment problems, compiler can't know this.)

with regards last example, don't indicate type of hash.data, it's hard say; if char*, void* or unsigned char*, language guarantees code (technically, provided char pointer created converting size_t*; in practice, provided pointer sufficiently aligned , pointed bytes not form trapping value size_t).

in general: guaranteed way of "type punning" memcpy. otherwise, pointer casts, such doing, guaranteed long or void*, char* or unsigned char*, @ least far aliasing concerned. (from 1 of these result in alignment problems, or accessing trapping value if dereference it.)

note may additional guarantees other standards. posix requires like:

void (*pf)(); *((void**)&pf) = ... 

to work, example. (generally, casting , dereferencing work, g++, if don't else in function aliasing might relevant.)

and of compilers know allow using union type punning, of time. (and @ least some, including g++, fail legal uses of union in other cases. correctly handling union tricky compiler writer if union isn't visible.)


Comments

Popular posts from this blog

javascript - JS causing window size to be bigger than necessary - Dropdown bug -

How to mention the localhost in android -

php - Calling a template part from a post -