WasmEdge / WasmEdge

WasmEdge is a lightweight, high-performance, and extensible WebAssembly runtime for cloud native, edge, and decentralized applications. It powers serverless apps, embedded functions, microservices, smart contracts, and IoT devices.

Home Page:https://WasmEdge.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

bug: Unexpected exception triggered by the instruction `memory.init`

erxiaozhou opened this issue · comments

Summary

The test case contains a memory.init instruction and it is supposed to be valid. However, an unexpected exception indicating "memory OOB" is triggered.
The instructions in the test case.

    i32.const 32768
    i32.const 4
    i32.const 1
    memory.init 0

Current State

There is an exception indicating "memory OOB".
Furthermore, the second line is confusing because 0x00008000 is smaller than 0x0000ffff.

[2024-01-16 17:39:10.332] [error] execution failed: out of bounds memory access, Code: 0x408
[2024-01-16 17:39:10.332] [error]     Accessing offset from: 0x00008000 to: 0x00008000 , Out of boundary: 0x0000ffff
[2024-01-16 17:39:10.332] [error]     In instruction: memory.init (0xfc 0x08) , Bytecode offset: 0x00000141
[2024-01-16 17:39:10.332] [error]     When executing function name: "to_test"

Expected State

No exception

Reproduction steps

  1. Build: ' cmake -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF .. '
  2. Execute: 'wasmedge --reactor <case_name> to_test'
    Case:

all_wamr_memory.init_no_exception.zip

  1. Get error

Screenshots

DESCRIPTION
image

Any logs you want to share for showing the specific issue

No response

Components

CLI

WasmEdge Version or Commit you used

930abbe

Operating system information

Ubuntu 20.04

Hardware Architecture

x86_64

Compiler flags and options

CMake flags: -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF

Hi @erxiaozhou , the exception is caused by the fact the input data segment is invalid with size 0.

The memory.init instruction is used to copy from a passive data segment to linear memory. In the wat sample code, the data segment definition is not provided. By adding some log messages in WasmEdge, I have seen that you defined three active data segments, which would be cleared after memory initialization (check lib/executor/instantiate/data.cpp L83). Therefore, when memory.init instruction calls setBytes (defined in file include/runtime/instance/memory.h) to copy the byte (size = 1 in your sample) from the 0-th data segmentat offset 4 to the memory at offset 0x8000, it raises the exception in the second check (i.e. "Check the input data validation"), as Slice.size() is 0.

  Expect<void> setBytes(Span<const Byte> Slice, uint32_t Offset, uint32_t Start,
                        uint32_t Length) noexcept {
    // Check the memory boundary.
    if (unlikely(!checkAccessBound(Offset, Length))) {
      spdlog::error(ErrCode::Value::MemoryOutOfBounds);
      spdlog::error(ErrInfo::InfoBoundary(Offset, Length, getBoundIdx()));
      return Unexpect(ErrCode::Value::MemoryOutOfBounds);
    }

    // Check the input data validation.
    if (unlikely(static_cast<uint64_t>(Start) + static_cast<uint64_t>(Length) >
                 Slice.size())) {
      spdlog::error(ErrCode::Value::MemoryOutOfBounds);
      spdlog::error(ErrInfo::InfoBoundary(Offset, Length, getBoundIdx()));
      return Unexpect(ErrCode::Value::MemoryOutOfBounds);
    }

    // Copy the data.
    if (likely(Length > 0)) {
      std::copy(Slice.begin() + Start, Slice.begin() + Start + Length,
                DataPtr + Offset);
    }
    return {};
  }

I have tested with the following wat and the corresponding wasm, and it can be executed successfully.

(module
    (memory 1)
    (data "hello") ;; passive data segment

    (func $main (export "_start")
        i32.const 32768
        i32.const 4
        i32.const 1
        memory.init 0
    )
)

I recommend refining the log message for the "input data validation" check due to its ambiguity, perhaps by introducing another ErrInfo function, such as InfoDataBoundary? @hydai

I think another error for this case is a good idea, would you like to give a PR?

Sure, I'd love to.

Hi @dannypsnl , I have introduced the error code DataOutOfBounds along with the corresponding error message "out of bounds data access" in include/common/enum.inc. Additionally, I modified the second check in setBytes as follows:

    // Check the input data validation.
    if (unlikely(static_cast<uint64_t>(Start) + static_cast<uint64_t>(Length) >
                 Slice.size())) {
      spdlog::error(ErrCode::Value::DataOutOfBounds);
      spdlog::error(ErrInfo::InfoBoundary(
          Start, Length,
          std::max(static_cast<uint32_t>(Slice.size()), UINT32_C(1)) -
              UINT32_C(1)));
      return Unexpect(ErrCode::Value::DataOutOfBounds);
    }

The error report appears as intended:
image

However, when I run the local test using LD_LIBRARY_PATH=$(pwd)/lib/api ctest, some tests failed due to mismatched error messages like the example shown below:
image

Given that I am new to the WasmEdge codebase, I have briefly reviewed the test code and noticed that the expected labels are provided in a JSON file (specifically, memory_init.json) generated in the build folder. Could you please guide me on where to modify the code such that the labels in the JSON file would be updated?

No, you will not able to simply fix in this way, because usually we still should report out of memory than out of data instance. There will need a check to split error message.

OK, please update me on any further instructions or actions I can take.