aboutsummaryrefslogtreecommitdiffstats
path: root/symbol.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2006-10-01 09:21:11 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2006-10-01 09:40:18 -0400
commitd24967cb847b7a04920698a9053ea8195046a831 (patch)
tree6bb9b9397080b04e75bce7ed05fc85a8a2593f86 /symbol.c
parent6ca174d56bdac762d5f8b205cfcc6c3723b3070e (diff)
downloadsparse-d24967cb847b7a04920698a9053ea8195046a831.tar.gz
[PATCH] handle fouled-bitwise
This stuff comes from handling smaller-than-int bitwise types (e.g. __le16). The problem is in handling things like __be16 x, y; ... if (x == (x & ~y)) The code is bitwise-clean, but current sparse can't deduce that. Operations allowed on bitwise types have the following property: (type)(x <op> y) can be substituted for x <op> y in any expression other than sizeof. That allows us to ignore usual arithmetical conversions for those types and treat e.g. | as __be16 x __be16 -> __be16, despite the promotion rules; resulting semantics will be the same. However, ~ on smaller-than-int does not have such property; indeed, ~y is guaranteed to _not_ fit into range of __be16 in the example above. That causes a lot of unpleasant problems when dealing with e.g. networking code - IP checksums are 16bit and ~ is often used in their (re)calculations. The way to deal with that is based on the observation that even though we do get junk in upper bits, it normally ends up being discarded and sparse can be taught to prove that. To do that we need "fouled" conterparts for short bitwise types. They will be assigned to (sub)expressions that might carry junk in upper bits, but trimming those bits would result in the value we'd get if all operations had been done within the bitwise type. E.g. in the example above y would be __be16, ~y - fouled __be16, x & ~y - __be16 again and x == (x & ~y) - boolean. Basically, we delay reporting an error on ~<short bitwise> for as long as possible in hope that taint will be cleansed later. Exact rules follow: * ~short_bitwise => corresponding fouled * any arithmetics that would be banned for bitwise => same warning as if we would have bitwise * if t1 is bitwise type and t2 - its fouled analog, then t1 & t2 => t1, t1 | t2 => t2, t1 ^ t2 => t2. * conversion of t2 to t1 is silent (be it passing as argument or assignment). Other conversions are banned. * x ? t1 : t2 => t2 * ~t2 => t2 (_not_ t1; something like ~(x ? y : ~y) is still fouled) * x ? t2 : t2 => t2, t2 {&,|,^} t2 => t2 (yes, even ^ - same as before). * x ? t2 : constant_valid_for_t1 => t2 * !t2 => warning, ditto for comparisons involving t2 in any way. * wrt casts t2 acts exactly as t1 would. * for sizeof, typeof and alignof t2 acts as promoted t1. Note that fouled can never be an lvalue or have types derived from it - can't happen. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'symbol.c')
-rw-r--r--symbol.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/symbol.c b/symbol.c
index 7d64f7f4..6c911124 100644
--- a/symbol.c
+++ b/symbol.c
@@ -423,6 +423,9 @@ struct symbol *examine_symbol_type(struct symbol * sym)
case SYM_RESTRICT:
examine_base_type(sym);
return sym;
+ case SYM_FOULED:
+ examine_base_type(sym);
+ return sym;
default:
sparse_error(sym->pos, "Examining unknown symbol type %d", sym->type);
break;
@@ -430,6 +433,41 @@ struct symbol *examine_symbol_type(struct symbol * sym)
return sym;
}
+static struct symbol_list *restr, *fouled;
+
+void create_fouled(struct symbol *type)
+{
+ if (type->bit_size < bits_in_int) {
+ struct symbol *new = alloc_symbol(type->pos, type->type);
+ *new = *type;
+ new->bit_size = bits_in_int;
+ new->type = SYM_FOULED;
+ new->ctype.base_type = type;
+ add_symbol(&restr, type);
+ add_symbol(&fouled, new);
+ }
+}
+
+struct symbol *befoul(struct symbol *type)
+{
+ struct symbol *t1, *t2;
+ while (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ PREPARE_PTR_LIST(restr, t1);
+ PREPARE_PTR_LIST(fouled, t2);
+ for (;;) {
+ if (t1 == type)
+ return t2;
+ if (!t1)
+ break;
+ NEXT_PTR_LIST(t1);
+ NEXT_PTR_LIST(t2);
+ }
+ FINISH_PTR_LIST(t2);
+ FINISH_PTR_LIST(t1);
+ return NULL;
+}
+
void check_declaration(struct symbol *sym)
{
int warned = 0;