使用-O3优化和奇数间距填充16bpp图像时崩溃

时间:2013-02-19 10:51:42

标签: c++ optimization g++

我编写了一个非常简单的代码来填充具有常量值(1024)的32x32 16bpp图像。图像缓冲区由std::vector托管。我的图像的音高/步幅(即两个连续行之间的字节数)足够大以容纳整行,但设置为奇数。这是我的代码:

#include <vector>
#include <stdint.h>

int main()
{
  int width = 32;
  int height = 32;
  int pitch = width * 2 + 1;

  std::vector<uint8_t> image(height * pitch);
  uint8_t* buffer = &image[0];

  for (int y = 0; y < height; y++)
  {
    uint16_t* p = reinterpret_cast<uint16_t*>(buffer + y * pitch);
    for (int x = 0; x < width; x++, p++)
    {
      *p = 1024;
    }
  }
}

我正在使用Linux x86_64和gcc 4.6.1(Ubuntu 11.10)。该代码可以使用-O0-O1-O2优化级别运行正常。 Valgrind不会报告任何访问冲突。但是,只要我切换到-O3或使用 -ftree-vectorize选项进行自动矢量化,程序就会崩溃:

# g++ -g -O3 ./test.cpp -Wall -pedantic && ./a.out
Segmentation fault

# g++ -g -O2 -ftree-vectorize ./test.cpp -Wall -pedantic && ./a.out
Segmentation fault

gdb和valgrind都没有提供任何有用的信息:

# valgrind ./a.out
==3840== Memcheck, a memory error detector
==3840== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==3840== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==3840== Command: ./a.out
==3840== 
==3840== 
==3840== Process terminating with default action of signal 11 (SIGSEGV)
==3840==  General Protection Fault
==3840==    at 0x4005B3: main (test.cpp:18)
==3840== 
==3840== HEAP SUMMARY:
==3840==     in use at exit: 2,080 bytes in 1 blocks
==3840==   total heap usage: 1 allocs, 0 frees, 2,080 bytes allocated
==3840== 
==3840== LEAK SUMMARY:
==3840==    definitely lost: 2,080 bytes in 1 blocks
==3840==    indirectly lost: 0 bytes in 0 blocks
==3840==      possibly lost: 0 bytes in 0 blocks
==3840==    still reachable: 0 bytes in 0 blocks
==3840==         suppressed: 0 bytes in 0 blocks
==3840== Rerun with --leak-check=full to see details of leaked memory
==3840== 
==3840== For counts of detected and suppressed errors, rerun with: -v
==3840== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
Segmentation fault

当我切换到带有-m32 gcc标志的32位二进制文​​件时,不会发生崩溃。如果我使用偶数音高(例如pitch = width * 2 + 2),它也不会发生。任何人都可以帮我发现我在代码中犯的(当然是愚蠢的)错误吗?非常感谢提前!


更新:正如Jonathan所建议的,我刚刚向GCC开发者报告了这个问题: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56392

1 个答案:

答案 0 :(得分:4)

Richard Blener在gcc Bugzilla

上回答了我的问题
  

“您正在取消引用指向uint16_t的指针,该指针与该类型没有充分对齐.C标准禁止此操作,导致未定义的行为。”

在我看来,应该生成有关此未定义行为的警告。另请注意,@ jmetcalfe在本文的评论中也给出了这种解释。