mirror of
https://github.com/extism/extism.git
synced 2026-01-09 22:07:57 -05:00
cleanup: host takes ownership of memory blocks it gets as arguments (#743)
This PR changes the host to take ownership of memory blocks passed into Extism host functions, see: https://github.com/extism/js-sdk/pull/71#issuecomment-2233687933
This commit is contained in:
@@ -495,6 +495,8 @@ pub unsafe fn store_u64(p: Pointer, x: u64) {
|
|||||||
/// Set the range of the input data in memory
|
/// Set the range of the input data in memory
|
||||||
/// h must always be a handle so that length works on it
|
/// h must always be a handle so that length works on it
|
||||||
/// len must match length(handle)
|
/// len must match length(handle)
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe fn input_set(h: Handle, len: u64) {
|
pub unsafe fn input_set(h: Handle, len: u64) {
|
||||||
let root = MemoryRoot::new();
|
let root = MemoryRoot::new();
|
||||||
@@ -509,6 +511,8 @@ pub unsafe fn input_set(h: Handle, len: u64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the range of the output data in memory
|
/// Set the range of the output data in memory
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe fn output_set(p: Pointer, len: u64) {
|
pub unsafe fn output_set(p: Pointer, len: u64) {
|
||||||
let root = MemoryRoot::new();
|
let root = MemoryRoot::new();
|
||||||
@@ -554,6 +558,8 @@ pub unsafe fn reset() {
|
|||||||
|
|
||||||
/// Set the error message offset, the handle passed to this
|
/// Set the error message offset, the handle passed to this
|
||||||
/// function should not be freed after this call
|
/// function should not be freed after this call
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe fn error_set(h: Handle) {
|
pub unsafe fn error_set(h: Handle) {
|
||||||
let root = MemoryRoot::new();
|
let root = MemoryRoot::new();
|
||||||
|
|||||||
0
runtime/src/extism-runtime.wasm
Executable file → Normal file
0
runtime/src/extism-runtime.wasm
Executable file → Normal file
@@ -20,6 +20,8 @@ macro_rules! args {
|
|||||||
/// Get a configuration value
|
/// Get a configuration value
|
||||||
/// Params: i64 (offset)
|
/// Params: i64 (offset)
|
||||||
/// Returns: i64 (offset)
|
/// Returns: i64 (offset)
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
pub(crate) fn config_get(
|
pub(crate) fn config_get(
|
||||||
mut caller: Caller<CurrentPlugin>,
|
mut caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
@@ -38,6 +40,7 @@ pub(crate) fn config_get(
|
|||||||
};
|
};
|
||||||
let val = data.manifest.config.get(key);
|
let val = data.manifest.config.get(key);
|
||||||
let ptr = val.map(|x| (x.len(), x.as_ptr()));
|
let ptr = val.map(|x| (x.len(), x.as_ptr()));
|
||||||
|
data.memory_free(handle)?;
|
||||||
let mem = match ptr {
|
let mem = match ptr {
|
||||||
Some((len, ptr)) => {
|
Some((len, ptr)) => {
|
||||||
let bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
|
let bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
|
||||||
@@ -55,6 +58,9 @@ pub(crate) fn config_get(
|
|||||||
/// Get a variable
|
/// Get a variable
|
||||||
/// Params: i64 (offset)
|
/// Params: i64 (offset)
|
||||||
/// Returns: i64 (offset)
|
/// Returns: i64 (offset)
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value, but the return value
|
||||||
|
/// will need to be freed
|
||||||
pub(crate) fn var_get(
|
pub(crate) fn var_get(
|
||||||
mut caller: Caller<CurrentPlugin>,
|
mut caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
@@ -73,6 +79,8 @@ pub(crate) fn var_get(
|
|||||||
};
|
};
|
||||||
let val = data.vars.get(key);
|
let val = data.vars.get(key);
|
||||||
let ptr = val.map(|x| (x.len(), x.as_ptr()));
|
let ptr = val.map(|x| (x.len(), x.as_ptr()));
|
||||||
|
data.memory_free(handle)?;
|
||||||
|
|
||||||
let mem = match ptr {
|
let mem = match ptr {
|
||||||
Some((len, ptr)) => {
|
Some((len, ptr)) => {
|
||||||
let bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
|
let bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
|
||||||
@@ -90,6 +98,8 @@ pub(crate) fn var_get(
|
|||||||
/// Set a variable, if the value offset is 0 then the provided key will be removed
|
/// Set a variable, if the value offset is 0 then the provided key will be removed
|
||||||
/// Params: i64 (key offset), i64 (value offset)
|
/// Params: i64 (key offset), i64 (value offset)
|
||||||
/// Returns: none
|
/// Returns: none
|
||||||
|
/// **Note**: this function takes ownership of the handles passed in
|
||||||
|
/// the caller should not `free` these values
|
||||||
pub(crate) fn var_set(
|
pub(crate) fn var_set(
|
||||||
mut caller: Caller<CurrentPlugin>,
|
mut caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
@@ -104,12 +114,12 @@ pub(crate) fn var_set(
|
|||||||
let voffset = args!(input, 1, i64) as u64;
|
let voffset = args!(input, 1, i64) as u64;
|
||||||
let key_offs = args!(input, 0, i64) as u64;
|
let key_offs = args!(input, 0, i64) as u64;
|
||||||
|
|
||||||
let key = {
|
let key_handle = match data.memory_handle(key_offs) {
|
||||||
let handle = match data.memory_handle(key_offs) {
|
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => anyhow::bail!("invalid handle offset for var key: {key_offs}"),
|
None => anyhow::bail!("invalid handle offset for var key: {key_offs}"),
|
||||||
};
|
};
|
||||||
let key = data.memory_str(handle)?;
|
let key = {
|
||||||
|
let key = data.memory_str(key_handle)?;
|
||||||
let key_len = key.len();
|
let key_len = key.len();
|
||||||
let key_ptr = key.as_ptr();
|
let key_ptr = key.as_ptr();
|
||||||
unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(key_ptr, key_len)) }
|
unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(key_ptr, key_len)) }
|
||||||
@@ -118,6 +128,7 @@ pub(crate) fn var_set(
|
|||||||
// Remove if the value offset is 0
|
// Remove if the value offset is 0
|
||||||
if voffset == 0 {
|
if voffset == 0 {
|
||||||
data.vars.remove(key);
|
data.vars.remove(key);
|
||||||
|
data.memory_free(key_handle)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +155,9 @@ pub(crate) fn var_set(
|
|||||||
|
|
||||||
let value = data.memory_bytes(handle)?.to_vec();
|
let value = data.memory_bytes(handle)?.to_vec();
|
||||||
|
|
||||||
|
data.memory_free(handle)?;
|
||||||
|
data.memory_free(key_handle)?;
|
||||||
|
|
||||||
// Insert the value from memory into the `vars` map
|
// Insert the value from memory into the `vars` map
|
||||||
data.vars.insert(key.to_string(), value);
|
data.vars.insert(key.to_string(), value);
|
||||||
|
|
||||||
@@ -153,6 +167,9 @@ pub(crate) fn var_set(
|
|||||||
/// Make an HTTP request
|
/// Make an HTTP request
|
||||||
/// Params: i64 (offset to JSON encoded HttpRequest), i64 (offset to body or 0)
|
/// Params: i64 (offset to JSON encoded HttpRequest), i64 (offset to body or 0)
|
||||||
/// Returns: i64 (offset)
|
/// Returns: i64 (offset)
|
||||||
|
/// **Note**: this function takes ownership of the handles passed in
|
||||||
|
/// the caller should not `free` these values, the result will need to
|
||||||
|
/// be freed.
|
||||||
pub(crate) fn http_request(
|
pub(crate) fn http_request(
|
||||||
#[allow(unused_mut)] mut caller: Caller<CurrentPlugin>,
|
#[allow(unused_mut)] mut caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
@@ -166,6 +183,7 @@ pub(crate) fn http_request(
|
|||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => anyhow::bail!("http_request input is invalid: {http_req_offset}"),
|
None => anyhow::bail!("http_request input is invalid: {http_req_offset}"),
|
||||||
};
|
};
|
||||||
|
data.free(handle)?;
|
||||||
let req: extism_manifest::HttpRequest = serde_json::from_slice(data.memory_bytes(handle)?)?;
|
let req: extism_manifest::HttpRequest = serde_json::from_slice(data.memory_bytes(handle)?)?;
|
||||||
output[0] = Val::I64(0);
|
output[0] = Val::I64(0);
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
@@ -182,6 +200,7 @@ pub(crate) fn http_request(
|
|||||||
None => anyhow::bail!("invalid handle offset for http request: {http_req_offset}"),
|
None => anyhow::bail!("invalid handle offset for http request: {http_req_offset}"),
|
||||||
};
|
};
|
||||||
let req: extism_manifest::HttpRequest = serde_json::from_slice(data.memory_bytes(handle)?)?;
|
let req: extism_manifest::HttpRequest = serde_json::from_slice(data.memory_bytes(handle)?)?;
|
||||||
|
data.memory_free(handle)?;
|
||||||
|
|
||||||
let body_offset = args!(input, 1, i64) as u64;
|
let body_offset = args!(input, 1, i64) as u64;
|
||||||
|
|
||||||
@@ -235,6 +254,10 @@ pub(crate) fn http_request(
|
|||||||
r.call()
|
r.call()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(handle) = data.memory_handle(body_offset) {
|
||||||
|
data.memory_free(handle)?;
|
||||||
|
}
|
||||||
|
|
||||||
let reader = match res {
|
let reader = match res {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
data.http_status = res.status();
|
data.http_status = res.status();
|
||||||
@@ -302,19 +325,21 @@ pub fn log(
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let data: &mut CurrentPlugin = caller.data_mut();
|
let data: &mut CurrentPlugin = caller.data_mut();
|
||||||
|
|
||||||
|
let offset = args!(input, 0, i64) as u64;
|
||||||
|
|
||||||
// Check if the current log level should be logged
|
// Check if the current log level should be logged
|
||||||
let global_log_level = tracing::level_filters::LevelFilter::current();
|
let global_log_level = tracing::level_filters::LevelFilter::current();
|
||||||
if global_log_level == tracing::level_filters::LevelFilter::OFF || level > global_log_level {
|
if global_log_level == tracing::level_filters::LevelFilter::OFF || level > global_log_level {
|
||||||
|
if let Some(handle) = data.memory_handle(offset) {
|
||||||
|
data.memory_free(handle)?;
|
||||||
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let offset = args!(input, 0, i64) as u64;
|
|
||||||
|
|
||||||
let handle = match data.memory_handle(offset) {
|
let handle = match data.memory_handle(offset) {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => anyhow::bail!("invalid handle offset for log message: {offset}"),
|
None => anyhow::bail!("invalid handle offset for log message: {offset}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let id = data.id.to_string();
|
let id = data.id.to_string();
|
||||||
let buf = data.memory_str(handle);
|
let buf = data.memory_str(handle);
|
||||||
|
|
||||||
@@ -338,12 +363,16 @@ pub fn log(
|
|||||||
},
|
},
|
||||||
Err(_) => tracing::error!(plugin = id, "unable to log message: {:?}", buf),
|
Err(_) => tracing::error!(plugin = id, "unable to log message: {:?}", buf),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.memory_free(handle)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to logs (warning)
|
/// Write to logs (warning)
|
||||||
/// Params: i64 (offset)
|
/// Params: i64 (offset)
|
||||||
/// Returns: none
|
/// Returns: none
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
pub(crate) fn log_warn(
|
pub(crate) fn log_warn(
|
||||||
caller: Caller<CurrentPlugin>,
|
caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
@@ -355,6 +384,8 @@ pub(crate) fn log_warn(
|
|||||||
/// Write to logs (info)
|
/// Write to logs (info)
|
||||||
/// Params: i64 (offset)
|
/// Params: i64 (offset)
|
||||||
/// Returns: none
|
/// Returns: none
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
pub(crate) fn log_info(
|
pub(crate) fn log_info(
|
||||||
caller: Caller<CurrentPlugin>,
|
caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
@@ -366,6 +397,8 @@ pub(crate) fn log_info(
|
|||||||
/// Write to logs (debug)
|
/// Write to logs (debug)
|
||||||
/// Params: i64 (offset)
|
/// Params: i64 (offset)
|
||||||
/// Returns: none
|
/// Returns: none
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
pub(crate) fn log_debug(
|
pub(crate) fn log_debug(
|
||||||
caller: Caller<CurrentPlugin>,
|
caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
@@ -377,6 +410,8 @@ pub(crate) fn log_debug(
|
|||||||
/// Write to logs (error)
|
/// Write to logs (error)
|
||||||
/// Params: i64 (offset)
|
/// Params: i64 (offset)
|
||||||
/// Returns: none
|
/// Returns: none
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
pub(crate) fn log_error(
|
pub(crate) fn log_error(
|
||||||
caller: Caller<CurrentPlugin>,
|
caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
@@ -388,6 +423,8 @@ pub(crate) fn log_error(
|
|||||||
/// Write to logs (trace)
|
/// Write to logs (trace)
|
||||||
/// Params: i64 (offset)
|
/// Params: i64 (offset)
|
||||||
/// Returns: none
|
/// Returns: none
|
||||||
|
/// **Note**: this function takes ownership of the handle passed in
|
||||||
|
/// the caller should not `free` this value
|
||||||
pub(crate) fn log_trace(
|
pub(crate) fn log_trace(
|
||||||
caller: Caller<CurrentPlugin>,
|
caller: Caller<CurrentPlugin>,
|
||||||
input: &[Val],
|
input: &[Val],
|
||||||
|
|||||||
Reference in New Issue
Block a user