[4/5] sim/erc32: avoid dereferencing type-punned pointer warnings

Message ID b36f2b9339266fdef2e34970f932782925744ba4.1665578246.git.aburgess@redhat.com
State New
Headers
Series Silence some build warnings in various simulators |

Commit Message

Andrew Burgess Oct. 12, 2022, 12:38 p.m. UTC
  When building the erc32 simulator I get a few warnings like this:

  /tmp/build/sim/../../src/sim/erc32/exec.c:1377:21: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   1377 |   sregs->fs[rd] = *((float32 *) & ddata[0]);
        |                    ~^~~~~~~~~~~~~~~~~~~~~~~

The type of '& ddata[0]' will be 'uint32_t *', which is what triggers
the warning.

This commit uses an intermediate pointer of type 'char *' when
performing the type-punning, which is well-defined behaviour, and will
silence the above warning.

With this change, I now see no warnings when compiling exec.c, which
means that the line in Makefile.in that disables -Werror can be
removed.

There should be no change in behaviour after this commit.
---
 sim/erc32/Makefile.in |  3 ---
 sim/erc32/exec.c      | 12 +++++++++---
 2 files changed, 9 insertions(+), 6 deletions(-)
  

Comments

Pedro Alves Oct. 12, 2022, 2:11 p.m. UTC | #1
On 2022-10-12 1:38 p.m., Andrew Burgess via Gdb-patches wrote:
> When building the erc32 simulator I get a few warnings like this:
> 
>   /tmp/build/sim/../../src/sim/erc32/exec.c:1377:21: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
>    1377 |   sregs->fs[rd] = *((float32 *) & ddata[0]);
>         |                    ~^~~~~~~~~~~~~~~~~~~~~~~
> 
> The type of '& ddata[0]' will be 'uint32_t *', which is what triggers
> the warning.
> 
> This commit uses an intermediate pointer of type 'char *' when
> performing the type-punning, which is well-defined behaviour, and will
> silence the above warning.

I'm afraid that's not correct.  That's still undefined behavior, it's just silencing
the warning.  The end result is still aliasing float32 and uint32_t objects, and risks
generating bogus code.  The char escape hatch only works if you access the object
representation via a character type.  Here, the patch is still accessing the object
representation of a uint32_t object via a floa32 type.

Here's an old article explaining strict aliasing (just one that I found via a quick google):

  https://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html

This scenario is the "CASTING TO CHAR*" one in that article.

> @@ -1345,7 +1345,8 @@ dispatch_instruction(struct pstate *sregs)
>  	    if (mexc) {
>  		sregs->trap = TRAP_DEXC;
>  	    } else {
> -		sregs->fs[rd] = *((float32 *) & data);
> +		char *ptr = (char *) &data;
> +		sregs->fs[rd] = *((float32 *) ptr);

The best IMHO is to do the type punning via a union, like e.g.:

  union { float32 f; uint32_t i; } u;
  u.i = data;
  sregs->fs[rd] = u.f;

See here in the C11 standard:

 https://port70.net/~nsz/c/c11/n1570.html#note95

and also the documentation of -fstrict-aliasing at:

  https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

Pedro Alves
  
Lancelot SIX Oct. 12, 2022, 5:02 p.m. UTC | #2
On Wed, Oct 12, 2022 at 03:11:27PM +0100, Pedro Alves wrote:
> On 2022-10-12 1:38 p.m., Andrew Burgess via Gdb-patches wrote:
> > When building the erc32 simulator I get a few warnings like this:
> > 
> >   /tmp/build/sim/../../src/sim/erc32/exec.c:1377:21: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
> >    1377 |   sregs->fs[rd] = *((float32 *) & ddata[0]);
> >         |                    ~^~~~~~~~~~~~~~~~~~~~~~~
> > 
> > The type of '& ddata[0]' will be 'uint32_t *', which is what triggers
> > the warning.
> > 
> > This commit uses an intermediate pointer of type 'char *' when
> > performing the type-punning, which is well-defined behaviour, and will
> > silence the above warning.
> 
> I'm afraid that's not correct.  That's still undefined behavior, it's just silencing
> the warning.  The end result is still aliasing float32 and uint32_t objects, and risks
> generating bogus code.  The char escape hatch only works if you access the object
> representation via a character type.  Here, the patch is still accessing the object
> representation of a uint32_t object via a floa32 type.
> 
> Here's an old article explaining strict aliasing (just one that I found via a quick google):
> 
>   https://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
> 
> This scenario is the "CASTING TO CHAR*" one in that article.
> 
> > @@ -1345,7 +1345,8 @@ dispatch_instruction(struct pstate *sregs)
> >  	    if (mexc) {
> >  		sregs->trap = TRAP_DEXC;
> >  	    } else {
> > -		sregs->fs[rd] = *((float32 *) & data);
> > +		char *ptr = (char *) &data;
> > +		sregs->fs[rd] = *((float32 *) ptr);
> 
> The best IMHO is to do the type punning via a union, like e.g.:
> 
>   union { float32 f; uint32_t i; } u;
>   u.i = data;
>   sregs->fs[rd] = u.f;
> 
> See here in the C11 standard:
> 
>  https://port70.net/~nsz/c/c11/n1570.html#note95
> 
> and also the documentation of -fstrict-aliasing at:
> 
>   https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
> 

Hi,

Another well defined (at least to my knowledge) solution to this problem
is memcpy.  You could do something like:

  memcpy (&sregt->fs[rd], ddata, sizeof (float32));

I tend to find this more straightforward than the type punning version,
but I would be happy with either.

Best,
Lancelot.

> Pedro Alves
  
Mike Frysinger Oct. 23, 2022, 12:34 p.m. UTC | #3
On 12 Oct 2022 13:38, Andrew Burgess via Gdb-patches wrote:
> When building the erc32 simulator I get a few warnings like this:
> 
>   /tmp/build/sim/../../src/sim/erc32/exec.c:1377:21: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
>    1377 |   sregs->fs[rd] = *((float32 *) & ddata[0]);
>         |                    ~^~~~~~~~~~~~~~~~~~~~~~~
> 
> The type of '& ddata[0]' will be 'uint32_t *', which is what triggers
> the warning.
> 
> This commit uses an intermediate pointer of type 'char *' when
> performing the type-punning, which is well-defined behaviour, and will
> silence the above warning.

this is kind of a poor fix.  if we can't arrange for the pointers to be
the right type, at least a memcpy would be better.
-mike
  
Andrew Burgess Oct. 24, 2022, 3:42 p.m. UTC | #4
Mike Frysinger <vapier@gentoo.org> writes:

> On 12 Oct 2022 13:38, Andrew Burgess via Gdb-patches wrote:
>> When building the erc32 simulator I get a few warnings like this:
>> 
>>   /tmp/build/sim/../../src/sim/erc32/exec.c:1377:21: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
>>    1377 |   sregs->fs[rd] = *((float32 *) & ddata[0]);
>>         |                    ~^~~~~~~~~~~~~~~~~~~~~~~
>> 
>> The type of '& ddata[0]' will be 'uint32_t *', which is what triggers
>> the warning.
>> 
>> This commit uses an intermediate pointer of type 'char *' when
>> performing the type-punning, which is well-defined behaviour, and will
>> silence the above warning.
>
> this is kind of a poor fix.  if we can't arrange for the pointers to be
> the right type, at least a memcpy would be better.

This was already discussed in this thread:

  https://sourceware.org/pipermail/gdb-patches/2022-October/192604.html

The version that got pushed:

  https://sourceware.org/pipermail/gdb-patches/2022-October/192647.html

does make use of memcpy.

Thanks,
Andrew
  

Patch

diff --git a/sim/erc32/Makefile.in b/sim/erc32/Makefile.in
index 786ae1dcc7b..41830aab726 100644
--- a/sim/erc32/Makefile.in
+++ b/sim/erc32/Makefile.in
@@ -32,9 +32,6 @@  SIM_EXTRA_CLEAN = clean-sis
 # behaviour of UART interrupt routines ...
 SIM_EXTRA_CFLAGS += -DFAST_UART -I$(srcroot)
 
-# Some modules don't build cleanly yet.
-exec.o: SIM_WERROR_CFLAGS =
-
 ## COMMON_POST_CONFIG_FRAG
 
 # `sis' doesn't need interf.o.
diff --git a/sim/erc32/exec.c b/sim/erc32/exec.c
index ef93692e7a2..af9ad9ea9ab 100644
--- a/sim/erc32/exec.c
+++ b/sim/erc32/exec.c
@@ -1345,7 +1345,8 @@  dispatch_instruction(struct pstate *sregs)
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
 	    } else {
-		sregs->fs[rd] = *((float32 *) & data);
+		char *ptr = (char *) &data;
+		sregs->fs[rd] = *((float32 *) ptr);
 	    }
 	    break;
 	case LDDF:
@@ -1371,13 +1372,18 @@  dispatch_instruction(struct pstate *sregs)
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
 	    } else {
+		char *ptr;
+
 		rd &= 0x1E;
 		sregs->flrd = rd;
-		sregs->fs[rd] = *((float32 *) & ddata[0]);
+
+		ptr = (char *) &ddata[0];
+		sregs->fs[rd] = *((float32 *) ptr);
 #ifdef STAT
 		sregs->nload++;	/* Double load counts twice */
 #endif
-		sregs->fs[rd + 1] = *((float32 *) & ddata[1]);
+		ptr = (char *) &ddata[1];
+		sregs->fs[rd + 1] = *((float32 *) ptr);
 		sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD +
 			       sregs->hold + sregs->fhold;
 	    }