Some undefined operations, like shifting by an amount bigger than the size, should not raise a warning during the optimization phase because the corresponding warning has already been issued during the expand phase. Mark the corresponding instructions as tainted and don't warn if already tainted. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- linearize.c | 19 +++++++++++++++++++ simplify.c | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/linearize.c b/linearize.c index 194afe664..938dbc07b 100644 --- a/linearize.c +++ b/linearize.c @@ -1002,6 +1002,23 @@ static pseudo_t linearize_store_gen(struct entrypoint *ep, return value; } +static void taint_undefined_behaviour(struct instruction *insn) +{ + pseudo_t src2; + + switch (insn->opcode) { + case OP_LSR: + case OP_ASR: + case OP_SHL: + src2 = insn->src2; + if (src2->type != PSEUDO_VAL) + break; + if ((unsigned long long)src2->value >= insn->size) + insn->tainted = 1; + break; + } +} + static pseudo_t add_binary_op(struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t left, pseudo_t right) { struct instruction *insn = alloc_typed_instruction(op, ctype); @@ -1407,6 +1424,7 @@ static pseudo_t linearize_assignment(struct entrypoint *ep, struct expression *e oldvalue = cast_pseudo(ep, oldvalue, target->ctype, ctype); opcode = map_opcode(op_trans[expr->op - SPECIAL_BASE], ctype); dst = add_binary_op(ep, ctype, opcode, oldvalue, value); + taint_undefined_behaviour(dst->def); value = cast_pseudo(ep, dst, ctype, expr->ctype); } value = linearize_store_gen(ep, value, &ad); @@ -1512,6 +1530,7 @@ static pseudo_t linearize_binop(struct entrypoint *ep, struct expression *expr) src2 = linearize_expression(ep, expr->right); op = map_opcode(opcode[expr->op], expr->ctype); dst = add_binary_op(ep, expr->ctype, op, src1, src2); + taint_undefined_behaviour(dst->def); return dst; } diff --git a/simplify.c b/simplify.c index 741b1272c..d09ff40ec 100644 --- a/simplify.c +++ b/simplify.c @@ -538,8 +538,9 @@ static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long val { unsigned int size = operand_size(insn, pseudo); - if (value >= size) { + if (value >= size && !insn->tainted) { warning(insn->pos, "right shift by bigger than source value"); + insn->tainted = 1; return replace_with_pseudo(insn, value_pseudo(0)); } if (!value) -- 2.18.0 -- To unsubscribe from this list: send the line "unsubscribe linux-sparse" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html