diff --git a/README.md b/README.md index d3ed0e2..a4ea6f0 100644 --- a/README.md +++ b/README.md @@ -35,17 +35,17 @@ int32_t EXTISM_EXPORTED_FUNCTION(greet) { // Load input static uint8_t inputData[Greet_Max_Input]; - extism_load_input(inputData, inputLen); + extism_load_input(0, inputData, inputLen); - // Allocate a new offset used to store greeting and name + // Allocate memory to store greeting and name const uint64_t greetingLen = sizeof(Greeting) - 1; const uint64_t outputLen = greetingLen + inputLen; - ExtismPointer offs = extism_alloc(outputLen); - extism_store(offs, (const uint8_t *)Greeting, greetingLen); - extism_store(offs + greetingLen, inputData, inputLen); + ExtismHandle handle = extism_alloc(outputLen); + extism_store_to_handle(handle, 0, Greeting, greetingLen); + extism_store_to_handle(handle, greetingLen, inputData, inputLen); // Set output - extism_output_set(offs, outputLen); + extism_output_set_from_handle(handle, 0, outputLen); return 0; } ``` @@ -71,7 +71,7 @@ command: ```bash extism call plugin.wasm greet --input="Benjamin" -# => Hello, Benjamin! +# => Hello, Benjamin ``` ### More Exports: Error Handling @@ -101,26 +101,26 @@ int32_t EXTISM_EXPORTED_FUNCTION(greet) { // Load input static uint8_t inputData[Greet_Max_Input]; - extism_load_input(inputData, inputLen); + extism_load_input(0, inputData, inputLen); inputData[inputLen] = '\0'; // Check if the input matches "benjamin", if it does // return an error if (is_benjamin((const char *)inputData)) { - ExtismPointer err = extism_alloc_string("ERROR", 5); + ExtismHandle err = extism_alloc_buf_from_sz("ERROR"); extism_error_set(err); return -1; } - // Allocate a new offset used to store greeting and name + // Allocate memory to store greeting and name const uint64_t greetingLen = sizeof(Greeting) - 1; const uint64_t outputLen = greetingLen + inputLen; - ExtismPointer offs = extism_alloc(outputLen); - extism_store(offs, (const uint8_t *)Greeting, greetingLen); - extism_store(offs + greetingLen, inputData, inputLen); + ExtismHandle handle = extism_alloc(outputLen); + extism_store_to_handle(handle, 0, Greeting, greetingLen); + extism_store_to_handle(handle, greetingLen, inputData, inputLen); // Set output - extism_output_set(offs, outputLen); + extism_output_set_from_handle(handle, 0, outputLen); return 0; } ``` @@ -135,7 +135,7 @@ extism call plugin.wasm greet --input="Benjamin" --wasi echo $? # print last status code # => 1 extism call plugin.wasm greet --input="Zach" --wasi -# => Hello, Zach! +# => Hello, Zach echo $? # => 0 ``` @@ -155,12 +155,12 @@ plug-in. These can be useful to statically configure the plug-in with some data static const char Greeting[] = "Hello, "; int32_t EXTISM_EXPORTED_FUNCTION(greet) { - ExtismPointer key = extism_alloc_string("user", 4); - ExtismPointer value = extism_config_get(key); + ExtismHandle key = extism_alloc_buf_from_sz("user"); + ExtismHandle value = extism_config_get(key); extism_free(key); if (value == 0) { - ExtismPointer err = extism_alloc_string("Invalid key", 11); + ExtismHandle err = extism_alloc_buf_from_sz("Invalid key"); extism_error_set(err); return -1; } @@ -170,22 +170,22 @@ int32_t EXTISM_EXPORTED_FUNCTION(greet) { // Load config value uint8_t *valueData = malloc(valueLen); if (valueData == NULL) { - ExtismPointer err = extism_alloc_string("OOM", 11); + ExtismHandle err = extism_alloc_buf_from_sz("OOM"); extism_error_set(err); return -1; } - extism_load(value, valueData, valueLen); + extism_load_from_handle(value, 0, valueData, valueLen); - // Allocate a new offset used to store greeting and name + // Allocate memory to store greeting and name const uint64_t greetingLen = sizeof(Greeting) - 1; const uint64_t outputLen = greetingLen + valueLen; - ExtismPointer offs = extism_alloc(outputLen); - extism_store(offs, (const uint8_t *)Greeting, greetingLen); - extism_store(offs + greetingLen, valueData, valueLen); + ExtismHandle handle = extism_alloc(outputLen); + extism_store_to_handle(handle, 0, Greeting, greetingLen); + extism_store_to_handle(handle, greetingLen, valueData, valueLen); free(valueData); // Set output - extism_output_set(offs, outputLen); + extism_output_set_from_handle(handle, 0, outputLen); return 0; } ``` @@ -195,7 +195,7 @@ To test it, the [Extism CLI](https://github.com/extism/cli) has a `--config` opt ```bash extism call plugin.wasm greet --config user=Benjamin -# => Hello, Benjamin! +# => Hello, Benjamin ``` ### Variables @@ -211,12 +211,12 @@ You can use `extism_var_get`, and `extism_var_set` to manipulate vars: #include int32_t EXTISM_EXPORTED_FUNCTION(count) { - ExtismPointer key = extism_alloc_string("count", 5); - ExtismPointer value = extism_var_get(key); + ExtismHandle key = extism_alloc_buf_from_sz("count"); + ExtismHandle value = extism_var_get(key); uint64_t count = 0; if (value != 0) { - extism_load(value, (uint8_t *)&count, sizeof(uint64_t)); + extism_load_from_handle(value, 0, &count, sizeof(uint64_t)); } count += 1; @@ -226,7 +226,7 @@ int32_t EXTISM_EXPORTED_FUNCTION(count) { } // Update the memory block - extism_store(value, (uint8_t *)&count, sizeof(uint64_t)); + extism_store_to_handle(value, 0, &count, sizeof(uint64_t)); // Set the variable extism_var_set(key, value); @@ -250,12 +250,12 @@ The `extism_log*` functions can be used to emit logs: #include int32_t EXTISM_EXPORTED_FUNCTION(log_stuff) { - ExtismPointer msg = extism_alloc_string("Hello!", 6); + ExtismHandle msg = extism_alloc_buf_from_sz("Hello!"); extism_log_info(msg); extism_log_debug(msg); extism_log_warn(msg); extism_log_error(msg); - extism_log("Hello!", 6, ExtismLogInfo); + extism_log_sz("Hello!", ExtismLogInfo); return 0; } ``` @@ -288,14 +288,14 @@ int32_t EXTISM_EXPORTED_FUNCTION(call_http) { \"url\": \"https://jsonplaceholder.typicode.com/todos/1\"\ }"; - ExtismPointer req = extism_alloc_string(reqStr, strlen(reqStr)); - ExtismPointer res = extism_http_request(req, 0); + ExtismHandle req = extism_alloc_buf_from_sz(reqStr); + ExtismHandle res = extism_http_request(req, 0); if (extism_http_status_code() != 200) { return -1; } - extism_output_set(res, extism_length(res)); + extism_output_set_from_handle(res, 0, extism_length(res)); return 0; } ``` @@ -318,18 +318,18 @@ to do this correctly. So we recommend reading out [concept doc on Host Functions Host functions have a similar interface as exports. You just need to declare them as `extern` on the top of your header file. You only declare the interface as it is the host's responsibility to provide the implementation: ```c -extern ExtismPointer a_python_func(ExtismPointer); +extern ExtismHandle a_python_func(ExtismHandle); ``` A namespace may be set for an import using the `IMPORT` macro in `extism-pdk.h`: ```c -IMPORT("my_module", "a_python_func") extern ExtismPointer a_python_func(ExtismPointer); +IMPORT("my_module", "a_python_func") extern ExtismHandle a_python_func(ExtismHandle); ``` > **Note**: The types we accept here are the same as the exports as the interface also uses the [convert crate](https://docs.rs/extism-convert/latest/extism_convert/). -To call this function, we pass an Extism pointer and receive one back: +To call this function, we pass an Extism handle and receive one back: ```c #define EXTISM_IMPLEMENTATION @@ -337,10 +337,10 @@ To call this function, we pass an Extism pointer and receive one back: #include int32_t EXTISM_EXPORTED_FUNCTION(hello_from_python) { - ExtismPointer arg = extism_alloc_string("Hello!", 6); - ExtismPointer res = a_python_func(arg); + ExtismHandle arg = extism_alloc_buf_from_sz("Hello!"); + ExtismHandle res = a_python_func(arg); extism_free(arg); - extism_output_set(res, extism_length(res)); + extism_output_set_from_handle(res, 0, extism_length(res)); return 0; } ``` @@ -407,6 +407,8 @@ All other source files using the pdk must include the header without `#define EX The C PDK does not require building with `libc`, but additional functions can be enabled when `libc` is available. `#define EXTISM_USE_LIBC` in each file before including the pdk (everywhere it is included) or, when compiling, pass it as a flag to clang: `-D EXTISM_USE_LIBC` +The low-level API that operates on `ExtismPointer` is no longer included by default, `#define EXTISM_ENABLE_LOW_LEVEL_API` in each file before including the pdk (everywhere it is included) or, when compiling, pass it as a flag to clang: `-D EXTISM_ENABLE_LOW_LEVEL_API` . Updating to use the `ExtismHandle`-based API is highly recommended. + The C PDK may be used from C++, however, the implementation must be built with a C compiler. See `cplusplus` in `tests/Makefile` for an example. ## Exports (details) diff --git a/examples/count-vowels/count-vowels.c b/examples/count-vowels/count-vowels.c index f5d94a5..f2dc783 100644 --- a/examples/count-vowels/count-vowels.c +++ b/examples/count-vowels/count-vowels.c @@ -1,3 +1,4 @@ +#define EXTISM_ENABLE_LOW_LEVEL_API #define EXTISM_IMPLEMENTATION #include "../../extism-pdk.h" @@ -19,9 +20,9 @@ int32_t EXTISM_EXPORTED_FUNCTION(count_vowels) { char out[128]; int n = snprintf(out, 128, "{\"count\": %llu}", count); - uint64_t offs_ = extism_alloc(n); - extism_store(offs_, (const uint8_t *)out, n); - extism_output_set(offs_, n); + ExtismHandle buf = extism_alloc(n); + extism_store(buf, out, n); + extism_output_set(buf, n); return 0; } diff --git a/examples/globals/globals.c b/examples/globals/globals.c index 9a2487a..8a53edd 100644 --- a/examples/globals/globals.c +++ b/examples/globals/globals.c @@ -9,9 +9,9 @@ int32_t EXTISM_EXPORTED_FUNCTION(globals) { char out[128]; int n = snprintf(out, 128, "{\"count\": %llu}", count); - uint64_t offs_ = extism_alloc(n); - extism_store(offs_, (const uint8_t *)out, n); - extism_output_set(offs_, n); + ExtismHandle buf = extism_alloc(n); + extism_store_to_handle(buf, 0, out, n); + extism_output_set_from_handle(buf, 0, n); count += 1; diff --git a/examples/host-functions/host-functions.c b/examples/host-functions/host-functions.c index 2735594..45ad4a8 100644 --- a/examples/host-functions/host-functions.c +++ b/examples/host-functions/host-functions.c @@ -1,10 +1,11 @@ +#define EXTISM_ENABLE_LOW_LEVEL_API #define EXTISM_IMPLEMENTATION #include "../../extism-pdk.h" #include EXTISM_IMPORT("extism:host/user", "hello_world") -extern uint64_t hello_world(uint64_t); +extern ExtismHandle hello_world(ExtismHandle); int32_t EXTISM_EXPORTED_FUNCTION(count_vowels) { uint64_t length = extism_input_length(); @@ -25,9 +26,9 @@ int32_t EXTISM_EXPORTED_FUNCTION(count_vowels) { char out[128]; int n = snprintf(out, 128, "{\"count\": %lld}", count); - uint64_t offs_ = extism_alloc(n); - extism_store(offs_, (const uint8_t *)out, n); - offs_ = hello_world(offs_); - extism_output_set(offs_, extism_length(offs_)); + ExtismHandle buf = extism_alloc(n); + extism_store_to_handle(buf, 0, out, n); + buf = hello_world(buf); + extism_output_set(buf, extism_length(buf)); return 0; } diff --git a/extism-pdk.h b/extism-pdk.h index a4dcfb1..f2ad23c 100644 --- a/extism-pdk.h +++ b/extism-pdk.h @@ -8,7 +8,7 @@ extern "C" { #include #include -typedef uint64_t ExtismPointer; +typedef uint64_t ExtismHandle; #define EXTISM_ENV_MODULE "extism:host/env" #define EXTISM_USER_MODULE "extism:host/user" @@ -24,100 +24,110 @@ typedef uint64_t ExtismPointer; #define EXTISM_IMPORT_USER(b) \ __attribute__((import_module(EXTISM_USER_MODULE), import_name(b))) -EXTISM_IMPORT_ENV("input_length") -extern uint64_t extism_input_length(void); -EXTISM_IMPORT_ENV("length") -extern uint64_t extism_length(const ExtismPointer); +EXTISM_IMPORT_ENV("length_unsafe") +extern uint64_t extism_length(const ExtismHandle); EXTISM_IMPORT_ENV("alloc") -extern ExtismPointer extism_alloc(const uint64_t); +extern ExtismHandle extism_alloc(const uint64_t); EXTISM_IMPORT_ENV("free") -extern void extism_free(ExtismPointer); -EXTISM_IMPORT_ENV("input_load_u8") -extern uint8_t extism_input_load_u8(const ExtismPointer); - -EXTISM_IMPORT_ENV("input_load_u64") -extern uint64_t extism_input_load_u64(const ExtismPointer); - -EXTISM_IMPORT_ENV("output_set") -extern void extism_output_set(const ExtismPointer, const uint64_t); +extern void extism_free(ExtismHandle); EXTISM_IMPORT_ENV("error_set") -extern void extism_error_set(const ExtismPointer); +extern void extism_error_set(const ExtismHandle); EXTISM_IMPORT_ENV("config_get") -extern ExtismPointer extism_config_get(const ExtismPointer); +extern ExtismHandle extism_config_get(const ExtismHandle); EXTISM_IMPORT_ENV("var_get") -extern ExtismPointer extism_var_get(const ExtismPointer); +extern ExtismHandle extism_var_get(const ExtismHandle); EXTISM_IMPORT_ENV("var_set") -extern void extism_var_set(ExtismPointer, const ExtismPointer); - -EXTISM_IMPORT_ENV("store_u8") -extern void extism_store_u8(ExtismPointer, const uint8_t); - -EXTISM_IMPORT_ENV("load_u8") -extern uint8_t extism_load_u8(const ExtismPointer); - -EXTISM_IMPORT_ENV("store_u64") -extern void extism_store_u64(ExtismPointer, const uint64_t); - -EXTISM_IMPORT_ENV("load_u64") -extern uint64_t extism_load_u64(const ExtismPointer); +extern void extism_var_set(ExtismHandle, const ExtismHandle); EXTISM_IMPORT_ENV("http_request") -extern ExtismPointer extism_http_request(const ExtismPointer, - const ExtismPointer); +extern ExtismHandle extism_http_request(const ExtismHandle, const ExtismHandle); EXTISM_IMPORT_ENV("http_status_code") extern int32_t extism_http_status_code(void); EXTISM_IMPORT_ENV("log_info") -extern void extism_log_info(const ExtismPointer); +extern void extism_log_info(const ExtismHandle); EXTISM_IMPORT_ENV("log_debug") -extern void extism_log_debug(const ExtismPointer); +extern void extism_log_debug(const ExtismHandle); EXTISM_IMPORT_ENV("log_warn") -extern void extism_log_warn(const ExtismPointer); +extern void extism_log_warn(const ExtismHandle); EXTISM_IMPORT_ENV("log_error") -extern void extism_log_error(const ExtismPointer); +extern void extism_log_error(const ExtismHandle); -// Load data from Extism memory, does not verify load is in bounds -void extism_load(const ExtismPointer offs, void *dest, const size_t n); +EXTISM_IMPORT_ENV("input_offset") +extern ExtismHandle extism_input_offset(void); + +EXTISM_IMPORT_ENV("input_length") +extern uint64_t extism_input_length(void); +// extism_length(extism_input_offset()); is also valid + +// Load data from Extism memory, verifies load is inbounds +bool extism_load_from_handle(const ExtismHandle src, const uint64_t src_offset, + void *dest, const size_t n); // Load data from input buffer, verifies load is inbounds -bool extism_load_input(void *dest, const size_t n); +static inline bool extism_load_input(const uint64_t src_offset, void *dest, + const size_t n) { + return extism_load_from_handle(extism_input_offset(), src_offset, dest, n); +} + +// Load n-1 bytes and zero terminate +// Verifies load is inbounds +bool extism_load_sz(const ExtismHandle src, uint64_t src_offset, char *dest, + const size_t n); // Load n-1 bytes from input buffer and zero terminate // Verifies load is inbounds -bool extism_load_input_sz(char *dest, const size_t n); +static inline bool extism_load_input_sz(const uint64_t src_offset, char *dest, + const size_t n) { + return extism_load_sz(extism_input_offset(), src_offset, dest, n); +} -// Copy data into Extism memory -void extism_store(ExtismPointer offs, const void *buffer, const size_t length); +// Copy data into Extism memory, verifies store is in bounds +bool extism_store_to_handle(ExtismHandle dest, const uint64_t dest_offset, + const void *buffer, const size_t n); // Allocate a buffer in Extism memory and copy into it -ExtismPointer extism_alloc_buf(const void *src, const size_t n); +ExtismHandle extism_alloc_buf(const void *src, const size_t n); __attribute__(( - deprecated("Use extism_alloc_buf instead."))) static inline ExtismPointer + deprecated("Use extism_alloc_buf instead."))) static inline ExtismHandle extism_alloc_string(const char *s, const size_t n) { return extism_alloc_buf(s, n); } #ifdef EXTISM_USE_LIBC +// get the length (n) and malloc(n), load n bytes from Extism memory +// into it. If outSize is provided, set it to n +void *extism_load_dup(const ExtismHandle h, size_t *outSize); + // get the input length (n) and malloc(n), load n bytes from Extism memory // into it. If outSize is provided, set it to n -void *extism_load_input_dup(size_t *outSize); +static inline void *extism_load_input_dup(size_t *outSize) { + return extism_load_dup(extism_input_offset(), outSize); +} + +// get the length, add 1 to it to get n. malloc(n), load n - 1 bytes +// from Extism memory into it. Zero terminate. If outSize is provided, set it +// to n +void *extism_load_sz_dup(const ExtismHandle h, size_t *outSize); // get the input length, add 1 to it to get n. malloc(n), load n - 1 bytes // from Extism memory into it. Zero terminate. If outSize is provided, set it // to n -void *extism_load_input_sz_dup(size_t *outSize); +static inline void *extism_load_input_sz_dup(size_t *outSize) { + return extism_load_sz_dup(extism_input_offset(), outSize); +} #endif // EXTISM_USE_LIBC // Allocate a buffer in Extism memory and copy string data into it // copied string is NOT null terminated -ExtismPointer extism_alloc_buf_from_sz(const char *sz); +ExtismHandle extism_alloc_buf_from_sz(const char *sz); typedef enum { ExtismLogInfo, @@ -132,6 +142,20 @@ void extism_log(const char *s, const size_t len, const ExtismLog level); // Write zero-terminated string to Extism log void extism_log_sz(const char *s, const ExtismLog level); +// Set the output from an ExtismHandle, returns false if outside the memory +// block is specified. +bool extism_output_set_from_handle(const ExtismHandle handle, + const uint64_t offset, const uint64_t n); + +// Set the output to the entire contents of an ExtismHandle +void extism_output_handle(const ExtismHandle handle); + +// Alloc a buf of Extism memory and output it +void extism_output_buf(const void *src, const size_t n); + +// set output to extism_alloc_buf_from_sz +void extism_output_buf_from_sz(const char *sz); + #ifdef __cplusplus } #endif @@ -143,90 +167,159 @@ void extism_log_sz(const char *s, const ExtismLog level); #define EXTISM_IMPLEMENTATION #endif -#ifdef EXTISM_IMPLEMENTATION -#ifndef extism_pdk_c -#define extism_pdk_c +#ifndef extism_low_level_imports_h +#if defined(EXTISM_ENABLE_LOW_LEVEL_API) || defined(EXTISM_IMPLEMENTATION) +#define extism_low_level_imports_h + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef EXTISM_ENABLE_LOW_LEVEL_API +typedef uint64_t ExtismPointer; +#else +#define ExtismPointer uint64_t +#endif + +EXTISM_IMPORT_ENV("input_load_u8") +extern uint8_t __extism_input_load_u8(const uint64_t); +EXTISM_IMPORT_ENV("input_load_u64") +extern uint64_t __extism_input_load_u64(const uint64_t); +EXTISM_IMPORT_ENV("output_set") +extern void __extism_output_set(const ExtismPointer, const uint64_t); +EXTISM_IMPORT_ENV("store_u8") +extern void __extism_store_u8(ExtismPointer, const uint8_t); +EXTISM_IMPORT_ENV("load_u8") +extern uint8_t __extism_load_u8(const ExtismPointer); +EXTISM_IMPORT_ENV("store_u64") +extern void __extism_store_u64(ExtismPointer, const uint64_t); +EXTISM_IMPORT_ENV("load_u64") +extern uint64_t __extism_load_u64(const ExtismPointer); + +#ifdef EXTISM_ENABLE_LOW_LEVEL_API +#define extism_input_load_u8 __extism_input_load_u8 +#define extism_input_load_u64 __extism_input_load_u64 +#define extism_output_set __extism_output_set +#define extism_store_u8 __extism_store_u8 +#define extism_load_u8 __extism_load_u8 +#define extism_store_u64 __extism_store_u64 +#define extism_load_u64 __extism_load_u64 // Load data from Extism memory, does not verify load is in bounds -void extism_load(const ExtismPointer offs, void *dest, const size_t n) { - const size_t chunk_count = n >> 3; - uint64_t *i64_buffer = dest; - for (size_t chunk_idx = 0; chunk_idx < chunk_count; chunk_idx++) { - i64_buffer[chunk_idx] = extism_load_u64(offs + (chunk_idx << 3)); - } +#define extism_load __extism_load - size_t remainder_offset = chunk_count << 3; - const size_t remainder_end = remainder_offset + (n & 7); - for (uint8_t *u8_buffer = dest; remainder_offset < remainder_end; - remainder_offset++) { - u8_buffer[remainder_offset] = extism_load_u8(offs + remainder_offset); - } +// Copy data into Extism memory, does not verify store is inbounds +#define extism_store __extism_store + +// Load n-1 bytes and zero terminate +// Does not verify load is inbounds +void extism_load_sz_unsafe(const ExtismPointer src, char *dest, const size_t n); + +// Returns 0 when the pointer doesn't refer to the start of +// the data section of a memory block. +EXTISM_IMPORT_ENV("length") +extern uint64_t extism_length_safe(const ExtismPointer); + +#else +#undef ExtismPointer +#endif + +#ifdef __cplusplus } +#endif +#endif // defined(EXTISM_ENABLE_LOW_LEVEL_API) || defined(EXTISM_IMPLEMENTATION) +#endif // extism_low_level_imports_h + +#ifdef EXTISM_IMPLEMENTATION +#ifndef extism_pdk_c +#define extism_pdk_c -// Load data from input buffer, does not verify load is inbounds -static void extism_load_input_unsafe(void *dest, const size_t n) { +#ifndef EXTISM_ENABLE_LOW_LEVEL_API +#define ExtismPointer uint64_t +#define EXTISM_LL_API static +#else +#define EXTISM_LL_API +#endif + +// Load data from Extism memory, does not verify load is in bounds +EXTISM_LL_API void __extism_load(const ExtismPointer offs, void *dest, + const size_t n) { const size_t chunk_count = n >> 3; uint64_t *i64_buffer = dest; for (size_t chunk_idx = 0; chunk_idx < chunk_count; chunk_idx++) { - i64_buffer[chunk_idx] = extism_input_load_u64(chunk_idx << 3); + i64_buffer[chunk_idx] = __extism_load_u64(offs + (chunk_idx << 3)); } size_t remainder_offset = chunk_count << 3; const size_t remainder_end = remainder_offset + (n & 7); for (uint8_t *u8_buffer = dest; remainder_offset < remainder_end; remainder_offset++) { - u8_buffer[remainder_offset] = extism_input_load_u8(remainder_offset); + u8_buffer[remainder_offset] = __extism_load_u8(offs + remainder_offset); } } -// Load data from input buffer, verifies load is inbounds -bool extism_load_input(void *dest, const size_t n) { - const uint64_t input_len = extism_input_length(); - if (n > input_len) { +bool extism_load_from_handle(const ExtismHandle src, const uint64_t src_offset, + void *dest, const size_t n) { + if ((src_offset + n) > extism_length(src)) { return false; } - extism_load_input_unsafe(dest, n); + const ExtismPointer offs = src + src_offset; + __extism_load(offs, dest, n); return true; } -// Load n-1 bytes from input buffer and zero terminate +// Load n-1 bytes and zero terminate // Does not verify load is inbounds -static void extism_load_input_sz_unsafe(char *dest, const size_t n) { - extism_load_input_unsafe(dest, n - 1); +EXTISM_LL_API void extism_load_sz_unsafe(const ExtismPointer src, char *dest, + const size_t n) { + __extism_load(src, dest, n - 1); dest[n - 1] = '\0'; } -// Load n-1 bytes from input buffer and zero terminate +// Load n-1 bytes and zero terminate // Verifies load is inbounds -bool extism_load_input_sz(char *dest, const size_t n) { - const uint64_t input_len = extism_input_length(); - if ((n - 1) > input_len) { +bool extism_load_sz(const ExtismHandle src, uint64_t src_offset, char *dest, + const size_t n) { + const uint64_t len = extism_length(src); + if ((src_offset + n - 1) > len) { return false; } - extism_load_input_sz_unsafe(dest, n); + extism_load_sz_unsafe(src + src_offset, dest, n); return true; } -// Copy data into Extism memory -void extism_store(ExtismPointer offs, const void *buffer, const size_t length) { +// Copy data into Extism memory, does not verify store is inbounds +EXTISM_LL_API void __extism_store(ExtismPointer offs, const void *buffer, + const size_t length) { const size_t chunk_count = length >> 3; const uint64_t *i64_buffer = buffer; for (size_t chunk_idx = 0; chunk_idx < chunk_count; chunk_idx++) { - extism_store_u64(offs + (chunk_idx << 3), i64_buffer[chunk_idx]); + __extism_store_u64(offs + (chunk_idx << 3), i64_buffer[chunk_idx]); } size_t remainder_offset = chunk_count << 3; const size_t remainder_end = remainder_offset + (length & 7); for (const uint8_t *u8_buffer = buffer; remainder_offset < remainder_end; remainder_offset++) { - extism_store_u8(offs + remainder_offset, u8_buffer[remainder_offset]); + __extism_store_u8(offs + remainder_offset, u8_buffer[remainder_offset]); } } +// Copy data into Extism memory, verifies store is in bounds +bool extism_store_to_handle(ExtismHandle dest, const uint64_t dest_offset, + const void *buffer, const size_t n) { + if ((dest_offset + n) > extism_length(dest)) { + return false; + } + ExtismPointer offs = dest + dest_offset; + __extism_store(offs, buffer, n); + return true; +} + // Allocate a buffer in Extism memory and copy into it -ExtismPointer extism_alloc_buf(const void *src, const size_t n) { - ExtismPointer ptr = extism_alloc(n); - extism_store(ptr, src, n); +ExtismHandle extism_alloc_buf(const void *src, const size_t n) { + ExtismHandle ptr = extism_alloc(n); + __extism_store(ptr, src, n); return ptr; } @@ -236,10 +329,10 @@ ExtismPointer extism_alloc_buf(const void *src, const size_t n) { #define extism_strlen strlen -// get the input length (n) and malloc(n), load n bytes from Extism memory +// get the length (n) and malloc(n), load n bytes from Extism memory // into it. If outSize is provided, set it to n -void *extism_load_input_dup(size_t *outSize) { - const uint64_t n = extism_input_length(); +void *extism_load_dup(const ExtismHandle h, size_t *outSize) { + const uint64_t n = extism_length(h); if (n > SIZE_MAX) { return NULL; } @@ -247,18 +340,18 @@ void *extism_load_input_dup(size_t *outSize) { if (!buf) { return NULL; } - extism_load_input_unsafe(buf, n); + __extism_load(h, buf, n); if (outSize) { *outSize = n; } return buf; } -// get the input length, add 1 to it to get n. malloc(n), load n - 1 bytes +// get the length, add 1 to it to get n. malloc(n), load n - 1 bytes // from Extism memory into it. Zero terminate. If outSize is provided, set it // to n -void *extism_load_input_sz_dup(size_t *outSize) { - uint64_t n = extism_input_length(); +void *extism_load_sz_dup(const ExtismHandle h, size_t *outSize) { + uint64_t n = extism_length(h); if (n > (SIZE_MAX - 1)) { return NULL; } @@ -267,7 +360,7 @@ void *extism_load_input_sz_dup(size_t *outSize) { if (!buf) { return NULL; } - extism_load_input_sz_unsafe(buf, n); + extism_load_sz_unsafe(h, buf, n); if (outSize) { *outSize = n; } @@ -285,29 +378,29 @@ static size_t extism_strlen(const char *sz) { // Allocate a buffer in Extism memory and copy string data into it // copied string is NOT null terminated -ExtismPointer extism_alloc_buf_from_sz(const char *sz) { +ExtismHandle extism_alloc_buf_from_sz(const char *sz) { return extism_alloc_buf(sz, extism_strlen(sz)); } // Write to Extism log void extism_log(const char *s, const size_t len, const ExtismLog level) { - ExtismPointer ptr = extism_alloc(len); - extism_store(ptr, s, len); + ExtismHandle buf = extism_alloc(len); + __extism_store(buf, s, len); switch (level) { case ExtismLogInfo: - extism_log_info(ptr); + extism_log_info(buf); break; case ExtismLogDebug: - extism_log_debug(ptr); + extism_log_debug(buf); break; case ExtismLogWarn: - extism_log_warn(ptr); + extism_log_warn(buf); break; case ExtismLogError: - extism_log_error(ptr); + extism_log_error(buf); break; } - extism_free(ptr); + extism_free(buf); } // Write zero-terminated string to Extism log @@ -316,5 +409,37 @@ void extism_log_sz(const char *s, const ExtismLog level) { extism_log(s, len, level); } +// Set the output from an ExtismHandle, returns false if outside the memory +// block is specified. +bool extism_output_set_from_handle(const ExtismHandle handle, + const uint64_t offset, const uint64_t n) { + if ((offset + n) > extism_length(handle)) { + return false; + } + __extism_output_set(handle + offset, n); + return true; +} + +// Set the output to the entire contents of an ExtismHandle +void extism_output_handle(const ExtismHandle handle) { + __extism_output_set(handle, extism_length(handle)); +} + +// Alloc a buf of Extism memory and output it +void extism_output_buf(const void *src, const size_t n) { + ExtismHandle handle = extism_alloc_buf(src, n); + __extism_output_set(handle, n); +} + +// set output to extism_alloc_buf_from_sz +void extism_output_buf_from_sz(const char *sz) { + const size_t n = extism_strlen(sz); + extism_output_buf(sz, n); +} + +#ifndef EXTISM_ENABLE_LOW_LEVEL_API +#undef ExtismPointer +#endif + #endif // extism_pdk_c #endif // EXTISM_IMPLEMENTATION diff --git a/tests/alloc.c b/tests/alloc.c index 45aa47f..5da0c88 100644 --- a/tests/alloc.c +++ b/tests/alloc.c @@ -1,3 +1,4 @@ +#define EXTISM_ENABLE_LOW_LEVEL_API #include "util.h" #define NPAGES0 2 @@ -5,7 +6,7 @@ #define PAGE1 65539 int32_t EXTISM_EXPORTED_FUNCTION(run_test) { - ExtismPointer buf[NPAGES0][NPAGES1]; + ExtismHandle buf[NPAGES0][NPAGES1]; for (int i = 0; i < NPAGES0; i++) { for (int j = 0; j < NPAGES1; j++) { buf[i][j] = extism_alloc(PAGE1); diff --git a/tests/alloc_buf_from_sz.c b/tests/alloc_buf_from_sz.c index 40e773e..0890c01 100644 --- a/tests/alloc_buf_from_sz.c +++ b/tests/alloc_buf_from_sz.c @@ -3,8 +3,8 @@ EXTISM_EXPORT_AS("run_test") int32_t run_test(void) { const char *msg = "Hello, world!"; - ExtismPointer ptr = extism_alloc_buf_from_sz(msg); - assert(ptr > 0); - assert(extism_length(ptr) == extism_strlen(msg)); + ExtismHandle buf = extism_alloc_buf_from_sz(msg); + assert(buf > 0); + assert(extism_length(buf) == extism_strlen(msg)); return 0; } diff --git a/tests/cplusplus.cpp b/tests/cplusplus.cpp index 8141503..fe2384f 100644 --- a/tests/cplusplus.cpp +++ b/tests/cplusplus.cpp @@ -3,10 +3,10 @@ EXTISM_EXPORT_AS("run_test") int32_t run_test(void) { const char *msg = "Hello, world!"; - ExtismPointer ptr = extism_alloc(strlen(msg)); - assert(ptr > 0); - extism_store(ptr, (const uint8_t *)msg, strlen(msg)); - assert(extism_length(ptr) == strlen(msg)); - extism_output_set(ptr, strlen(msg)); + ExtismHandle buf = extism_alloc(strlen(msg)); + assert(buf > 0); + extism_store_to_handle(buf, 0, msg, strlen(msg)); + assert(extism_length(buf) == strlen(msg)); + extism_output_handle(buf); return 0; } diff --git a/tests/fail.c b/tests/fail.c index 43fdd2f..72a617e 100644 --- a/tests/fail.c +++ b/tests/fail.c @@ -3,8 +3,8 @@ int32_t EXTISM_EXPORTED_FUNCTION(run_test) { const char *msg = "Some error message"; - ExtismPointer ptr = extism_alloc(extism_strlen(msg)); - extism_store(ptr, (const uint8_t *)msg, extism_strlen(msg)); - extism_error_set(ptr); + ExtismHandle h = extism_alloc(extism_strlen(msg)); + extism_store_to_handle(h, 0, (const uint8_t *)msg, extism_strlen(msg)); + extism_error_set(h); return 1; } diff --git a/tests/hello.c b/tests/hello.c index 7a35c36..8fd6e28 100644 --- a/tests/hello.c +++ b/tests/hello.c @@ -3,10 +3,10 @@ EXTISM_EXPORT_AS("run_test") int32_t run_test(void) { const char *msg = "Hello, world!"; - ExtismPointer ptr = extism_alloc(extism_strlen(msg)); - assert(ptr > 0); - extism_store(ptr, (const uint8_t *)msg, extism_strlen(msg)); - assert(extism_length(ptr) == extism_strlen(msg)); - extism_output_set(ptr, extism_strlen(msg)); + ExtismHandle buf = extism_alloc(extism_strlen(msg)); + assert(buf > 0); + extism_store_to_handle(buf, 0, msg, extism_strlen(msg)); + assert(extism_length(buf) == extism_strlen(msg)); + extism_output_handle(buf); return 0; } diff --git a/tests/load_input_bounds_checks.c b/tests/load_input_bounds_checks.c index fcafcec..746a72b 100644 --- a/tests/load_input_bounds_checks.c +++ b/tests/load_input_bounds_checks.c @@ -3,12 +3,12 @@ EXTISM_EXPORT_AS("run_test") int32_t run_test(void) { char c[2]; - extism_load_input_unsafe(c, 0); - assert(extism_load_input(c, 0)); - assert(!extism_load_input(c, 1)); - extism_load_input_sz_unsafe(c, 1); - assert(!extism_load_input_sz(c, 0)); - assert(extism_load_input_sz(c, 1)); - assert(!extism_load_input_sz(c, 2)); + __extism_load(extism_input_offset(), c, 0); + assert(extism_load_input(0, c, 0)); + assert(!extism_load_input(0, c, 1)); + extism_load_sz_unsafe(extism_input_offset(), c, 1); + assert(!extism_load_input_sz(0, c, 0)); + assert(extism_load_input_sz(0, c, 1)); + assert(!extism_load_input_sz(0, c, 2)); return 0; }