From 1764b7aca9cbcf822649e5c69694c1f4158dab64 Mon Sep 17 00:00:00 2001 From: mrdudz Date: Sat, 28 Jan 2023 12:29:05 +0100 Subject: [PATCH] fix for #1941, taken from https://github.com/acqn/cc65/commit/22d435b68966b86929d3c393f3bbc1593b261cee --- src/cc65/shiftexpr.c | 37 +++++++++++++++++--------------- test/val/bug1941-shift-by-zero.c | 28 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 test/val/bug1941-shift-by-zero.c diff --git a/src/cc65/shiftexpr.c b/src/cc65/shiftexpr.c index b8fb70434..1224bfecb 100644 --- a/src/cc65/shiftexpr.c +++ b/src/cc65/shiftexpr.c @@ -169,27 +169,21 @@ void ShiftExpr (struct ExprDesc* Expr) } } - /* If the shift count is zero, nothing happens. If the left hand - ** side is a constant, the result is constant. - */ - if (Expr2.IVal == 0 || lconst) { - - /* Set the type */ + /* If the left hand side is a constant, the result is constant */ + if (lconst) { + /* Set the result type */ Expr->Type = ResultType; - if (lconst) { - - /* Evaluate the result */ - switch (Tok) { - case TOK_SHL: Expr->IVal <<= Expr2.IVal; break; - case TOK_SHR: Expr->IVal >>= Expr2.IVal; break; - default: /* Shutup gcc */ break; - } - - /* Limit the calculated value to the range of its type */ - LimitExprValue (Expr, 1); + /* Evaluate the result */ + switch (Tok) { + case TOK_SHL: Expr->IVal <<= Expr2.IVal; break; + case TOK_SHR: Expr->IVal >>= Expr2.IVal; break; + default: /* Shutup gcc */ break; } + /* Limit the calculated value to the range of its type */ + LimitExprValue (Expr, 1); + /* Result is already got, remove the generated code */ RemoveCode (&Mark1); @@ -197,6 +191,15 @@ void ShiftExpr (struct ExprDesc* Expr) continue; } + /* If the shift count is zero, nothing happens */ + if (Expr2.IVal == 0) { + /* Result is already got, remove the pushing code */ + RemoveCode (&Mark2); + + /* Be sure to mark the value as in the primary */ + goto MakeRVal; + } + /* If we're shifting an integer or unsigned to the right, the lhs ** has a quasi-const address, and the shift count is larger than 8, ** we can load just the high byte as a char with the correct diff --git a/test/val/bug1941-shift-by-zero.c b/test/val/bug1941-shift-by-zero.c new file mode 100644 index 000000000..eaeba814f --- /dev/null +++ b/test/val/bug1941-shift-by-zero.c @@ -0,0 +1,28 @@ +/* Bug 1941 - Bitwise shift char types by 0 count results in out-of-range access */ + +#include +#include + +uint8_t foo = 42U; /* "Low byte" */ +uint8_t goo = 1U; /* "High byte" - you need it to reproduce the issue */ +int16_t bar = 256; /* ...or just do it with this */ + +_Static_assert (sizeof (foo >> 0) == sizeof (int), "Shift result should be int-promoted"); +_Static_assert (sizeof ((int8_t)bar << 0) == sizeof (int), "Shift result should be int-promoted"); + +unsigned failures; + +int main(void) +{ + if (foo >> 0 != foo) { + ++failures; + printf("foo failed\n"); + } + + if ((int8_t)bar << 0 != (int8_t)bar) { + ++failures; + printf("bar failed\n"); + } + + return failures; +}