Skip to contentSkip to conversation

sparse: fix bogus shift too big warning when rhs is a variable

PATCH In review Sam Ravnborg 3 participants 5 messages Jun 16, 2014 – Jun 28, 2014 Sparse checker

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 sparse: fix bogus shift too big warning when rhs is a variable

From 3e742071e931669108f55b4aae2fb074d1c029cc Mon Sep 17 00:00:00 2001
From: Sam Ravnborg <[email protected]>
Date: Mon, 16 Jun 2014 19:02:05 +0200
Subject: [PATCH] sparse: fix bogus shift too big warning when rhs is a
variable

sparse warned about "shift too big" if the rhs was a variable. As sparse usually cannot deduct the value of a variable silence these warnings.

Before this patch following code snippet would generate a warning:

static int doshift(int foo)

{
	return 1 << foo;
}

sparse did not know the value of 'foo' so reported a warning. Ignore the warning expect in the cases where the rhs of the shift is a constant.

Include a few simple tests for left-shift and right-shift.

---
 expand.c                 |  2 +-
 validation/left-shift.c  | 31 +++++++++++++++++++++++++++++++
 validation/right-shift.c | 31 +++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 1 deletion(-)
 create mode 100644 validation/left-shift.c
 create mode 100644 validation/right-shift.c
expand.c +1 -1
index 0f6720c..ce955d3 100644
@@ -187,7 +187,7 @@ static int simplify_int_binop(struct expression *expr, struct symbol *ctype)
 		return 0;
 	r = right->value;
 	if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
-		if (r >= ctype->bit_size) {
+		if (right->flags & Int_const_expr && r >= ctype->bit_size) {
 			if (conservative)
 				return 0;
 			r = check_shift_count(expr, ctype, r);
validation/left-shift.c new file +31 -0
new file mode 100644
index 0000000..e8d929b
@@ -0,0 +1,31 @@
+static unsigned int leftshift1(unsigned int value, unsigned int shift)
+{
+        return 1 << 1000;
+}
+
+static unsigned int leftshift2(unsigned int value, unsigned int shift)
+{
+        return value << 1000;
+}
+
+static unsigned int leftshift3(unsigned int value, unsigned int shift)
+{
+
+        return 1 << value;
+}
+
+static unsigned int leftshift4(unsigned int value, unsigned int shift)
+{
+
+        return value << shift;
+}
+
+/*
+ * check-name: Left shift - shift too big
+ *
+ * check-error-start
+left-shift.c:3:18: warning: shift too big (1000) for type int
+left-shift.c:8:22: warning: shift too big (1000) for type unsigned int
+ * check-error-end
+ */
+
validation/right-shift.c new file +31 -0
new file mode 100644
index 0000000..9be6006
@@ -0,0 +1,31 @@
+static unsigned int rightshift1(unsigned int value, unsigned int shift)
+{
+        return 1 >> 1000;
+}
+
+static unsigned int rightshift2(unsigned int value, unsigned int shift)
+{
+        return value >> 1000;
+}
+
+static unsigned int rightshift3(unsigned int value, unsigned int shift)
+{
+
+        return 1 >> value;
+}
+
+static unsigned int rightshift4(unsigned int value, unsigned int shift)
+{
+
+        return value >> shift;
+}
+
+/*
+ * check-name: Right shift - shift too big
+ *
+ * check-error-start
+right-shift.c:3:18: warning: shift too big (1000) for type int
+right-shift.c:8:22: warning: shift too big (1000) for type unsigned int
+ * check-error-end
+ */
+
Signature · 1 line
1.9.3
Reviewed-by on v1 1/1
#1 lore raw
Quoted 12 lines · Sam Ravnborg

From 3e742071e931669108f55b4aae2fb074d1c029cc Mon Sep 17 00:00:00 2001
From: Sam Ravnborg <[email protected]>
Date: Mon, 16 Jun 2014 19:02:05 +0200
Subject: [PATCH] sparse: fix bogus shift too big warning when rhs is a
variable

sparse warned about "shift too big" if the rhs was a variable. As sparse usually cannot deduct the value of a variable silence these warnings.

Before this patch following code snippet would generate a warning:

Quoted 7 lines

static int doshift(int foo)

{
	return 1 << foo;
}

sparse did not know the value of 'foo' so reported a warning. Ignore the warning expect in the cases where the rhs of the shift

s/expect/except/

Quoted 6 lines

is a constant.

Include a few simple tests for left-shift and right-shift.

Thanks for fixing this!

Quoted 102 lines
---
 expand.c                 |  2 +-
 validation/left-shift.c  | 31 +++++++++++++++++++++++++++++++
 validation/right-shift.c | 31 +++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 1 deletion(-)
 create mode 100644 validation/left-shift.c
 create mode 100644 validation/right-shift.c
expand.c +1 -1
index 0f6720c..ce955d3 100644
@@ -187,7 +187,7 @@ static int simplify_int_binop(struct expression *expr, struct symbol *ctype)
 		return 0;
 	r = right->value;
 	if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
-		if (r >= ctype->bit_size) {
+		if (right->flags & Int_const_expr && r >= ctype->bit_size) {
 			if (conservative)
 				return 0;
 			r = check_shift_count(expr, ctype, r);
validation/left-shift.c new file +31 -0
new file mode 100644
index 0000000..e8d929b
@@ -0,0 +1,31 @@
+static unsigned int leftshift1(unsigned int value, unsigned int shift)
+{
+        return 1 << 1000;
+}
+
+static unsigned int leftshift2(unsigned int value, unsigned int shift)
+{
+        return value << 1000;
+}
+
+static unsigned int leftshift3(unsigned int value, unsigned int shift)
+{
+
+        return 1 << value;
+}
+
+static unsigned int leftshift4(unsigned int value, unsigned int shift)
+{
+
+        return value << shift;
+}
+
+/*
+ * check-name: Left shift - shift too big
+ *
+ * check-error-start
+left-shift.c:3:18: warning: shift too big (1000) for type int
+left-shift.c:8:22: warning: shift too big (1000) for type unsigned int
+ * check-error-end
+ */
+
validation/right-shift.c new file +31 -0
new file mode 100644
index 0000000..9be6006
@@ -0,0 +1,31 @@
+static unsigned int rightshift1(unsigned int value, unsigned int shift)
+{
+        return 1 >> 1000;
+}
+
+static unsigned int rightshift2(unsigned int value, unsigned int shift)
+{
+        return value >> 1000;
+}
+
+static unsigned int rightshift3(unsigned int value, unsigned int shift)
+{
+
+        return 1 >> value;
+}
+
+static unsigned int rightshift4(unsigned int value, unsigned int shift)
+{
+
+        return value >> shift;
+}
+
+/*
+ * check-name: Right shift - shift too big
+ *
+ * check-error-start
+right-shift.c:3:18: warning: shift too big (1000) for type int
+right-shift.c:8:22: warning: shift too big (1000) for type unsigned int
+ * check-error-end
+ */
+
Signature · 6 lines
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
maintainer
#2 lore raw
In reply to Sam Ravnborg

Still catching up my emails.

Quoted 3 lines · Sam Ravnborg

sparse warned about "shift too big" if the rhs was a variable. As sparse usually cannot deduct the value of a variable silence these warnings.

That is very strange. It should not happen.

Quoted 11 lines

Before this patch following code snippet would generate a warning:

static int doshift(int foo)

{
        return 1 << foo;
}

sparse did not know the value of 'foo' so reported a warning. Ignore the warning expect in the cases where the rhs of the shift is a constant.

That is strange. I can't duplicate the bug with your test case:
With tip of chrisl repository,
I get the following error with your test case:
./sparse /tmp/b.c
/tmp/b.c:3:18: warning: shift too big (1000) for type int /tmp/b.c:8:22: warning: shift too big (1000) for type unsigned int

expand.c static int simplify_int_binop(struct expression *expr, struct symbol *ctype) · line 190

Quoted 11 lines
expand.c +1 -1
index 0f6720c..ce955d3 100644
@@ -187,7 +187,7 @@ static int simplify_int_binop(struct expression *expr, struct symbol *ctype)
                return 0;
        r = right->value;
        if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
-               if (r >= ctype->bit_size) {
+               if (right->flags & Int_const_expr && r >= ctype->bit_size) {

This does not explain why it fix the bug. In simplify_int_binop() There is the code check for this is constant expr on rhs. The non constant value should just bail out early.

    if (right->type != EXPR_VALUE)
        return 0;

That is right before your change. Plus I can't duplicate the bug myself.

I suspect there is something else going on. Any way to help me reproduce the bug?

I am using gcc 4.8.2 on x86_64.

Chris

maintainer
#3 lore raw
Quoted 5 lines · Christopher Li

That is right before your change. Plus I can't duplicate the bug myself.

I suspect there is something else going on. Any way to help me reproduce the bug?

Never mind, I just saw the other email thread discussing this bug. I will try the test case provide there.

Chris

maintainer
#4 lore raw
Quoted 4 lines · Christopher Li

Never mind, I just saw the other email thread discussing this bug. I will try the test case provide there.

Ok, I just reply to the other email.
The bug is in the kernel source, a valid complain.
Sparse is doing the right thing here. Not a sparse bug, it is feature.

Chris