1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
//! Create, read, write, grow, destroy memory of an instance. use crate::deprecated::{get_global_store, wasmer_limits_t, wasmer_result_t}; use crate::error::{update_last_error, CApiError}; use std::{cell::Cell, ptr}; use wasmer::{Bytes, Memory, MemoryType, Pages}; /// Opaque pointer to a `wasmer_vm::Memory` value in Rust. /// /// A `wasmer_vm::Memory` represents a WebAssembly memory. It is /// possible to create one with `wasmer_memory_new()` and pass it as /// imports of an instance, or to read it from exports of an instance /// with `wasmer_export_to_memory()`. #[repr(C)] #[derive(Clone)] pub struct wasmer_memory_t; /// Creates a new empty WebAssembly memory for the given descriptor. /// /// The result is stored in the first argument `memory` if successful, /// i.e. when the function returns /// `wasmer_result_t::WASMER_OK`. Otherwise, /// `wasmer_result_t::WASMER_ERROR` is returned, and /// `wasmer_last_error_length()` with `wasmer_last_error_message()` /// must be used to read the error message. /// /// The caller owns the memory and is responsible to free it with /// `wasmer_memory_destroy()`. /// /// Example: /// /// ```c /// // 1. The memory object. /// wasmer_memory_t *memory = NULL; /// /// // 2. The memory descriptor. /// wasmer_limits_t memory_descriptor = { /// .min = 10, /// .max = { /// .has_some = true, /// .some = 15, /// }, /// }; /// /// // 3. Initialize the memory. /// wasmer_result_t result = wasmer_memory_new(&memory, memory_descriptor); /// /// if (result != WASMER_OK) { /// int error_length = wasmer_last_error_length(); /// char *error = malloc(error_length); /// wasmer_last_error_message(error, error_length); /// // Do something with `error`… /// } /// /// // 4. Free the memory! /// wasmer_memory_destroy(memory); /// ``` #[no_mangle] pub unsafe extern "C" fn wasmer_memory_new( memory: *mut *mut wasmer_memory_t, limits: wasmer_limits_t, ) -> wasmer_result_t { let max = if limits.max.has_some { Some(Pages(limits.max.some)) } else { None }; let store = get_global_store(); let desc = MemoryType::new(Pages(limits.min), max, false); match Memory::new(store, desc) { Ok(new_memory) => { *memory = Box::into_raw(Box::new(new_memory)) as *mut wasmer_memory_t; wasmer_result_t::WASMER_OK } Err(err) => { update_last_error(CApiError { msg: err.to_string(), }); wasmer_result_t::WASMER_ERROR } } } /// Grows a memory by the given number of pages (of 65Kb each). /// /// The functions return `wasmer_result_t::WASMER_OK` upon success, /// `wasmer_result_t::WASMER_ERROR` otherwise. Use /// `wasmer_last_error_length()` with `wasmer_last_error_message()` to /// read the error message. /// /// Example: /// /// ```c /// wasmer_result_t result = wasmer_memory_grow(memory, 10); /// /// if (result != WASMER_OK) { /// // … /// } /// ``` #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_grow(memory: *mut wasmer_memory_t, delta: u32) -> wasmer_result_t { if memory.is_null() { update_last_error(CApiError { msg: "`memory` is NULL.".to_string(), }); return wasmer_result_t::WASMER_ERROR; } let memory = unsafe { &*(memory as *mut Memory) }; let grow_result = memory.grow(Pages(delta)); match grow_result { Ok(_) => wasmer_result_t::WASMER_OK, Err(err) => { update_last_error(CApiError { msg: err.to_string(), }); wasmer_result_t::WASMER_ERROR } } } /// Reads the current length (in pages) of the given memory. /// /// The function returns zero if `memory` is a null pointer. /// /// Example: /// /// ```c /// uint32_t memory_length = wasmer_memory_length(memory); /// /// printf("Memory pages length: %d\n", memory_length); /// ``` #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_length(memory: *const wasmer_memory_t) -> u32 { if memory.is_null() { return 0; } let memory = unsafe { &*(memory as *const Memory) }; let Pages(length) = memory.size(); length } /// Gets a pointer to the beginning of the contiguous memory data /// bytes. /// /// The function returns `NULL` if `memory` is a null pointer. /// /// Note that when the memory grows, it can be reallocated, and thus /// the returned pointer can be invalidated. /// /// Example: /// /// ```c /// uint8_t *memory_data = wasmer_memory_data(memory); /// char *str = (char*) malloc(sizeof(char) * 7); /// /// for (uint32_t nth = 0; nth < 7; ++nth) { /// str[nth] = (char) memory_data[nth]; /// } /// ``` #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_data(memory: *const wasmer_memory_t) -> *mut u8 { if memory.is_null() { return ptr::null_mut(); } let memory = unsafe { &*(memory as *const Memory) }; memory.view::<u8>()[..].as_ptr() as *mut Cell<u8> as *mut u8 } /// Gets the size in bytes of the memory data. /// /// This function returns 0 if `memory` is a null pointer. /// /// Example: /// /// ```c /// uint32_t memory_data_length = wasmer_memory_data_length(memory); /// ``` #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_data_length(memory: *const wasmer_memory_t) -> u32 { if memory.is_null() { return 0; } let memory = unsafe { &*(memory as *const Memory) }; let Bytes(length) = memory.size().bytes(); length as u32 } /// Frees memory for the given `wasmer_memory_t`. /// /// Check the `wasmer_memory_new()` function to get a complete /// example. /// /// If `memory` is a null pointer, this function does nothing. /// /// Example: /// /// ```c /// // Get a memory. /// wasmer_memory_t *memory = NULL; /// wasmer_result_t result = wasmer_memory_new(&memory, memory_descriptor); /// /// // Destroy the memory. /// wasmer_memory_destroy(memory); /// ``` #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub extern "C" fn wasmer_memory_destroy(memory: *mut wasmer_memory_t) { if !memory.is_null() { unsafe { Box::from_raw(memory as *mut Memory) }; } }