Compiling 7-zip source code with MinGW GCC 4.8.2 on Windows64 I found a crash.
Here is a code snippet of 7-zip 9.20, Sha1.cpp:
const unsigned kBlockSize = 64;
...
void CContext::UpdateRar(Byte *data, size_t size, bool rar350Mode) {
...
for (int i = 0; i < kBlockSizeInWords; i++) {
UInt32 d = _buffer[i];
data[i * 4 + 0 - kBlockSize] = (Byte)(d); // <<= DISASSEMBLED
data[i * 4 + 1 - kBlockSize] = (Byte)(d >> 8);
data[i * 4 + 2 - kBlockSize] = (Byte)(d >> 16);
data[i * 4 + 3 - kBlockSize] = (Byte)(d >> 24);
}
}
Compiling with MinGW GCC 4.8.2 (on Windows) gets:
0x0000000045b65f75 <+149>: mov eax,0xffffffc0
0x0000000045b65f7a <+154>: nop WORD PTR [rax+rax*1+0x0]
0x0000000045b65f80 <+160>: mov r10d,DWORD PTR [r11+0x24]
0x0000000045b65f84 <+164>: mov edx,eax
0x0000000045b65f86 <+166>: add r11,0x4
0x0000000045b65f8a <+170>: mov ecx,r10d
0x0000000045b65f8d <+173>: mov BYTE PTR [rbx+rdx*1],r10b
In the last line rbx
points to the data
and 64
should be subtracted from this address. This is done by adding -64
. In the first line of the assembler snippet 0xffffffc0
(-64
(Int32)) saved into eax
and then moved to edx
. But in the last line
0x0000000045b65f8d <+173>: mov BYTE PTR [rbx+rdx*1],r10b
the rdx
register instead of the edx
register used. At this point the top part of the rdx
is 0, so +64
would work just fine. But adding -64
requires the top part of the rdx
register to hold 0xFFFFFFFF
. Adding &data+0xffffffc0
in 64bit mode produces an invalid address and crashes.
The problem is fixed by changing the assignment (adding (int)
cast):
data[i * 4 + 0 - (int)kBlockSize] = (Byte)(d);
data[i * 4 + 1 - (int)kBlockSize] = (Byte)(d >> 8);
data[i * 4 + 2 - (int)kBlockSize] = (Byte)(d >> 16);
data[i * 4 + 3 - (int)kBlockSize] = (Byte)(d >> 24);
My questions are:
- Is it a bug or feature?
- Are there some GCC flags to prevent this behavior?
- How can I make sure, that entire 7-zip binary of mine is free of such errors?
UPDATE: It turn out, that this behavior doesn't depend on optimization flags and is only observed on Windows