[PATCH 5/7] big-shift: fix warning message for negative or over-sized shifts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In order to preserve shifts with negative count and give a proper
warning for them, we first need to identify when the shift must
be considered as negative. This identification is made complicated
by the fact that PSEUDO_VAL are typeless.

The solution chosen here is to try to first sign extend the shift
count (with the size of an int and the size of the instruction).
If after this extension the count appears as negative it is treated
as such (and this new value replace the old one to avoid to have to
redo this at each simplification run), otherwise it is considered
as unsigned. The only case where a negative count could be wrongly
interpreted as a big unsigned value would be if:
	size target int < instruction's size < size host value
which can't happen for now since sizeof(int) == 4 on all targets
and sizeof(value) is 8.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx>
---
 simplify.c                  | 23 ++++++++++++++++++-----
 validation/shift-negative.c |  1 -
 validation/shift-undef.c    | 24 ++++++++++++------------
 3 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/simplify.c b/simplify.c
index 5fb1a8cd3..1b258eb63 100644
--- a/simplify.c
+++ b/simplify.c
@@ -542,17 +542,30 @@ undef:
 static long long check_shift_count(struct instruction *insn, unsigned long long uval)
 {
 	unsigned int size = insn->size;
+	long long sval = uval;
 
 	if (uval < size)
 		return uval;
-	if (insn->tainted)
-		return uval;
 
-	if (Wshift_count_overflow) {
-		warning(insn->pos, "shift by bigger than operand's width");
+	sval = sign_extend_safe(sval, size);
+	sval = sign_extend_safe(sval, bits_in_int);
+	if (sval < 0)
+		insn->src2 = value_pseudo(sval);
+	if (insn->tainted)
+		return sval;
+
+	if (sval < 0 && Wshift_count_negative)
+		warning(insn->pos, "shift count is negative (%lld)", sval);
+	if (sval > 0 && Wshift_count_overflow) {
+		struct symbol *ctype = insn->type;
+		const char *tname;
+		if (ctype->type == SYM_NODE)
+			ctype = ctype->ctype.base_type;
+		tname = show_typename(ctype);
+		warning(insn->pos, "shift too big (%llu) for type %s", sval, tname);
 	}
 	insn->tainted = 1;
-	return uval;
+	return sval;
 }
 
 static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value)
diff --git a/validation/shift-negative.c b/validation/shift-negative.c
index 533fc68a4..fff5cf123 100644
--- a/validation/shift-negative.c
+++ b/validation/shift-negative.c
@@ -7,7 +7,6 @@ unsigned int fo2(unsigned int a) { return a >> ((a & 0) ^ ~0); }
 /*
  * check-name: shift-negative
  * check-command: sparse -Wno-decl $file
- * check-known-to-fail
  *
  * check-error-start
 shift-negative.c:1:45: warning: shift count is negative (-1)
diff --git a/validation/shift-undef.c b/validation/shift-undef.c
index 54c8359b2..4e94fa23d 100644
--- a/validation/shift-undef.c
+++ b/validation/shift-undef.c
@@ -130,12 +130,12 @@ shift-undef.c:17:30: warning: shift too big (108) for type unsigned int
 shift-undef.c:18:30: warning: shift count is negative (-7)
 shift-undef.c:19:30: warning: shift count is negative (-8)
 shift-undef.c:20:30: warning: shift count is negative (-9)
-shift-undef.c:21:29: warning: shift by bigger than operand's width
-shift-undef.c:22:29: warning: shift by bigger than operand's width
-shift-undef.c:23:29: warning: shift by bigger than operand's width
-shift-undef.c:24:29: warning: shift by bigger than operand's width
-shift-undef.c:25:29: warning: shift by bigger than operand's width
-shift-undef.c:26:29: warning: shift by bigger than operand's width
+shift-undef.c:21:29: warning: shift too big (109) for type int
+shift-undef.c:22:29: warning: shift too big (110) for type unsigned int
+shift-undef.c:23:29: warning: shift too big (111) for type unsigned int
+shift-undef.c:24:29: warning: shift count is negative (-10)
+shift-undef.c:25:29: warning: shift count is negative (-11)
+shift-undef.c:26:29: warning: shift count is negative (-12)
 shift-undef.c:32:11: warning: shift too big (100) for type int
 shift-undef.c:33:11: warning: shift too big (101) for type unsigned int
 shift-undef.c:34:11: warning: shift too big (102) for type unsigned int
@@ -154,11 +154,11 @@ shift-undef.c:46:30: warning: shift too big (108) for type unsigned int
 shift-undef.c:47:30: warning: shift count is negative (-7)
 shift-undef.c:48:30: warning: shift count is negative (-8)
 shift-undef.c:49:30: warning: shift count is negative (-9)
-shift-undef.c:50:26: warning: shift by bigger than operand's width
-shift-undef.c:51:26: warning: shift by bigger than operand's width
-shift-undef.c:52:26: warning: shift by bigger than operand's width
-shift-undef.c:53:26: warning: shift by bigger than operand's width
-shift-undef.c:54:26: warning: shift by bigger than operand's width
-shift-undef.c:55:26: warning: shift by bigger than operand's width
+shift-undef.c:50:26: warning: shift too big (109) for type int
+shift-undef.c:51:26: warning: shift too big (110) for type int
+shift-undef.c:52:26: warning: shift too big (111) for type int
+shift-undef.c:53:26: warning: shift count is negative (-10)
+shift-undef.c:54:26: warning: shift count is negative (-11)
+shift-undef.c:55:26: warning: shift count is negative (-12)
  * check-error-end
  */
-- 
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



[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux