Skip to content

Commit 6f79a2d

Browse files
committed
fix: implement deallocation for fixed-length lists with heap elements
The deallocate and deallocate_indirect functions in the core ABI had incomplete handling for FixedLengthList types. deallocate had a todo!() that would panic when flat deallocation was needed for fixed-length lists containing resources. deallocate_indirect was a silent no-op that would leak memory for fixed-length lists containing heap-allocated elements like strings or nested lists. For flat deallocation, reuse flat_for_each_record_type with repeated element types. For indirect deallocation, reuse deallocate_indirect_fields with a vec of repeated element types to correctly compute memory offsets and deallocate each element.
1 parent fd57889 commit 6f79a2d

File tree

3 files changed

+138
-2
lines changed

3 files changed

+138
-2
lines changed

.idea/workspace.xml

Lines changed: 89 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/core/src/abi.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2404,7 +2404,13 @@ impl<'a, B: Bindgen> Generator<'a, B> {
24042404
TypeDefKind::Resource => unreachable!(),
24052405
TypeDefKind::Unknown => unreachable!(),
24062406

2407-
TypeDefKind::FixedLengthList(..) => todo!(),
2407+
TypeDefKind::FixedLengthList(element, size) => {
2408+
self.flat_for_each_record_type(
2409+
ty,
2410+
iter::repeat_n(element, *size as usize),
2411+
|me, ty| me.deallocate(ty, what),
2412+
);
2413+
}
24082414
TypeDefKind::Map(..) => todo!(),
24092415
},
24102416
}
@@ -2526,7 +2532,10 @@ impl<'a, B: Bindgen> Generator<'a, B> {
25262532
TypeDefKind::Future(_) => unreachable!(),
25272533
TypeDefKind::Stream(_) => unreachable!(),
25282534
TypeDefKind::Unknown => unreachable!(),
2529-
TypeDefKind::FixedLengthList(_, _) => {}
2535+
TypeDefKind::FixedLengthList(element, size) => {
2536+
let tys: Vec<Type> = iter::repeat_n(*element, *size as usize).collect();
2537+
self.deallocate_indirect_fields(&tys, addr, offset, what);
2538+
}
25302539
TypeDefKind::Map(..) => todo!(),
25312540
},
25322541
}

crates/rust/tests/codegen.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,44 @@ mod newtyped_list {
142142
}
143143
}
144144
}
145+
146+
#[test]
147+
fn fixed_length_list_deallocation() {
148+
let wit = r#"
149+
package test:fll-dealloc;
150+
151+
world test {
152+
export return-string-array: func() -> list<string, 3>;
153+
export accept-string-array: func(a: list<string, 3>);
154+
}
155+
"#;
156+
157+
let mut resolve = wit_bindgen_core::wit_parser::Resolve::default();
158+
let pkg = resolve.push_str("test.wit", wit).unwrap();
159+
let world = resolve.select_world(&[pkg], None).unwrap();
160+
161+
let opts = wit_bindgen_rust::Opts {
162+
generate_all: true,
163+
..Default::default()
164+
};
165+
166+
let mut generator = opts.build();
167+
let mut files = wit_bindgen_core::Files::default();
168+
use wit_bindgen_core::WorldGenerator;
169+
generator.generate(&mut resolve, world, &mut files).unwrap();
170+
171+
let (_name, contents) = files.iter().next().unwrap();
172+
let code = String::from_utf8_lossy(contents);
173+
174+
// Verify post-return deallocation functions are generated for
175+
// fixed-length lists containing heap-allocated elements (strings)
176+
assert!(
177+
code.contains("cabi_post_"),
178+
"expected cabi_post_ deallocation function for fixed-length list \
179+
with string elements, but none was generated"
180+
);
181+
}
182+
145183
#[allow(unused, reason = "testing codegen, not functionality")]
146184
mod retyped_list {
147185
use std::ops::Deref;

0 commit comments

Comments
 (0)