In prqlc/bindings/prqlc-c/src/lib.rs (lines 238-242), the prqlc_destroy_compile_result function reconstructs a Vec<i8> from a pointer that originally pointed to Vec<Message>:
drop(Vec::from_raw_parts(
res.messages as *mut i8,
res.messages_len,
res.messages_len,
));
This has two issues:
-
Wrong element type: The pointer is cast to *mut i8 but the original allocation was for Message elements. When the Vec is dropped, dealloc is called with messages_len * size_of::<i8>() bytes, but the actual allocation size was capacity * size_of::<Message>() bytes. This is undefined behavior per the Vec::from_raw_parts safety contract.
-
Capacity assumption: The capacity is set to messages_len, but the original Vec was created with Vec::with_capacity(err.inner.len()). While these should be equal in practice (the Vec is extended with exactly err.inner.len() items), the safety contract requires the exact capacity from the original allocation.
Suggested fix:
drop(Vec::from_raw_parts(
res.messages as *mut Message,
res.messages_len,
res.messages_len,
));
The individual Message fields are already cleaned up in the loop above (lines 218-236), so the Vec destructor just needs to free the allocation with the correct layout.
In
prqlc/bindings/prqlc-c/src/lib.rs(lines 238-242), theprqlc_destroy_compile_resultfunction reconstructs aVec<i8>from a pointer that originally pointed toVec<Message>:This has two issues:
Wrong element type: The pointer is cast to
*mut i8but the original allocation was forMessageelements. When the Vec is dropped,deallocis called withmessages_len * size_of::<i8>()bytes, but the actual allocation size wascapacity * size_of::<Message>()bytes. This is undefined behavior per the Vec::from_raw_parts safety contract.Capacity assumption: The capacity is set to
messages_len, but the original Vec was created withVec::with_capacity(err.inner.len()). While these should be equal in practice (the Vec is extended with exactlyerr.inner.len()items), the safety contract requires the exact capacity from the original allocation.Suggested fix:
The individual
Messagefields are already cleaned up in the loop above (lines 218-236), so the Vec destructor just needs to free the allocation with the correct layout.