fix: Vec.as_ptr() might return a dangling pointer (#760)

Both [as_ptr][as_ptr] and [as_mut_ptr][as_mut_ptr] are allowed to return
a dangling raw pointer when the Vec size is 0.

The idea is that you should guard that read checking the size. This
probably works well in most cases, but at the very least in the
java-sdk, the JNA machinery tries to be helpful and it dereferences the
pointer, causing a SIGSEGV.

The solution is to check if the resulting vector is empty and return
null instead. A new, empty vector would be better, but I think that
would not solve the problem, because the problem is caused by a new,
empty vector in the first place.

Caveat: this might break consumers downstream.
On the other hand: consumers that do not check for the nInput, nOutput
counts are just waiting to explode, like JNA.

This addresses https://github.com/extism/java-sdk/issues/27

[as_ptr]:
https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_ptr
[as_mut_ptr]:
https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_mut_ptr

Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
This commit is contained in:
Edoardo Vacchi
2024-09-04 18:41:55 +02:00
committed by GitHub
parent d2a3699f43
commit 34096bd9c0

View File

@@ -1,6 +1,6 @@
#![allow(clippy::missing_safety_doc)]
use std::os::raw::c_char;
use std::{os::raw::c_char, ptr::null_mut};
use crate::*;
@@ -231,12 +231,28 @@ pub unsafe extern "C" fn extism_function_new(
})
.collect();
// We cannot simply "get" the Vec's storage pointer because
// the underlying storage might be invalid when the Vec is empty.
// In that case, we return (null, 0).
let (inputs_ptr, inputs_len) = if inputs.is_empty() {
(core::ptr::null(), 0 as Size)
} else {
(inputs.as_ptr(), inputs.len() as Size)
};
let (output_ptr, output_len) = if output_tmp.is_empty() {
(null_mut(), 0 as Size)
} else {
(output_tmp.as_mut_ptr(), output_tmp.len() as Size)
};
func(
plugin,
inputs.as_ptr(),
inputs.len() as Size,
output_tmp.as_mut_ptr(),
output_tmp.len() as Size,
inputs_ptr,
inputs_len,
output_ptr,
output_len,
user_data.as_ptr(),
);