aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/validation
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-06-02 17:30:10 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-07-23 01:40:31 +0200
commit7792c8509a076ad8572983e335c58902647f6755 (patch)
tree0f23bf7a4c09ca6d2afed1b7de61d6051187e203 /validation
parent9fb59b83b936e16ec1fd600e68cd3cf9f1048fbe (diff)
downloadsparse-dev-7792c8509a076ad8572983e335c58902647f6755.tar.gz
big-shift: use the type width for too big shift
Currently, during simplification, when it's checked if the shift amount of a shift instruction is in range, it's not the instruction's size (which is the same as the type's width) that is used but the 'operand size' as returned by operand_size(). operand_size() is a bit like poor man's Value Range Propagation or VRP without Propagation, and use the knowledge of previous instructions to deduce the effective size of the operand. For example, if the operand is the result of a narrowing cast or have been ANDed with a known mask, or was a bitfield, the size returned is the one of the cast or the mask and may be smaller than its type. A priori, using more precise knowledge is a good thing but in the present case it's not because it causes warning for things that are totally legal, meaningfull and used all the time. For example, we don't want to warn in the following code: struct bf { int u:8; }; int bf(struct bf *p) { return p->s << 24; } Another situation where such warnings are not desirable is when the shift instruction 'is far' from the one defining the size, for example when the shift occurs in an inline function and this inline function is called with a smaller type. So, use the instruction size instead of the effective operand size when checking the range of a shift instruction. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Diffstat (limited to 'validation')
-rw-r--r--validation/shift-undef.c57
1 files changed, 45 insertions, 12 deletions
diff --git a/validation/shift-undef.c b/validation/shift-undef.c
index aba226c1..bc4b2b84 100644
--- a/validation/shift-undef.c
+++ b/validation/shift-undef.c
@@ -74,6 +74,39 @@ int ok(int s, unsigned int u, int p)
return 1;
}
+struct bf {
+ unsigned int u:8;
+ int s:8;
+};
+
+int bf(struct bf *p)
+{
+ unsigned int r = 0;
+ r += p->s << 8;
+ r += p->s >> 8;
+ r += p->u >> 8;
+ return r;
+}
+
+/*
+ * The following is used in the kernel at several places
+ * It shouldn't emit any warnings.
+ */
+typedef unsigned long long u64;
+typedef unsigned int u32;
+
+extern void hw_w32x2(u32 hi, u32 lo);
+
+inline void hw_w64(u64 val)
+{
+ hw_w32x2(val >> 32, (u32) val);
+}
+
+void hw_write(u32 val)
+{
+ hw_w64(val);
+}
+
/*
* check-name: shift too big or negative
* check-command: sparse -Wno-decl $file
@@ -97,12 +130,12 @@ shift-undef.c:17:30: warning: shift too big (108) for type unsigned int
shift-undef.c:18:30: warning: shift too big (4294967289) for type int
shift-undef.c:19:30: warning: shift too big (4294967288) for type unsigned int
shift-undef.c:20:30: warning: shift too big (4294967287) for type unsigned int
-shift-undef.c:21:29: warning: right shift by bigger than source value
-shift-undef.c:22:29: warning: right shift by bigger than source value
-shift-undef.c:23:29: warning: right shift by bigger than source value
-shift-undef.c:24:29: warning: right shift by bigger than source value
-shift-undef.c:25:29: warning: right shift by bigger than source value
-shift-undef.c:26:29: warning: right shift by bigger than source value
+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: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
@@ -121,11 +154,11 @@ shift-undef.c:46:30: warning: shift too big (108) for type unsigned int
shift-undef.c:47:30: warning: shift too big (4294967289) for type int
shift-undef.c:48:30: warning: shift too big (4294967288) for type unsigned int
shift-undef.c:49:30: warning: shift too big (4294967287) for type unsigned int
-shift-undef.c:50:26: warning: right shift by bigger than source value
-shift-undef.c:51:26: warning: right shift by bigger than source value
-shift-undef.c:52:26: warning: right shift by bigger than source value
-shift-undef.c:53:26: warning: right shift by bigger than source value
-shift-undef.c:54:26: warning: right shift by bigger than source value
-shift-undef.c:55:26: warning: right shift by bigger than source value
+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
* check-error-end
*/