From d1685cb79a0ab467b4009efe15ecc9d1b558bd5c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 23 May 2013 17:34:24 +0300 Subject: [PATCH] sval: make some more fixes to sval_binop_overflows() So this is partly Monte Carlo coding where I just keep changing things until they work. I don't understand overflows very well... :/ The code looks like this: x = a - b; Obviously if "a" and "b" are unsigned and "b" is larger then that doesn't work as intended. So I complain about that. Otherwise I change the equation into "x = a + (-b)" because I know how to handle addition overflows. But sometimes change "b" to negative can overflow so I check for that. And finally it turns out that my check for addition overflows was utter rubbish. I have looked up how other people test for this on the internet and tried to copy the normal algorithm. Signed-off-by: Dan Carpenter --- smatch_sval.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/smatch_sval.c b/smatch_sval.c index b0b6c084..902d8da4 100644 --- a/smatch_sval.c +++ b/smatch_sval.c @@ -447,6 +447,25 @@ sval_t sval_binop(sval_t left, int op, sval_t right) return ret; } +int sval_unop_overflows(sval_t sval, int op) +{ + if (op != '-') + return 0; + if (sval_positive_bits(sval) == 32 && sval.value == INT_MIN) + return 1; + if (sval_positive_bits(sval) == 64 && sval.value == LLONG_MIN) + return 1; + if (sval_is_negative(sval)) + return 0; + if (sval_signed(sval)) + return 0; + if (sval_bits(sval) == 32 && sval.uvalue > INT_MAX) + return 1; + if (sval_bits(sval) == 64 && sval.uvalue > LLONG_MAX) + return 1; + return 0; +} + int sval_binop_overflows(sval_t left, int op, sval_t right) { struct symbol *type; @@ -462,15 +481,27 @@ int sval_binop_overflows(sval_t left, int op, sval_t right) switch (op) { case '+': - if (left.uvalue > max.uvalue - right.uvalue) - return 1; + if (sval_is_negative(right)) { + if (left.value < min.value - right.value) + return 1; + } else { + if (left.uvalue > max.uvalue - right.uvalue) + return 1; + } return 0; case '*': return right.uvalue != 0 && left.uvalue > max.uvalue / right.uvalue; case '-': - if (sval_binop_overflows(min, '+', left)) + if (type_unsigned(type)) { + if (sval_cmp(left, right) < 0) + return 1; + return 0; + } + + if (sval_unop_overflows(right, '-')) return 1; - if (sval_cmp(right, sval_binop(min, '+', left)) < 0) + right = sval_preop(right, '-'); + if (sval_binop_overflows(left, '+', right)) return 1; return 0; } -- 2.11.4.GIT