[PATCH v2] Silence misguided GCC warning about alignment issues

Daniel Thompson daniel.thompson at linaro.org
Mon Aug 14 11:12:32 UTC 2017


On 07/08/17 21:58, Johannes Schindelin wrote:
> When compiling xz_dec_stream.c with GCC (at least with versions 5.4.0
> and 7.1.0), it complains thusly:
> 
> 	In function 'dec_stream_footer':
> 	error: dereferencing type-punned pointer will break
> 	      strict-aliasing rules [-Werror=strict-aliasing]
> 	   if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
> 	       ^~

A different title might be better.

This is *not* a warning about alignment issue; it is a warning about a 
potential aliasing issue: two pointers of different (non-char) types 
that could point to the same memory.


Daniel.


> 
> Despite the arrow pointing to the xz_crc32() call, the actual problem is
> the get_le32() macro expansion.
> 
> The thing is, the `buf` field was put just after two fields of type
> size_t for the express purpose of avoiding alignment issues, as per the
> comment above the `temp` struct >
> Meaning: GCC gets this all wrong and should not complain.
> 
> An earlier attempt to fix (76b65624b (unxz: get_le32
> macro is obviously wrong, 2017-08-07)) this by simply forcing
> get_unaligned_32() (which is unnecessarily slow because it rebuilds a
> 32-bit int from accessing already-aligned bytes one by one) was a bit
> heavy-handed.
> 
> But we can help GCC by turning the get_le32() macro into an inline
> function. So let's do that, it also helps compile time safety by making
> the code a little bit stricter.
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin at gmx.de>
> ---
> Published-As: https://github.com/dscho/busybox-w32/releases/tag/busybox-type-punned-warning-v2
> Fetch-It-Via: git fetch https://github.com/dscho/busybox-w32 busybox-type-punned-warning-v2
> 
> Interdiff vs v1:
>   diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
>   index 0be85500c..e24cff98b 100644
>   --- a/archival/libarchive/decompress_unxz.c
>   +++ b/archival/libarchive/decompress_unxz.c
>   @@ -37,6 +37,11 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
>     || !defined(put_unaligned_be32)
>    # error get_unaligned_le32 accessors are not defined
>    #endif
>   +static ALWAYS_INLINE uint32_t get_le32_fast(const void *p)
>   +{
>   +  return *(uint32_t *)p;
>   +}
>   +#define get_le32 get_le32_fast
>    
>    #include "unxz/xz_dec_bcj.c"
>    #include "unxz/xz_dec_lzma2.c"
>   diff --git a/archival/libarchive/unxz/xz_dec_stream.c b/archival/libarchive/unxz/xz_dec_stream.c
>   index 8131ee30a..bf791055b 100644
>   --- a/archival/libarchive/unxz/xz_dec_stream.c
>   +++ b/archival/libarchive/unxz/xz_dec_stream.c
>   @@ -423,15 +423,6 @@ static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s)
>    	if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
>    		return XZ_DATA_ERROR;
>    
>   -#if defined(__GNUC__)
>   -	/*
>   -	 * The temp.buf field is put just after two fields of type size_t for
>   -	 * the express purpose of avoiding alignment issues. But GCC complains
>   -	 * about it nevertheless... so: shut GCC up for a few lines.
>   -	 */
>   -#pragma GCC diagnostic push
>   -#pragma GCC diagnostic ignored "-Wstrict-aliasing"
>   -#endif
>    	if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
>    		return XZ_DATA_ERROR;
>    
>   @@ -442,9 +433,6 @@ static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s)
>    	 */
>    	if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
>    		return XZ_DATA_ERROR;
>   -#if defined(__GNUC__)
>   -#pragma GCC diagnostic pop
>   -#endif
>    
>    	if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
>    		return XZ_DATA_ERROR;
>   archival/libarchive/decompress_unxz.c | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
> index 0be85500c..e24cff98b 100644
> --- a/archival/libarchive/decompress_unxz.c
> +++ b/archival/libarchive/decompress_unxz.c
> @@ -37,6 +37,11 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
>    || !defined(put_unaligned_be32)
>   # error get_unaligned_le32 accessors are not defined
>   #endif
> +static ALWAYS_INLINE uint32_t get_le32_fast(const void *p)
> +{
> +  return *(uint32_t *)p;
> +}
> +#define get_le32 get_le32_fast
>   
>   #include "unxz/xz_dec_bcj.c"
>   #include "unxz/xz_dec_lzma2.c"
> 
> base-commit: a907b828d6e9f1357fc2e1db09d3eb1d3fb9b826
> 



More information about the busybox mailing list