aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qbe.c7
-rw-r--r--test/bitfield-initializer-overflow.c3
-rw-r--r--test/bitfield-initializer-overflow.qbe1
3 files changed, 10 insertions, 1 deletions
diff --git a/qbe.c b/qbe.c
index c496c41..deb5520 100644
--- a/qbe.c
+++ b/qbe.c
@@ -1266,7 +1266,12 @@ emitdata(struct decl *d, struct init *init)
bits |= cur->expr->constant.i << cur->bits.before % 8;
for (offset = start; offset < end; ++offset, bits >>= 8)
printf("b %u, ", (unsigned)bits & 0xff);
- bits &= 0xff >> cur->bits.after % 8;
+ /*
+ clear the upper `after` bits in the last byte,
+ or all bits when `after` is 0 (we ended on a
+ byte boundary).
+ */
+ bits &= 0x7f >> (cur->bits.after + 7) % 8;
} else {
printf("%c ", cur->expr->type->kind == TYPEARRAY ? cur->expr->type->base->repr->ext : cur->expr->type->repr->ext);
dataitem(cur->expr, cur->end - cur->start);
diff --git a/test/bitfield-initializer-overflow.c b/test/bitfield-initializer-overflow.c
new file mode 100644
index 0000000..54de7c9
--- /dev/null
+++ b/test/bitfield-initializer-overflow.c
@@ -0,0 +1,3 @@
+struct {
+ unsigned : 30, a : 2, b;
+} s = {5};
diff --git a/test/bitfield-initializer-overflow.qbe b/test/bitfield-initializer-overflow.qbe
new file mode 100644
index 0000000..be0a065
--- /dev/null
+++ b/test/bitfield-initializer-overflow.qbe
@@ -0,0 +1 @@
+export data $s = align 4 { z 3, b 64, z 4 }