aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-11-29 15:11:46 -0500
committerBruce Hill <bruce@bruce-hill.com>2025-11-29 15:11:46 -0500
commit75b7ee2a08aefbdb2e2202718326fadd96ee0ef0 (patch)
treec5376b68b658398399c47d20a37b6acebaf1807f
parentbb2f890fd470fff3e42698710b56c68164491d85 (diff)
Fix for undefined behavior on structs/enums with paddingv2025-11-29.2
-rw-r--r--CHANGES.md6
-rw-r--r--src/types.c14
2 files changed, 18 insertions, 2 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 212fe54c..b4910bb8 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,11 @@
# Version History
+## v2025-11-29.2
+
+### Bugfixes
+
+- Fix for undefined behavior on enums and structs with padding.
+
## v2025-11-29
### Syntax changes
diff --git a/src/types.c b/src/types.c
index 04784735..6ed24f6c 100644
--- a/src/types.c
+++ b/src/types.c
@@ -459,15 +459,25 @@ PUREFUNC bool is_packed_data(type_t *t) {
|| t->tag == FunctionType) {
return true;
} else if (t->tag == StructType) {
+ size_t offset = 0;
for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) {
if (!is_packed_data(field->type)) return false;
+ size_t align = type_align(field->type);
+ if (align > 0 && offset % align != 0) return false;
+ offset += type_size(field->type);
}
- return true;
+ size_t overall_align = type_align(t);
+ return overall_align == 0 || (offset % overall_align == 0);
} else if (t->tag == EnumType) {
+ size_t offset = sizeof(int32_t);
for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) {
if (!is_packed_data(tag->type)) return false;
+ size_t align = type_align(tag->type);
+ if (align > 0 && offset % align != 0) return false;
+ offset += type_size(tag->type);
}
- return true;
+ size_t overall_align = type_align(t);
+ return overall_align == 0 || (offset % overall_align == 0);
} else {
return false;
}