Re: Strict aliasing and malloc
narwhal x <[email protected]>
| Newsgroups | gmane.comp.lib.newlib |
|---|---|
| Message-ID | <CADekCYG7hrCFm-29TMTb+j75t7SwMQc+tix3fU9H4eSrhSLnAg@mail.gmail.com> |
On Tue, Jul 3, 2018 at 8:07 PM, Brian Inglis <[email protected]> wrote: > On 2018-07-03 09:16, narwhal x wrote: >> Hello, >> >> I have a question regarding newlib and the -fstrict-aliasing implied >> by turning on O2. >> >> The strict aliasing implied by the ISO standard and enabled in gcc >> with O2 (This might be specific to gcc, but could be the case with any >> compiler with aliasing optimizations) makes it so you can only cast a >> pointer to a compatible type, and a special case is malloc, which >> should return an "undeclared type" *. >> >> I however did not find the -fno-strict-aliasing flag in any >> configuration or makefile (If I just overlooked it, and the flag is >> mandatory that would answer my question) >> >> My question: >> In newlib/libc/stdlib/mallocr.c on line 2212 you have the statement: >> "top = (mchunkptr)brk;" >> Here top is of type "mchunkptr" and brk is a "char *". The standard >> says that you can not just alias a incompatible type and dereference >> it (unless it's a malloc'ed variable, as it would change it's type >> when written to, but how do you inform the compiler?) >> >> As an example, see 4.2.1 (p. 63) in >> https://www.cl.cam.ac.uk/~pes20/cerberus/notes30.pdf >> >> So is this allowed? Or am I missing something. >> >> * After asking in the gcc IRC, they mentioned that the way they go >> about having the special case for malloc is making sure the libc >> library is linked from a library and no LTO is performed. >> >> >> My main reason for asking is just wanting to know how a malloc >> implementation should deal with these restrictions stated by the ISO C >> standard, and improve my understanding of the (sometimes confusing) >> aliasing rules. > > Pointer types char * and void * can be converted to other data pointer types, > and character types can alias other types, but you should not alias objects via > casts or conversions of pointers to objects stored as incompatible types, > because optimization could eliminate the stores, so the underlying storage of > the object of incompatible type may not be updated, and the compiler would not > know that because the type is different, as the compiler does not track possible > aliasing of incompatible types. Roughly IMHO HTH YMMV ;^> > > Implementations of malloc use char * internally and convert those to char ** and > int * to maintain their internal housekeeping data at the start of the block, > often using unions, returning a pointer to universally aligned storage following > that block prefix, often resulting in malloc overhead of one or more universally > aligned blocks per allocation; reducing space overhead takes more work: see e.g. > https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/stdlib/mallocr.c;h=ecc445f3d36365a4840e31c737db5018ddba42e9;hb=8e732f7f7f684f22b283f39a5d407375b3b0b3af > -- > Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada Forgive me if I misunderstand, but doesn't your recap regarding strict aliasing agree with my understanding that this is an aliasing violation? Because you mention (correctly I think) > ... you should not alias objects via > casts or conversions of pointers to objects stored as incompatible types ... And in the case I mentioned (one of many) in mallocr.c on line 2212 you have the statement: >> "top = (mchunkptr)brk;" Here brk is declared as: char *brk and is returned by sbrk (in my case) which takes memory from the heap declared somewhere in a linkerscript (or similar) AFAIK. But top is a mchunk *, which is a struct. So this is not a compatible type right (so the ARE incompatible)? You could cast from mchunk * TO char * and dereference it according to the standard, but not the other way around. Also if you look at the document I linked in my initial mail >> As an example, see 4.2.1 (p. 63) in >> https://www.cl.cam.ac.uk/~pes20/cerberus/notes30.pdf Isn't this exactly what is done in mallocr.c ? And they state specifically that this can only be done when strict aliasing is NOT uphold. And that seems to be in accordance to the standard. I get that this is how the space is managed internally, I also know a lot of embedded applications and networking stacks do this casting from a char * to a struct *, but these also had to disable strict aliasing to avoid bugs. So am I missing something? If I am talking nonsense or misunderstanding something please let me know. I know it works basically always, but isn't this technically undefined behavior without -fno-strict-aliasing? Thanks