Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm_memory_data_size returns more memory that 65536 for a page #4029

Open
khagankhan opened this issue Jan 17, 2025 · 0 comments
Open

wasm_memory_data_size returns more memory that 65536 for a page #4029

khagankhan opened this issue Jan 17, 2025 · 0 comments

Comments

@khagankhan
Copy link

khagankhan commented Jan 17, 2025

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

load-wamr.zip

  • 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 the wasm-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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant