diff options
author | Sami Kerola | 2018-05-12 23:45:58 +0200 |
---|---|---|
committer | Karel Zak | 2018-05-28 13:36:38 +0200 |
commit | 33b2e30284c915e952968051d6bdba4bb282f87e (patch) | |
tree | ca45c31d4e01294ec4fa482520d544deea59c915 /include/debugobj.h | |
parent | nls: remove translation strings (diff) | |
download | kernel-qcow2-util-linux-33b2e30284c915e952968051d6bdba4bb282f87e.tar.gz kernel-qcow2-util-linux-33b2e30284c915e952968051d6bdba4bb282f87e.tar.xz kernel-qcow2-util-linux-33b2e30284c915e952968051d6bdba4bb282f87e.zip |
include/pt-mbr.h: fix integer overflow
gcc -fsanitize=undefined gives following warning.
include/pt-mbr.h:27:51: runtime error: left shift of 248 by 24 places cannot
be represented in type 'int'
It looks like char is converted internally to int before bit-shift, and that
type overflows when char value is greater than 127. Following code snippet
will show the effect what is stored when undefined behaviour happens.
#include <stdio.h>
#include <inttypes.h>
int main(int argc, unsigned char **argv)
{
char p[] = { 170, 170, 170, 170 };
unsigned int uint = p[3];
uint64_t res = 0;
/* overflow */
res = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
printf("%" PRIu64 "\n", res);
/* this is fine */
res = 0;
res = p[0] | (p[1] << 8) | (p[2] << 16) | (uint << 24);
printf("%" PRIu64 "\n", res);
return 0;
}
I tested gcc 8.1.0, clang 6.0.0, and tcc 0.9.27 and they all printed the
same values.
$ ./a.out
18446744073709551530
4294967210
Because output is result of undefined behavior what is stored may change in
future, and other compilers / version might do something different. In the
case of what pt-mbr.h the destination data type size was commonly 32 bits in
size, that truncated excess rubbish from bitshift. Needless to say that was
not very robust code.
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Diffstat (limited to 'include/debugobj.h')
0 files changed, 0 insertions, 0 deletions