Skip to content

Commit

Permalink
add wzaero code
Browse files Browse the repository at this point in the history
  • Loading branch information
faddat committed Jan 6, 2025
1 parent 58af4fd commit ef57261
Show file tree
Hide file tree
Showing 10,186 changed files with 453,216 additions and 85 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
103 changes: 62 additions & 41 deletions internal/runtime/wazeroruntime.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,27 @@ type Region struct {
}

// validateRegion performs plausibility checks on a Region
func validateRegion(region *Region) error {
func validateRegion(region *Region, memory api.Memory) error {
// Match vm/src/memory.rs validation exactly
if region.Offset == 0 {
return fmt.Errorf("region has zero offset")
return fmt.Errorf("zero offset")
}
if region.Length > region.Capacity {
return fmt.Errorf("region length %d exceeds capacity %d", region.Length, region.Capacity)
return fmt.Errorf("length %d exceeds capacity %d", region.Length, region.Capacity)
}

// Check for overflow like Rust impl
if uint64(region.Offset)+uint64(region.Capacity) > math.MaxUint32 {
return fmt.Errorf("region out of range: offset %d, capacity %d", region.Offset, region.Capacity)
}

// Add memory bounds check
memSize := uint64(memory.Size()) * wasmPageSize
if uint64(region.Offset)+uint64(region.Capacity) > memSize {
return fmt.Errorf("region exceeds memory bounds: offset=%d, capacity=%d, memSize=%d",
region.Offset, region.Capacity, memSize)
}

return nil
}

Expand All @@ -97,66 +108,76 @@ func newMemoryManager(memory api.Memory, module api.Module) *memoryManager {
}

// writeToMemory writes data to WASM memory and returns the pointer and size
// writeToMemory writes data to WASM memory and returns a pointer to a Region struct + the size.
func (m *memoryManager) writeToMemory(data []byte) (uint32, uint32, error) {
if data == nil {
return 0, 0, nil
}

// Get the allocate function
// 1) Lookup "allocate"
allocate := m.module.ExportedFunction("allocate")
if allocate == nil {
return 0, 0, fmt.Errorf("allocate function not found in WASM module")
}

// Allocate memory for the Region struct (12 bytes) and the data
size := uint32(len(data))
results, err := allocate.Call(context.Background(), uint64(size+regionSize))

// 2) Allocate space for the data
dataResult, err := allocate.Call(context.Background(), uint64(size))
if err != nil {
return 0, 0, fmt.Errorf("failed to allocate memory for data: %w", err)
}
dataPtr := uint32(dataResult[0])

// 3) Write the data
if !m.memory.Write(dataPtr, data) {
// Attempt to free the partially allocated data
if deallocate := m.module.ExportedFunction("deallocate"); deallocate != nil {
_, _ = deallocate.Call(context.Background(), uint64(dataPtr))
}
return 0, 0, fmt.Errorf("failed to write data to memory at ptr=%d size=%d", dataPtr, size)
}

// 4) Allocate space for the Region struct
regionResult, err := allocate.Call(context.Background(), regionSize)
if err != nil {
return 0, 0, fmt.Errorf("failed to allocate memory: %w", err)
// Attempt to free the data pointer
if deallocate := m.module.ExportedFunction("deallocate"); deallocate != nil {
_, _ = deallocate.Call(context.Background(), uint64(dataPtr))
}
return 0, 0, fmt.Errorf("failed to allocate memory for region struct: %w", err)
}
ptr := uint32(results[0])
regionPtr := uint32(regionResult[0])

// Create and write the Region struct
// 5) Construct the Region
region := &Region{
Offset: ptr + regionSize, // Data starts after the Region struct
Offset: dataPtr,
Capacity: size,
Length: size,
}

// Validate the region before writing
if err := validateRegion(region); err != nil {
deallocate := m.module.ExportedFunction("deallocate")
if deallocate != nil {
if _, err := deallocate.Call(context.Background(), uint64(ptr)); err != nil {
return 0, 0, fmt.Errorf("deallocation failed: %w", err)
}
// 6) Validate the region
if err := validateRegion(region, m.memory); err != nil {
// Attempt to free both pointers
if deallocate := m.module.ExportedFunction("deallocate"); deallocate != nil {
_, _ = deallocate.Call(context.Background(), uint64(dataPtr))
_, _ = deallocate.Call(context.Background(), uint64(regionPtr))
}
return 0, 0, fmt.Errorf("invalid region: %w", err)
}

// Write the Region struct
if err := m.writeRegion(ptr, region); err != nil {
deallocate := m.module.ExportedFunction("deallocate")
if deallocate != nil {
if _, err := deallocate.Call(context.Background(), uint64(ptr)); err != nil {
return 0, 0, fmt.Errorf("deallocation failed: %w", err)
}
// 7) Write the region struct to memory
if err := m.writeRegion(regionPtr, region); err != nil {
// Attempt to free both pointers
if deallocate := m.module.ExportedFunction("deallocate"); deallocate != nil {
_, _ = deallocate.Call(context.Background(), uint64(dataPtr))
_, _ = deallocate.Call(context.Background(), uint64(regionPtr))
}
return 0, 0, fmt.Errorf("failed to write region: %w", err)
}

// Write the actual data
if !m.memory.Write(region.Offset, data) {
deallocate := m.module.ExportedFunction("deallocate")
if deallocate != nil {
if _, err := deallocate.Call(context.Background(), uint64(ptr)); err != nil {
return 0, 0, fmt.Errorf("deallocation failed: %w", err)
}
}
return 0, 0, fmt.Errorf("failed to write data to memory at ptr=%d size=%d", region.Offset, size)
}

return ptr, size, nil
// 8) Return the pointer to the Region struct (not the data pointer)
return regionPtr, size, nil
}

// readFromMemory reads data from WASM memory
Expand All @@ -172,7 +193,7 @@ func (m *memoryManager) readFromMemory(ptr, size uint32) ([]byte, error) {
}

// Validate the region
if err := validateRegion(region); err != nil {
if err := validateRegion(region, m.memory); err != nil {
return nil, fmt.Errorf("invalid region: %w", err)
}

Expand Down Expand Up @@ -215,7 +236,7 @@ func (m *memoryManager) readRegion(ptr uint32) (*Region, error) {
}

// Validate the region
if err := validateRegion(region); err != nil {
if err := validateRegion(region, m.memory); err != nil {
return nil, fmt.Errorf("invalid region: %w", err)
}

Expand All @@ -229,7 +250,7 @@ func (m *memoryManager) writeRegion(ptr uint32, region *Region) error {
}

// Validate the region before writing
if err := validateRegion(region); err != nil {
if err := validateRegion(region, m.memory); err != nil {
return fmt.Errorf("invalid region: %w", err)
}

Expand All @@ -256,7 +277,7 @@ func (m *memoryManager) writeRegion(ptr uint32, region *Region) error {
func NewWazeroRuntime() (*WazeroRuntime, error) {
// Create a new wazero runtime with memory configuration
runtimeConfig := wazero.NewRuntimeConfig().
WithMemoryLimitPages(4096). // Set max memory to 256 MiB (4096 * 64KB)
WithMemoryLimitPages(65536). // Set max memory to limit maximum memory usage
WithMemoryCapacityFromMax(false) // Eagerly allocate memory

r := wazero.NewRuntimeWithConfig(context.Background(), runtimeConfig)
Expand Down Expand Up @@ -1149,7 +1170,7 @@ func (w *WazeroRuntime) callContractFn(
}

// Validate the result region
if err := validateRegion(resultRegion); err != nil {
if err := validateRegion(resultRegion, mm.memory); err != nil {
errStr := fmt.Sprintf("[callContractFn] Error: invalid result region: %v", err)
fmt.Println(errStr)
return nil, types.GasReport{}, errors.New(errStr)
Expand Down
7 changes: 7 additions & 0 deletions wazero/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
2 changes: 2 additions & 0 deletions wazero/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Improves experience of commands like `make format` on Windows
* text=auto eol=lf
3 changes: 3 additions & 0 deletions wazero/.github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

* @mathetake
31 changes: 31 additions & 0 deletions wazero/.github/ISSUE_TEMPLATE/bug-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
name: Bug Report
about: Create a report to help us improve wazero.
title: ''
labels: bug
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Description of the host and wasm code that reproduces the behavior.
Smoothest debugging will be if you can share a repository with the
actual code.

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Environment (please complete the relevant information):**
- Go version: [e.g. 1.19.1]
- wazero Version: [e.g. c815060196bbfaa2d0f66a6ddbe64ba026523944]
- Host architecture: [e.g. amd64]
- Runtime mode: [e.g. interpreter or compiler]

**Additional context**
Add any other context about the problem here.
20 changes: 20 additions & 0 deletions wazero/.github/ISSUE_TEMPLATE/feature-request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Feature Request
about: Suggest an idea for wazero to support.
title: ''
labels: enhancement
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. e.g. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
24 changes: 24 additions & 0 deletions wazero/.github/actions/vmactions/template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: VM Actions matrix
description: VM Actions matrix template

inputs:
run:
description: 'The CI command to run'
required: true
release:
description: 'The OS release version'
required: false
envs:
description: 'The envs to pass into vm'
required: false

runs:
using: composite
steps:
- uses: ${VMACTIONS}
with:
usesh: true
copyback: false
run: ${{inputs.run}}
envs: ${{inputs.envs}}
release: ${{inputs.release}}
47 changes: 47 additions & 0 deletions wazero/.github/wasi_testsuite_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# adapter for wazero until/unless https://github.com/WebAssembly/wasi-testsuite/pull/55

import argparse
import subprocess
import sys
import os
import shlex

# shlex.split() splits according to shell quoting rules
WAZERO = shlex.split(os.getenv("TEST_RUNTIME_EXE", "wazero"))

parser = argparse.ArgumentParser()
parser.add_argument("--version", action="store_true")
parser.add_argument("--test-file", action="store")
parser.add_argument("--arg", action="append", default=[])
parser.add_argument("--env", action="append", default=[])
parser.add_argument("--dir", action="append", default=[])

args = parser.parse_args()

if args.version:
version = subprocess.run(
WAZERO + ["version"], capture_output=True, text=True
).stdout.strip()
if version == "dev":
version = "0.0.0"
print("wazero", version)
sys.exit(0)

TEST_FILE = args.test_file
TEST_DIR = os.path.dirname(TEST_FILE)
PROG_ARGS = []
if args.arg:
PROG_ARGS = ["--"] + args.arg
ENV_ARGS = [f"-env={e}" for e in args.env]
cwd = os.getcwd()
DIR_ARGS = [f"-mount={cwd}/{dir}:{dir}" for dir in args.dir]

PROG = (
WAZERO
+ ["run", "-hostlogging=filesystem"]
+ ENV_ARGS
+ DIR_ARGS
+ [TEST_FILE]
+ PROG_ARGS
)
sys.exit(subprocess.run(PROG, cwd=TEST_DIR).returncode)
4 changes: 4 additions & 0 deletions wazero/.github/wasi_testsuite_skip.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"WASI Rust tests": {
}
}
37 changes: 37 additions & 0 deletions wazero/.github/workflows/clear_cache.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This job cleans up the unnecessary caches created on PRs.
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
name: cleanup caches by a branch
on:
# Only runs on the PRs are closed, regardless of it is merged or not.
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-your-pull_request-workflow-when-a-pull-request-merges
pull_request:
types:
- closed

jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4

- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
REPO=${{ github.repository }}
BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge"
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Loading

0 comments on commit ef57261

Please sign in to comment.