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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With