mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Compare commits
2 Commits
ripple/was
...
ripple/was
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a1e72f066 | ||
|
|
52baedc571 |
18
clang_format.sh
Executable file
18
clang_format.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
modified=$1
|
||||
dir=`pwd`
|
||||
clangf=clang-format-10
|
||||
clangf=clang-format
|
||||
if [ "$1" = "--all" ]
|
||||
then
|
||||
modified=`git status|egrep "modified|new file"|egrep "(cpp|h)$" | sed -E -e 's/modified://' -e 's/new file://' -e 's/^[[:space:]]+//'`
|
||||
fi
|
||||
for i in $modified
|
||||
do
|
||||
basedir=$(dirname "$i")
|
||||
file=$(basename "$i")
|
||||
echo "$basedir $file"
|
||||
cd $basedir
|
||||
$clangf -style=file -i "$file"
|
||||
cd $dir
|
||||
done
|
||||
@@ -715,6 +715,141 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testWasmMemory()
|
||||
{
|
||||
testcase("Wasm additional memory limit tests");
|
||||
auto& engine = WasmEngine::instance();
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(memoryPointerAtLimitHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
if (BEAST_EXPECT(re.has_value()))
|
||||
{
|
||||
BEAST_EXPECT(re->result == 1);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(memoryPointerOverLimitHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(memoryOffsetOverLimitHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
{
|
||||
auto const ws =
|
||||
boost::algorithm::unhex(memoryEndOfWordOverLimitHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(memoryGrow0To1PageHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
if (BEAST_EXPECT(re.has_value()))
|
||||
{
|
||||
BEAST_EXPECT(re->result == 1);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(memoryLastByteOf8MBHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
if (BEAST_EXPECT(re.has_value()))
|
||||
{
|
||||
BEAST_EXPECT(re->result == 1);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(memoryGrow1MoreThan8MBHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
if (BEAST_EXPECT(re.has_value()))
|
||||
{
|
||||
BEAST_EXPECT(re->result == -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testWasmTable()
|
||||
{
|
||||
testcase("Wasm table limit tests");
|
||||
auto& engine = WasmEngine::instance();
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(table64ElementsHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
if (BEAST_EXPECT(re.has_value()))
|
||||
{
|
||||
BEAST_EXPECT(re->result == 1);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(table65ElementsHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(table2TablesHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testWasmProposal()
|
||||
{
|
||||
testcase("Wasm disabled proposal tests");
|
||||
auto& engine = WasmEngine::instance();
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(proposalMutableGlobalHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testWasmTrap()
|
||||
{
|
||||
testcase("Wasm trap tests");
|
||||
auto& engine = WasmEngine::instance();
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(trapDivideBy0Hex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testWasmWasi()
|
||||
{
|
||||
testcase("Wasm Wasi tests");
|
||||
auto& engine = WasmEngine::instance();
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(wasiGetTimeHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
{
|
||||
auto const ws = boost::algorithm::unhex(wasiPrintHex);
|
||||
Bytes const wasm(ws.begin(), ws.end());
|
||||
auto const re = engine.run(wasm, "finish");
|
||||
BEAST_EXPECT(!re.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -736,6 +871,11 @@ struct Wasm_test : public beast::unit_test::suite
|
||||
testCodecovWasm();
|
||||
testDisabledFloat();
|
||||
|
||||
testWasmMemory();
|
||||
testWasmTable();
|
||||
testWasmProposal();
|
||||
testWasmTrap();
|
||||
testWasmWasi();
|
||||
// perfTest();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1068,3 +1068,138 @@ extern std::string const disabledFloatHex =
|
||||
"6503050b5f5f686561705f6261736503060a5f5f686561705f656e640307"
|
||||
"0d5f5f6d656d6f72795f6261736503080c5f5f7461626c655f6261736503"
|
||||
"090a150202000b100043000000c54300200045921a41010b";
|
||||
|
||||
extern std::string const memoryPointerAtLimitHex =
|
||||
"0061736d010000000105016000017f030201000503010001070a010666696e69736800000a"
|
||||
"0e010c0041ffff032d00001a41010b";
|
||||
|
||||
extern std::string const memoryPointerOverLimitHex =
|
||||
"0061736d010000000105016000017f030201000503010001070a010666696e69736800000a"
|
||||
"0e010c00418080042d00001a41010b";
|
||||
|
||||
extern std::string const memoryOffsetOverLimitHex =
|
||||
"0061736d010000000105016000017f030201000503010001071302066d656d6f7279020006"
|
||||
"66696e69736800000a0e010c00410028028080041a41010b";
|
||||
|
||||
extern std::string const memoryEndOfWordOverLimitHex =
|
||||
"0061736d010000000105016000017f030201000503010001071302066d656d6f7279020006"
|
||||
"66696e69736800000a0e010c0041feff032802001a41010b";
|
||||
|
||||
extern std::string const memoryGrow0To1PageHex =
|
||||
"0061736d010000000105016000017f030201000503010000071302066d656d6f7279020006"
|
||||
"66696e69736800000a0b010900410140001a41010b";
|
||||
|
||||
extern std::string const memoryGrow1To0PageHex =
|
||||
"0061736d010000000105016000017f030201000503010001071302066d656d6f7279020006"
|
||||
"66696e69736800000a0b010900417f40001a41010b";
|
||||
|
||||
extern std::string const memoryLastByteOf8MBHex =
|
||||
"0061736d010000000105016000017f030201000506010180018001071302066d656d6f7279"
|
||||
"02000666696e69736800000a0f010d0041ffffff032d00001a41010b";
|
||||
|
||||
extern std::string const memoryGrow1MoreThan8MBHex =
|
||||
"0061736d010000000105016000017f03020100050401008001071302066d656d6f72790200"
|
||||
"0666696e69736800000a1301110041014000417f460440417f0f0b41010b";
|
||||
|
||||
extern std::string const memoryGrow0MoreThan8MBHex =
|
||||
"0061736d010000000105016000017f03020100050401008001071302066d656d6f72790200"
|
||||
"0666696e69736800000a1301110041004000417f460440417f0f0b41010b";
|
||||
|
||||
extern std::string const memoryInit1MoreThan8MBHex =
|
||||
"0061736d010000000105016000017f030201000506010181018101071302066d656d6f7279"
|
||||
"02000666696e69736800000a0f010d0041ffffff032d00001a41010b";
|
||||
|
||||
extern std::string const memoryNegativeAddressHex =
|
||||
"0061736d010000000105016000017f030201000506010180018001071302066d656d6f7279"
|
||||
"02000666696e69736800000a0c010a00417f2d00001a41010b";
|
||||
|
||||
extern std::string const table64ElementsHex =
|
||||
"0061736d010000000108026000006000017f0303020001040401700040070a010666696e69"
|
||||
"736800010946010041000b4000000000000000000000000000000000000000000000000000"
|
||||
"00000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"00000a090202000b040041010b";
|
||||
|
||||
extern std::string const table65ElementsHex =
|
||||
"0061736d010000000108026000006000017f0303020001040401700041070a010666696e69"
|
||||
"736800010947010041000b4100000000000000000000000000000000000000000000000000"
|
||||
"00000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"0000000a090202000b040041010b";
|
||||
|
||||
extern std::string const table2TablesHex =
|
||||
"0061736d010000000108026000006000017f03030200010409027001010170010101070a01"
|
||||
"0666696e6973680001090f020041000b0100020141000b0001000a090202000b040041010"
|
||||
"b";
|
||||
|
||||
extern std::string const tableUintMaxHex =
|
||||
"0061736d010000000105016000017f030201000408017000ffffffff0f070a010666696e69"
|
||||
"736800000a0601040041010b";
|
||||
|
||||
extern std::string const proposalMutableGlobalHex =
|
||||
"0061736d010000000105016000017f030201000606017f0141000b07140207636f756e7465"
|
||||
"7203000666696e69736800000a0d010b00230041016a240041010b";
|
||||
|
||||
extern std::string const proposalGcStructNewHex =
|
||||
"0061736d01000000010b026000017f5f027f017f0103020100070a010666696e6973680000"
|
||||
"0a0a010800fb01011a41010b";
|
||||
|
||||
extern std::string const proposalMultiValueHex =
|
||||
"0061736d010000000110036000027f7f6000017f60027f7f017f0303020001070a01066669"
|
||||
"6e69736800010a14020600410a41140b0b00100002026a411e460b0b";
|
||||
|
||||
extern std::string const proposalSignExtHex =
|
||||
"0061736d010000000105016000017f03020100070a010666696e69736800000a0b01090041"
|
||||
"ff01c0417f460b";
|
||||
|
||||
extern std::string const proposalFloatToIntHex =
|
||||
"0061736d010000000105016000017f03020100070a010666696e69736800000a1201100043"
|
||||
"f9021550fc0041ffffffff07460b";
|
||||
|
||||
extern std::string const proposalBulkMemoryHex =
|
||||
"0061736d010000000105016000017f030201000503010001071302066d656d6f7279020006"
|
||||
"66696e69736800000a1f011d004100412a3a000041e40041004101fc0a000041e4002d0000"
|
||||
"412a460b";
|
||||
|
||||
extern std::string const proposalRefTypesHex =
|
||||
"0061736d010000000105016000017f020f0103656e76057461626c65016f00010302010007"
|
||||
"0a010666696e69736800000a0c010a004100d06f260041010b";
|
||||
|
||||
extern std::string const proposalTailCallHex =
|
||||
"0061736d010000000105016000017f0303020000070a010666696e69736800010a0b020400"
|
||||
"41010b040012000b";
|
||||
|
||||
extern std::string const proposalExtendedConst =
|
||||
"0061736d010000000105016000017f030201000609017f00410a41206a0b070a010666696e"
|
||||
"69736800000a090107002300412a460b";
|
||||
|
||||
extern std::string const trapDivideBy0Hex =
|
||||
"0061736d010000000105016000017f03020100070a010666696e69736800000a0c010a0041"
|
||||
"2a41006d1a41010b";
|
||||
|
||||
extern std::string const trapIntOverflow =
|
||||
"0061736d010000000105016000017f03020100070a010666696e69736800000a0d010b0041"
|
||||
"8080808078417f6d0b";
|
||||
|
||||
extern std::string const trapUnreachable =
|
||||
"0061736d010000000105016000017f03020100070a010666696e69736800000a0701050000"
|
||||
"41010b";
|
||||
|
||||
extern std::string const trapNullCall =
|
||||
"0061736d010000000105016000017f03020100040401700001070a010666696e6973680000"
|
||||
"0a0901070041001100000b";
|
||||
|
||||
extern std::string const trapFuncSigMismatch =
|
||||
"0061736d010000000108026000006000017f0303020001040401700001070a010666696e69"
|
||||
"736800010907010041000b01000a0d020300010b070041001101000b";
|
||||
|
||||
extern std::string const wasiGetTimeHex =
|
||||
"0061736d01000000010c0260037f7e7f017f6000017f02290116776173695f736e61707368"
|
||||
"6f745f70726576696577310e636c6f636b5f74696d655f6765740000030201010503010001"
|
||||
"071302066d656d6f727902000666696e69736800010a16011400410042e807410010004504"
|
||||
"7f410105417f0b0b";
|
||||
|
||||
extern std::string const wasiPrintHex =
|
||||
"0061736d01000000010d0260047f7f7f7f017f6000017f02230116776173695f736e617073"
|
||||
"686f745f70726576696577310866645f77726974650000030201010503010001071302066d"
|
||||
"656d6f727902000666696e69736800010a1d011b01017f4118210041014100410120001000"
|
||||
"45047f410105417f0b0b0b1e030041100b0648656c6c6f0a0041000b04100000000041040b"
|
||||
"0406000000";
|
||||
|
||||
@@ -27,3 +27,39 @@ extern std::string const floatTestsWasmHex;
|
||||
extern std::string const float0Hex;
|
||||
|
||||
extern std::string const disabledFloatHex;
|
||||
|
||||
extern std::string const memoryPointerAtLimitHex;
|
||||
extern std::string const memoryPointerOverLimitHex;
|
||||
extern std::string const memoryOffsetOverLimitHex;
|
||||
extern std::string const memoryEndOfWordOverLimitHex;
|
||||
extern std::string const memoryGrow0To1PageHex;
|
||||
extern std::string const memoryGrow1To0PageHex;
|
||||
extern std::string const memoryLastByteOf8MBHex;
|
||||
extern std::string const memoryGrow1MoreThan8MBHex;
|
||||
extern std::string const memoryGrow0MoreThan8MBHex;
|
||||
extern std::string const memoryInit1MoreThan8MBHex;
|
||||
extern std::string const memoryNegativeAddressHex;
|
||||
|
||||
extern std::string const table64ElementsHex;
|
||||
extern std::string const table65ElementsHex;
|
||||
extern std::string const table2TablesHex;
|
||||
extern std::string const tableUintMaxHex;
|
||||
|
||||
extern std::string const proposalMutableGlobalHex;
|
||||
extern std::string const proposalGcStructNewHex;
|
||||
extern std::string const proposalMultiValueHex;
|
||||
extern std::string const proposalSignExtHex;
|
||||
extern std::string const proposalFloatToIntHex;
|
||||
extern std::string const proposalBulkMemoryHex;
|
||||
extern std::string const proposalRefTypesHex;
|
||||
extern std::string const proposalTailCallHex;
|
||||
extern std::string const proposalExtendedConst;
|
||||
|
||||
extern std::string const trapDivideBy0Hex;
|
||||
extern std::string const trapIntOverflow;
|
||||
extern std::string const trapUnreachable;
|
||||
extern std::string const trapNullCall;
|
||||
extern std::string const trapFuncSigMismatch;
|
||||
|
||||
extern std::string const wasiGetTimeHex;
|
||||
extern std::string const wasiPrintHex;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
(module
|
||||
;; 1. Define Memory: 1 Page = 64KB = 65,536 bytes
|
||||
(memory 1)
|
||||
|
||||
;; Export memory so the host can inspect it if needed
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $test_straddle (result i32)
|
||||
;; Push the address onto the stack.
|
||||
;; 65534 is valid, but it is only 2 bytes away from the end.
|
||||
i32.const 65534
|
||||
|
||||
;; Attempt to load an i32 (4 bytes) from that address.
|
||||
;; This requires bytes 65534, 65535, 65536, and 65537.
|
||||
;; Since 65536 is the first invalid byte, this MUST trap.
|
||||
i32.load
|
||||
|
||||
;; Clean up the stack.
|
||||
;; The load pushed a value, but we don't care what it is.
|
||||
drop
|
||||
|
||||
;; Return 1 to signal "I survived the memory access"
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
;; Export the function so you can call it from your host (JS, Python, etc.)
|
||||
(export "finish" (func $test_straddle))
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
(module
|
||||
;; Start at your limit: 128 pages (8MB)
|
||||
(memory 128)
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $try_grow_beyond_limit (result i32)
|
||||
;; Attempt to grow by 0 page
|
||||
i32.const 0
|
||||
memory.grow
|
||||
|
||||
;; memory.grow returns:
|
||||
;; -1 if the growth failed (Correct behavior for your limit)
|
||||
;; 128 (old size) if growth succeeded (Means limit was bypassed)
|
||||
|
||||
;; Check if result == -1
|
||||
i32.const -1
|
||||
i32.eq
|
||||
if
|
||||
;; Growth FAILED (Host blocked it). Return -1.
|
||||
i32.const -1
|
||||
return
|
||||
end
|
||||
|
||||
;; Growth SUCCEEDED (Host allowed it). Return 1.
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $try_grow_beyond_limit))
|
||||
)
|
||||
26
src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat
Normal file
26
src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat
Normal file
@@ -0,0 +1,26 @@
|
||||
(module
|
||||
;; 1. Define Memory: Start with 0 pages
|
||||
(memory 0)
|
||||
|
||||
;; Export memory to host
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $grow_from_zero (result i32)
|
||||
;; We have 0 pages. We want to add 1 page.
|
||||
;; Push delta (1) onto stack.
|
||||
i32.const 1
|
||||
|
||||
;; Grow the memory.
|
||||
;; If successful: memory becomes 64KB, returns old size (0).
|
||||
;; If failed: memory stays 0, returns -1.
|
||||
memory.grow
|
||||
|
||||
;; Drop the return value of memory.grow
|
||||
drop
|
||||
|
||||
;; Return 1 (as requested)
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $grow_from_zero))
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
(module
|
||||
;; Start at your limit: 128 pages (8MB)
|
||||
(memory 128)
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $try_grow_beyond_limit (result i32)
|
||||
;; Attempt to grow by 1 page
|
||||
i32.const 1
|
||||
memory.grow
|
||||
|
||||
;; memory.grow returns:
|
||||
;; -1 if the growth failed (Correct behavior for your limit)
|
||||
;; 128 (old size) if growth succeeded (Means limit was bypassed)
|
||||
|
||||
;; Check if result == -1
|
||||
i32.const -1
|
||||
i32.eq
|
||||
if
|
||||
;; Growth FAILED (Host blocked it). Return -1.
|
||||
i32.const -1
|
||||
return
|
||||
end
|
||||
|
||||
;; Growth SUCCEEDED (Host allowed it). Return 1.
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $try_grow_beyond_limit))
|
||||
)
|
||||
24
src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat
Normal file
24
src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat
Normal file
@@ -0,0 +1,24 @@
|
||||
(module
|
||||
;; 1. Define Memory: Start with 1 pages
|
||||
(memory 1)
|
||||
|
||||
;; Export memory to host
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $grow_negative (result i32)
|
||||
;; We have 1 page. We want to reduce 1 page.
|
||||
;; Push delta (-1) onto stack.
|
||||
i32.const -1
|
||||
|
||||
;; Grow the memory.
|
||||
memory.grow
|
||||
|
||||
;; Drop the return value of memory.grow
|
||||
drop
|
||||
|
||||
;; Return 1 (as requested)
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $grow_negative))
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
(module
|
||||
;; Define memory: 129 pages (> 8MB limit) min, 129 pages max
|
||||
(memory 129 129)
|
||||
|
||||
;; Export memory so host can verify size
|
||||
(export "memory" (memory 0))
|
||||
|
||||
;; access last byte of 8MB limit
|
||||
(func $access_last_byte (result i32)
|
||||
;; Math: 128 pages * 64,536 bytes/page = 8,388,608 bytes
|
||||
;; Valid indices: 0 to 8,388,607
|
||||
|
||||
;; Push the address of the LAST valid byte
|
||||
i32.const 8388607
|
||||
|
||||
;; Load byte from that address
|
||||
i32.load8_u
|
||||
|
||||
;; Drop the value (we don't care what it is, just that we could read it)
|
||||
drop
|
||||
|
||||
;; Return 1 to indicate success
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $access_last_byte))
|
||||
)
|
||||
26
src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat
Normal file
26
src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat
Normal file
@@ -0,0 +1,26 @@
|
||||
(module
|
||||
;; Define memory: 128 pages (8MB) min, 128 pages max
|
||||
(memory 128 128)
|
||||
|
||||
;; Export memory so host can verify size
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $access_last_byte (result i32)
|
||||
;; Math: 128 pages * 64,536 bytes/page = 8,388,608 bytes
|
||||
;; Valid indices: 0 to 8,388,607
|
||||
|
||||
;; Push the address of the LAST valid byte
|
||||
i32.const 8388607
|
||||
|
||||
;; Load byte from that address
|
||||
i32.load8_u
|
||||
|
||||
;; Drop the value (we don't care what it is, just that we could read it)
|
||||
drop
|
||||
|
||||
;; Return 1 to indicate success
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $access_last_byte))
|
||||
)
|
||||
23
src/test/app/wasm_fixtures/wat/memory_negative_address.wat
Normal file
23
src/test/app/wasm_fixtures/wat/memory_negative_address.wat
Normal file
@@ -0,0 +1,23 @@
|
||||
(module
|
||||
;; Define memory: 128 pages (8MB) min, 128 pages max
|
||||
(memory 128 128)
|
||||
|
||||
;; Export memory so host can verify size
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $access_last_byte (result i32)
|
||||
;; Push a negative address
|
||||
i32.const -1
|
||||
|
||||
;; Load byte from that address
|
||||
i32.load8_u
|
||||
|
||||
;; Drop the value
|
||||
drop
|
||||
|
||||
;; Return 1 to indicate success
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $access_last_byte))
|
||||
)
|
||||
27
src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat
Normal file
27
src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat
Normal file
@@ -0,0 +1,27 @@
|
||||
(module
|
||||
;; 1. Define Memory: 1 Page = 64KB
|
||||
(memory 1)
|
||||
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $test_offset_overflow (result i32)
|
||||
;; 1. Push the base address onto the stack.
|
||||
;; We use '0', which is the safest, most valid address possible.
|
||||
i32.const 0
|
||||
|
||||
;; 2. Attempt to load using a static offset.
|
||||
;; syntax: i32.load offset=N align=N
|
||||
;; We set the offset to 65536 (the size of the memory).
|
||||
;; The effective address becomes 0 + 65536 = 65536.
|
||||
i32.load offset=65536
|
||||
|
||||
;; Clean up the stack.
|
||||
;; The load pushed a value, but we don't care what it is.
|
||||
drop
|
||||
|
||||
;; Return 1 to signal "I survived the memory access"
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $test_offset_overflow))
|
||||
)
|
||||
22
src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat
Normal file
22
src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat
Normal file
@@ -0,0 +1,22 @@
|
||||
(module
|
||||
;; Define 1 page of memory (64KB = 65,536 bytes)
|
||||
(memory 1)
|
||||
|
||||
(func $read_edge (result i32)
|
||||
;; Push the index of the LAST valid byte
|
||||
i32.const 65535
|
||||
|
||||
;; Load 1 byte (unsigned)
|
||||
i32.load8_u
|
||||
|
||||
;; Clean up the stack.
|
||||
;; The load pushed a value, but we don't care what it is.
|
||||
drop
|
||||
|
||||
;; Return 1 to signal "I survived the memory access"
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
;; Export as "finish" as requested
|
||||
(export "finish" (func $read_edge))
|
||||
)
|
||||
23
src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat
Normal file
23
src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat
Normal file
@@ -0,0 +1,23 @@
|
||||
(module
|
||||
;; Define 1 page of memory (64KB = 65,536 bytes)
|
||||
(memory 1)
|
||||
|
||||
(func $read_overflow (result i32)
|
||||
;; Push the index of the FIRST invalid byte
|
||||
;; Memory is 0..65535, so 65536 is out of bounds.
|
||||
i32.const 65536
|
||||
|
||||
;; Load 1 byte (unsigned)
|
||||
i32.load8_u
|
||||
|
||||
;; Clean up the stack.
|
||||
;; The load pushed a value, but we don't care what it is.
|
||||
drop
|
||||
|
||||
;; Return 1 to signal "I survived the memory access"
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
;; Export as "finish" as requested
|
||||
(export "finish" (func $read_overflow))
|
||||
)
|
||||
25
src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat
Normal file
25
src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat
Normal file
@@ -0,0 +1,25 @@
|
||||
(module
|
||||
;; Define 1 page of memory
|
||||
(memory 1)
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $test_bulk_ops (result i32)
|
||||
;; Setup: Write value 42 at index 0 so we have something to copy
|
||||
(i32.store8 (i32.const 0) (i32.const 42))
|
||||
|
||||
;; Test memory.copy (Opcode 0xFC 0x0A)
|
||||
;; Copy 1 byte from offset 0 to offset 100
|
||||
(memory.copy
|
||||
(i32.const 100) ;; Destination Offset
|
||||
(i32.const 0) ;; Source Offset
|
||||
(i32.const 1) ;; Size (bytes)
|
||||
)
|
||||
|
||||
;; Verify: Read byte at offset 100. Should be 42.
|
||||
(i32.load8_u (i32.const 100))
|
||||
(i32.const 42)
|
||||
i32.eq
|
||||
)
|
||||
|
||||
(export "finish" (func $test_bulk_ops))
|
||||
)
|
||||
15
src/test/app/wasm_fixtures/wat/proposal_extended_const.wat
Normal file
15
src/test/app/wasm_fixtures/wat/proposal_extended_const.wat
Normal file
@@ -0,0 +1,15 @@
|
||||
(module
|
||||
;; 1. Define a global using an EXTENDED constant expression.
|
||||
;; MVP only allows (i32.const X).
|
||||
;; This proposal allows (i32.add (i32.const X) (i32.const Y)).
|
||||
(global $g i32 (i32.add (i32.const 10) (i32.const 32)))
|
||||
|
||||
(func $finish (result i32)
|
||||
;; 2. verify the global equals 42
|
||||
global.get $g
|
||||
i32.const 42
|
||||
i32.eq
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
18
src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat
Normal file
18
src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat
Normal file
@@ -0,0 +1,18 @@
|
||||
(module
|
||||
(func $test_saturation (result i32)
|
||||
;; 1. Push a float that is too big for a 32-bit integer
|
||||
;; 1e10 (10 billion) > 2.14 billion (Max i32)
|
||||
f32.const 1.0e10
|
||||
|
||||
;; 2. Attempt saturating conversion (Opcode 0xFC 0x00)
|
||||
;; If supported: Clamps to MAX_I32.
|
||||
;; If disabled: Validation error (unknown instruction).
|
||||
i32.trunc_sat_f32_s
|
||||
|
||||
;; 3. Check if result is MAX_I32 (2147483647)
|
||||
i32.const 2147483647
|
||||
i32.eq
|
||||
)
|
||||
|
||||
(export "finish" (func $test_saturation))
|
||||
)
|
||||
12
src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat
Normal file
12
src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat
Normal file
@@ -0,0 +1,12 @@
|
||||
;; generated by wasm-tools print gc_test.wasm that has the following hex
|
||||
;; 0061736d01000000010b026000017f5f027f017f0103020100070a010666696e69736800000a0a010800fb01011a41010b
|
||||
(module
|
||||
(type (;0;) (func (result i32)))
|
||||
(type (;1;) (struct (field (mut i32)) (field (mut i32))))
|
||||
(export "finish" (func 0))
|
||||
(func (;0;) (type 0) (result i32)
|
||||
struct.new_default 1
|
||||
drop
|
||||
i32.const 1
|
||||
)
|
||||
)
|
||||
22
src/test/app/wasm_fixtures/wat/proposal_multi_value.wat
Normal file
22
src/test/app/wasm_fixtures/wat/proposal_multi_value.wat
Normal file
@@ -0,0 +1,22 @@
|
||||
(module
|
||||
;; 1. Function returning TWO values (Multi-Value feature)
|
||||
(func $get_numbers (result i32 i32)
|
||||
i32.const 10
|
||||
i32.const 20
|
||||
)
|
||||
|
||||
(func $finish (result i32)
|
||||
;; Call pushes [10, 20] onto the stack
|
||||
call $get_numbers
|
||||
|
||||
;; 2. Block taking TWO parameters (Multi-Value feature)
|
||||
;; It consumes the [10, 20] from the stack.
|
||||
block (param i32 i32) (result i32)
|
||||
i32.add ;; 10 + 20 = 30
|
||||
i32.const 30 ;; Expected result
|
||||
i32.eq ;; Compare: returns 1 if equal
|
||||
end
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
25
src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat
Normal file
25
src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat
Normal file
@@ -0,0 +1,25 @@
|
||||
(module
|
||||
;; Define a mutable global initialized to 0
|
||||
(global $counter (mut i32) (i32.const 0))
|
||||
|
||||
;; EXPORTING a mutable global is the key feature of this proposal.
|
||||
;; In strict MVP, exported globals had to be immutable (const).
|
||||
(export "counter" (global $counter))
|
||||
|
||||
(func $finish (result i32)
|
||||
;; 1. Get current value
|
||||
global.get $counter
|
||||
|
||||
;; 2. Add 1
|
||||
i32.const 1
|
||||
i32.add
|
||||
|
||||
;; 3. Set new value (Mutation)
|
||||
global.set $counter
|
||||
|
||||
;; 4. Return 1 for success
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
18
src/test/app/wasm_fixtures/wat/proposal_ref_types.wat
Normal file
18
src/test/app/wasm_fixtures/wat/proposal_ref_types.wat
Normal file
@@ -0,0 +1,18 @@
|
||||
(module
|
||||
;; Import a table from the host that holds externrefs
|
||||
(import "env" "table" (table 1 externref))
|
||||
|
||||
(func $test_ref_types (result i32)
|
||||
;; Store a null externref into the table at index 0
|
||||
;; If reference_types is disabled, 'externref' and 'ref.null' will fail parsing.
|
||||
(table.set
|
||||
(i32.const 0) ;; Index
|
||||
(ref.null extern) ;; Value (Null External Reference)
|
||||
)
|
||||
|
||||
;; Return 1 (Success)
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $test_ref_types))
|
||||
)
|
||||
18
src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat
Normal file
18
src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat
Normal file
@@ -0,0 +1,18 @@
|
||||
(module
|
||||
(func $test_sign_ext (result i32)
|
||||
;; Push 255 (0x000000FF) onto the stack
|
||||
i32.const 255
|
||||
|
||||
;; Sign-extend from 8-bit to 32-bit
|
||||
;; If 255 is treated as an i8, it is -1.
|
||||
;; Result should be -1 (0xFFFFFFFF).
|
||||
;; Without this proposal, this opcode (0xC0) causes a validation error.
|
||||
i32.extend8_s
|
||||
|
||||
;; Check if result is -1
|
||||
i32.const -1
|
||||
i32.eq
|
||||
)
|
||||
|
||||
(export "finish" (func $test_sign_ext))
|
||||
)
|
||||
1
src/test/app/wasm_fixtures/wat/proposal_stringref.wat
Normal file
1
src/test/app/wasm_fixtures/wat/proposal_stringref.wat
Normal file
@@ -0,0 +1 @@
|
||||
;;hard to generate
|
||||
15
src/test/app/wasm_fixtures/wat/proposal_tail_call.wat
Normal file
15
src/test/app/wasm_fixtures/wat/proposal_tail_call.wat
Normal file
@@ -0,0 +1,15 @@
|
||||
(module
|
||||
;; Define a simple function we can tail-call
|
||||
(func $target (result i32)
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(func $finish (result i32)
|
||||
;; Try to use the 'return_call' instruction (Opcode 0x12)
|
||||
;; If Tail Call proposal is disabled, this fails to Compile/Validate.
|
||||
;; If enabled, it jumps to $target, which returns 1.
|
||||
return_call $target
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
24
src/test/app/wasm_fixtures/wat/table_2_tables.wat
Normal file
24
src/test/app/wasm_fixtures/wat/table_2_tables.wat
Normal file
@@ -0,0 +1,24 @@
|
||||
(module
|
||||
;; Define a dummy function to put in the tables
|
||||
(func $dummy)
|
||||
|
||||
;; TABLE 0: The default table (allowed in MVP)
|
||||
;; Size: 1 initial, 1 max
|
||||
(table $t0 1 1 funcref)
|
||||
|
||||
;; Initialize Table 0 at index 0
|
||||
(elem (table $t0) (i32.const 0) $dummy)
|
||||
|
||||
;; TABLE 1: The second table (Requires Reference Types proposal)
|
||||
;; If strict MVP is enforced, the parser should error here.
|
||||
(table $t1 1 1 funcref)
|
||||
|
||||
;; Initialize Table 1 at index 0
|
||||
(elem (table $t1) (i32.const 0) $dummy)
|
||||
|
||||
(func $finish (result i32)
|
||||
;; If we successfully loaded a module with 2 tables, return 1.
|
||||
i32.const 1
|
||||
)
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
25
src/test/app/wasm_fixtures/wat/table_64_elements.wat
Normal file
25
src/test/app/wasm_fixtures/wat/table_64_elements.wat
Normal file
@@ -0,0 +1,25 @@
|
||||
(module
|
||||
;; Define a table with exactly 64 entries
|
||||
(table 64 funcref)
|
||||
|
||||
;; A dummy function to reference
|
||||
(func $dummy)
|
||||
|
||||
;; Initialize the table at offset 0 with 64 references to $dummy
|
||||
(elem (i32.const 0)
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 8
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 16
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 24
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 32
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 40
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 48
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 56
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 64
|
||||
)
|
||||
|
||||
;; Standard finish function
|
||||
(func $finish (result i32)
|
||||
i32.const 1
|
||||
)
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
25
src/test/app/wasm_fixtures/wat/table_65_elements.wat
Normal file
25
src/test/app/wasm_fixtures/wat/table_65_elements.wat
Normal file
@@ -0,0 +1,25 @@
|
||||
(module
|
||||
;; Define a table with exactly 65 entries
|
||||
(table 65 funcref)
|
||||
|
||||
;; A dummy function to reference
|
||||
(func $dummy)
|
||||
|
||||
;; Initialize the table at offset 0 with 65 references to $dummy
|
||||
(elem (i32.const 0)
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 8
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 16
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 24
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 32
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 40
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 48
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 56
|
||||
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 64
|
||||
$dummy ;; 65 (The one that breaks the camel's back)
|
||||
)
|
||||
|
||||
(func $finish (result i32)
|
||||
i32.const 1
|
||||
)
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
15
src/test/app/wasm_fixtures/wat/table_uint_max.wat
Normal file
15
src/test/app/wasm_fixtures/wat/table_uint_max.wat
Normal file
@@ -0,0 +1,15 @@
|
||||
(module
|
||||
;; Definition: (table <min> <optional_max> <type>)
|
||||
;; We use 0xFFFFFFFF (4,294,967,295), which is the unsigned equivalent of -1.
|
||||
;; This tests if the runtime handles the maximum possible u32 value
|
||||
;; without integer overflows or attempting a massive allocation.
|
||||
;;
|
||||
;; Note that using -1 as the table size cannot be parsed by wasm-tools or wat2wasm
|
||||
(table 0xFFFFFFFF funcref)
|
||||
|
||||
(func $finish (result i32)
|
||||
;; If the module loads despite the massive table, return 1.
|
||||
i32.const 1
|
||||
)
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
15
src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat
Normal file
15
src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat
Normal file
@@ -0,0 +1,15 @@
|
||||
(module
|
||||
(func $finish (export "finish") (result i32)
|
||||
;; Setup for Requirement 2: Divide an i32 by 0
|
||||
i32.const 42 ;; Push numerator
|
||||
i32.const 0 ;; Push denominator (0)
|
||||
i32.div_s ;; Perform signed division (42 / 0)
|
||||
|
||||
;; --- NOTE: Execution usually traps (crashes) at the line above ---
|
||||
|
||||
;; Logic to satisfy Requirement 1: Return i32 = 1
|
||||
;; If execution continued, we would drop the division result and return 1
|
||||
drop ;; Clear the stack
|
||||
i32.const 1 ;; Push the return value
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
(module
|
||||
;; Define a table with 1 slot
|
||||
(table 1 funcref)
|
||||
|
||||
;; Define Type A: Takes nothing, returns nothing
|
||||
(type $type_void (func))
|
||||
|
||||
;; Define Type B: Takes nothing, returns i32
|
||||
(type $type_i32 (func (result i32)))
|
||||
|
||||
;; Define a function of Type A
|
||||
(func $void_func (type $type_void)
|
||||
nop
|
||||
)
|
||||
|
||||
;; Put Type A function into Table[0]
|
||||
(elem (i32.const 0) $void_func)
|
||||
|
||||
(func $finish (result i32)
|
||||
;; Attempt to call Index 0, but CLAIM we expect Type B (result i32).
|
||||
;; The function at Index 0 matches Type A.
|
||||
;; TRAP: "indirect call type mismatch"
|
||||
|
||||
;; 1. Push the table index (0) onto the stack
|
||||
i32.const 0
|
||||
|
||||
;; 2. Call indirect using Type B signature.
|
||||
;; This pops the index (0) from the stack.
|
||||
call_indirect (type $type_i32)
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
18
src/test/app/wasm_fixtures/wat/trap_int_overflow.wat
Normal file
18
src/test/app/wasm_fixtures/wat/trap_int_overflow.wat
Normal file
@@ -0,0 +1,18 @@
|
||||
(module
|
||||
(func $test_int_overflow (result i32)
|
||||
;; 1. Push INT_MIN (-2147483648)
|
||||
;; In Hex: 0x80000000
|
||||
i32.const -2147483648
|
||||
|
||||
;; 2. Push -1
|
||||
i32.const -1
|
||||
|
||||
;; 3. Signed Division
|
||||
;; This specific case is the ONLY integer arithmetic operation
|
||||
;; (besides divide by zero) that traps in the spec.
|
||||
;; Result would be +2147483648, which is too big for signed i32.
|
||||
i32.div_s
|
||||
)
|
||||
|
||||
(export "finish" (func $test_int_overflow))
|
||||
)
|
||||
22
src/test/app/wasm_fixtures/wat/trap_null_call.wat
Normal file
22
src/test/app/wasm_fixtures/wat/trap_null_call.wat
Normal file
@@ -0,0 +1,22 @@
|
||||
(module
|
||||
;; Table size is 1, so Index 0 is VALID bounds.
|
||||
;; However, we do NOT initialize it, so it contains 'ref.null'.
|
||||
(table 1 funcref)
|
||||
|
||||
(type $t (func (result i32)))
|
||||
|
||||
(func $finish (result i32)
|
||||
;; Call Index 0.
|
||||
;; Bounds check passes (0 < 1).
|
||||
;; Null check fails.
|
||||
;; TRAP: "uninitialized element" or "undefined element"
|
||||
|
||||
;; 1. Push the index (0) onto the stack first
|
||||
i32.const 0
|
||||
|
||||
;; 2. Perform the call. This pops the index.
|
||||
call_indirect (type $t)
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
12
src/test/app/wasm_fixtures/wat/trap_unreachable.wat
Normal file
12
src/test/app/wasm_fixtures/wat/trap_unreachable.wat
Normal file
@@ -0,0 +1,12 @@
|
||||
(module
|
||||
(func $finish (result i32)
|
||||
;; This instruction explicitly causes a trap.
|
||||
;; It consumes no fuel (beyond the instruction itself) and stops execution.
|
||||
unreachable
|
||||
|
||||
;; This code is dead and never reached
|
||||
i32.const 1
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
38
src/test/app/wasm_fixtures/wat/wasi_get_time.wat
Normal file
38
src/test/app/wasm_fixtures/wat/wasi_get_time.wat
Normal file
@@ -0,0 +1,38 @@
|
||||
(module
|
||||
;; Import clock_time_get from WASI
|
||||
;; Signature: (param clock_id precision return_ptr) (result errno)
|
||||
(import "wasi_snapshot_preview1" "clock_time_get"
|
||||
(func $clock_time_get (param i32 i64 i32) (result i32))
|
||||
)
|
||||
|
||||
(memory 1)
|
||||
(export "memory" (memory 0))
|
||||
|
||||
(func $finish (result i32)
|
||||
;; We will store the timestamp (a 64-bit integer) at address 0.
|
||||
;; No setup required in memory beforehand!
|
||||
|
||||
;; Call the function
|
||||
(call $clock_time_get
|
||||
(i32.const 0) ;; clock_id: 0 = Realtime (Wallclock)
|
||||
(i64.const 1000) ;; precision: 1000ns (hint to OS)
|
||||
(i32.const 0) ;; result_ptr: Write the time to address 0
|
||||
)
|
||||
|
||||
;; The function returns an 'errno' (error code).
|
||||
;; 0 = Success. Anything else = Error.
|
||||
|
||||
;; Check if errno (top of stack) is 0
|
||||
i32.eqz
|
||||
if (result i32)
|
||||
;; Success! The time is now stored in heap[0..8].
|
||||
;; We return 1 as requested.
|
||||
i32.const 1
|
||||
else
|
||||
;; Failed (maybe WASI is disabled or clock is missing)
|
||||
i32.const -1
|
||||
end
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
59
src/test/app/wasm_fixtures/wat/wasi_print.wat
Normal file
59
src/test/app/wasm_fixtures/wat/wasi_print.wat
Normal file
@@ -0,0 +1,59 @@
|
||||
(module
|
||||
;; Import WASI fd_write
|
||||
;; Signature: (fd, iovs_ptr, iovs_len, nwritten_ptr) -> errno
|
||||
(import "wasi_snapshot_preview1" "fd_write"
|
||||
(func $fd_write (param i32 i32 i32 i32) (result i32))
|
||||
)
|
||||
|
||||
(memory 1)
|
||||
(export "memory" (memory 0))
|
||||
|
||||
;; --- DATA SEGMENTS ---
|
||||
|
||||
;; 1. The String Data "Hello\n" placed at offset 16
|
||||
;; We assume offset 0-16 is reserved for the IOVec struct
|
||||
(data (i32.const 16) "Hello\n")
|
||||
|
||||
;; 2. The IO Vector (struct iovec) placed at offset 0
|
||||
;; Structure: { buf_ptr: u32, buf_len: u32 }
|
||||
|
||||
;; Field 1: buf_ptr = 16 (Location of "Hello\n")
|
||||
;; Encoded in little-endian: 10 00 00 00
|
||||
(data (i32.const 0) "\10\00\00\00")
|
||||
|
||||
;; Field 2: buf_len = 6 (Length of "Hello\n")
|
||||
;; Encoded in little-endian: 06 00 00 00
|
||||
(data (i32.const 4) "\06\00\00\00")
|
||||
|
||||
(func $finish (result i32)
|
||||
(local $nwritten_ptr i32)
|
||||
|
||||
;; We will ask WASI to write the "number of bytes written" to address 24
|
||||
;; (safely after our string data)
|
||||
i32.const 24
|
||||
local.set $nwritten_ptr
|
||||
|
||||
;; Call fd_write
|
||||
(call $fd_write
|
||||
(i32.const 1) ;; fd: 1 = STDOUT
|
||||
(i32.const 0) ;; iovs_ptr: Address 0 (where we defined the struct)
|
||||
(i32.const 1) ;; iovs_len: We are passing 1 vector
|
||||
(local.get $nwritten_ptr) ;; nwritten_ptr: Address 24
|
||||
)
|
||||
|
||||
;; The function returns an 'errno' (i32).
|
||||
;; 0 means Success.
|
||||
|
||||
;; Check if errno == 0
|
||||
i32.eqz
|
||||
if (result i32)
|
||||
;; Success: Return 1
|
||||
i32.const 1
|
||||
else
|
||||
;; Failure: Return -1
|
||||
i32.const -1
|
||||
end
|
||||
)
|
||||
|
||||
(export "finish" (func $finish))
|
||||
)
|
||||
Reference in New Issue
Block a user