[PATCH 2/2] qemu_process: Fix theoretical overflow in uint to bool typecast
Michal Prívozník
mprivozn at redhat.com
Wed Feb 9 09:26:17 UTC 2022
On 2/9/22 10:08, Peter Krempa wrote:
> On Wed, Feb 09, 2022 at 09:39:50 +0100, Michal Privoznik wrote:
>> The qemuPrepareNVRAM() function accepts three arguments and the
>> last one being a boolean type. However, when the function is
>> called from qemuProcessPrepareHost() the argument passed is a
>> result of logical and of @flags (unsigned int) and
>> VIR_QEMU_PROCESS_START_RESET_NVRAM value. In theory this is
>> unsafe to do because if the value of the flag is ever changed
>
> I don't think that this is accurate as casting a unsigned int (32bits)
> to a bool (8 bits) works properly even when the lower 8 bits of the
> value equal to 0:
>
> $ cat bool.c
> #include <stdint.h>
> #include <stdio.h>
> #include <limits.h>
> #include <stdbool.h>
>
> void p(char *s, unsigned long long v, uint8_t u, bool b) {
> printf("%30s: %30llu: %4u: %d\n", s, v, u, b);
> }
>
> #define E(val) \
> p(#val, (val), (val), (val))
>
> #define T(type) \
> E(type - 1);\
> E(type);\
> E(type + 1)
>
> int main() {
> printf("bool size: %u\n", sizeof(bool));
> E(0);
> T(CHAR_MAX);
> T(UCHAR_MAX);
> T(UINT8_MAX);
> T(INT_MAX);
> T(UINT_MAX);
> }
>
>
> $ ./a.out
> bool size: 1
> 0: 0: 0: 0
> 0x7f - 1: 126: 126: 1
> 0x7f: 127: 127: 1
> 0x7f + 1: 128: 128: 1
> (0x7f * 2 + 1) - 1: 254: 254: 1
> (0x7f * 2 + 1): 255: 255: 1
> (0x7f * 2 + 1) + 1: 256: 0: 1
> (255) - 1: 254: 254: 1
> (255): 255: 255: 1
> (255) + 1: 256: 0: 1
> 0x7fffffff - 1: 2147483646: 254: 1
> 0x7fffffff: 2147483647: 255: 1
> 0x7fffffff + 1: 18446744071562067968: 0: 1
> (0x7fffffff * 2U + 1U) - 1: 4294967294: 254: 1
> (0x7fffffff * 2U + 1U): 4294967295: 255: 1
> (0x7fffffff * 2U + 1U) + 1: 0: 0: 0
>
Ah, looks like GCC is clever enough. For the following code:
void pb(bool b) {
printf("%u\n", b);
}
int main(int argc, char *argv[])
{
unsigned int x = -1;
pb(x & (1 << (sizeof(bool) * 8)));
return 0;
}
GCC generates some extra code when calling the pb() function:
1172: c7 45 fc ff ff ff ff movl $0xffffffff,-0x4(%rbp)
1179: 8b 45 fc mov -0x4(%rbp),%eax
117c: 25 00 01 00 00 and $0x100,%eax
1181: 85 c0 test %eax,%eax
1183: 0f 95 c0 setne %al
1186: 0f b6 c0 movzbl %al,%eax
1189: 89 c7 mov %eax,%edi
118b: e8 a9 ff ff ff call 1139 <pb>
IOW, the compiler does "sign extension", well "reduction". Clang
produces similar assembler, except it makes doubly sure that bool has
just the lowest bit set:
401166: c7 45 ec ff ff ff ff movl $0xffffffff,-0x14(%rbp)
40116d: 8b 45 ec mov -0x14(%rbp),%eax
401170: 25 00 01 00 00 and $0x100,%eax
401175: 83 f8 00 cmp $0x0,%eax
401178: 0f 95 c0 setne %al
40117b: 0f b6 f8 movzbl %al,%edi
40117e: 83 e7 01 and $0x1,%edi
401181: e8 9a ff ff ff call 401120 <pb>
So, since compilers are now clever enough, I guess we can stop writing
the expression like I did.
Michal
More information about the libvir-list
mailing list