Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crash while filling a 16bpp image with -O3 optimization and odd pitch

I have written a very simple code to fill a 32x32 16bpp image with a constant value (1024). The image buffer is hosted by a std::vector. The pitch/stride of my image (i.e. the number of bytes between two successive lines) is large enough to hold an entire line, but is set an odd number. Here is my code:

#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;
    }
  }
}

I am using Linux x86_64 with gcc 4.6.1 (Ubuntu 11.10). The code runs fine with the -O0, -O1 and -O2 optimization levels. Valgrind does not report any access violation. However, as soon as I switch to -O3 or use the -ftree-vectorize option for auto-vectorization, the program crashes:

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

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

Neither gdb nor valgrind provide any helpful information:

# 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

The crash does not happen when I switch to 32bit binaries with the -m32 gcc flag. It does not occur either if I use an even pitch (e.g. pitch = width * 2 + 2). Could anyone help me to spot the (certainly stupid) error I make in my code? Many thanks in advance!


UPDATE: As suggested by Jonathan, I have just reported this problem to the GCC developers: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56392

like image 467
Tisys Avatar asked Feb 19 '13 10:02

Tisys


1 Answers

My question has been answered by Richard Blener on the gcc Bugzilla:

"You are dereferencing a pointer to uint16_t that is not sufficiently aligned for that type. The C standard prohibits this, resulting in undefined behavior."

In my opinion, a warning should however be generated about this undefined behavior. Please also note that this explanation was also given by @jmetcalfe in the comments to this post.

like image 187
Tisys Avatar answered Oct 21 '22 09:10

Tisys