summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-05-23 20:12:15 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-05-23 20:12:15 -0700
commit6357ea31bd2755d29a1643b71e15da5b8facc779 (patch)
tree54c52c42b8b7126353adf50ed1bd917826b98bf5
parentcb02f7fe49ee2793131939e6582e358be035a742 (diff)
downloadtxr-6357ea31bd2755d29a1643b71e15da5b8facc779.tar.gz
txr-6357ea31bd2755d29a1643b71e15da5b8facc779.tar.bz2
txr-6357ea31bd2755d29a1643b71e15da5b8facc779.zip
oop: corruption bugfix.
* struct.c (alloc_seen): Fix under-sized alloca and memset, where the size being used is the number of elements, but should be the number of bytes. This showed up as a failure in the tests/012/oop-mi.tl on PPC64, uncovered by a completely unrelated change in eval.c. The unrelated code never executes during the failed test case; it just affects some memory contents of the stack somehow. The under-allocated array is used during structure type initialization to hold a bitmask which helps to suppress the duplicate initiation of base structures which are inherited multiple times (duplicate bases). I think why this shows up on PPC64 is the big endian order. The sizes involved are small. The test case has a couple of duplicate bases only, but a full 64 bit mask needs to be allocated for that since the mask is an array of ucnum. On little endian, it doesn't matter than only a single byte is allocated: that is enough for 8 duplicate bases, and because of the byte order, those bases land into the byte that is allocated. On big endian, the bases will be on the high part of the 64 bit word, and thus over in the area we didn't allocate. To reproduce an issue on little endian, you need an inheritance hierarchy with more duplicate bases.
-rw-r--r--struct.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/struct.c b/struct.c
index d68b222e..9fcfd2ad 100644
--- a/struct.c
+++ b/struct.c
@@ -769,7 +769,8 @@ val allocate_struct(val type)
#define alloc_seen(name, size_name) \
const int bits_ucnum = sizeof (ucnum) * CHAR_BIT; \
- size_t size_name = (st->ndsupers + bits_ucnum - 1) / bits_ucnum; \
+ size_t nelem_name = (st->ndsupers + bits_ucnum - 1) / bits_ucnum; \
+ size_t size_name = nelem_name * sizeof (ucnum); \
ucnum *name ## tmp = coerce(ucnum *, alloca(size_name)); \
ucnum *name = (memset(name ## tmp, 0, size_name), name ## tmp)