wasm_memory_data_size
returns more memory that 65536 for a page #4029
Description
Observations on wasm_memory_data_size
API in WAMR
While testing the WAMR runtime, I observed that the wasm_memory_data_size
function returns 98304 bytes for a module with a single memory page, instead of the expected 65536 bytes as defined by the WebAssembly specification. The module does not invoke memory.grow
or any similar operations.
Example module:
(module (import "env" "addToCrc" (func $addToCrc (param i32))) (memory $mem 1)
(export "_memory" (memory $mem))
(table 0 funcref)
(elem (i32.const 0))
(func
$main
(export "_main")
(result i32)
(local $i32_storage i32)
(local $i64_storage i64)
(local $f32_storage f32)
(local $f64_storage f64)
i32.const
315
i32.load8_s
offset=87
align=1)
(func $crc_globals (export "_crc_globals") (local $storage i64)))
In this function I am trying to test memory contents, globals and return of _main to do differential testing. Of that I am using the following main code snippets to do:
// Handle `_memory` export
wasm_memory_t *memory = wasm_extern_as_memory(exports.data[0]);
if (memory) {
const uint8_t *memory_data = (const uint8_t *)wasm_memory_data(memory);
size_t memory_size = wasm_memory_data_size(memory);
//size_t memory_size = wasm_memory_size(memory);
printf("Memory size: %zu bytes\n", memory_size);
// Iterate through aligned words only
for (size_t i = 0; i + 4 <= memory_size; i += 4) {
uint32_t value;
memcpy(&value, memory_data + i, sizeof(value));
printf("Memory word at %zu: %u\n", i, value);
update_crc(value);
}
} else {
printf("_memory export not found.\n");
}
However, when I do that size_t memory_size = wasm_memory_data_size(memory);
gives the number Memory size: 98304 bytes
instead of 65536
which is also reflected in the generated CRC that differs from other runtimes and also differs each run because of memory access that has undefined values each time. Some examples where memory addresses greater that 65536 holds undefined values each time:
FIRST RUN WITH WAMR:
Memory word at 65540: 1610616831
Memory word at 65544: 0
Memory word at 65548: 0
Memory word at 65552: 0
Memory word at 65556: 0
Memory word at 65560: 2809450164
Memory word at 65564: 21919
Memory word at 65568: 32760
Memory word at 65572: 0
Memory word at 65576: 0
SECOND RUN WITH WAMR:
Memory word at 65540: 1610616831
Memory word at 65544: 0
Memory word at 65548: 0
Memory word at 65552: 0
Memory word at 65556: 0
Memory word at 65560: 298987188
Memory word at 65564: 22001
Memory word at 65568: 32760
Memory word at 65572: 0
Memory word at 65576: 0
THIRD RUN WITH WAMR:
Memory word at 65540: 1610616831
Memory word at 65544: 0
Memory word at 65548: 0
Memory word at 65552: 0
Memory word at 65556: 0
Memory word at 65560: 140189364
Memory word at 65564: 21984
Memory word at 65568: 32760
Memory word at 65572: 0
Expected Behavior:
When I change it manually to i + 4 <= memory_size
to i + 4 <= 65536
in the for loop it works just fine. It gives the same CRC hash as other 5 runtimes.
The similar API usage from wasm-interp of WABT returns the 65536 and works fine:
if (memory) {
const uint8_t* memory_data = memory->UnsafeData();
size_t memory_size = memory->ByteSize();
// std::cout << "Processing memory for CRC. Size: " << memory_size << " bytes." << std::endl;
for (size_t i = 0; i < memory_size; i += 4) {
uint32_t value = *reinterpret_cast<const uint32_t*>(memory_data + i);
//std::cout << "Memory word at " << i << ": " << value << std::endl;
update_crc(value);
}
}
The other runtimes have the similar API and they work as expected.
I added some debug statements to wasm_memory_data_size
API and got the following final result.
API with debug statements:
size_t wasm_memory_data_size(const wasm_memory_t *memory)
{
// Check if the memory is valid
if (!memory || !memory->inst_comm_rt) {
printf("[DEBUG] Invalid memory or runtime instance.\n");
return 0;
}
// Access the common module instance
WASMModuleInstanceCommon *module_inst_comm = memory->inst_comm_rt;
#if WASM_ENABLE_INTERP != 0
// Handle the Bytecode module type
if (module_inst_comm->module_type == Wasm_Module_Bytecode) {
printf("[DEBUG] Module type: Wasm_Module_Bytecode.\n");
WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
WASMMemoryInstance *memory_inst = module_inst->memories[memory->memory_idx_rt];
// Debug print for page count and page size
printf("[DEBUG] cur_page_count: %u\n", memory_inst->cur_page_count);
printf("[DEBUG] num_bytes_per_page: %u\n", memory_inst->num_bytes_per_page);
return (size_t)memory_inst->cur_page_count * memory_inst->num_bytes_per_page;
}
#endif
#if WASM_ENABLE_AOT != 0
// Handle the AoT module type
if (module_inst_comm->module_type == Wasm_Module_AoT) {
printf("[DEBUG] Module type: Wasm_Module_AoT.\n");
AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm;
AOTMemoryInstance *memory_inst =
((AOTMemoryInstance **)module_inst->memories)[memory->memory_idx_rt];
// Debug print for page count and page size
printf("[DEBUG] cur_page_count: %u\n", memory_inst->cur_page_count);
printf("[DEBUG] num_bytes_per_page: %u\n", memory_inst->num_bytes_per_page);
return (size_t)memory_inst->cur_page_count * memory_inst->num_bytes_per_page;
}
#endif
// Handle incorrect module type or compilation flags
printf("[DEBUG] Unexpected module type or invalid compilation flags.\n");
return 0;
}
Result:
Running WAMR on file: ./diff.wasm
_main executed successfully.
[DEBUG] Module type: Wasm_Module_Bytecode.
[DEBUG] cur_page_count: 1
[DEBUG] num_bytes_per_page: 98304
Memory size: 98304 bytes
Reproduce
- Please install and unzip it
- Compile it (Please give the correct path to wasm-micro-runtime in the compiler flags. Build process was simple see the end of this report):
g++ -o wamr_program main.c src/wamr_driver.c src/crc_utils.cpp -Iinclude -I../../targets/wasm-micro-runtime/core/iwasm/include -I../../targets/wasm-micro-runtime/core/shared/utils -I../../targets/wasm-micro-runtime/core/shared/platform/linux -L../../targets/wasm-micro-runtime/product-mini/platforms/linux/build -Wl,-rpath,../../targets/wasm-micro-runtime/product-mini/platforms/linux/build -liwasm -lz
- Save the above exmaple wasm module and use
wat2wasm
to convert to wasm. - Run the compiled
wamr_program on that file
: (Please give correct path to thewasm-micro-runtime
in your machine)
LD_LIBRARY_PATH=../../targets/wasm-micro-runtime/product-mini/platforms/linux/build:$LD_LIBRARY_PATH ./wamr_program ./diff.wasm
Observe:
Running WAMR on file: ./test2.wasm
_main executed successfully.
addToCrc called with value: 607
_crc_globals returned: 0
[DEBUG] Module type: Wasm_Module_Bytecode.
[DEBUG] cur_page_count: 1
[DEBUG] num_bytes_per_page: 98304
Memory size: 98304 bytes
c5b6e90a
Final CRC: 3317098762
You have to add Debug statements to the API in question in wasm-micro-runtime/core/iwasm/common/wasm_c_api.c
to see the outputs with [DEBUG] in it.
Wamr version: iwasm 2.2.0
Build:
cd /wasm-micro-runtime/product-mini/platforms/linux/
mkdir build
cd build
cmake ..
make