public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* 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: 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: 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: 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

* 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: 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 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 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: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 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

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).