aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linearize.c
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-06-20 23:52:14 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-08-06 18:30:44 +0200
commit9aa1c8656be5fee7394cb242a80d7ea8eed32385 (patch)
tree499fd2c3b3154ac371873dae541798cab2e021c0 /linearize.c
parentc2a5bd264187f42564b7055bce4cf72a7985cbc5 (diff)
downloadsparse-dev-9aa1c8656be5fee7394cb242a80d7ea8eed32385.tar.gz
bad-shift: wait dead code elimination to warn about bad shifts
Sparse complains when a shift amount is too big for the size of its operand or if it's negative. However, it does this even for expressions that are never evaluated. It's especially annoying in the kernel for type generic macros, for example the ones in arch/*/include/asm/cmpxchg.h So, remove all warnings done at expansion time and avoid any simplifications of such expressions. Same, at linearization and optimization time but in this case mark the instructions as 'tainted' to inhibit any further simplifications. Finally, at the end of the optimization phase, warn for the tainted instructions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Diffstat (limited to 'linearize.c')
-rw-r--r--linearize.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/linearize.c b/linearize.c
index 49274681..5a8e7497 100644
--- a/linearize.c
+++ b/linearize.c
@@ -2468,6 +2468,49 @@ static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stm
return VOID;
}
+static void check_tainted_insn(struct instruction *insn)
+{
+ unsigned long long uval;
+ long long sval;
+ pseudo_t src2;
+
+ switch (insn->opcode) {
+ case OP_DIVU: case OP_DIVS:
+ case OP_MODU: case OP_MODS:
+ if (insn->src2 == value_pseudo(0))
+ warning(insn->pos, "divide by zero");
+ break;
+ case OP_SHL: case OP_LSR: case OP_ASR:
+ src2 = insn->src2;
+ if (src2->type != PSEUDO_VAL)
+ break;
+ uval = src2->value;
+ if (uval < insn->size)
+ break;
+ sval = sign_extend(uval, insn->size);
+ if (Wshift_count_negative && sval < 0)
+ warning(insn->pos, "shift count is negative (%lld)", sval);
+ else if (Wshift_count_overflow)
+ warning(insn->pos, "shift too big (%llu) for type %s", uval, show_typename(insn->type));
+ }
+}
+
+///
+// issue warnings after all possible DCE
+static void late_warnings(struct entrypoint *ep)
+{
+ struct basic_block *bb;
+ FOR_EACH_PTR(ep->bbs, bb) {
+ struct instruction *insn;
+ FOR_EACH_PTR(bb->insns, insn) {
+ if (!insn->bb)
+ continue;
+ if (insn->tainted)
+ check_tainted_insn(insn);
+ } END_FOR_EACH_PTR(insn);
+ } END_FOR_EACH_PTR(bb);
+}
+
static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_type)
{
struct statement *stmt = base_type->stmt;
@@ -2514,6 +2557,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t
add_one_insn(ep, ret);
optimize(ep);
+ late_warnings(ep);
return ep;
}