From f77d16b47e2cd0fc52435aaa0bdc1c4ad8593086 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Thu, 13 Feb 2020 13:26:40 +0100 Subject: [PATCH] Fix undefined behaviour in number serialisation. When optimising, the compiler is allowed to reorder the read calls in the following code: return (uint16_t)read_uint8_t(info) | ((uint16_t)read_uint8_t(info) << 8); Since read_uint8_t() has side effects, this could read a totally wrong value and has to be rewritten as such: uint16_t value = (uint16_t)read_uint8_t(info); value |= (uint16_t)read_uint8_t(info) << 8; return value; This bug has been observed with Visual Studio 2019. --- src/eris.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/eris.c b/src/eris.c index c49c5f6..6b3fb50 100644 --- a/src/eris.c +++ b/src/eris.c @@ -639,28 +639,31 @@ read_uint8_t(Info *info) { static uint16_t read_uint16_t(Info *info) { - return (uint16_t)read_uint8_t(info) | - ((uint16_t)read_uint8_t(info) << 8); + uint16_t value = (uint16_t)read_uint8_t(info); + value |= (uint16_t)read_uint8_t(info) << 8; + return value; } static uint32_t read_uint32_t(Info *info) { - return (uint32_t)read_uint8_t(info) | - ((uint32_t)read_uint8_t(info) << 8) | - ((uint32_t)read_uint8_t(info) << 16) | - ((uint32_t)read_uint8_t(info) << 24); + uint32_t value = (uint32_t)read_uint8_t(info); + value |= (uint32_t)read_uint8_t(info) << 8; + value |= (uint32_t)read_uint8_t(info) << 16; + value |= (uint32_t)read_uint8_t(info) << 24; + return value; } static uint64_t read_uint64_t(Info *info) { - return (uint64_t)read_uint8_t(info) | - ((uint64_t)read_uint8_t(info) << 8) | - ((uint64_t)read_uint8_t(info) << 16) | - ((uint64_t)read_uint8_t(info) << 24) | - ((uint64_t)read_uint8_t(info) << 32) | - ((uint64_t)read_uint8_t(info) << 40) | - ((uint64_t)read_uint8_t(info) << 48) | - ((uint64_t)read_uint8_t(info) << 56); + uint64_t value = (uint64_t)read_uint8_t(info); + value |= (uint64_t)read_uint8_t(info) << 8; + value |= (uint64_t)read_uint8_t(info) << 16; + value |= (uint64_t)read_uint8_t(info) << 24; + value |= (uint64_t)read_uint8_t(info) << 32; + value |= (uint64_t)read_uint8_t(info) << 40; + value |= (uint64_t)read_uint8_t(info) << 48; + value |= (uint64_t)read_uint8_t(info) << 56; + return value; } static int16_t