Comment 45 for bug 250425

Revision history for this message
Cesar Eduardo Barros (cesarb) wrote :

The problem is an interaction between the uncommon (to put it mildly) way zsnes calls memcpy to restore its global state from the "regsbackup" buffer, and _FORTIFY_SOURCE:

gcc -ggdb3 -pipe -I. -I/usr/local/include -I/usr/include -D__UNIXSDL__ -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT -DNO_DEBUGGER -D__LIBAO__ -D__OPENGL__ -march=i486 -O3 -fomit-frame-pointer -fprefetch-loop-arrays -fforce-addr -s -D__RELEASE__ -o initc.o -c initc.c
[...]
In function ‘memcpy’,
    inlined from ‘powercycle’ at initc.c:2624:
/usr/include/bits/string3.h:52: warning: call to __builtin___memcpy_chk will always overflow destination buffer

The corresponding block of code is:

    sramsavedis = 0;
    memcpy(&sndrot, regsbackup, 3019);

And the declaration for the relevant variables, from the same file:

extern unsigned char NextLineCache, sramsavedis, sndrot, regsbackup[3019];

The reason this strange memcpy call will always work correctly is that the storage for sndrot and the rest of the state variables is allocated in assembly (cpu/regs.inc, included from cpu/table.asm), in a way which guarantees that all the correct variables will be sequential in memory, with no padding (sndrot is just the first variable on that block). However, gcc cannot know that; it sees instead an attempt to write 3019 bytes to a single byte-sized variable, which will obviously overflow (and, in fact, overflowing is precisely the desired behaviour!).

The easiest way to fix this is to disable the extra security checks (via -D_FORTIFY_SOURCE=0). There might be other places which use that unusual "design pattern", so simply fixing that memcpy call might not be enough.