aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-12-20 16:12:38 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-12-29 14:39:38 +0100
commitf07a1053a90039a2d88ed62f74add2ee131d67b7 (patch)
tree805425a74adf49c8f6c74f853db71124f296bedd
parent09fcd53fd30883985aa5aeacc24808ba02fb7be1 (diff)
downloadsparse-f07a1053a90039a2d88ed62f74add2ee131d67b7.tar.gz
packed: no out-of-bound access of packed bitfields
There is (at least) 2 ways by which packed bitfields doesn't follow normal layout/access rules and as consequence can't (always) be accessed the usual way (load the whole underlying word, then shift and mask to isolate the bitfield). At least two different cases are a concern: 1) there is no padding at the end of a bitfield sequence. For example, the following struct is only 3 bytes width: struct s { int f:24; } __packed; So, trying to access the bitfield by first doing a 32-bit load will create an out-of-bound access. 2) a bitfield smaller than one word may need more than one word to be accessed. For example, with the following struct struct { int a:5; int f:30; int z:5; } __packed; the bitfield 'f', while smaller than one 32-bit word, can't be accessed with a single 32-bit access. At machine level, these bitfields should be accessed with several, possibly smaller, loads and their corresponding values reconstructed from these, making things much more complicated than for non-packed bitfields. But at IR level, things can be a little more flexible and things can stay simple by using sub-word or super-word accesses (until these need to be lowered to be usable at machine level). In other words, the example here can be safely accessed with respectively a 24-bit and a 40-bit load. This is what is done in this patch. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--linearize.c13
-rw-r--r--symbol.h1
2 files changed, 12 insertions, 2 deletions
diff --git a/linearize.c b/linearize.c
index 0250c6bb..e80715ab 100644
--- a/linearize.c
+++ b/linearize.c
@@ -977,8 +977,17 @@ static struct symbol *bitfield_base_type(struct symbol *sym)
if (sym) {
if (sym->type == SYM_NODE)
base = base->ctype.base_type;
- if (base->type == SYM_BITFIELD)
- return base->ctype.base_type;
+ if (base->type == SYM_BITFIELD) {
+ base = base->ctype.base_type;
+ if (sym->packed) {
+ int size = bits_to_bytes(sym->bit_offset + sym->bit_size);
+ sym = __alloc_symbol(0);
+ *sym = *base;
+ sym->bit_size = bytes_to_bits(size);
+ return sym;
+ }
+ return base;
+ }
}
return sym;
}
diff --git a/symbol.h b/symbol.h
index 5c5a7f12..866d5752 100644
--- a/symbol.h
+++ b/symbol.h
@@ -192,6 +192,7 @@ struct symbol {
accessed:1,
builtin:1,
torename:1,
+ packed:1,
transparent_union:1;
int rank:3; // arithmetic's rank
struct expression *array_size;