From 231aa88ee5170f28c3a6f9c2bd3055ba7f242c99 Mon Sep 17 00:00:00 2001 From: Mark O'Donovan Date: Mon, 9 Mar 2026 21:24:32 +0000 Subject: [PATCH] target/arm_simulator: fix undefined behaviour Shifting 32 bit unsigned variables by 32 bits is undefined behaviour Change-Id: I846619a522c747f9c3b11a814a1864d1d51cfe87 Signed-off-by: Mark O'Donovan Reviewed-on: https://review.openocd.org/c/openocd/+/9502 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arm_simulator.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/target/arm_simulator.c b/src/target/arm_simulator.c index e9f667116..8a87e4412 100644 --- a/src/target/arm_simulator.c +++ b/src/target/arm_simulator.c @@ -27,25 +27,31 @@ static uint32_t arm_shift(uint8_t shift, uint32_t rm, shift_amount &= 0xff; if (shift == 0x0) { /* LSL */ - if ((shift_amount > 0) && (shift_amount <= 32)) { + if (shift_amount > 0 && shift_amount < 32) { return_value = rm << shift_amount; *carry = rm >> (32 - shift_amount); + } else if (shift_amount == 32) { + return_value = 0x0; + *carry = rm & 0x1; } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ return_value = rm; } else if (shift == 0x1) { /* LSR */ - if ((shift_amount > 0) && (shift_amount <= 32)) { + if (shift_amount > 0 && shift_amount < 32) { return_value = rm >> shift_amount; *carry = (rm >> (shift_amount - 1)) & 1; + } else if (shift_amount == 32) { + return_value = 0x0; + *carry = (rm >> 31) & 0x1; } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ return_value = rm; } else if (shift == 0x2) { /* ASR */ - if ((shift_amount > 0) && (shift_amount <= 32)) { + if (shift_amount > 0 && shift_amount < 32) { /* C right shifts of unsigned values are guaranteed to * be logical (shift in zeroes); simulate an arithmetic * shift (shift in signed-bit) by adding the sign bit @@ -54,7 +60,7 @@ static uint32_t arm_shift(uint8_t shift, uint32_t rm, return_value = rm >> shift_amount; if (rm & 0x80000000) return_value |= 0xffffffff << (32 - shift_amount); - } else if (shift_amount > 32) { + } else if (shift_amount >= 32) { if (rm & 0x80000000) { return_value = 0xffffffff; *carry = 0x1;