This is a small and admittedly contrived demo showing how some weird but safe code could become vulnerable if run in an environment where some shared library has changed the FPU's FTZ/DAZ bits to force denormals to zero.
To run it:
# Create an empty file
$ touch gofast.c
# Build it with -ffast-math, which links in crtfastmath.o, installing a
# constructor that enables FTZ+DAZ on load.
$ gcc -ffast-math -fpic -shared gofast.c -o gofast.so
# Build our main program, WITHOUT -ffast-math. Enable ASAN so we catch
# any overflows, no matter how small.
$ gcc -fsanitize=address ffast_and_furious.c -o ffast_and_furious -ldl -lm
# Run without the "fast" option and see that it's safe
$ ./ffast_and_furious
DEBUG: Will write to pixbuf[127]
# Now run it with "fast", which loads gofast.so, enabling FTZ/DAZ
$ ./ffast_and_furious fast
Loaded ./gofast.so
Fast math mode enabled! Gotta go fast!
DEBUG: Will write to pixbuf[128]
=================================================================
==922888==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60c0000000c0 at pc 0x55f753dd4422 bp 0x7ffdf8c54bf0 sp 0x7ffdf8c54be0
WRITE of size 1 at 0x60c0000000c0 thread T0
#0 0x55f753dd4421 in put_pixel (/home/moyix/ffast_and_furious+0x1421)
#1 0x55f753dd45ba in main (/home/moyix/ffast_and_furious+0x15ba)
#2 0x7f4dccb40082 in __libc_start_main ../csu/libc-start.c:308
#3 0x55f753dd426d in _start (/home/moyix/ffast_and_furious+0x126d)
0x60c0000000c0 is located 0 bytes to the right of 128-byte region [0x60c000000040,0x60c0000000c0)
allocated by thread T0 here:
#0 0x7f4dccf70808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x55f753dd4586 in main (/home/moyix/ffast_and_furious+0x1586)
#2 0x7f4dccb40082 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/moyix/ffast_and_furious+0x1421) in put_pixel
Shadow bytes around the buggy address:
0x0c187fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c187fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c187fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c187fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c187fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x0c187fff8010: 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa
0x0c187fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c187fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c187fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c187fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c187fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==922888==ABORTING