Compare commits

..

19 Commits

Author SHA1 Message Date
Benjamin Eckel
f4c61e8c44 feat: add default cache config (#615)
Co-authored-by: zach <zach@dylibso.com>
2023-11-29 14:32:01 -06:00
Benjamin Eckel
452bb2f498 chore: Bump 0.5.4 (#549) 2023-10-25 15:46:30 -05:00
zach
c043decd95 chore: backport latest kernel changes (#547)
- Updates to fix a possible issue with a value on stack being stored at
a very high offset in extism kernel memory
2023-10-25 11:37:37 -07:00
Benjamin Eckel
ec70b0e7b8 Release: 0.5.3 stable release (#538)
Cuts a new 0.5.3 release from stable.
2023-10-24 12:29:39 -05:00
zach
1452b9fb42 chore: backport latest kernel changes to stable (#528) 2023-10-20 10:16:33 -07:00
Benjamin Eckel
9f69a68df4 chore: fix elixir release action (#497)
This is 404ing for some reason. But Elixir doesn't need the shared
library so i'm removing it.

https://github.com/extism/extism/actions/runs/6425026823/job/17446865267
2023-10-05 17:32:20 -05:00
Benjamin Eckel
dbf9f34dc6 chore: Release elixir v0.5.1 (#496) 2023-10-05 17:14:54 -05:00
Benjamin Eckel
c8a9478da1 chore: also bump rust SDK to 0.5.2 2023-09-21 10:22:39 -05:00
Benjamin Eckel
e89ddd5a2a chore: Bump to 0.5.2 2023-09-21 09:41:27 -05:00
zach
93392e0884 fix(stable): improve the way the kernel calculates how many pages to allocate (#471)
Fixes a bug in the kernel memory allocator where the space used by the
`MemoryRoot` wasn't being considered

---------

Co-authored-by: Benjamin Eckel <bhelx@users.noreply.github.com>
2023-09-20 16:02:42 -07:00
Benjamin Eckel
4ebd0eb372 chore: always run the publish of SDK 2023-09-18 19:17:47 -05:00
zach
8feee0c693 cleanup(stable): use wasm-strip on extism-runtime.wasm (#467) 2023-09-18 19:08:27 -05:00
Benjamin Eckel
773ab32a45 chore: Bump to 0.5.1 2023-09-18 18:55:46 -05:00
Benjamin Eckel
6a041d0c39 fix: Fixes rounding issue in kernel num_pages (#466)
There were some scenarios where the kernel was not allocating enough
pages to get data back into the plugin. So some host functions were
failing when the output was right on this boundary.

Related https://github.com/moonrepo/proto/issues/208

We will come back with tests and cherry pick this over to main. For now
we want to get out a 0.5.1 fix
2023-09-18 18:53:30 -05:00
Benjamin Eckel
745a03ece4 release: Bump elixir nif to rust 0.5 (#431) 2023-08-24 13:37:48 -05:00
Benjamin Eckel
67eb8c1571 release: Bump the rest of the SDKs (#430) 2023-08-24 12:41:31 -05:00
zach
6a15884963 fix: remove call to bash from build.rs (#429)
I think this will fix the issue with CI hanging - this fixes the issue
when building Elixir, which seems to be the same as the CI issue
2023-08-23 19:12:51 -05:00
zach
72f62c4035 chore: bump libextism version (#428) 2023-08-23 15:49:50 -05:00
Benjamin Eckel
e86398a612 release: Bump runtime to 0.5.0 (#427)
Co-authored-by: zach <zach@dylibso.com>
2023-08-23 13:58:33 -05:00
24 changed files with 422 additions and 327 deletions

View File

@@ -10,13 +10,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install extism shared library
shell: bash
run: |
mkdir -p /home/runner/.local/bin/
export PATH="/home/runner/.local/bin/:$PATH"
curl https://raw.githubusercontent.com/extism/cli/main/install.sh | sh
extism --sudo --prefix /usr/local install
- name: Setup Elixir Host SDK
uses: erlef/setup-beam@v1
with:

View File

@@ -20,6 +20,7 @@ jobs:
target: ${{ matrix.target }}
- name: Release Rust Manifest Crate
if: always()
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
run: |
@@ -29,6 +30,7 @@ jobs:
sleep 5
- name: Release Rust Host SDK
if: always()
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
run: |

View File

@@ -1,28 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>10</LangVersion>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>10</LangVersion>
</PropertyGroup>
<PropertyGroup>
<PackageId>Extism.Sdk</PackageId>
<Version>0.6.0</Version>
<Authors>Extism Contributors</Authors>
<Description>Extism SDK that allows hosting Extism plugins in .NET apps.</Description>
<Tags>extism, wasm, plugin</Tags>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<PropertyGroup>
<PackageId>Extism.Sdk</PackageId>
<Version>0.7.0</Version>
<Authors>Extism Contributors</Authors>
<Description>Extism SDK that allows hosting Extism plugins in .NET apps.</Description>
<Tags>extism, wasm, plugin</Tags>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\"/>
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -4,7 +4,7 @@ defmodule Extism.MixProject do
def project do
[
app: :extism,
version: "0.4.0",
version: "0.5.1",
elixir: "~> 1.12",
start_permanent: Mix.env() == :prod,
deps: deps(),

View File

@@ -13,6 +13,6 @@ crate-type = ["cdylib"]
[workspace]
[dependencies]
rustler = "0.28.0"
extism = "0.4.0"
rustler = "0.29.1"
extism = "0.5.2"
log = "0.4"

View File

@@ -1,6 +1,6 @@
cabal-version: 3.0
name: extism
version: 0.3.0
version: 0.5.0
license: BSD-3-Clause
maintainer: oss@extism.org
author: Extism authors
@@ -22,7 +22,7 @@ library
base >= 4.16.1 && < 5,
bytestring >= 0.11.3 && <= 0.12,
json >= 0.10 && <= 0.11,
extism-manifest >= 0.0.0 && < 0.3.0
extism-manifest >= 0.0.0 && < 0.4.0
test-suite extism-example
type: exitcode-stdio-1.0

View File

@@ -1,6 +1,6 @@
cabal-version: 3.0
name: extism-manifest
version: 0.2.0
version: 0.3.0
license: BSD-3-Clause
maintainer: oss@extism.org
author: Extism authors

View File

@@ -1,193 +1,194 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.extism.sdk</groupId>
<artifactId>extism</artifactId>
<packaging>jar</packaging>
<version>0.4.0</version>
<name>extism</name>
<url>https://github.com/extism/extism</url>
<description>Java-SDK for Extism to use webassembly from Java</description>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.extism.sdk</groupId>
<artifactId>extism</artifactId>
<packaging>jar</packaging>
<version>0.5.0</version>
<name>extism</name>
<url>https://github.com/extism/extism</url>
<description>Java-SDK for Extism to use webassembly from Java</description>
<licenses>
<license>
<name>BSD 3-Clause</name>
<url>https://opensource.org/licenses/BSD-3-Clause</url>
</license>
</licenses>
<licenses>
<license>
<name>BSD 3-Clause</name>
<url>https://opensource.org/licenses/BSD-3-Clause</url>
</license>
</licenses>
<organization>
<name>Dylibso, Inc.</name>
<url>https://dylib.so</url>
</organization>
<organization>
<name>Dylibso, Inc.</name>
<url>https://dylib.so</url>
</organization>
<developers>
<developer>
<name>The Extism Authors</name>
<email>oss@extism.org</email>
<roles>
<role>Maintainer</role>
</roles>
<organization>Dylibso, Inc.</organization>
<organizationUrl>https://dylib.so</organizationUrl>
</developer>
</developers>
<developers>
<developer>
<name>The Extism Authors</name>
<email>oss@extism.org</email>
<roles>
<role>Maintainer</role>
</roles>
<organization>Dylibso, Inc.</organization>
<organizationUrl>https://dylib.so</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/extism/extism.git</connection>
<developerConnection>scm:git:ssh://git@github.com/extism/extism.git</developerConnection>
<url>https://github.com/extism/extism/tree/main/java</url>
<tag>main</tag>
</scm>
<scm>
<connection>scm:git:git://github.com/extism/extism.git</connection>
<developerConnection>scm:git:ssh://git@github.com/extism/extism.git</developerConnection>
<url>https://github.com/extism/extism/tree/main/java</url>
<tag>main</tag>
</scm>
<issueManagement>
<system>Github</system>
<url>https://github.com/extism/extism/issues</url>
</issueManagement>
<issueManagement>
<system>Github</system>
<url>https://github.com/extism/extism/issues</url>
</issueManagement>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- dependencies -->
<jna.version>5.12.1</jna.version>
<gson.version>2.10</gson.version>
<!-- dependencies -->
<jna.version>5.12.1</jna.version>
<gson.version>2.10</gson.version>
<!-- testing -->
<junit-jupiter-engine.version>5.9.1</junit-jupiter-engine.version>
<assertj-core.version>3.23.1</assertj-core.version>
<!-- testing -->
<junit-jupiter-engine.version>5.9.1</junit-jupiter-engine.version>
<assertj-core.version>3.23.1</assertj-core.version>
<!-- maven plugins -->
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<!-- maven plugins -->
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<!-- jreleaser -->
<jreleaser.git.root.search>true</jreleaser.git.root.search>
</properties>
<!-- jreleaser -->
<jreleaser.git.root.search>true</jreleaser.git.root.search>
</properties>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<additionalJOption>-Xdoclint:none</additionalJOption>
</configuration>
<executions>
<execution>
<id>attach-javadoc</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-source</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jreleaser</groupId>
<artifactId>jreleaser-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<jreleaser>
<release>
<github>
<skipRelease>true</skipRelease>
</github>
</release>
<signing>
<active>ALWAYS</active>
<armored>true</armored>
</signing>
<deploy>
<maven>
<nexus2>
<maven-central>
<active>ALWAYS</active>
<url>https://s01.oss.sonatype.org/service/local</url>
<!--
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<additionalJOption>-Xdoclint:none</additionalJOption>
</configuration>
<executions>
<execution>
<id>attach-javadoc</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-source</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jreleaser</groupId>
<artifactId>jreleaser-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<jreleaser>
<release>
<github>
<skipRelease>true</skipRelease>
</github>
</release>
<signing>
<active>ALWAYS</active>
<armored>true</armored>
</signing>
<deploy>
<maven>
<nexus2>
<maven-central>
<active>ALWAYS</active>
<url>https://s01.oss.sonatype.org/service/local</url>
<!--
<closeRepository>false</closeRepository>
<releaseRepository>false</releaseRepository>
-->
<stagingRepositories>target/staging-deploy</stagingRepositories>
</maven-central>
</nexus2>
</maven>
</deploy>
</jreleaser>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<jna.library.path>../target/release</jna.library.path>
</systemPropertyVariables>
</configuration>
</plugin>
<stagingRepositories>target/staging-deploy</stagingRepositories>
</maven-central>
</nexus2>
</maven>
</deploy>
</jreleaser>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>${jna.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter-engine.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
</build>
</profile>
</profiles>
<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>model-assert</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<jna.library.path>../target/release</jna.library.path>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>${jna.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter-engine.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>model-assert</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -2,6 +2,6 @@
cargo build --release --target wasm32-unknown-unknown --package extism-runtime-kernel --bin extism-runtime
cp target/wasm32-unknown-unknown/release/extism-runtime.wasm .
wasm-strip extism-runtime.wasm || :
wasm-strip extism-runtime.wasm
mv extism-runtime.wasm ../runtime/src/extism-runtime.wasm

View File

@@ -17,13 +17,13 @@
//! ## Input/Output
//!
//! Input and output are just allocated blocks of memory that are marked as either input or output using
//! the `extism_input_set` or `extism_output_set` functions. The global variables `INPUT_OFFSET` contains
//! the offset in memory to the input data and `INPUT_LENGTH` contains the size of the input data. `OUTPUT_OFFSET`
//! and `OUTPUT_LENGTH` are used for the output data.
//! the `extism_input_set` or `extism_output_set` functions. The MemoryRoot field `input_offset` contains
//! the offset in memory to the input data and `input_length` contains the size of the input data. `output_offset`
//! and `output_length` are used for the output data.
//!
//! ## Error handling
//!
//! The `ERROR` global is used to track the current error message. If it is set to `0` then there is no error.
//! The `error` field is used to track the current error message. If it is set to `0` then there is no error.
//! The length of the error message can be retreived using `extism_length`.
//!
//! ## Memory offsets
@@ -45,31 +45,6 @@ pub type Length = u64;
/// WebAssembly page size
const PAGE_SIZE: usize = 65536;
/// Determines the amount of bytes that can be wasted by re-using a block. If more than this number is wasted by re-using
/// a block then it will be split into two smaller blocks.
const BLOCK_SPLIT_SIZE: usize = 128;
/// Offset to the input data
static mut INPUT_OFFSET: Pointer = 0;
/// Length of the input data
static mut INPUT_LENGTH: Length = 0;
/// Offset to the output data
static mut OUTPUT_OFFSET: Pointer = 0;
/// Offset to the input data
static mut OUTPUT_LENGTH: Length = 0;
/// Current error message
static mut ERROR: AtomicU64 = AtomicU64::new(0);
/// Determines if the kernel has been initialized already
static mut INITIALIZED: AtomicBool = AtomicBool::new(false);
/// A pointer to the first page that will be managed by Extism, this is set during initialization
static mut START_PAGE: usize = 0;
/// Provides information about the usage status of a `MemoryBlock`
#[repr(u8)]
#[derive(PartialEq)]
@@ -87,19 +62,34 @@ pub enum MemoryStatus {
///
/// The overall layout of the Extism-manged memory is organized like this:
/// |------|-------|---------|-------|--------------|
/// | Root | Block | Data | Block | Data | ...
/// |------|-------|---------|-------|--------------|
/// |------|-------+---------|-------+--------------|
/// | Root | Block + Data | Block + Data | ...
/// |------|-------+---------|-------+--------------|
///
/// Where `Root` and `Block` are fixed to the size of the `MemoryRoot` and `MemoryBlock` structs. But
/// the size of `Data` is dependent on the allocation size.
///
/// This means that the offset of a `Block` is the size of `Root` plus the size of all existing `Blocks`
/// including their data.
#[repr(C)]
pub struct MemoryRoot {
/// Position of the bump allocator, relative to `START_PAGE`
/// Set to true after initialization
pub initialized: AtomicBool,
/// Position of the bump allocator, relative to `blocks` field
pub position: AtomicU64,
/// The total size of all data allocated using this allocator
pub length: AtomicU64,
/// A pointer to where the blocks begin
/// Offset of error block
pub error: AtomicU64,
/// Input position in memory
pub input_offset: Pointer,
/// Input length
pub input_length: Length,
/// Output position in memory
pub output_offset: Pointer,
/// Output length
pub output_length: Length,
/// A pointer to the start of the first block
pub blocks: [MemoryBlock; 0],
}
@@ -119,37 +109,50 @@ pub struct MemoryBlock {
/// Returns the number of pages needed for the given number of bytes
pub fn num_pages(nbytes: u64) -> usize {
let nbytes = nbytes as f64;
let page = PAGE_SIZE as f64;
((nbytes / page) + 0.5) as usize
let npages = nbytes / PAGE_SIZE as u64;
let remainder = nbytes % PAGE_SIZE as u64;
if remainder != 0 {
(npages + 1) as usize
} else {
npages as usize
}
}
// Get the `MemoryRoot` at the correct offset in memory
// Get the `MemoryRoot`, this is always stored at offset 1 in memory
#[inline]
unsafe fn memory_root() -> &'static mut MemoryRoot {
&mut *((START_PAGE * PAGE_SIZE) as *mut MemoryRoot)
&mut *(1 as *mut MemoryRoot)
}
impl MemoryRoot {
/// Initialize or load the `MemoryRoot` from the correct position in memory
pub unsafe fn new() -> &'static mut MemoryRoot {
let root = memory_root();
// If this fails then `INITIALIZED` is already `true` and we can just return the
// already initialized `MemoryRoot`
if INITIALIZED
if root
.initialized
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
return memory_root();
return root;
}
// Ensure that at least one page is allocated to store the `MemoryRoot` data
START_PAGE = core::arch::wasm32::memory_grow(0, 1);
if START_PAGE == usize::MAX {
panic!("Out of memory");
if core::arch::wasm32::memory_size(0) == 0 {
if core::arch::wasm32::memory_grow(0, 1) == usize::MAX {
core::arch::wasm32::unreachable()
}
}
root.input_offset = 0;
root.input_length = 0;
root.output_offset = 0;
root.output_length = 0;
root.error.store(0, Ordering::Release);
// Initialize the `MemoryRoot` length, position and data
let root = memory_root();
root.length.store(
PAGE_SIZE as u64 - core::mem::size_of::<MemoryRoot>() as u64,
Ordering::Release,
@@ -174,6 +177,27 @@ impl MemoryRoot {
self.length.load(Ordering::Acquire) as usize,
);
self.position.store(0, Ordering::Release);
self.error.store(0, Ordering::Release);
self.input_offset = 0;
self.input_length = 0;
self.output_offset = 0;
self.output_length = 0;
}
#[inline(always)]
#[allow(unused)]
fn pointer_in_bounds(&self, p: Pointer) -> bool {
let start_ptr = self.blocks.as_ptr() as Pointer;
p >= start_ptr && p < start_ptr + self.length.load(Ordering::Acquire) as Pointer
}
#[inline(always)]
#[allow(unused)]
fn pointer_in_bounds_fast(p: Pointer) -> bool {
// Similar to `pointer_in_bounds` but less accurate on the upper bound. This uses the total memory size,
// instead of checking `MemoryRoot::length`
let end = core::arch::wasm32::memory_size(0) << 16;
p >= core::mem::size_of::<Self>() as Pointer && p <= end as Pointer
}
// Find a block that is free to use, this can be a new block or an existing freed block. The `self_position` argument
@@ -190,6 +214,7 @@ impl MemoryRoot {
while (block as u64) < self.blocks.as_ptr() as u64 + self_position {
let b = &mut *block;
// Get the block status, this lets us know if we are able to re-use it
let status = b.status.load(Ordering::Acquire);
// An unused block is safe to use
@@ -200,7 +225,7 @@ impl MemoryRoot {
// Re-use freed blocks when they're large enough
if status == MemoryStatus::Free as u8 && b.size >= length as usize {
// Split block if there is too much excess
if b.size - length as usize >= BLOCK_SPLIT_SIZE {
if b.size - length as usize >= 128 {
b.size -= length as usize;
b.used = 0;
@@ -242,13 +267,13 @@ impl MemoryRoot {
let curr = self.blocks.as_ptr() as u64 + self_position;
// Get the number of bytes available
let mem_left = self_length - self_position;
let mem_left = self_length - self_position - core::mem::size_of::<MemoryRoot>() as u64;
// When the allocation is larger than the number of bytes available
// we will need to try to grow the memory
if length >= mem_left {
// Calculate the number of pages needed to cover the remaining bytes
let npages = num_pages(length);
let npages = num_pages(length - mem_left);
let x = core::arch::wasm32::memory_grow(0, npages);
if x == usize::MAX {
return None;
@@ -276,8 +301,7 @@ impl MemoryRoot {
/// Finds the block at an offset in memory
pub unsafe fn find_block(&mut self, offs: Pointer) -> Option<&mut MemoryBlock> {
if offs >= self.blocks.as_ptr() as Pointer + self.length.load(Ordering::Acquire) as Pointer
{
if !Self::pointer_in_bounds_fast(offs) {
return None;
}
let ptr = offs - core::mem::size_of::<MemoryBlock>() as u64;
@@ -293,9 +317,7 @@ impl MemoryBlock {
/// is calculated based on metadata provided by the current block
#[inline]
pub unsafe fn next_ptr(&mut self) -> *mut MemoryBlock {
self.data
.as_mut_ptr()
.add(self.size + core::mem::size_of::<MemoryBlock>()) as *mut MemoryBlock
self.data.as_mut_ptr().add(self.size) as *mut MemoryBlock
}
/// Mark a block as free
@@ -305,11 +327,14 @@ impl MemoryBlock {
}
}
// Extism functions - these functions should be
// Extism functions
/// Allocate a block of memory and return the offset
#[no_mangle]
pub unsafe fn extism_alloc(n: Length) -> Pointer {
if n == 0 {
return 0;
}
let region = MemoryRoot::new();
let block = region.alloc(n);
match block {
@@ -321,9 +346,19 @@ pub unsafe fn extism_alloc(n: Length) -> Pointer {
/// Free allocated memory
#[no_mangle]
pub unsafe fn extism_free(p: Pointer) {
let block = MemoryRoot::new().find_block(p);
if p == 0 {
return;
}
let root = MemoryRoot::new();
let block = root.find_block(p);
if let Some(block) = block {
block.free();
// If the input pointer is freed for some reason, make sure the input length to 0
// since the original data is gone
if p == root.input_offset {
root.input_length = 0;
}
}
}
@@ -343,100 +378,144 @@ pub unsafe fn extism_length(p: Pointer) -> Length {
/// Load a byte from Extism-managed memory
#[no_mangle]
pub unsafe fn extism_load_u8(p: Pointer) -> u8 {
#[cfg(feature = "bounds-checking")]
if !MemoryRoot::pointer_in_bounds_fast(p) {
return 0;
}
*(p as *mut u8)
}
/// Load a u64 from Extism-managed memory
#[no_mangle]
pub unsafe fn extism_load_u64(p: Pointer) -> u64 {
#[cfg(feature = "bounds-checking")]
if !MemoryRoot::pointer_in_bounds_fast(p + core::mem::size_of::<u64>() as u64 - 1) {
return 0;
}
*(p as *mut u64)
}
/// Load a byte from the input data
#[no_mangle]
pub unsafe fn extism_input_load_u8(p: Pointer) -> u8 {
*((INPUT_OFFSET + p) as *mut u8)
let root = MemoryRoot::new();
#[cfg(feature = "bounds-checking")]
if p >= root.input_length {
return 0;
}
*((root.input_offset + p) as *mut u8)
}
/// Load a u64 from the input data
#[no_mangle]
pub unsafe fn extism_input_load_u64(p: Pointer) -> u64 {
*((INPUT_OFFSET + p) as *mut u64)
let root = MemoryRoot::new();
#[cfg(feature = "bounds-checking")]
if p + core::mem::size_of::<u64>() as Pointer > root.input_length {
return 0;
}
*((root.input_offset + p) as *mut u64)
}
/// Write a byte in Extism-managed memory
#[no_mangle]
pub unsafe fn extism_store_u8(p: Pointer, x: u8) {
#[cfg(feature = "bounds-checking")]
if !MemoryRoot::pointer_in_bounds_fast(p) {
return;
}
*(p as *mut u8) = x;
}
/// Write a u64 in Extism-managed memory
#[no_mangle]
pub unsafe fn extism_store_u64(p: Pointer, x: u64) {
unsafe {
*(p as *mut u64) = x;
#[cfg(feature = "bounds-checking")]
if !MemoryRoot::pointer_in_bounds_fast(p + core::mem::size_of::<u64>() as u64 - 1) {
return;
}
*(p as *mut u64) = x;
}
/// Set the range of the input data in memory
#[no_mangle]
pub fn extism_input_set(p: Pointer, len: Length) {
unsafe {
INPUT_OFFSET = p;
INPUT_LENGTH = len;
pub unsafe fn extism_input_set(p: Pointer, len: Length) {
let root = MemoryRoot::new();
#[cfg(feature = "bounds-checking")]
{
if !root.pointer_in_bounds(p) || !root.pointer_in_bounds(p + len - 1) {
return;
}
}
root.input_offset = p;
root.input_length = len;
}
/// Set the range of the output data in memory
#[no_mangle]
pub fn extism_output_set(p: Pointer, len: Length) {
unsafe {
OUTPUT_OFFSET = p;
OUTPUT_LENGTH = len;
pub unsafe fn extism_output_set(p: Pointer, len: Length) {
let root = MemoryRoot::new();
#[cfg(feature = "bounds-checking")]
{
if !root.pointer_in_bounds(p) || !root.pointer_in_bounds(p + len - 1) {
return;
}
}
root.output_offset = p;
root.output_length = len;
}
/// Get the input length
#[no_mangle]
pub fn extism_input_length() -> Length {
unsafe { INPUT_LENGTH }
unsafe { MemoryRoot::new().input_length }
}
/// Get the input offset in Exitsm-managed memory
#[no_mangle]
pub fn extism_input_offset() -> Length {
unsafe { INPUT_OFFSET }
unsafe { MemoryRoot::new().input_offset }
}
/// Get the output length
#[no_mangle]
pub fn extism_output_length() -> Length {
unsafe { OUTPUT_LENGTH }
pub unsafe fn extism_output_length() -> Length {
unsafe { MemoryRoot::new().output_length }
}
/// Get the output offset in Extism-managed memory
#[no_mangle]
pub fn extism_output_offset() -> Length {
unsafe { OUTPUT_OFFSET }
pub unsafe fn extism_output_offset() -> Length {
MemoryRoot::new().output_offset
}
/// Reset the allocator
#[no_mangle]
pub unsafe fn extism_reset() {
ERROR.store(0, Ordering::SeqCst);
MemoryRoot::new().reset()
}
/// Set the error message offset
#[no_mangle]
pub unsafe fn extism_error_set(ptr: Pointer) {
ERROR.store(ptr, Ordering::SeqCst);
let root = MemoryRoot::new();
// Allow ERROR to be set to 0
if ptr == 0 {
root.error.store(ptr, Ordering::SeqCst);
return;
}
if !root.pointer_in_bounds(ptr) {
return;
}
root.error.store(ptr, Ordering::SeqCst);
}
/// Get the error message offset, if it's `0` then no error has been set
#[no_mangle]
pub unsafe fn extism_error_get() -> Pointer {
ERROR.load(Ordering::SeqCst)
MemoryRoot::new().error.load(Ordering::SeqCst)
}
/// Get the position of the allocator, this can be used as an indication of how many bytes are currently in-use

View File

@@ -1,6 +1,6 @@
[package]
name = "libextism"
version = "0.4.0"
version = "0.5.4"
edition = "2021"
authors = ["The Extism Authors", "oss@extism.org"]
license = "BSD-3-Clause"

View File

@@ -1,6 +1,6 @@
{
"name": "@extism/extism",
"version": "0.4.0",
"version": "0.5.0",
"description": "Extism Host SDK for Node",
"keywords": [
"extism",

View File

@@ -1,5 +1,5 @@
VERSION?=0.3.0
TAG?=0.4.0
VERSION?=0.4.0
TAG?=0.5.0
build:
dune build

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "extism"
version = "0.4.0"
version = "0.5.0"
description = "Extism Host SDK for python"
authors = ["The Extism Authors <oss@extism.org>"]
license = "BSD-3-Clause"

View File

@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Extism
VERSION = "0.4.0"
VERSION = '0.5.0'
end

View File

@@ -1,6 +1,6 @@
[package]
name = "extism-runtime"
version = "0.5.0"
version = "0.5.5"
edition = "2021"
authors = ["The Extism Authors", "oss@extism.org"]
license = "BSD-3-Clause"
@@ -22,7 +22,7 @@ log4rs = "1.1"
url = "2"
glob = "0.3"
ureq = {version = "2.5", optional=true}
extism-manifest = { version = "0.4.0", path = "../manifest" }
extism-manifest = { version = "0.5.0", path = "../manifest" }
uuid = { version = "1", features = ["v4"] }
libc = "0.2"

View File

@@ -1,15 +1,5 @@
fn main() {
println!("cargo:rerun-if-changed=src/extism-runtime.wasm");
let dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
// Attempt to build the kernel, this is only done as a convenience when developing the
// kernel an should not be relied on. When changes are made to the kernel run
// `sh build.sh` in the `kernel/` directory to ensure it run successfully.
let _ = std::process::Command::new("bash")
.args(&["build.sh"])
.current_dir(dir.join("../kernel"))
.status()
.unwrap();
let fn_macro = "
#define EXTISM_FUNCTION(N) extern void N(ExtismCurrentPlugin*, const ExtismVal*, ExtismSize, ExtismVal*, ExtismSize, void*)

Binary file not shown.

View File

@@ -104,6 +104,9 @@ pub trait InternalExt {
}
fn memory_alloc(&mut self, n: Size) -> Result<u64, Error> {
if n == 0 {
return Ok(0);
}
let (linker, mut store) = self.linker_and_store();
let output = &mut [Val::I64(0)];
linker
@@ -113,7 +116,7 @@ pub trait InternalExt {
.unwrap()
.call(&mut store, &[Val::I64(n as i64)], output)?;
let offs = output[0].unwrap_i64() as u64;
if offs == 0 {
if offs == 0 && n > 0 {
anyhow::bail!("out of memory")
}
trace!("memory_alloc: {}, {}", offs, n);

View File

@@ -200,6 +200,7 @@ pub(crate) fn http_request(
Some(res.into_reader())
}
Err(e) => {
log::error!("Unable to make HTTP request: {:?}", e);
if let Some(res) = e.into_response() {
data.http_status = res.status();
Some(res.into_reader())

View File

@@ -132,7 +132,8 @@ impl Plugin {
Config::new()
.epoch_interruption(true)
.debug_info(std::env::var("EXTISM_DEBUG").is_ok())
.profiler(profiling_strategy()),
.profiler(profiling_strategy())
.cache_config_load_default()?,
)?;
let mut imports = imports.into_iter();
let (manifest, modules) = Manifest::new(&engine, wasm.as_ref())?;
@@ -334,23 +335,25 @@ impl Plugin {
internal.linker = linker;
}
let bytes = unsafe { std::slice::from_raw_parts(input, len) };
trace!("Input size: {}", bytes.len());
if len > 0 {
let bytes = unsafe { std::slice::from_raw_parts(input, len) };
trace!("Input size: {}", bytes.len());
if let Some(f) = self.linker.get(&mut self.store, "env", "extism_reset") {
f.into_func().unwrap().call(&mut self.store, &[], &mut [])?;
} else {
error!("Call to extism_reset failed");
}
if let Some(f) = self.linker.get(&mut self.store, "env", "extism_reset") {
f.into_func().unwrap().call(&mut self.store, &[], &mut [])?;
} else {
error!("Call to extism_reset failed");
}
let offs = self.memory_alloc_bytes(bytes)?;
let offs = self.memory_alloc_bytes(bytes)?;
if let Some(f) = self.linker.get(&mut self.store, "env", "extism_input_set") {
f.into_func().unwrap().call(
&mut self.store,
&[Val::I64(offs as i64), Val::I64(len as i64)],
&mut [],
)?;
if let Some(f) = self.linker.get(&mut self.store, "env", "extism_input_set") {
f.into_func().unwrap().call(
&mut self.store,
&[Val::I64(offs as i64), Val::I64(len as i64)],
&mut [],
)?;
}
}
Ok(())

View File

@@ -1,6 +1,6 @@
[package]
name = "extism"
version = "0.4.0"
version = "0.5.5"
edition = "2021"
authors = ["The Extism Authors", "oss@extism.org"]
license = "BSD-3-Clause"
@@ -10,7 +10,7 @@ description = "Extism Host SDK for Rust"
[dependencies]
extism-manifest = { version = "0.5.0", path = "../manifest" }
extism-runtime = { version = "0.5.0", path = "../runtime"}
extism-runtime = { version = "0.5.5", path = "../runtime"}
serde_json = "1"
log = "0.4"
anyhow = "1"

View File

@@ -45,6 +45,7 @@ mod tests {
const WASM: &[u8] = include_bytes!("../../wasm/code-functions.wasm");
const WASM_LOOP: &[u8] = include_bytes!("../../wasm/loop.wasm");
const WASM_GLOBALS: &[u8] = include_bytes!("../../wasm/globals.wasm");
const REFLECT_WASM: &[u8] = include_bytes!("../../wasm/reflect.wasm");
fn hello_world(
plugin: &mut CurrentPlugin,
@@ -53,8 +54,8 @@ mod tests {
_user_data: UserData,
) -> Result<(), Error> {
let input_offs = inputs[0].unwrap_i64() as u64;
let input = plugin.memory_read_str(input_offs).unwrap().to_string();
let length = plugin.memory_length(input_offs);
let input = plugin.memory_read(input_offs, length).to_vec();
let output = plugin.memory_alloc_bytes(&input).unwrap();
outputs[0] = Val::I64(output as i64);
Ok(())
@@ -282,7 +283,7 @@ mod tests {
});
let start = std::time::Instant::now();
let _output = plugin.call("infinite_loop", "abc123");
let _output = plugin.call("infinite_loop", "");
let end = std::time::Instant::now();
let time = end - start;
println!("Cancelled plugin ran for {:?}", time);
@@ -319,4 +320,26 @@ mod tests {
assert_eq!(count.get("count").unwrap().as_i64().unwrap(), i);
}
}
#[test]
fn test_fuzz_reflect_plugin() {
// assert!(set_log_file("stdout", Some(log::Level::Trace)));
let f = Function::new(
"host_reflect",
[ValType::I64],
[ValType::I64],
None,
hello_world,
);
let context = Context::new();
let mut plugin = Plugin::new(&context, REFLECT_WASM, [f], true).unwrap();
for i in 1..65540 {
let input = "a".repeat(i);
let output = plugin.call("reflect", input.clone());
let output = std::str::from_utf8(output.unwrap()).unwrap();
assert_eq!(output, input);
}
}
}

BIN
wasm/reflect.wasm Normal file

Binary file not shown.