* strict aliasing: how to swap pointers @ 2008-04-29 23:58 Evan Jones 2008-04-30 1:00 ` Rupert Wood 2008-04-30 9:03 ` Sergei Organov 0 siblings, 2 replies; 22+ messages in thread From: Evan Jones @ 2008-04-29 23:58 UTC (permalink / raw) To: gcc-help I have a function to swap any two pointers (assuming that sizeof(void*) == sizeof(T*)). I would like to use it without violating strict aliasing rules. I have a workaround, but I would like to verify that this is the right way to do this. The test case: void* exchange(void** ptr, void* next); int main() { int v1 = 42; int v2 = 123; int* a = &v1; int before = *a; exchange(reinterpret_cast<void**>(&a), &v2); int after = *a; printf("before: %d after: %d\n", before, after); return 0; } Output from Redhat's version of gcc 4.1.2 20070925: test.cc: In function ‘int main()’: test.cc:16: warning: dereferencing type-punned pointer will break strict-aliasing rules The output from the program is correct. My workaround avoids the warning, but I think it will still permit GCC to generate undesired optimizations, since it says nothing about the *values* pointed to: union { int** int_ptr; void** void_ptr; } temp = { &a }; exchange(temp.void_ptr, &v2); I believe this may be incorrect, since *int_ptr and *void_ptr have distinct types, and hence GCC could decide that they cannot possibly be aliases? What is the "right" way to fix this? Thanks for your help, Evan Jones -- Evan Jones http://evanjones.ca/ ^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: strict aliasing: how to swap pointers 2008-04-29 23:58 strict aliasing: how to swap pointers Evan Jones @ 2008-04-30 1:00 ` Rupert Wood 2008-04-30 1:17 ` OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) Robert William Fuller 2008-04-30 4:46 ` strict aliasing: how to swap pointers Evan Jones 2008-04-30 9:03 ` Sergei Organov 1 sibling, 2 replies; 22+ messages in thread From: Rupert Wood @ 2008-04-30 1:00 UTC (permalink / raw) To: 'Evan Jones'; +Cc: gcc-help Evan Jones wrote: > I have a function to swap any two pointers (assuming that > sizeof(void*) == sizeof(T*)). I would like to use it without > violating strict aliasing rules. I don't know how to fight aliasing rules but as another approach you could template the function instead, i.e. template<typename T> T* exchange(T** ptr, T* next); exchange<int>(&a, &v2); since you're using C++ here. Rup. ^ permalink raw reply [flat|nested] 22+ messages in thread
* OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) 2008-04-30 1:00 ` Rupert Wood @ 2008-04-30 1:17 ` Robert William Fuller 2008-04-30 3:03 ` Gareth Buxton 2008-04-30 7:59 ` me22 2008-04-30 4:46 ` strict aliasing: how to swap pointers Evan Jones 1 sibling, 2 replies; 22+ messages in thread From: Robert William Fuller @ 2008-04-30 1:17 UTC (permalink / raw) To: gcc-help Rupert Wood wrote: > Evan Jones wrote: > >> I have a function to swap any two pointers (assuming that >> sizeof(void*) == sizeof(T*)). I would like to use it without >> violating strict aliasing rules. > > I don't know how to fight aliasing rules but as another approach you could template the function instead, i.e. > > template<typename T> T* exchange(T** ptr, T* next); > > exchange<int>(&a, &v2); > > since you're using C++ here. </begin rant> What a fabulous idea for a programming language! Why not instantiate code for every subtle variation of a type? Then, create a giant library called STL for that very purpose. Watch your executables grow to multiple megabytes in size guaranteeing they won't fit into the cache of any processor. What better way to bring your quad-core processor to its knees. All hail the grand design of C++! Ah, thank you :-) I feel better now. That was cathartic. </end rant> ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) 2008-04-30 1:17 ` OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) Robert William Fuller @ 2008-04-30 3:03 ` Gareth Buxton 2008-04-30 7:59 ` me22 1 sibling, 0 replies; 22+ messages in thread From: Gareth Buxton @ 2008-04-30 3:03 UTC (permalink / raw) To: gcc-help [-- Attachment #1: Type: text/plain, Size: 1274 bytes --] On Tue, 29 Apr 2008 20:28:33 -0400 Robert William Fuller <hydrologiccycle@gmail.com> wrote: > Rupert Wood wrote: > > Evan Jones wrote: > > > >> I have a function to swap any two pointers (assuming that > >> sizeof(void*) == sizeof(T*)). I would like to use it without > >> violating strict aliasing rules. > > > > I don't know how to fight aliasing rules but as another approach > > you could template the function instead, i.e. > > > > template<typename T> T* exchange(T** ptr, T* next); > > > > exchange<int>(&a, &v2); > > > > since you're using C++ here. > > </begin rant> > > What a fabulous idea for a programming language! Why not instantiate > code for every subtle variation of a type? Then, create a giant > library called STL for that very purpose. Watch your executables > grow to multiple megabytes in size guaranteeing they won't fit into > the cache of any processor. What better way to bring your quad-core > processor to its knees. All hail the grand design of C++! > > Ah, thank you :-) I feel better now. That was cathartic. > > </end rant> Clearly we just need bigger processor caches. Those boys down in hardware just been slacking. Not keeping up with the latest developments in software! [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) 2008-04-30 1:17 ` OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) Robert William Fuller 2008-04-30 3:03 ` Gareth Buxton @ 2008-04-30 7:59 ` me22 2008-04-30 10:21 ` Rupert Wood 1 sibling, 1 reply; 22+ messages in thread From: me22 @ 2008-04-30 7:59 UTC (permalink / raw) To: Robert William Fuller; +Cc: gcc-help On Tue, Apr 29, 2008 at 8:28 PM, Robert William Fuller <hydrologiccycle@gmail.com> wrote: > > </begin rant> > > What a fabulous idea for a programming language! Why not instantiate code > for every subtle variation of a type? Then, create a giant library called > STL for that very purpose. Watch your executables grow to multiple > megabytes in size guaranteeing they won't fit into the cache of any > processor. What better way to bring your quad-core processor to its knees. > All hail the grand design of C++! > > Ah, thank you :-) I feel better now. That was cathartic. > > </end rant> > <begin tags do not contain slashes> Not turning on inlining? What a great idea! It's obviously better to do a function call for a tiny little operation than to just inline the code. Why, that way the functions even show up! That must be better than stripping it from the binary since it's never called. Who needs strong static type safety, anyways? </end tag> ^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) 2008-04-30 7:59 ` me22 @ 2008-04-30 10:21 ` Rupert Wood 0 siblings, 0 replies; 22+ messages in thread From: Rupert Wood @ 2008-04-30 10:21 UTC (permalink / raw) To: 'me22', 'Robert William Fuller'; +Cc: gcc-help me22 wrote: > <begin tags do not contain slashes> > > Not turning on inlining? What a great idea! It's obviously better to > do a function call for a tiny little operation than to just inline the > code. Why, that way the functions even show up! That must be better > than stripping it from the binary since it's never called. Who needs > strong static type safety, anyways? > > </end tag> I agree, code like this should probably get inlined (or at least be available to the optimizer to inline if it wants) but even if it's not the compiler doesn't actually need to instantiate a new exchange method for every type. All pointers are the same size (modulo funny platforms) and copying a pointer is the same operation regardless of what it points to (modulo smart pointers). So the actual exchange operation is always the same, so the assembly generated for all instances of this method will be the same, and so the compiler only need emit one copy of exchange and reuse it for all calls. Even if exchange operated opaquely on types and structures rather than pointers it would only need one instance for types sizeof == 4, one for types sizeof == 8 etc. Rup. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 1:00 ` Rupert Wood 2008-04-30 1:17 ` OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) Robert William Fuller @ 2008-04-30 4:46 ` Evan Jones 2008-04-30 10:13 ` Andrew Haley 1 sibling, 1 reply; 22+ messages in thread From: Evan Jones @ 2008-04-30 4:46 UTC (permalink / raw) To: Rupert Wood; +Cc: gcc-help Rupert Wood wrote: > I don't know how to fight aliasing rules but as another approach you > could template the function instead, i.e. > > template<typename T> T* exchange(T** ptr, T* next); > > exchange<int>(&a, &v2); > > since you're using C++ here. I initially dismissed this solution since the implementation of exchange is either a typical swap using a temporary, a compare-and-swap sequence or a mutex, depending on various compilation options. I wanted to avoid including the implementation in the header to avoid a bunch of #ifdefs. However, your email made me try to avoid the warning with a template wrapper: template <typename T> T* exchange_template(T** ptr, T* next) { return reinterpret_cast<T*>( exchange(reinterpret_cast<void**>(ptr), next)); } ... exchange_template(&a, &v2); I don't understand why, but this compiles without warnings. It also avoids needing to look up the aliasing rules, and places the dangerous cast in a single location, so this seems like a better solution. I would still like to know if my original solution is "correct" or not, since it would be needed for C. Evan Jones -- Evan Jones http://evanjones.ca/ ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 4:46 ` strict aliasing: how to swap pointers Evan Jones @ 2008-04-30 10:13 ` Andrew Haley 2008-04-30 11:45 ` Andrew Haley 2008-04-30 14:43 ` Evan Jones 0 siblings, 2 replies; 22+ messages in thread From: Andrew Haley @ 2008-04-30 10:13 UTC (permalink / raw) To: Evan Jones; +Cc: Rupert Wood, gcc-help Evan Jones wrote: > Rupert Wood wrote: >> I don't know how to fight aliasing rules but as another approach you >> could template the function instead, i.e. >> >> template<typename T> T* exchange(T** ptr, T* next); >> >> exchange<int>(&a, &v2); >> >> since you're using C++ here. > > I initially dismissed this solution since the implementation of exchange > is either a typical swap using a temporary, a compare-and-swap sequence > or a mutex, depending on various compilation options. I wanted to avoid > including the implementation in the header to avoid a bunch of #ifdefs. > However, your email made me try to avoid the warning with a template > wrapper: > > > template <typename T> > T* exchange_template(T** ptr, T* next) { > return reinterpret_cast<T*>( > exchange(reinterpret_cast<void**>(ptr), next)); > } > > ... > > exchange_template(&a, &v2); > > > I don't understand why, but this compiles without warnings. It also > avoids needing to look up the aliasing rules, and places the dangerous > cast in a single location, so this seems like a better solution. > > I would still like to know if my original solution is "correct" or not, > since it would be needed for C. We have no way to know, since you didn't provide us with the source of exchange(), and that's where the aliasing violation, if any, would occur. However, the answer is almost certainly no. I don't know why you're trying to do something so simple in such a difficult way. If you really want to do this in standard portable C, the easiest way is a macro: #define SWAP(TYPE, A, B) do { TYPE tmp = a; b = b; b = tmp; } while (0) You can't portably cast a pointer to an int* to a pointer to a void* and then dereference the resulting pointers since the things they point to might not even be the same size. The union hack will work on gcc, though. Andrew. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 10:13 ` Andrew Haley @ 2008-04-30 11:45 ` Andrew Haley 2008-04-30 13:31 ` Jędrzej Dudkiewicz 2008-04-30 14:43 ` Evan Jones 1 sibling, 1 reply; 22+ messages in thread From: Andrew Haley @ 2008-04-30 11:45 UTC (permalink / raw) To: Evan Jones; +Cc: Rupert Wood, gcc-help Andrew Haley wrote: > Evan Jones wrote: >> Rupert Wood wrote: >>> I don't know how to fight aliasing rules but as another approach you >>> could template the function instead, i.e. >>> >>> template<typename T> T* exchange(T** ptr, T* next); >>> >>> exchange<int>(&a, &v2); >>> >>> since you're using C++ here. >> I initially dismissed this solution since the implementation of exchange >> is either a typical swap using a temporary, a compare-and-swap sequence >> or a mutex, depending on various compilation options. I wanted to avoid >> including the implementation in the header to avoid a bunch of #ifdefs. >> However, your email made me try to avoid the warning with a template >> wrapper: >> >> >> template <typename T> >> T* exchange_template(T** ptr, T* next) { >> return reinterpret_cast<T*>( >> exchange(reinterpret_cast<void**>(ptr), next)); >> } >> >> ... >> >> exchange_template(&a, &v2); >> >> >> I don't understand why, but this compiles without warnings. It also >> avoids needing to look up the aliasing rules, and places the dangerous >> cast in a single location, so this seems like a better solution. >> >> I would still like to know if my original solution is "correct" or not, >> since it would be needed for C. > > We have no way to know, since you didn't provide us with the source of > exchange(), and that's where the aliasing violation, if any, would > occur. > > However, the answer is almost certainly no. I don't know why you're > trying to do something so simple in such a difficult way. If you really > want to do this in standard portable C, the easiest way is a macro: > > #define SWAP(TYPE, A, B) do { TYPE tmp = a; b = b; b = tmp; } while (0) Err, #define SWAP(TYPE, A, B) do { TYPE tmp = a; a = b; b = tmp; } while (0) > > You can't portably cast a pointer to an int* to a pointer to a void* > and then dereference the resulting pointers since the things they point > to might not even be the same size. The union hack will work on gcc, > though. > > Andrew. > > ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 11:45 ` Andrew Haley @ 2008-04-30 13:31 ` Jędrzej Dudkiewicz 2008-04-30 14:29 ` Andrew Haley 0 siblings, 1 reply; 22+ messages in thread From: Jędrzej Dudkiewicz @ 2008-04-30 13:31 UTC (permalink / raw) To: gcc-help > > #define SWAP(TYPE, A, B) do { TYPE tmp = a; b = b; b = tmp; } while (0) > > Err, > #define SWAP(TYPE, A, B) do { TYPE tmp = a; a = b; b = tmp; } while (0) Seems that #define SWAP(TYPE, A, B) do { TYPE tmp = A; A = B; B = tmp; } while (0) would be even better. -- Jędrzej Dudkiewicz I really hate this damn machine, I wish that they would sell it. It never does just what I want, but only what I tell it. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 13:31 ` Jędrzej Dudkiewicz @ 2008-04-30 14:29 ` Andrew Haley 0 siblings, 0 replies; 22+ messages in thread From: Andrew Haley @ 2008-04-30 14:29 UTC (permalink / raw) To: gcc-help JÄdrzej Dudkiewicz wrote: >> > #define SWAP(TYPE, A, B) do { TYPE tmp = a; b = b; b = tmp; } while (0) >> >> Err, >> #define SWAP(TYPE, A, B) do { TYPE tmp = a; a = b; b = tmp; } while (0) > > Seems that > > #define SWAP(TYPE, A, B) do { TYPE tmp = A; A = B; B = tmp; } while (0) > > would be even better. No kidding. :-) Andrew. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 10:13 ` Andrew Haley 2008-04-30 11:45 ` Andrew Haley @ 2008-04-30 14:43 ` Evan Jones 2008-04-30 14:49 ` John Love-Jensen 2008-04-30 15:22 ` Andrew Haley 1 sibling, 2 replies; 22+ messages in thread From: Evan Jones @ 2008-04-30 14:43 UTC (permalink / raw) To: Andrew Haley, Sergei Organov; +Cc: gcc-help On Apr 30, 2008, at 4:55 , Andrew Haley wrote: > We have no way to know, since you didn't provide us with the source of > exchange(), and that's where the aliasing violation, if any, would > occur. Oops! Sorry, I meant to. The simplest implementation is a swap using a temporary: void* exchange(void** ptr, void* next) { void* old = *ptr; *ptr = next; return old; } > However, the answer is almost certainly no. I don't know why you're > trying to do something so simple in such a difficult way. If you really > want to do this in standard portable C, the easiest way is a macro: I have implementations of exchange() that either use a temporary, a compare-and-swap, a load-linked/store-conditional, or a mutex. There is some project-specific configuration to link against the appropriate implementation. On Apr 30, 2008, at 12:18, Sergei Organov wrote: > Now, here is a solution that does not break strict aliasing rules: > > $ cat alias.cc > #include <cstdio> > #include <cstring> > > using namespace std; > > void swap(void* p1, void* p2) > { > void* t; > memcpy(&t, p1, sizeof(t)); > memcpy(p1, p2, sizeof(t)); > memcpy(p2, &t, sizeof(t)); > } This seems reasonable. In my version, I would simply return t, rather than using the last memcpy. What is confusing to me about the strict aliasing warning is that I thought GCC must conservatively assume that a void* pointer can point to anything, since T* is convertible to void*. Hence, it seems to me that casting a T** to void** should not result in a type-punning warning. Additionally I'm confused because the warning is quite "fragile." This causes the warning: void** voidptrptr = reinterpret_cast<void**>(&intptr); This does not: int** intptrptr = &intptr; void** voidptrptr = reinterpret_cast<void**>(intptrptr); To me, these appear to be equivalent. Thanks for the help, I appreciate it. Evan Jones -- Evan Jones http://evanjones.ca/ ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 14:43 ` Evan Jones @ 2008-04-30 14:49 ` John Love-Jensen 2008-04-30 15:15 ` Evan Jones 2008-04-30 15:22 ` Andrew Haley 1 sibling, 1 reply; 22+ messages in thread From: John Love-Jensen @ 2008-04-30 14:49 UTC (permalink / raw) To: Evan Jones; +Cc: GCC-help Hi Evan, > What is confusing to me about the strict aliasing warning is that I > thought GCC must conservatively assume that a void* pointer can point to > anything, since T* is convertible to void*. Correct. > Hence, it seems to me that casting a T** to void** should not result in a > type-punning warning. void** is not void*. HTH, --Eljay ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 14:49 ` John Love-Jensen @ 2008-04-30 15:15 ` Evan Jones 2008-04-30 15:33 ` Andrew Haley 0 siblings, 1 reply; 22+ messages in thread From: Evan Jones @ 2008-04-30 15:15 UTC (permalink / raw) To: John Love-Jensen; +Cc: GCC-help John Love-Jensen wrote: > void** is not void*. Ah, of course. So with strict aliasing, GCC assumes that a void** pointer only points to variables of exactly type void*? This would explain my confusion. I was assuming that since T* is convertible to void*, void** can point to any T*. It makes sense that this is not true. I wish I could get GCC to generate a "surprising" optimization for a void**/T** type pun, but I have been unable to do so. This, of course, doesn't mean that ignoring the warning is safe. It seems to me that the lesson for me is that when doing low-level type-unsafe manipulation, void* pointers should be used. Since GCC must assume that void* pointers can point anywhere, it will not be able to optimize away the accesses to them, which is what I want in this case. Please correct me if I am wrong about this. Thanks, Evan -- Evan Jones http://evanjones.ca/ ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 15:15 ` Evan Jones @ 2008-04-30 15:33 ` Andrew Haley 2008-04-30 18:01 ` Evan Jones 0 siblings, 1 reply; 22+ messages in thread From: Andrew Haley @ 2008-04-30 15:33 UTC (permalink / raw) To: Evan Jones; +Cc: John Love-Jensen, GCC-help Evan Jones wrote: > John Love-Jensen wrote: >> void** is not void*. > > Ah, of course. So with strict aliasing, GCC assumes that a void** > pointer only points to variables of exactly type void*? This would > explain my confusion. I was assuming that since T* is convertible to > void*, void** can point to any T*. It makes sense that this is not true. > > I wish I could get GCC to generate a "surprising" optimization for a > void**/T** type pun, but I have been unable to do so. This, of course, > doesn't mean that ignoring the warning is safe. > > It seems to me that the lesson for me is that when doing low-level > type-unsafe manipulation, void* pointers should be used. Since GCC must > assume that void* pointers can point anywhere, it will not be able to > optimize away the accesses to them, which is what I want in this case. > Please correct me if I am wrong about this. gcc will look through temporaries of type void* if the information is visible. So, trying to defeat the type system by using void* variable as temporaries doesnt work because gcc will simply delete any pointless temporaries. so, this: int *sp = &int_var; void *vp = sp; *(short*)vp = 22; is undefined behaviour, and may well not do what you want. Andrew. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 15:33 ` Andrew Haley @ 2008-04-30 18:01 ` Evan Jones 2008-04-30 20:38 ` Andrew Haley 2008-04-30 21:49 ` Sergei Organov 0 siblings, 2 replies; 22+ messages in thread From: Evan Jones @ 2008-04-30 18:01 UTC (permalink / raw) To: Andrew Haley; +Cc: GCC-help Andrew Haley wrote: > so, this: > > int *sp = &int_var; > void *vp = sp; > *(short*)vp = 22; > > is undefined behaviour, and may well not do what you want. Ignoring platform specific issues like byte order and size, is it safe to use memcpy instead? Example: int *sp = &int_var; void *vp = sp; short value = 22; memcpy(vp, &value, sizeof(value)); In my experiments with strict aliasing and GCC, replacing accesses like this with memcpy resolves the problem, even when GCC inlines the memcpy into a simple load/store. It seems to me that this should be okay, since the write through a void pointer is permitted to alias anything? Or is the only safe way to use the mayalias attribute? I think I'm starting to understand why many people insist on using -fno-strict-aliasing. Evan -- Evan Jones http://evanjones.ca/ ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 18:01 ` Evan Jones @ 2008-04-30 20:38 ` Andrew Haley 2008-04-30 21:49 ` Sergei Organov 1 sibling, 0 replies; 22+ messages in thread From: Andrew Haley @ 2008-04-30 20:38 UTC (permalink / raw) To: Evan Jones; +Cc: GCC-help Evan Jones wrote: > Andrew Haley wrote: >> so, this: >> >> int *sp = &int_var; >> void *vp = sp; >> *(short*)vp = 22; >> >> is undefined behaviour, and may well not do what you want. > > Ignoring platform specific issues like byte order and size, is it safe > to use memcpy instead? Example: > > int *sp = &int_var; > void *vp = sp; > short value = 22; > memcpy(vp, &value, sizeof(value)); This is okay, albeit non-portable. > In my experiments with strict aliasing and GCC, replacing accesses like > this with memcpy resolves the problem, even when GCC inlines the memcpy > into a simple load/store. It seems to me that this should be okay, since > the write through a void pointer is permitted to alias anything? It's okay if and only if you're not doing anything with pointers to incompatible types. > Or is the only safe way to use the mayalias attribute? > > I think I'm starting to understand why many people insist on using > -fno-strict-aliasing. Why not write in Standard C? I don't understand this determination to try to subvert the type system via pointers. What application actually needs it? If you *really* need to access the bits in a float you can do that via a union. Andrew. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 18:01 ` Evan Jones 2008-04-30 20:38 ` Andrew Haley @ 2008-04-30 21:49 ` Sergei Organov 1 sibling, 0 replies; 22+ messages in thread From: Sergei Organov @ 2008-04-30 21:49 UTC (permalink / raw) To: gcc-help Evan Jones <evanj@MIT.EDU> writes: > Andrew Haley wrote: >> so, this: >> >> int *sp = &int_var; >> void *vp = sp; >> *(short*)vp = 22; >> >> is undefined behaviour, and may well not do what you want. > > Ignoring platform specific issues like byte order and size, is it safe > to use memcpy instead? Example: > > int *sp = &int_var; > void *vp = sp; > short value = 22; > memcpy(vp, &value, sizeof(value)); It's safe w.r.t. aliasing rules, provided memcpy() implementation is safe, and chances are high that memcpy() is safe ;) > In my experiments with strict aliasing and GCC, replacing accesses > like this with memcpy resolves the problem, even when GCC inlines the > memcpy into a simple load/store. It seems to me that this should be > okay, since the write through a void pointer is permitted to alias > anything? AFAIK, there is no way to write through void pointer ;) You need to cast to something else before writing anyway. It's "[[un]signed] char *" that you can use to write to and read from anything. This is what makes it possible to implement memcpy() in C/C++. -- Sergei. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 14:43 ` Evan Jones 2008-04-30 14:49 ` John Love-Jensen @ 2008-04-30 15:22 ` Andrew Haley 2008-05-03 0:45 ` Matthew Woehlke 1 sibling, 1 reply; 22+ messages in thread From: Andrew Haley @ 2008-04-30 15:22 UTC (permalink / raw) To: Evan Jones; +Cc: Sergei Organov, gcc-help Evan Jones wrote: > On Apr 30, 2008, at 4:55 , Andrew Haley wrote: >> We have no way to know, since you didn't provide us with the source of >> exchange(), and that's where the aliasing violation, if any, would >> occur. > > Oops! Sorry, I meant to. The simplest implementation is a swap using a > temporary: > > void* exchange(void** ptr, void* next) { > void* old = *ptr; > *ptr = next; > return old; > } Ok, so you have an aliasing violation. >> However, the answer is almost certainly no. I don't know why you're >> trying to do something so simple in such a difficult way. If you really >> want to do this in standard portable C, the easiest way is a macro: > > I have implementations of exchange() that either use a temporary, a > compare-and-swap, a load-linked/store-conditional, or a mutex. There is > some project-specific configuration to link against the appropriate > implementation. OK, there is no way to do this in standard C. > On Apr 30, 2008, at 12:18, Sergei Organov wrote: >> Now, here is a solution that does not break strict aliasing rules: >> >> $ cat alias.cc >> #include <cstdio> >> #include <cstring> >> >> using namespace std; >> >> void swap(void* p1, void* p2) >> { >> void* t; >> memcpy(&t, p1, sizeof(t)); >> memcpy(p1, p2, sizeof(t)); >> memcpy(p2, &t, sizeof(t)); >> } > > This seems reasonable. In my version, I would simply return t, rather > than using the last memcpy. > > What is confusing to me about the strict aliasing warning is that I > thought GCC must conservatively assume that a void* pointer can point to > anything, since T* is convertible to void*. Hence, it seems to me that > casting a T** to void** should not result in a type-punning warning. It will. Consider an arch which has pointers to char (and void *) that are two words in size, and pointers to int that are one word in size. On such an arch your exchange() function won't work, which is one reason why you need a macro to do it in Standard C. > Additionally I'm confused because the warning is quite "fragile." This > causes the warning: > > void** voidptrptr = reinterpret_cast<void**>(&intptr); > > This does not: > > int** intptrptr = &intptr; > void** voidptrptr = reinterpret_cast<void**>(intptrptr); > > To me, these appear to be equivalent. Indeed. It's a heuristic, and it doesn't see all cases of aliasing violations. Andrew. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-30 15:22 ` Andrew Haley @ 2008-05-03 0:45 ` Matthew Woehlke 2008-05-03 9:10 ` Andrew Haley 0 siblings, 1 reply; 22+ messages in thread From: Matthew Woehlke @ 2008-05-03 0:45 UTC (permalink / raw) To: gcc-help Andrew Haley wrote: > Consider an arch which has pointers to char (and void *) that are two words > in size, and pointers to int that are one word in size. On such an arch > your exchange() function won't work, which is one reason why you need a macro > to do it in Standard C. What platforms are there where sizeof(T*) != sizeof(void*) for some T? -- Matthew First time I've gotten a programming job that required a drug test. I was worried they were going to say 'you don't have enough LSD in your system to do Unix programming'. -- Paul Tomblin (from cluefire.net) ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-05-03 0:45 ` Matthew Woehlke @ 2008-05-03 9:10 ` Andrew Haley 0 siblings, 0 replies; 22+ messages in thread From: Andrew Haley @ 2008-05-03 9:10 UTC (permalink / raw) To: Matthew Woehlke; +Cc: gcc-help Matthew Woehlke wrote: > Andrew Haley wrote: >> Consider an arch which has pointers to char (and void *) that are two >> words >> in size, and pointers to int that are one word in size. On such an arch >> your exchange() function won't work, which is one reason why you need >> a macro >> to do it in Standard C. > > What platforms are there where sizeof(T*) != sizeof(void*) for some T? I'm not sure: certainly nothing gcc supports, because gcc internally uses Pmode for all pointers. DEC-10 possibly, maybe others. And of course, some segmented architectures have pointers of different sizes. Andrew. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: strict aliasing: how to swap pointers 2008-04-29 23:58 strict aliasing: how to swap pointers Evan Jones 2008-04-30 1:00 ` Rupert Wood @ 2008-04-30 9:03 ` Sergei Organov 1 sibling, 0 replies; 22+ messages in thread From: Sergei Organov @ 2008-04-30 9:03 UTC (permalink / raw) To: gcc-help Evan Jones <evanj@MIT.EDU> writes: > I have a function to swap any two pointers (assuming that > sizeof(void*) == sizeof(T*)). I would like to use it without violating > strict aliasing rules. Violation (or not) of strict aliasing rules is *inside* the swap function. It's at the time when you access objects the aliasing rules apply, not at the time of conversion of pointer types. As you didn't show the code of your exchange() function, it's impossible to say if you violate strict aliasing or not, though I somehow feel you do. > I have a workaround, but I would like to verify that this is the right > way to do this. > > The test case: > > void* exchange(void** ptr, void* next); I'd expect a function to swap two pointers to have prototype of the form: void exchange(void** p1, void** p2); doing something like that: { void* t = *p1; *p1 = *p2; *p2 = t; } However, your prototype is rather different. Now, here is a solution that does not break strict aliasing rules: $ cat alias.cc #include <cstdio> #include <cstring> using namespace std; void swap(void* p1, void* p2) { void* t; memcpy(&t, p1, sizeof(t)); memcpy(p1, p2, sizeof(t)); memcpy(p2, &t, sizeof(t)); } int main() { int v1 = 42; int v2 = 123; int* a = &v1; int* b = &v2; int before = *a; swap(&a, &b); int after = *a; printf("before: %d after: %d\n", before, after); return 0; } $ g++-4.1 -O2 -W -Wall -o alias alias.cc $ ./alias before: 42 after: 123 $ Please note that GCC is capable to optimize-out memcpy() calls, so the resulting code should be rather optimal. -- Sergei. ^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2008-05-03 9:10 UTC | newest] Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-04-29 23:58 strict aliasing: how to swap pointers Evan Jones 2008-04-30 1:00 ` Rupert Wood 2008-04-30 1:17 ` OT Rant on why C++ Sucks (Was Re: strict aliasing: how to swap pointers) Robert William Fuller 2008-04-30 3:03 ` Gareth Buxton 2008-04-30 7:59 ` me22 2008-04-30 10:21 ` Rupert Wood 2008-04-30 4:46 ` strict aliasing: how to swap pointers Evan Jones 2008-04-30 10:13 ` Andrew Haley 2008-04-30 11:45 ` Andrew Haley 2008-04-30 13:31 ` Jędrzej Dudkiewicz 2008-04-30 14:29 ` Andrew Haley 2008-04-30 14:43 ` Evan Jones 2008-04-30 14:49 ` John Love-Jensen 2008-04-30 15:15 ` Evan Jones 2008-04-30 15:33 ` Andrew Haley 2008-04-30 18:01 ` Evan Jones 2008-04-30 20:38 ` Andrew Haley 2008-04-30 21:49 ` Sergei Organov 2008-04-30 15:22 ` Andrew Haley 2008-05-03 0:45 ` Matthew Woehlke 2008-05-03 9:10 ` Andrew Haley 2008-04-30 9:03 ` Sergei Organov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).