GCC 可能未初始化警告 - 误报?

问题描述 投票:0回答:0

我花了一天时间尝试调试 GCC 12.2 中的

maybe-uninitialized
警告。我终于将代码缩减为一个最小的可重现示例,表明该警告是误报。

下面的程序为四个“桶”分配内存,每个桶存储一个整数标志和一个字符指针,它们将通过指针算法访问。然后它将每个桶中的整数标志设置为

0
。然后它无限循环遍历每个桶并仅当标志为
1
时才打印字符指针指向的(假设的)字符串。由于所有标志都设置为
0
,因此不会打印任何内容。

#include <stdlib.h>
#include <stdalign.h>
#include <stdio.h>
#include <stddef.h>

// Diagram of layout of one bucket
// +---------+-----------------------------+---------+-----------------------------------+
// |   int   | padding to alignof( char* ) |  char*  | padding to alignof( max_align_t ) |
// +---------+-----------------------------+---------+-----------------------------------+

// Macros to describe layout
#define ROUND_UP( num, multiple ) ( ( ( num + multiple - 1 ) / multiple ) * multiple )
#define CHAR_PTR_OFFSET ROUND_UP( sizeof( int ), alignof( char* ) )
#define BUCKET_SIZE ROUND_UP( CHAR_PTR_OFFSET + sizeof( char* ), alignof( max_align_t ) )

int main( void )
{
  // Allocate memory for four buckets
  char *data = malloc( BUCKET_SIZE * 4 );
  if( !data )
    return 1;
  
  // Set the int in each bucket to 0
  for( size_t i = 0; i < 4; ++i )
    *( int* )( data + BUCKET_SIZE * i ) = 0;
  
  // Loop over all four buckets infinitely,
  // dereferencing the char pointer in each one ONLY IF the integer is not zero (i.e. never)
  for( size_t i = 0; ; i = ( i + 1 ) % 4 )
    if( *( int* )( data + BUCKET_SIZE * i ) == 1 )
      puts( *( char** )( data + BUCKET_SIZE * i + CHAR_PTR_OFFSET ) );
  
  return 0;
}

GCC 与

-std=c11 -O3 -pedantic -Wall
生成以下警告:

31:7: warning: '*data_17 + _6' may be used uninitialized [-Wmaybe-uninitialized]
31 |       puts( *( char** )( data + BUCKET_SIZE * i + CHAR_PTR_OFFSET ) );

如果我用

for( size_t i = 0; ; i = ( i + 1 ) % 4 )
替换
for( size_t i = 0; i < 4; ++i )
,警告就会消失。似乎当循环是无限的(或者,在我的实际项目中,由于与
i
无关的某些条件而中止),GCC 无法检测到
*( int* )( data + BUCKET_SIZE * i ) == 1
将始终评估为 false,因此从未访问过 char 指针或取消引用。

我说 GCC 在这里产生误报是对的,还是我遗漏了什么?

c gcc gcc-warning
© www.soinside.com 2019 - 2024. All rights reserved.