diff --git a/build/cmake/Memory.cmake b/build/cmake/Memory.cmake new file mode 100644 index 00000000..0be04fb4 --- /dev/null +++ b/build/cmake/Memory.cmake @@ -0,0 +1,99 @@ +# Copyright 2025 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################ +# Memory size configuration +################################################################################ + +# The memory size option configures enclave and interpreter memory +# size values. The variable may have the value of "SMALL", "MEDIUM" or +# "LARGE". This is a project variable because the configurations +# depend on one another (the interpreter heap size must fit into the +# enclave heap, for example). +SET(PDO_MEMORY_CONFIG "MEDIUM" CACHE STRING "Set memory size parameters for enclave and interpreter") +IF (DEFINED ENV{PDO_MEMORY_CONFIG}) + SET(PDO_MEMORY_CONFIG $ENV{PDO_MEMORY_CONFIG}) +ENDIF() +SET(MEMORY_SIZE_OPTIONS "SMALL" "MEDIUM" "LARGE") +IF (NOT ${PDO_MEMORY_CONFIG} IN_LIST MEMORY_SIZE_OPTIONS) + MESSAGE(FATAL_ERROR "Invalid memory size; ${PDO_MEMORY_CONFIG}") +ENDIF() + +# Module heap and stack, these are related to the contract maximum +# size, we could specify these and derive the maximum contract size +# from them +IF (${PDO_MEMORY_CONFIG} STREQUAL "SMALL") + MATH(EXPR CONTRACT_HEAP_SIZE "2 * 1024 * 1024") + MATH(EXPR CONTRACT_STACK_SIZE "1 * 1024 * 1024") +ELSEIF (${PDO_MEMORY_CONFIG} STREQUAL "MEDIUM") + MATH(EXPR CONTRACT_HEAP_SIZE "4 * 1024 * 1024") + MATH(EXPR CONTRACT_STACK_SIZE "2 * 1024 * 1024") +ELSEIF (${PDO_MEMORY_CONFIG} STREQUAL "LARGE") + MATH(EXPR CONTRACT_HEAP_SIZE "8 * 1024 * 1024") + MATH(EXPR CONTRACT_STACK_SIZE "4 * 1024 * 1024") +ELSE() + MESSAGE(FATAL_ERROR "Invalid memory size; ${PDO_MEMORY_CONFIG}") +ENDIF() + +# This determines the reserved memory size in the enclave, that is, +# the interpreters linear memory is currently stored in the enclave +# reserve memory. The padding is expected to be constant over the +# size of the contract. +MATH(EXPR CONTRACT_PADDING "1 * 1024 * 1024") +MATH(EXPR CONTRACT_MAXIMUM_SIZE "${CONTRACT_HEAP_SIZE} + ${CONTRACT_STACK_SIZE} + ${CONTRACT_PADDING}") + +# Global heap is used for the management structures that store WAMR +# state information, not specific to the module or contract size. This +# memory is allocated from the enclave heap/stack. Note that it is +# difficult (and not particularly well documented) to determine what +# this number should be. The current computation represents a best +# guess and will need to be adjusted as appropriate. +MATH(EXPR CONTRACT_GLOBAL_HEAP_SIZE "4 * 1024 * 1024 + ${CONTRACT_MAXIMUM_SIZE}") + +# State cache size is one of the main consumers of memory, probably impacts +# both enclave stack and heap, the state data block size is probably not +# important enough to provide variable sizing. Should probably just set it +# to 8K and leave it. +MATH(EXPR STATE_CACHE_SIZE "4 * 1024 * 1024") +MATH(EXPR STATE_DATA_BLOCK_SIZE "8 * 1024") + +# The worker stack and heap sizes are per-thread allocations. The heap +# size must be large enough to hold the state cache, the global heap, and +# some padding. For now, the stack size is a fraction of the heap. +MATH(EXPR ENCLAVE_WORKER_HEAP "${STATE_CACHE_SIZE} + ${CONTRACT_GLOBAL_HEAP_SIZE} + ${CONTRACT_MAXIMUM_SIZE}") +MATH(EXPR ENCLAVE_WORKER_STACK "${ENCLAVE_WORKER_HEAP} / 4") + +# The WAMR requirement for reserved memory is the WAMR heap size plus +# the total memory required by the WASM module that is loaded. We can +# set a limit here and trust the wawaka module to enforce the +# limit. Note that the contract heap is double counted (explicitly and +# again in the contract maximum size). This is a reflection of how the +# contract interpreter handles reserved memory allocation. +MATH(EXPR ENCLAVE_WORKER_RESERVED_SIZE "${CONTRACT_HEAP_SIZE} + ${CONTRACT_MAXIMUM_SIZE}") + +# The worker thread count corresponds roughly to the expected number +# of concurrent workers in the enclave, each will allocate memory to +# the contract interpreter. +SET(ENCLAVE_WORKER_THREADS "2") + +# Heap padding is memory expected to be used by the enclave outside +# the interpreter (that is, it does not depend on the configuration of +# the interpreter). +MATH(EXPR ENCLAVE_STACK_PADDING "4 * 1024 * 1024") +MATH(EXPR ENCLAVE_HEAP_PADDING "4 * 1024 * 1024") + +# And the final numbers allocate enough space for each worker plus the shared padding +MATH(EXPR ENCLAVE_STACK_SIZE "${ENCLAVE_WORKER_THREADS} * ${ENCLAVE_WORKER_STACK} + ${ENCLAVE_STACK_PADDING}") +MATH(EXPR ENCLAVE_HEAP_SIZE "${ENCLAVE_WORKER_THREADS} * ${ENCLAVE_WORKER_HEAP} + ${ENCLAVE_HEAP_PADDING}") +MATH(EXPR ENCLAVE_RESERVED_SIZE "${ENCLAVE_WORKER_THREADS} * ${ENCLAVE_WORKER_RESERVED_SIZE}") diff --git a/build/cmake/ProjectVariables.cmake b/build/cmake/ProjectVariables.cmake index 88a6974b..4393ea52 100644 --- a/build/cmake/ProjectVariables.cmake +++ b/build/cmake/ProjectVariables.cmake @@ -66,19 +66,10 @@ IF (NOT DEFINED ENV{PDO_SOURCE_ROOT}) ENDIF() SET(PDO_SOURCE_ROOT $ENV{PDO_SOURCE_ROOT}) -# The memory size option configures enclave and interpreter memory -# size values. The variable may have the value of "SMALL", "MEDIUM" or -# "LARGE". This is a project variable because the configurations -# depend on one another (the interpreter heap size must fit into the -# enclave heap, for example). -SET(PDO_MEMORY_CONFIG "MEDIUM" CACHE STRING "Set memory size parameters for enclave and interpreter") -IF (DEFINED ENV{PDO_MEMORY_CONFIG}) - SET(PDO_MEMORY_CONFIG $ENV{PDO_MEMORY_CONFIG}) -ENDIF() -SET(MEMORY_SIZE_OPTIONS "SMALL" "MEDIUM" "LARGE") -IF (NOT ${PDO_MEMORY_CONFIG} IN_LIST MEMORY_SIZE_OPTIONS) - MESSAGE(FATAL_ERROR "Invalid memory size; ${PDO_MEMORY_CONFIG}") -ENDIF() +# Pull in the configuration for memory allocation across the entire +# project including the state cache and interpreter size in common and +# the enclave allocation in the eservice. +INCLUDE(Memory) # Get the current version using the get_version # utility; note that this will provide 0.0.0 as diff --git a/build/cmake/SGX.cmake b/build/cmake/SGX.cmake index 73447aae..a4fb438c 100644 --- a/build/cmake/SGX.cmake +++ b/build/cmake/SGX.cmake @@ -21,31 +21,15 @@ IF (NOT DEFINED ENV{PDO_SGX_KEY_ROOT}) ENDIF() SET(PDO_SGX_KEY_ROOT "$ENV{PDO_SGX_KEY_ROOT}") -# Memory size should be set in ProjectVariables.cmake which must be included +# Memory size should be set in Memory.cmake which must be included # before this file. There are three values for memory size: SMALL, MEDIUM # and LARGE. Each provides defaults for memory allocation. See the note -# about memory size in ProjectVariables.cmake regarding dependencies between +# about memory size in Memory.cmake regarding dependencies between # memory settings here and in other parts of PDO. IF (NOT DEFINED PDO_MEMORY_CONFIG) MESSAGE(FATAL_ERROR "PDO_MEMORY_CONFIG not defined") ENDIF() -IF (${PDO_MEMORY_CONFIG} STREQUAL "SMALL") - MATH(EXPR ENCLAVE_STACK_SIZE "2 * 1024 * 1024") - MATH(EXPR ENCLAVE_HEAP_SIZE "32 * 1024 * 1024") - MATH(EXPR ENCLAVE_RESERVED_SIZE "1 * 1024 * 1024") -ELSEIF (${PDO_MEMORY_CONFIG} STREQUAL "MEDIUM") - MATH(EXPR ENCLAVE_STACK_SIZE "2 * 1024 * 1024") - MATH(EXPR ENCLAVE_HEAP_SIZE "64 * 1024 * 1024") - MATH(EXPR ENCLAVE_RESERVED_SIZE "2 * 1024 * 1024") -ELSEIF (${PDO_MEMORY_CONFIG} STREQUAL "LARGE") - MATH(EXPR ENCLAVE_STACK_SIZE "2 * 1024 * 1024") - MATH(EXPR ENCLAVE_HEAP_SIZE "128 * 1024 * 1024") - MATH(EXPR ENCLAVE_RESERVED_SIZE "4 * 1024 * 1024") -ELSE() - MESSAGE(FATAL_ERROR "Invalid memory size; ${PDO_MEMORY_CONFIG}") -ENDIF() - # There are effectively three build modes for SGX: # 1) SIM mode with PDO_DEBUG_BUILD enabled # 2) HW mode with PDO_DEBUG_BUILD enabled diff --git a/build/template/eservice.toml b/build/template/eservice.toml index 1dba95df..1d484e18 100644 --- a/build/template/eservice.toml +++ b/build/template/eservice.toml @@ -22,10 +22,10 @@ HttpPort = ${{7100+_count_}} Host = "${host}" # Max number of threads for processing WSGI requests -WorkerThreads = 8 +WorkerThreads = 4 # Suggested number of threads for processing other requests -ReactorThreads = 8 +ReactorThreads = 4 # -------------------------------------------------- # StorageService -- information about KV block stores @@ -79,7 +79,7 @@ BaseName = "${identity}" [EnclaveModule] # Number of available enclave workers to service requests -NumberOfEnclaves = '7' +NumberOfEnclaves = '1' # ias_url is the URL of the Intel Attestation Service (IAS) server. The # example server is for debug enclaves only, @@ -88,4 +88,3 @@ ias_url = 'https://api.trustedservices.intel.com/sgx/dev' # sgx key root folder configuration sgx_key_root = "${sgx_key_root}" - diff --git a/build/tests/wawaka/memory-test.json b/build/tests/wawaka/memory-test.json index 86ac26db..998a33fc 100644 --- a/build/tests/wawaka/memory-test.json +++ b/build/tests/wawaka/memory-test.json @@ -53,20 +53,6 @@ "KeywordParameters": { "levels" : 2147483647 }, "expected":"2147483647" }, - { - "description" : "deep recursion test 2^32 levels should {invert}", - "MethodName": "deep_recursion_test", - "KeywordParameters": { "levels" : 2147483648 }, - "invert": "fail", - "expected": "method evaluation failed" - }, - { - "description" : "deep recursion test 10G levels should {invert}", - "MethodName": "deep_recursion_test", - "KeywordParameters": { "levels" : 10000000000 }, - "invert": "fail", - "expected": "method evaluation failed" - }, { "description" : "deep recursion test {KeywordParameters}", "MethodName": "deep_recursion_test", diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 9cc7ffa5..8cbc00c6 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -39,6 +39,15 @@ IF (BUILD_TRUSTED OR BUILD_UNTRUSTED) INCLUDE(SGX) ENDIF() +# Memory size should be set in ProjectVariables.cmake which must be included +# before this file. There are three values for memory size: SMALL, MEDIUM +# and LARGE. Each provides defaults for memory allocation. See the note +# about memory size in ProjectVariables.cmake regarding dependencies between +# memory settings here and in other parts of PDO. +IF (NOT DEFINED PDO_MEMORY_CONFIG) + MESSAGE(FATAL_ERROR "PDO_MEMORY_CONFIG not defined") +ENDIF() + ################################################################################ # Common components for both trusted and untrusted common libraries ################################################################################ @@ -81,6 +90,8 @@ IF (BUILD_CLIENT) TARGET_COMPILE_OPTIONS(${C_COMMON_LIB_NAME} PRIVATE ${OPENSSL_CFLAGS}) + TARGET_COMPILE_DEFINITIONS(${C_COMMON_LIB_NAME} PRIVATE "STATE_DATA_BLOCK_SIZE=${STATE_DATA_BLOCK_SIZE}") + TARGET_COMPILE_DEFINITIONS(${C_COMMON_LIB_NAME} PRIVATE "STATE_CACHE_SIZE=${STATE_CACHE_SIZE}") TARGET_COMPILE_DEFINITIONS(${C_COMMON_LIB_NAME} PRIVATE "_UNTRUSTED_=1") TARGET_COMPILE_DEFINITIONS(${C_COMMON_LIB_NAME} PRIVATE "_CLIENT_ONLY_=1") ENDIF() @@ -96,6 +107,8 @@ IF (BUILD_UNTRUSTED) ADD_LIBRARY(${U_COMMON_LIB_NAME} STATIC ${PROJECT_HEADERS} ${PROJECT_SOURCES}) SGX_PREPARE_UNTRUSTED(${U_COMMON_LIB_NAME}) + TARGET_COMPILE_DEFINITIONS(${U_COMMON_LIB_NAME} PRIVATE "STATE_DATA_BLOCK_SIZE=${STATE_DATA_BLOCK_SIZE}") + TARGET_COMPILE_DEFINITIONS(${U_COMMON_LIB_NAME} PRIVATE "STATE_CACHE_SIZE=${STATE_CACHE_SIZE}") TARGET_COMPILE_DEFINITIONS(${U_COMMON_LIB_NAME} PRIVATE "_UNTRUSTED_=1") ENDIF() @@ -107,6 +120,9 @@ IF (BUILD_TRUSTED) ADD_LIBRARY(${T_COMMON_LIB_NAME} STATIC ${PROJECT_HEADERS} ${PROJECT_SOURCES}) SGX_PREPARE_TRUSTED(${T_COMMON_LIB_NAME}) + + TARGET_COMPILE_DEFINITIONS(${T_COMMON_LIB_NAME} PRIVATE "STATE_DATA_BLOCK_SIZE=${STATE_DATA_BLOCK_SIZE}") + TARGET_COMPILE_DEFINITIONS(${T_COMMON_LIB_NAME} PRIVATE "STATE_CACHE_SIZE=${STATE_CACHE_SIZE}") ENDIF() ################################################################################ diff --git a/common/error.h b/common/error.h index f05a8455..ab6213f4 100644 --- a/common/error.h +++ b/common/error.h @@ -17,6 +17,7 @@ #include #include +#include #include "pdo_error.h" #if _CLIENT_ONLY_ @@ -24,6 +25,7 @@ #include "sgx_error.h" #endif +#define ERROR_MESSAGE_SIZE 1024 namespace pdo { namespace error { @@ -179,24 +181,48 @@ namespace pdo { template inline void ThrowIfNull( const PointerType ptr, - const char* msg = nullptr + const char* msg = nullptr, + ... ) { - if (!ptr) { - throw ValueError(msg ? msg : "Unexpected null parameter."); + va_list args; + va_start(args, msg); + + if (ptr == nullptr) { + if (msg == nullptr) + throw ValueError("Unexpected null parameter."); + + char buffer[ERROR_MESSAGE_SIZE] = {0}; + vsnprintf(buffer, ERROR_MESSAGE_SIZE, msg, args); + va_end(args); + throw ValueError(buffer); } + + va_end(args); } // ThrowIfNull // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX template inline void ThrowIf( bool condition, - const char* msg + const char* msg, + ... ) { + va_list args; + va_start(args, msg); + if (condition) { - throw except(msg); + if (msg == nullptr) + throw except("Unexpected null parameter."); + + char buffer[ERROR_MESSAGE_SIZE] = {0}; + vsnprintf(buffer, ERROR_MESSAGE_SIZE, msg, args); + va_end(args); + throw except(buffer); } + + va_end(args); } // ThrowIf // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/common/interpreter/wawaka_wasm/CMakeLists.txt b/common/interpreter/wawaka_wasm/CMakeLists.txt index 1b847638..a6ba6af1 100644 --- a/common/interpreter/wawaka_wasm/CMakeLists.txt +++ b/common/interpreter/wawaka_wasm/CMakeLists.txt @@ -22,132 +22,89 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.10 FATAL_ERROR) IF (NOT DEFINED ENV{WASM_SRC}) MESSAGE(FATAL_ERROR "WASM_SRC environment variable not defined!") ENDIF() -SET(WASM_SRC "$ENV{WASM_SRC}") +SET (WAMR_ROOT_DIR "$ENV{WASM_SRC}") # Make sure wasm-micro-runtime submodule has been cloned -FILE(GLOB WAMR_SUBMOD ${WASM_SRC}) +FILE(GLOB WAMR_SUBMOD ${WAMR_ROOT_DIR}) LIST(LENGTH WAMR_SUBMOD SUBMOD_CONTENTS) IF (SUBMOD_CONTENTS EQUAL 0) MESSAGE(FATAL_ERROR "WAMR git submodule has not been cloned. Please run `git submodule update --init` first.") ENDIF() -# Reset default linker flags -SET (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") -SET (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") - -# Set WAMR_BUILD_TARGET -IF (NOT DEFINED WAMR_BUILD_TARGET) - IF (CMAKE_SIZEOF_VOID_P EQUAL 8) - # Build as X86_64 by default in 64-bit platform - SET (WAMR_BUILD_TARGET "X86_64") - ELSE () - # Build as X86_32 by default in 32-bit platform - SET (WAMR_BUILD_TARGET "X86_32") - ENDIF () -ENDIF () - -IF (NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE Release) +# Memory size should be set in Memory.cmake which must be included +# before this file. There are three values for memory size: SMALL, MEDIUM +# and LARGE. Each provides defaults for memory allocation. See the note +# about memory size in Memory.cmake regarding dependencies between +# memory settings here and in other parts of PDO. +IF (NOT DEFINED PDO_MEMORY_CONFIG) + MESSAGE(FATAL_ERROR "PDO_MEMORY_CONFIG not defined") ENDIF() -# Disable AoT by default +################################################################# +# WAMR Library +# +# The WAMR library is built using a slightly modified version +# of the build script found in product-mini/platforms/linux-sgx/ +################################################################# + +# Set up the WAMR build configuration for use with Wawaka SET (WAMR_BUILD_AOT 0) +SET (WAMR_BUILD_JIT 0) SET (WAMR_BUILD_INTERP 1) + +# Set the interpreter type IF (PDO_INTERPRETER STREQUAL "wawaka-opt") SET (WAMR_BUILD_FAST_INTERP 1) ADD_DEFINITIONS (-DUSE_WAWAKA_OPT=1) MESSAGE(STATUS "Building wawaka in optimized INTERP mode") ELSE() - # Disable optimized interpreter by default SET (WAMR_BUILD_FAST_INTERP 0) - MESSAGE(STATUS "Building wawaka in INTERP mode") + ADD_DEFINITIONS (-DUSE_WAWAKA_OPT=0) + MESSAGE(STATUS "Building wawaka in regular INTERP mode") ENDIF() -# Disable JIT by default for all runtime modes. -SET (WAMR_BUILD_JIT 0) - -IF (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) - # Enable libc builtin support by default - SET (WAMR_BUILD_LIBC_BUILTIN 1) -ENDIF () +# Build LIBC support but we do not want any of the +# WASI system calls or pthread support +SET (WAMR_BUILD_LIBC_BUILTIN 1) +SET (WAMR_BUILD_LIBC_WASI 0) +SET (WAMR_BUILD_LIB_PTHREAD 0) -IF (NOT DEFINED WAMR_BUILD_LIBC_WASI) - # Disable libc wasi support by default - SET (WAMR_BUILD_LIBC_WASI 0) -ENDIF () - -################################################################################ +# No need for multi-module support +SET (WAMR_BUILD_MULTI_MODULE 0) -SET(IWASM_STATIC_NAME iwasm) -SET(WAWAKA_STATIC_NAME wwasm) -PROJECT(wawaka_wasm C CXX) +# WASI/clang compiles references so we need +# to ensure WAMR supports them +SET (WAMR_BUILD_REF_TYPES 1) -SET (WAMR_BUILD_PLATFORM "linux-sgx") +# We do not want heap sharing support between modules +SET (WASM_ENABLE_SHARED_HEAP 0) -SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") -SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ - -Wall -Wno-unused-parameter -Wno-pedantic \ - -nostdinc -fvisibility=hidden -fpie" ) +# --------------- Other flags that are not required --------------- -SET (WAMR_ROOT_DIR ${WASM_SRC}) -SET (SHARED_DIR ${WAMR_ROOT_DIR}/core/shared) -SET (IWASM_DIR ${WAMR_ROOT_DIR}/core/iwasm) -SET (APP_FRAMEWORK_DIR ${WAMR_ROOT_DIR}/core/app-framework) +# In theory this should remove the mmap calls, in practice it doesn't +# appear to work that way. +# SET(WAMR_DISABLE_STACK_HW_BOUND_CHECK 1) +# SET(WAMR_DISABLE_HW_BOUND_CHECK 1) -ENABLE_LANGUAGE (ASM) +# This is used to distinguish between pre-allocated buffers and WAMR +# managed dynamic allocators in the application. It is not needed. +# SET (WASM_ENABLE_GLOBAL_HEAP_POOL 0) -################################################################# -# WAMR Library -################################################################# -# include the build config template file -INCLUDE (${WAMR_ROOT_DIR}/build-scripts/config_common.cmake) - -INCLUDE (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) -INCLUDE (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) -INCLUDE (${SHARED_DIR}/utils/shared_utils.cmake) - -# this picks up the libc_erro.h, this appears to be an error in WAMR in that the -# test for WASI is AFTER the attempt to include a file that is only available when -# WASI is turned on. -INCLUDE (${SHARED_DIR}/platform/common/libc-util/platform_common_libc_util.cmake) - -IF (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) - INCLUDE (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake) -ENDIF () -IF (WAMR_BUILD_LIBC_WASI EQUAL 1) - INCLUDE (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake) -ENDIF () - -INCLUDE (${IWASM_DIR}/common/iwasm_common.cmake) - -IF (WAMR_BUILD_INTERP EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1) - INCLUDE (${IWASM_DIR}/interpreter/iwasm_interp.cmake) -ENDIF () - -ADD_LIBRARY (${IWASM_STATIC_NAME} - ${PLATFORM_SHARED_SOURCE} - ${PLATFORM_COMMON_LIBC_UTIL_SOURCE} - ${MEM_ALLOC_SHARED_SOURCE} - ${UTILS_SHARED_SOURCE} - ${LIBC_BUILTIN_SOURCE} - ${LIBC_WASI_SOURCE} - ${WAMR_POSIX_SOURCES} - ${IWASM_COMMON_SOURCE} - ${IWASM_INTERP_SOURCE} - ${IWASM_COMPL_SOURCE} - # this is necessary because WAMR currently does not have a definition - # for os_is_handle_valid in the sgx_platform.c file - ${CMAKE_CURRENT_SOURCE_DIR}/wamr_fixes.c - ) - -TARGET_INCLUDE_DIRECTORIES(${IWASM_STATIC_NAME} PUBLIC ${SHARED_DIR}/include) -TARGET_INCLUDE_DIRECTORIES(${IWASM_STATIC_NAME} PUBLIC ${IWASM_DIR}/include) +SET(IWASM_STATIC_NAME iwasm) +INCLUDE (${CMAKE_CURRENT_SOURCE_DIR}/wamr/wamr.cmake) ################################################################# # Wawaka Interpreter ################################################################# +PROJECT(wawaka_wasm C CXX) + +SET(WAWAKA_STATIC_NAME wwasm) + +SET (SHARED_DIR ${WAMR_ROOT_DIR}/core/shared) +SET (IWASM_DIR ${WAMR_ROOT_DIR}/core/iwasm) + FILE(GLOB WWASM_PROJECT_HEADERS *.h) -FILE(GLOB WWASM_PROJECT_SOURCES *.cpp) +FILE(GLOB WWASM_PROJECT_SOURCES *.cpp wamr/*.c) ADD_LIBRARY(${WAWAKA_STATIC_NAME} ${WWASM_PROJECT_HEADERS} @@ -158,32 +115,22 @@ SGX_PREPARE_TRUSTED(${WAWAKA_STATIC_NAME}) # RUNTIME_MEM_POOL_SIZE: The WASM runtime's global memory pool size # HEAP_SIZE: Size of the runtime's heap for dynamic allocations by a WASM module. # STACK_SIZE: Size of the runtime's stack for executing a WASM module -# Layout: RUNTIME_MEM_POOL_SIZE > HEAP_SIZE + STACK_SIZE + padding -# The numbers below were chosen to set RUNTIME_MEM_POOL_SIZE to be about -# 1/8 of the size of the enclave heap size defined in the SGX.cmake file. -IF (NOT DEFINED PDO_MEMORY_CONFIG) - MESSAGE(FATAL_ERROR "PDO_MEMORY_CONFIG not defined") -ENDIF() +SET (WW_STACK_SIZE ${ENCLAVE_WORKER_STACK}) +SET (WW_HEAP_SIZE ${ENCLAVE_WORKER_HEAP}) -IF (${PDO_MEMORY_CONFIG} STREQUAL "SMALL") - MATH(EXPR WW_RUNTIME_MEM_POOL_SIZE "4 * 1024 * 1024") - MATH(EXPR WW_STACK_SIZE "512 * 1024") - MATH(EXPR WW_HEAP_SIZE "3 * 1024 * 1024") -ELSEIF (${PDO_MEMORY_CONFIG} STREQUAL "MEDIUM") - MATH(EXPR WW_RUNTIME_MEM_POOL_SIZE "8 * 1024 * 1024") - MATH(EXPR WW_STACK_SIZE "512 * 1024") - MATH(EXPR WW_HEAP_SIZE "7 * 1024 * 1024") -ELSEIF (${PDO_MEMORY_CONFIG} STREQUAL "LARGE") - MATH(EXPR WW_RUNTIME_MEM_POOL_SIZE "16 * 1024 * 1024") - MATH(EXPR WW_STACK_SIZE "512 * 1024") - MATH(EXPR WW_HEAP_SIZE "15 * 1024 * 1024") -ELSE() - MESSAGE(FATAL_ERROR "Invalid memory size; ${PDO_MEMORY_CONFIG}") +# MEM_POOL_SIZE determined from the stack and heap size plus padding, padding +# factor is just a multiplier that can be adjusted to increase the padding +MATH(EXPR WW_RUNTIME_MEM_POOL_SIZE "${WW_STACK_SIZE} + ${WW_HEAP_SIZE}") + +# Check that the runtime memory pool size is not larger than the enclave heap size +IF (WW_RUNTIME_MEM_POOL_SIZE GREATER ENCLAVE_HEAP_SIZE) + MESSAGE(FATAL_ERROR "Invalid memory size; RUNTIME_MEM_POOL_SIZE too big for the enclave heap size") ENDIF() -TARGET_COMPILE_DEFINITIONS(${WAWAKA_STATIC_NAME} PRIVATE RUNTIME_MEM_POOL_SIZE=${WW_RUNTIME_MEM_POOL_SIZE}) -TARGET_COMPILE_DEFINITIONS(${WAWAKA_STATIC_NAME} PRIVATE HEAP_SIZE=${WW_HEAP_SIZE}) -TARGET_COMPILE_DEFINITIONS(${WAWAKA_STATIC_NAME} PRIVATE STACK_SIZE=${WW_STACK_SIZE}) +TARGET_COMPILE_DEFINITIONS(${WAWAKA_STATIC_NAME} PRIVATE MAXIMUM_SIZE=${CONTRACT_MAXIMUM_SIZE}) +TARGET_COMPILE_DEFINITIONS(${WAWAKA_STATIC_NAME} PRIVATE GLOBAL_HEAP_SIZE=${CONTRACT_GLOBAL_HEAP_SIZE}) +TARGET_COMPILE_DEFINITIONS(${WAWAKA_STATIC_NAME} PRIVATE HEAP_SIZE=${CONTRACT_HEAP_SIZE}) +TARGET_COMPILE_DEFINITIONS(${WAWAKA_STATIC_NAME} PRIVATE STACK_SIZE=${CONTRACT_STACK_SIZE}) TARGET_INCLUDE_DIRECTORIES(${WAWAKA_STATIC_NAME} PRIVATE ${INTERPRETER_INCLUDE_DIRS}) TARGET_INCLUDE_DIRECTORIES(${WAWAKA_STATIC_NAME} PRIVATE ${IWASM_DIR}/include) diff --git a/common/interpreter/wawaka_wasm/WasmExtensions.cpp b/common/interpreter/wawaka_wasm/WasmExtensions.cpp index 171a9667..2dda0412 100644 --- a/common/interpreter/wawaka_wasm/WasmExtensions.cpp +++ b/common/interpreter/wawaka_wasm/WasmExtensions.cpp @@ -37,36 +37,6 @@ namespace pe = pdo::error; -/* ----------------------------------------------------------------- * - * NAME: memchr - * ----------------------------------------------------------------- */ -extern "C" int32 memchr_wrapper( - wasm_exec_env_t exec_env, - int32 src_offset, - int32 ch, - uint32 src_size) -{ - wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); - try { - if (src_size == 0) - return 0; - - void *src = get_buffer(module_inst, src_offset, src_size); - if (src == NULL) - return 0; - - void *ptr = memchr(src, ch, src_size); - if (ptr == NULL) - return 0; - - return wasm_runtime_addr_native_to_app(module_inst, ptr); - } - catch (...) { - SAFE_LOG(PDO_LOG_ERROR, "unexpected failure in %s", __FUNCTION__); - return false; - } -} - /* ----------------------------------------------------------------- * * NAME: _contract_log_wrapper * ----------------------------------------------------------------- */ @@ -86,6 +56,17 @@ extern "C" bool contract_log_wrapper( } } +/* ----------------------------------------------------------------- * + * NAME: _contract_abort_wrapper + * ----------------------------------------------------------------- */ +extern "C" void contract_abort_wrapper( + wasm_exec_env_t exec_env, + const char* buffer) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_runtime_set_exception(module_inst, buffer); +} + /* ----------------------------------------------------------------- * * NAME: simple_hash * ----------------------------------------------------------------- */ @@ -137,7 +118,8 @@ extern "C" double strtod_wrapper( extern "C" void abort_wrapper(wasm_exec_env_t exec_env) { - abort(); + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_runtime_set_exception(module_inst, "env.abort()"); } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -154,10 +136,6 @@ WASM_PASSTHRU_FUNCTION(islower) WASM_PASSTHRU_FUNCTION(ispunct) WASM_PASSTHRU_FUNCTION(isblank) -#if 0 -WASM_PASSTHRU_FUNCTION(isascii) -#endif - static NativeSymbol native_symbols[] = { /* Missing libc functions */ @@ -165,9 +143,6 @@ static NativeSymbol native_symbols[] = EXPORT_WASM_API_WITH_SIG2(islower,"(i)i"), EXPORT_WASM_API_WITH_SIG2(ispunct,"(i)i"), EXPORT_WASM_API_WITH_SIG2(isblank,"(i)i"), -#if 0 - EXPORT_WASM_API_WITH_SIG2(isascii,"(i)i"), -#endif EXPORT_WASM_API_WITH_SIG2(abort,"()"), /* Crypto operations from WasmCryptoExtensions.h */ @@ -204,11 +179,10 @@ static NativeSymbol native_symbols[] = EXPORT_WASM_API_WITH_SIG2(key_value_open,"(*~*~)i"), EXPORT_WASM_API_WITH_SIG2(key_value_finalize,"(iii)i"), - /* Utility functions */ EXPORT_WASM_API_WITH_SIG2(contract_log, "(i$)i"), + EXPORT_WASM_API_WITH_SIG2(contract_abort, "($)"), EXPORT_WASM_API_WITH_SIG2(simple_hash, "(*~)i"), - EXPORT_WASM_API_WITH_SIG2(memchr, "(iii)i"), EXPORT_WASM_API_WITH_SIG2(strtod, "($*)F"), }; @@ -216,20 +190,13 @@ static NativeSymbol native_symbols[] = } #endif -bool RegisterNativeFunctions(void) +bool InitializeNativeSymbols(RuntimeInitArgs& init_args) { - try { - size_t native_symbols_count = sizeof(native_symbols)/sizeof(NativeSymbol); - if (! wasm_runtime_register_natives("env", native_symbols, native_symbols_count)) - { - SAFE_LOG(PDO_LOG_ERROR, "failed to register native functions"); - return false; - } - } - catch (...) { - SAFE_LOG(PDO_LOG_ERROR, "exception throw while registering native functions"); - return false; - } + size_t native_symbols_count = sizeof(native_symbols)/sizeof(NativeSymbol); + + init_args.native_module_name = "env"; + init_args.n_native_symbols = native_symbols_count; + init_args.native_symbols = native_symbols; return true; } diff --git a/common/interpreter/wawaka_wasm/WasmExtensions.h b/common/interpreter/wawaka_wasm/WasmExtensions.h index 20686af9..17420442 100644 --- a/common/interpreter/wawaka_wasm/WasmExtensions.h +++ b/common/interpreter/wawaka_wasm/WasmExtensions.h @@ -232,12 +232,22 @@ bool contract_log( const uint32_t loglevel, const char *buffer); +void contract_abort( + const char* buffer); + int simple_hash(uint8_t *buffer, const size_t buflen); #ifdef __cplusplus } #endif +#define CONTRACT_SAFE_ABORT(FMT, ...) \ + { \ + char buf[512]; \ + snprintf(buf, 512, FMT, ##__VA_ARGS__); \ + contract_abort(buf); \ + } + #define CONTRACT_SAFE_LOG(LEVEL, FMT, ...) \ { \ char buf[512]; \ diff --git a/common/interpreter/wawaka_wasm/WasmStateExtensions.cpp b/common/interpreter/wawaka_wasm/WasmStateExtensions.cpp index b021f873..90ae1896 100644 --- a/common/interpreter/wawaka_wasm/WasmStateExtensions.cpp +++ b/common/interpreter/wawaka_wasm/WasmStateExtensions.cpp @@ -81,14 +81,14 @@ extern "C" bool key_value_set_wrapper( if (state == NULL) return false; - if (key_buffer == NULL) + if (key_buffer == NULL || key_buffer_length == 0) return false; if (val_buffer == NULL) return false; - ByteArray ba_key(key_buffer, key_buffer + key_buffer_length); - ByteArray ba_val(val_buffer, val_buffer + val_buffer_length); + const ByteArray ba_key(key_buffer, key_buffer + key_buffer_length); + const ByteArray ba_val(val_buffer, val_buffer + val_buffer_length); state->UnprivilegedPut(ba_key, ba_val); return true; @@ -120,10 +120,10 @@ extern "C" bool key_value_get_wrapper( if (state == NULL) return false; - if (key_buffer == NULL) + if (key_buffer == NULL || key_buffer_length == 0) return false; - ByteArray ba_key(key_buffer, key_buffer + key_buffer_length); + const ByteArray ba_key(key_buffer, key_buffer + key_buffer_length); ByteArray ba_val = state->UnprivilegedGet(ba_key); if (ba_val.size() == 0) @@ -162,10 +162,10 @@ extern "C" bool privileged_key_value_get_wrapper( if (state == NULL) return false; - if (key_buffer == NULL) + if (key_buffer == NULL || key_buffer_length == 0) return false; - ByteArray ba_key(key_buffer, key_buffer + key_buffer_length); + const ByteArray ba_key(key_buffer, key_buffer + key_buffer_length); ByteArray ba_val = state->PrivilegedGet(ba_key); if (ba_val.size() == 0) @@ -206,7 +206,7 @@ extern "C" int32 key_value_create_wrapper( return false; } - ByteArray ba_encryption_key(aes_key_buffer, aes_key_buffer + aes_key_buffer_length); + const ByteArray ba_encryption_key(aes_key_buffer, aes_key_buffer + aes_key_buffer_length); // find an empty slot we can use for the kv store pstate::Basic_KV_Plus** kv_store_pool = (pstate::Basic_KV_Plus**)wasm_runtime_get_custom_data(module_inst); @@ -258,7 +258,7 @@ extern "C" int32 key_value_open_wrapper( if (id_hash_buffer == NULL || id_hash_buffer_length <= 0) return false; - ByteArray ba_id_hash(id_hash_buffer, id_hash_buffer + id_hash_buffer_length); + const ByteArray ba_id_hash(id_hash_buffer, id_hash_buffer + id_hash_buffer_length); if (aes_key_buffer == NULL || aes_key_buffer_length != pdo::crypto::constants::SYM_KEY_LEN) { @@ -266,7 +266,7 @@ extern "C" int32 key_value_open_wrapper( return false; } - ByteArray ba_encryption_key(aes_key_buffer, aes_key_buffer + aes_key_buffer_length); + const ByteArray ba_encryption_key(aes_key_buffer, aes_key_buffer + aes_key_buffer_length); // find an empty slot we can use for the kv store pstate::Basic_KV_Plus** kv_store_pool = (pstate::Basic_KV_Plus**)wasm_runtime_get_custom_data(module_inst); @@ -325,6 +325,7 @@ extern "C" bool key_value_finalize_wrapper( // Call finalize and cross your fingers ByteArray ba_val; + SAFE_LOG(PDO_LOG_INFO, "finalizing key/value store"); state->Finalize(ba_val); if (ba_val.size() == 0) { diff --git a/common/interpreter/wawaka_wasm/WawakaInterpreter.cpp b/common/interpreter/wawaka_wasm/WawakaInterpreter.cpp index 3c4d7cc9..25680db1 100644 --- a/common/interpreter/wawaka_wasm/WawakaInterpreter.cpp +++ b/common/interpreter/wawaka_wasm/WawakaInterpreter.cpp @@ -37,12 +37,9 @@ namespace pc = pdo::contracts; namespace pe = pdo::error; namespace pstate = pdo::state; -// Should be defined in WasmExtensions.cpp -extern bool RegisterNativeFunctions(void); - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -#ifdef USE_WAWAKA_OPT +#if USE_WAWAKA_OPT const std::string WawakaInterpreter::identity_ = "wawaka-opt"; #else const std::string WawakaInterpreter::identity_ = "wawaka"; @@ -65,6 +62,9 @@ pc::ContractInterpreter* pdo::contracts::CreateInterpreter(void) // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX extern "C" { #include "wasm_export.h" +#include "wasm_runtime.h" + +extern uint32 wasm_get_module_total_mem_consumption(const WASMModule *module); //#include "sample.h" @@ -83,6 +83,39 @@ int wasm_printer(const char *msg) } /* extern "C" */ +// Should be defined in WasmExtensions.cpp +extern bool InitializeNativeSymbols(RuntimeInitArgs& init_args); + +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +bool WawakaInterpreter::close_kv_store(void) +{ + bool result = true; + ByteArray statehash; + + for (size_t i = 1; i < kv_store_pool_.size(); i++) + { + if (kv_store_pool_[i] == NULL) + continue; + + result = false; + + SAFE_LOG(PDO_LOG_WARNING, "kv_store_pool_ slot not finalized: %u", i); + try { + kv_store_pool_[i]->Finalize(statehash); + delete kv_store_pool_[i]; + kv_store_pool_[i] = NULL; + } + catch (std::exception& e) + { + // Only log the exception here + SAFE_LOG(PDO_LOG_ERROR, "Exception occured while finalizing outstanding state pool: %s", e.what()); + } + } + + // returns false if there were any outstanding kv stores + return result; +} + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void WawakaInterpreter::parse_response_string( int32 response_app, @@ -92,21 +125,21 @@ void WawakaInterpreter::parse_response_string( { // Convert the wasm address for the result string into an // address in the native code - uint32 response_app_beg, response_app_end; + uint64_t response_app_beg, response_app_end; pe::ThrowIf( response_app == 0, report_interpreter_error("invalid result pointer", "no response")); pe::ThrowIf( - ! wasm_runtime_get_app_addr_range(wasm_module_inst, response_app, &response_app_beg, &response_app_end), + ! wasm_runtime_get_app_addr_range(wasm_module_inst_, response_app, &response_app_beg, &response_app_end), report_interpreter_error("invalid result pointer", "out of range")); pe::ThrowIf( response_app_beg == response_app_end, report_interpreter_error("invalid result pointer", "empty response")); - char *result = (char*)wasm_runtime_addr_app_to_native(wasm_module_inst, response_app); + char *result = (char*)wasm_runtime_addr_app_to_native(wasm_module_inst_, response_app); pe::ThrowIfNull(result, report_interpreter_error("invalid result pointer", "invalid address")); const char *result_end = result + (response_app_end - response_app); @@ -142,28 +175,36 @@ const char* WawakaInterpreter::report_interpreter_error( void WawakaInterpreter::load_contract_code( const std::string& code) { - char error_buf[128]; + SAFE_LOG(PDO_LOG_DEBUG, "load contract code"); + + char error_buf[128] = {0}; binary_code_ = Base64EncodedStringToByteArray(code); - SAFE_LOG(PDO_LOG_DEBUG, "initialize the wasm interpreter"); - wasm_module = wasm_runtime_load((uint8*)binary_code_.data(), binary_code_.size(), error_buf, sizeof(error_buf)); - if (wasm_module == NULL) - SAFE_LOG(PDO_LOG_CRITICAL, "load failed with error <%s>", error_buf); - - pe::ThrowIfNull(wasm_module, "module load failed"); - - /* exec_envs in WAMR maintain the corresponding module's stack. - So we can pass a dummy stack size here, since we're explictly - creating an exec_env for the contract below. - */ - // HEAP_SIZE defined through gcc definitions - wasm_module_inst = wasm_runtime_instantiate(wasm_module, 0, HEAP_SIZE, error_buf, sizeof(error_buf)); - pe::ThrowIfNull(wasm_module_inst, "failed to instantiate the module"); - - /* this is where we set the module's stack size */ - // STACK_SIZE defined through gcc definitions - wasm_exec_env = wasm_runtime_create_exec_env(wasm_module_inst, STACK_SIZE); - pe::ThrowIfNull(wasm_exec_env, "failed to create the wasm execution environment"); + // This is not the right check, but it is something to start with + pe::ThrowIf( + binary_code_.size() > MAXIMUM_SIZE, + "insufficient memory for the module"); + + wasm_module_ = wasm_runtime_load((uint8*)binary_code_.data(), binary_code_.size(), error_buf, sizeof(error_buf)); + pe::ThrowIfNull(wasm_module_, "module load failed with error %s", error_buf); + pe::ThrowIf( + wasm_runtime_get_module_package_type(wasm_module_) != Wasm_Module_Bytecode, + "unsupported module type"); + + uint32 module_memory = wasm_get_module_total_mem_consumption((const WASMModule*)wasm_module_); + SAFE_LOG(PDO_LOG_DEBUG, "module memory consumption = %u", module_memory); + + pe::ThrowIf( + module_memory > MAXIMUM_SIZE, + "insufficient interpreter memory; %u required, %u available", module_memory, MAXIMUM_SIZE); + + wasm_module_inst_ = wasm_runtime_instantiate(wasm_module_, STACK_SIZE, HEAP_SIZE, error_buf, sizeof(error_buf)); + pe::ThrowIfNull(wasm_module_inst_, "failed to instantiate the module; %s", error_buf); + + wasm_exec_env_ = wasm_runtime_create_exec_env(wasm_module_inst_, STACK_SIZE); + pe::ThrowIfNull(wasm_exec_env_, "failed to create the wasm execution environment"); + + SAFE_LOG(PDO_LOG_DEBUG, "contract code loaded"); } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -177,40 +218,38 @@ int32 WawakaInterpreter::initialize_contract( SAFE_LOG(PDO_LOG_DEBUG, "wasm initialize_contract"); - wasm_func = wasm_runtime_lookup_function(wasm_module_inst, "ww_initialize", "(i32)i32"); + wasm_func = wasm_runtime_lookup_function(wasm_module_inst_, "ww_initialize"); if (wasm_func == NULL) - wasm_func = wasm_runtime_lookup_function(wasm_module_inst, "_ww_initialize", "(i32)i32"); + wasm_func = wasm_runtime_lookup_function(wasm_module_inst_, "_ww_initialize"); pe::ThrowIfNull(wasm_func, "Unable to locate the initialize function"); - uint32 argv[1], buf_offset = 0; + uint32 argv[1] = {0}, buf_offset = 0; try { // might need to add a null terminator - argv[0] = buf_offset = (int32)wasm_runtime_module_malloc(wasm_module_inst, env.length() + 1, (void**)&buffer); - pe::ThrowIf(argv[0] == 0, - "module malloc failed for some reason"); + argv[0] = buf_offset = (int32)wasm_runtime_module_malloc(wasm_module_inst_, env.length() + 1, (void**)&buffer); + pe::ThrowIf(argv[0] == 0, "module malloc failed for some reason"); memcpy(buffer, env.c_str(), env.length()); buffer[env.length()] = '\0'; pe::ThrowIf( - !wasm_runtime_call_wasm(wasm_exec_env, - wasm_func, 1, argv), - "execution failed for some reason"); + ! wasm_runtime_call_wasm(wasm_exec_env_, wasm_func, 1, argv), + "initialize_contract: execution failed for some reason"); SAFE_LOG(PDO_LOG_DEBUG, "RESULT=%u", argv[0]); result = argv[0]; } catch (pe::RuntimeError& e) { SAFE_LOG(PDO_LOG_ERROR, "Exception: %s", e.what()); - const char *exception = wasm_runtime_get_exception(wasm_module_inst); + const char *exception = wasm_runtime_get_exception(wasm_module_inst_); if (exception != NULL) SAFE_LOG(PDO_LOG_ERROR, "wasm exception = %s", exception); result = 0; } if (buf_offset) - wasm_runtime_module_free(wasm_module_inst, buf_offset); + wasm_runtime_module_free(wasm_module_inst_, buf_offset); return result; } @@ -227,78 +266,82 @@ int32 WawakaInterpreter::evaluate_function( SAFE_LOG(PDO_LOG_DEBUG, "evaluate_function"); pc::validate_invocation_request(args); - wasm_func = wasm_runtime_lookup_function(wasm_module_inst, "ww_dispatch", "(i32i32)i32"); + wasm_func = wasm_runtime_lookup_function(wasm_module_inst_, "ww_dispatch"); if (wasm_func == NULL) - wasm_func = wasm_runtime_lookup_function(wasm_module_inst, "_ww_dispatch", "(i32i32)i32"); + wasm_func = wasm_runtime_lookup_function(wasm_module_inst_, "_ww_dispatch"); pe::ThrowIfNull(wasm_func, "Unable to locate the dispatch function"); - uint32 argv[2], buf_offset0 = 0, buf_offset1 = 0; + uint32 argv[2] = {0}, buf_offset0 = 0, buf_offset1 = 0; try { // might need to add a null terminator - argv[0] = buf_offset0 = (int32)wasm_runtime_module_malloc(wasm_module_inst, args.length() + 1, (void**)&buffer); - pe::ThrowIf(argv[0] == 0, - "module malloc failed for some reason"); + argv[0] = buf_offset0 = wasm_runtime_module_malloc(wasm_module_inst_, args.length() + 1, (void**)&buffer); + pe::ThrowIf(argv[0] == 0, "module malloc failed for some reason"); memcpy(buffer, args.c_str(), args.length()); buffer[args.length()] = '\0'; - argv[1] = buf_offset1 = (int32)wasm_runtime_module_malloc(wasm_module_inst, env.length() + 1, (void**)&buffer); - pe::ThrowIf(argv[1] == 0, - "module malloc failed for some reason"); + argv[1] = buf_offset1 = wasm_runtime_module_malloc(wasm_module_inst_, env.length() + 1, (void**)&buffer); + pe::ThrowIf(argv[1] == 0, "module malloc failed for some reason"); memcpy(buffer, env.c_str(), env.length()); buffer[env.length()] = '\0'; pe::ThrowIf( - !wasm_runtime_call_wasm(wasm_exec_env, - wasm_func, 2, argv), - "execution failed for some reason"); + ! wasm_runtime_call_wasm(wasm_exec_env_, wasm_func, 2, argv), + "evaluate_function: execution failed for some reason"); SAFE_LOG(PDO_LOG_DEBUG, "RESULT=%u", argv[0]); result = argv[0]; } catch (pe::RuntimeError& e) { SAFE_LOG(PDO_LOG_ERROR, "Exception: %s", e.what()); - const char *exception = wasm_runtime_get_exception(wasm_module_inst); + const char *exception = wasm_runtime_get_exception(wasm_module_inst_); if (exception != NULL) SAFE_LOG(PDO_LOG_ERROR, "wasm exception = %s", exception); result = 0; } if (buf_offset0) - wasm_runtime_module_free(wasm_module_inst, buf_offset0); + wasm_runtime_module_free(wasm_module_inst_, buf_offset0); if (buf_offset1) - wasm_runtime_module_free(wasm_module_inst, buf_offset1); + wasm_runtime_module_free(wasm_module_inst_, buf_offset1); return result; } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void WawakaInterpreter::Finalize(void) { - // Clear the code buffer - binary_code_.clear(); + if (! initialized_) + return; // Destroy the environment - if (wasm_exec_env != NULL) + if (wasm_exec_env_ != NULL) { - wasm_runtime_destroy_exec_env(wasm_exec_env); - wasm_exec_env = NULL; + wasm_runtime_destroy_exec_env(wasm_exec_env_); + wasm_exec_env_ = NULL; } - if (wasm_module_inst != NULL) + if (wasm_module_inst_ != NULL) { - wasm_runtime_deinstantiate(wasm_module_inst); - wasm_module_inst = NULL; + wasm_runtime_deinstantiate(wasm_module_inst_); + wasm_module_inst_ = NULL; } - if (wasm_module != NULL) + if (wasm_module_ != NULL) { - wasm_runtime_unload(wasm_module); - wasm_module = NULL; + wasm_runtime_unload(wasm_module_); + wasm_module_ = NULL; } wasm_runtime_destroy(); + + // release any heap resources + global_mem_pool_buf_.resize(0); + binary_code_.resize(0); + + // mark as uninitialized + initialized_ = false; } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -310,24 +353,45 @@ WawakaInterpreter::~WawakaInterpreter(void) // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void WawakaInterpreter::Initialize(void) { - RuntimeInitArgs init_args; - bool result; + SAFE_LOG(PDO_LOG_DEBUG, "initialize wawaka interpreter"); + SAFE_LOG(PDO_LOG_DEBUG, "interpreter memory profile: <%u, %u, %u>", STACK_SIZE, HEAP_SIZE, GLOBAL_HEAP_SIZE); - SAFE_LOG(PDO_LOG_DEBUG, "initialize wasm interpreter"); + // Make sure there are no lingering resources + Finalize(); + + // Initialize the code buffer and error message + binary_code_.clear(); + error_msg_.clear(); + // Clear the kv_store_pool_ + kv_store_pool_.fill(nullptr); + + // Clear out the global memory pool + global_mem_pool_buf_.resize(GLOBAL_HEAP_SIZE); + + // Configure the WAMR print function os_set_print_function(wasm_printer); + // Construct the runtime arguments + RuntimeInitArgs init_args; + bool result; + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.running_mode = Mode_Interp; + init_args.mem_alloc_type = Alloc_With_Pool; - init_args.mem_alloc_option.pool.heap_buf = global_mem_pool_buf; - init_args.mem_alloc_option.pool.heap_size = sizeof(global_mem_pool_buf); + init_args.mem_alloc_option.pool.heap_buf = global_mem_pool_buf_.data(); + init_args.mem_alloc_option.pool.heap_size = global_mem_pool_buf_.size(); + + init_args.max_thread_num = 1; + + InitializeNativeSymbols(init_args); result = wasm_runtime_full_init(&init_args); pe::ThrowIf(! result, "failed to initialize wasm runtime environment"); - bool registered = RegisterNativeFunctions(); - pe::ThrowIf(! registered, "failed to register native functions"); + initialized_ = true; } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -354,12 +418,8 @@ void WawakaInterpreter::create_initial_contract_state( // this doesn't really set thread local data since it is // not supported for sgx, it does however attach the data // to the module so we can use it in the extensions - kv_store_pool[0] = &inoutContractState; - for (size_t i = 1; i < KV_STORE_POOL_MAX_SIZE; i++) - kv_store_pool[i] = NULL; - - //wasm_runtime_set_custom_data(wasm_module_inst, (void*)&inoutContractState); - wasm_runtime_set_custom_data(wasm_module_inst, (void*)kv_store_pool); + kv_store_pool_[0] = &inoutContractState; + wasm_runtime_set_custom_data(wasm_module_inst_, kv_store_pool_.data()); // serialize the environment parameter for the method std::string env; @@ -373,15 +433,11 @@ void WawakaInterpreter::create_initial_contract_state( std::map outDependencies; parse_response_string(response_app, outMessageResult, outStateChangedFlag, outDependencies); - // We could throw an exception if the store is not finalized - // or we could just finalize and throw away the block id, which - // effectively loses access to the kv store, seems like throwing - // an exception is the right idea - for (size_t i = 1; i < KV_STORE_POOL_MAX_SIZE; i++) - pe::ThrowIf(kv_store_pool[i] != NULL, "failed to close contract KV store"); + // for the moment, not closing the kv store is bad practice but not an error + (void) close_kv_store(); // this should be in finally... later... - wasm_runtime_set_custom_data(wasm_module_inst, NULL); + wasm_runtime_set_custom_data(wasm_module_inst_, NULL); } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -403,12 +459,8 @@ void WawakaInterpreter::send_message_to_contract( load_contract_code(inContractCode.Code); // set up the key value store information - kv_store_pool[0] = &inoutContractState; - for (size_t i = 1; i < KV_STORE_POOL_MAX_SIZE; i++) - kv_store_pool[i] = NULL; - - //wasm_runtime_set_custom_data(wasm_module_inst, (void*)&inoutContractState); - wasm_runtime_set_custom_data(wasm_module_inst, (void*)kv_store_pool); + kv_store_pool_[0] = &inoutContractState; + wasm_runtime_set_custom_data(wasm_module_inst_, kv_store_pool_.data()); // serialize the environment parameter for the method std::string env; @@ -417,13 +469,9 @@ void WawakaInterpreter::send_message_to_contract( int32 response_app = evaluate_function(inMessage.Message, env); parse_response_string(response_app, outMessageResult, outStateChangedFlag, outDependencies); - // We could throw an exception if the store is not finalized - // or we could just finalize and throw away the block id, which - // effectively loses access to the kv store, seems like throwing - // an exception is the right idea - for (size_t i = 1; i < KV_STORE_POOL_MAX_SIZE; i++) - pe::ThrowIf(kv_store_pool[i] != NULL, "failed to close contract KV store"); + // for the moment, not closing the kv store is bad practice but not an error + (void) close_kv_store(); // this should be in finally... later... - wasm_runtime_set_custom_data(wasm_module_inst, NULL); + wasm_runtime_set_custom_data(wasm_module_inst_, NULL); } diff --git a/common/interpreter/wawaka_wasm/WawakaInterpreter.h b/common/interpreter/wawaka_wasm/WawakaInterpreter.h index 379efcb3..4ea38631 100644 --- a/common/interpreter/wawaka_wasm/WawakaInterpreter.h +++ b/common/interpreter/wawaka_wasm/WawakaInterpreter.h @@ -15,8 +15,9 @@ #pragma once -#include +#include #include +#include #include "basic_kv.h" #include "ContractInterpreter.h" @@ -34,15 +35,23 @@ namespace pc = pdo::contracts; class WawakaInterpreter : public pc::ContractInterpreter { private: - std::string error_msg_; - - // RUNTIME_MEM_POOL_SIZE defined through gcc definitions - char global_mem_pool_buf[RUNTIME_MEM_POOL_SIZE] = { 0 }; - wasm_module_t wasm_module = NULL; - wasm_module_inst_t wasm_module_inst = NULL; - wasm_exec_env_t wasm_exec_env = NULL; - ByteArray binary_code_; - pdo::state::Basic_KV_Plus* kv_store_pool[KV_STORE_POOL_MAX_SIZE] = { 0 }; + bool initialized_ = false; // true if the interpreter has been initialized + + std::string error_msg_; // error message from the last operation + ByteArray binary_code_; // binary code of the contract to be executed + + // CONTRACT_GLOBAL_HEAP defined through gcc definitions + ByteArray global_mem_pool_buf_; + + // KV_STORE_POOL_MAX_SIZE defined through gcc definitions + std::array kv_store_pool_ = { 0 }; + + // WAMR state variables + wasm_module_t wasm_module_ = NULL; + wasm_module_inst_t wasm_module_inst_ = NULL; + wasm_exec_env_t wasm_exec_env_ = NULL; + + bool close_kv_store(void); void parse_response_string( int32 response_app, diff --git a/common/interpreter/wawaka_wasm/wamr/patch.sh b/common/interpreter/wawaka_wasm/wamr/patch.sh new file mode 100755 index 00000000..6b34ace0 --- /dev/null +++ b/common/interpreter/wawaka_wasm/wamr/patch.sh @@ -0,0 +1,54 @@ +#! /bin/bash +# Copyright 2025 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source ${PDO_SOURCE_ROOT}/bin/lib/common.sh + +OUTPUT_FILE=${PDO_OUTPUT_FILE:-${PWD}/.applied} +PATCH_DIR=${PWD}/patches +WAMR_ROOT_DIR=${WASM_SRC} + +while getopts "o:p:w:" opt; do + case $opt in + o) + OUTPUT_FILE=$OPTARG ;; + p) + PATCH_DIR=$OPTARG ;; + w) + WAMR_ROOT_DIR=$OPTARG ;; + \?) + die "Invalid option: -$OPTARG" >&2 ;; + esac +done + +# ----------------------------------------------------------------- +# Patch wamr +# ----------------------------------------------------------------- +# The following patches are applied to the source code, we use a dry +# run in order to check if the patch is already applied. If it is not +# then apply it + +pushd ${WAMR_ROOT_DIR} || exit 1 + +for patch in ${PATCH_DIR}/*.patch; do + patch -p1 -N --dry-run --silent <"$patch" >/dev/null 2>/dev/null || continue + patch -p1 <"$patch" +done + +popd + +# ----------------------------------------------------------------- +# record that we applied the patches +# ----------------------------------------------------------------- +touch ${OUTPUT_FILE} diff --git a/common/interpreter/wawaka_wasm/wamr/patches/000_sgx_platform.patch b/common/interpreter/wawaka_wasm/wamr/patches/000_sgx_platform.patch new file mode 100644 index 00000000..8b221e3e --- /dev/null +++ b/common/interpreter/wawaka_wasm/wamr/patches/000_sgx_platform.patch @@ -0,0 +1,24 @@ +diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c +index db350bc8..b72885d6 100644 +--- a/core/shared/platform/linux-sgx/sgx_platform.c ++++ b/core/shared/platform/linux-sgx/sgx_platform.c +@@ -183,8 +183,16 @@ void + os_munmap(void *addr, size_t size) + { + uint64 aligned_size, page_size; ++ sgx_status_t st = 0; + + page_size = getpagesize(); + aligned_size = (size + page_size - 1) & ~(page_size - 1); +- sgx_free_rsrv_mem(addr, aligned_size); ++ ++ /* de-initialize the allocated memory */ ++ memset(addr, 0, aligned_size); ++ ++ st = sgx_free_rsrv_mem(addr, aligned_size); ++ if (st != SGX_SUCCESS) ++ os_printf("os_munmap(addr=0x%" PRIx64 ", size=%u) failed.\n", ++ (uintptr_t)addr, size); + } + + int diff --git a/common/interpreter/wawaka_wasm/wamr/wamr.cmake b/common/interpreter/wawaka_wasm/wamr/wamr.cmake new file mode 100644 index 00000000..54c51944 --- /dev/null +++ b/common/interpreter/wawaka_wasm/wamr/wamr.cmake @@ -0,0 +1,110 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +## ----------------------------------------------------------------- +## Modified from WAMR product-mini/platforms/linux-sgx/CMakeLists_minimal.txt +## to support custom library name and custom WAMR_ROOT_DIR and automated +## patching of WAMR source code. +## ----------------------------------------------------------------- +project (iwasm) + +set (WAMR_BUILD_PLATFORM "linux-sgx") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# Set WAMR_BUILD_TARGET +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default + # Please install Intel SGX SDKv2.8 or later. + set (WAMR_BUILD_AOT 1) +endif () + +if (NOT DEFINED WAMR_BUILD_JIT) + # Disable JIT by default. + set (WAMR_BUILD_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 0) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Enable multiple modules + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Enable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 0) +endif () + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ + -Wall -Wno-unused-parameter -Wno-pedantic \ + -nostdinc -fvisibility=hidden -fpie" ) + +## ----------------------------------------------------------------- +## local changes for Wawaka customization +## ----------------------------------------------------------------- +INCLUDE(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +ADD_LIBRARY(${IWASM_STATIC_NAME} ${WAMR_RUNTIME_LIB_SOURCE}) +SET_VERSION_INFO (${IWASM_STATIC_NAME}) + +# apply patches to the WAMR source code before compiling, the patch command +# will apply patches found in the patches directory. A sentinel file is +# created in the build directory to indicate that patches have been applied. +# Note that the WAMR submodule will be in a dirty state after patches. +ADD_CUSTOM_COMMAND( + PRE_BUILD + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/.patches_applied + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/wamr/patches/*.patch ${CMAKE_CURRENT_SOURCE_DIR}/wamr/patch.sh + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/wamr/patch.sh + -p ${CMAKE_CURRENT_SOURCE_DIR}/wamr/patches + -w ${WAMR_ROOT_DIR} + -o ${CMAKE_CURRENT_BINARY_DIR}/.patches_applied + COMMENT "Applying patch to WAMR source code" +) + +ADD_CUSTOM_TARGET( + apply_wamr_patch + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/.patches_applied + COMMENT "Applying patch to WAMR source code" +) + +ADD_DEPENDENCIES(${IWASM_STATIC_NAME} apply_wamr_patch) diff --git a/common/interpreter/wawaka_wasm/wamr/wamr_fixes.c b/common/interpreter/wawaka_wasm/wamr/wamr_fixes.c new file mode 100644 index 00000000..a82d76c4 --- /dev/null +++ b/common/interpreter/wawaka_wasm/wamr/wamr_fixes.c @@ -0,0 +1,86 @@ +#include "wasm_export.h" +#include "wasm_runtime.h" +#include "platform_internal.h" + +/* Basic functionality copied from wasm_get_module_mem_consumption in + core/iwasm/interpreter/wasm_runtime.c. This function is not exposed + outside the interpreter module, so we need to duplicate it here. It + has been modified to return only the total memory consumption. + */ + +uint32 wasm_get_module_total_mem_consumption(const WASMModule *module) +{ + uint32 i, size; + WASMModuleMemConsumption memory_consumption; + WASMModuleMemConsumption *mem_conspn = &memory_consumption; + + memset(mem_conspn, 0, sizeof(WASMModuleMemConsumption)); + + mem_conspn->module_struct_size = sizeof(WASMModule); + + mem_conspn->types_size = sizeof(WASMFuncType *) * module->type_count; + for (i = 0; i < module->type_count; i++) { + WASMFuncType *type = module->types[i]; + size = offsetof(WASMFuncType, types) + + sizeof(uint8) * (type->param_count + type->result_count); + mem_conspn->types_size += size; + } + + mem_conspn->imports_size = sizeof(WASMImport) * module->import_count; + + mem_conspn->functions_size = + sizeof(WASMFunction *) * module->function_count; + for (i = 0; i < module->function_count; i++) { + WASMFunction *func = module->functions[i]; + WASMFuncType *type = func->func_type; + size = sizeof(WASMFunction) + func->local_count + + sizeof(uint16) * (type->param_count + func->local_count); +#if WASM_ENABLE_FAST_INTERP != 0 + size += + func->code_compiled_size + sizeof(uint32) * func->const_cell_num; +#endif + mem_conspn->functions_size += size; + } + + mem_conspn->tables_size = sizeof(WASMTable) * module->table_count; + mem_conspn->memories_size = sizeof(WASMMemory) * module->memory_count; + mem_conspn->globals_size = sizeof(WASMGlobal) * module->global_count; + mem_conspn->exports_size = sizeof(WASMExport) * module->export_count; + + mem_conspn->table_segs_size = + sizeof(WASMTableSeg) * module->table_seg_count; + for (i = 0; i < module->table_seg_count; i++) { + WASMTableSeg *table_seg = &module->table_segments[i]; + mem_conspn->tables_size += + sizeof(InitializerExpression *) * table_seg->value_count; + } + + mem_conspn->data_segs_size = sizeof(WASMDataSeg *) * module->data_seg_count; + for (i = 0; i < module->data_seg_count; i++) { + mem_conspn->data_segs_size += sizeof(WASMDataSeg); + } + + if (module->const_str_list) { + StringNode *node = module->const_str_list, *node_next; + while (node) { + node_next = node->next; + mem_conspn->const_strs_size += + sizeof(StringNode) + strlen(node->str) + 1; + node = node_next; + } + } + + mem_conspn->total_size += mem_conspn->module_struct_size; + mem_conspn->total_size += mem_conspn->types_size; + mem_conspn->total_size += mem_conspn->imports_size; + mem_conspn->total_size += mem_conspn->functions_size; + mem_conspn->total_size += mem_conspn->tables_size; + mem_conspn->total_size += mem_conspn->memories_size; + mem_conspn->total_size += mem_conspn->globals_size; + mem_conspn->total_size += mem_conspn->exports_size; + mem_conspn->total_size += mem_conspn->table_segs_size; + mem_conspn->total_size += mem_conspn->data_segs_size; + mem_conspn->total_size += mem_conspn->const_strs_size; + + return mem_conspn->total_size; +} diff --git a/common/interpreter/wawaka_wasm/wamr_fixes.c b/common/interpreter/wawaka_wasm/wamr_fixes.c deleted file mode 100644 index 3677a0f2..00000000 --- a/common/interpreter/wawaka_wasm/wamr_fixes.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "platform_internal.h" - -bool -os_is_handle_valid(os_file_handle *handle) -{ - assert(handle != NULL); - return *handle > -1; -} diff --git a/common/packages/parson/parson.cpp b/common/packages/parson/parson.cpp index 76aaa153..69c72006 100644 --- a/common/packages/parson/parson.cpp +++ b/common/packages/parson/parson.cpp @@ -99,16 +99,6 @@ static JSON_Malloc_Function parson_malloc = malloc; static JSON_Free_Function parson_free = free; -#ifndef COMPILE_FOR_SGX -static int parson_escape_slashes = 1; -#else -static int parson_escape_slashes = 0; -#endif - -static char *parson_float_format = NULL; - -static JSON_Number_Serialization_Function parson_number_serialization_function = NULL; - #define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */ typedef int parson_bool_t; @@ -157,17 +147,9 @@ struct json_array_t { }; /* Various */ -#ifndef COMPILE_FOR_SGX -static char * read_file(const char *filename); -#endif static void remove_comments(char *string, const char *start_token, const char *end_token); static char * parson_strndup(const char *string, size_t n); static char * parson_strdup(const char *string); -#ifndef COMPILE_FOR_SGX -static int parson_sprintf(char * s, const char * format, ...); -#else -#define parson_snprintf(s, size, format, ...) snprintf(s, size, format, ##__VA_ARGS__) -#endif static int hex_char_to_int(char c); static JSON_Status parse_utf16_hex(const char *string, unsigned int *result); @@ -213,44 +195,10 @@ static JSON_Value * parse_null_value(const char **string); static JSON_Value * parse_value(const char **string, size_t nesting); /* Serialization */ -static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf); +static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty); static int json_serialize_string(const char *string, size_t len, char *buf); /* Various */ -#ifndef COMPILE_FOR_SGX -static char * read_file(const char * filename) { - FILE *fp = fopen(filename, "r"); - size_t size_to_read = 0; - size_t size_read = 0; - long pos; - char *file_contents; - if (!fp) { - return NULL; - } - fseek(fp, 0L, SEEK_END); - pos = ftell(fp); - if (pos < 0) { - fclose(fp); - return NULL; - } - size_to_read = pos; - rewind(fp); - file_contents = (char*)parson_malloc(sizeof(char) * (size_to_read + 1)); - if (!file_contents) { - fclose(fp); - return NULL; - } - size_read = fread(file_contents, 1, size_to_read, fp); - if (size_read == 0 || ferror(fp)) { - fclose(fp); - parson_free(file_contents); - return NULL; - } - fclose(fp); - file_contents[size_read] = '\0'; - return file_contents; -} -#endif static void remove_comments(char *string, const char *start_token, const char *end_token) { parson_bool_t in_string = PARSON_FALSE, escaped = PARSON_FALSE; @@ -302,26 +250,6 @@ static char * parson_strdup(const char *string) { return parson_strndup(string, strlen(string)); } -#ifndef COMPILE_FOR_SGX -static int parson_sprintf(char * s, const char * format, ...) { - int result; - va_list args; - va_start(args, format); - - #if defined(__APPLE__) && defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - #endif - result = vsprintf(s, format, args); - #if defined(__APPLE__) && defined(__clang__) - #pragma clang diagnostic pop - #endif - - va_end(args); - return result; -} -#endif - static int hex_char_to_int(char c) { if (c >= '0' && c <= '9') { return c - '0'; @@ -1160,8 +1088,9 @@ static JSON_Value * parse_null_value(const char **string) { }\ } while (0) -static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf) +static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty) { + char num_buf[PARSON_NUM_BUF_SIZE] = {0}; const char *key = NULL, *string = NULL; JSON_Value *temp_value = NULL; JSON_Array *array = NULL; @@ -1184,7 +1113,7 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le APPEND_INDENT(level+1); } temp_value = json_array_get_value(array, i); - written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf); + written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty); if (written < 0) { return -1; } @@ -1233,7 +1162,7 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le APPEND_STRING(" "); } temp_value = json_object_get_value_at(object, i); - written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf); + written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty); if (written < 0) { return -1; } @@ -1277,24 +1206,16 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le return written_total; case JSONNumber: num = json_value_get_number(value); - if (buf != NULL) { - num_buf = buf; - } - if (parson_number_serialization_function) { - written = parson_number_serialization_function(num, num_buf); - } else { - const char *float_format = parson_float_format ? parson_float_format : PARSON_DEFAULT_FLOAT_FORMAT; -#ifndef COMPILE_FOR_SGX - written = parson_sprintf(num_buf, float_format, num); -#else - written = parson_snprintf(num_buf, PARSON_NUM_BUF_SIZE, float_format, num); -#endif - } - if (written < 0) { + written = snprintf(num_buf, sizeof(num_buf) - 1, PARSON_DEFAULT_FLOAT_FORMAT, num); + if (written <= 0) { return -1; } if (buf != NULL) { - buf += written; + // no need to update buf pointer since we are just returning the value + memcpy(buf, num_buf, written); + // written must be less than num_buf size - 1, so + // there should be space for the null terminator + buf[written] = '\0'; } written_total += written; return written_total; @@ -1356,11 +1277,7 @@ static int json_serialize_string(const char *string, size_t len, char *buf) { case '\x1e': APPEND_STRING("\\u001e"); break; case '\x1f': APPEND_STRING("\\u001f"); break; case '/': - if (parson_escape_slashes) { - APPEND_STRING("\\/"); /* to make json embeddable in xml\/html */ - } else { - APPEND_STRING("/"); - } + APPEND_STRING("/"); break; default: if (buf != NULL) { @@ -1379,31 +1296,6 @@ static int json_serialize_string(const char *string, size_t len, char *buf) { #undef APPEND_INDENT /* Parser API */ -#ifndef COMPILE_FOR_SGX -JSON_Value * json_parse_file(const char *filename) { - char *file_contents = read_file(filename); - JSON_Value *output_value = NULL; - if (file_contents == NULL) { - return NULL; - } - output_value = json_parse_string(file_contents); - parson_free(file_contents); - return output_value; -} -#endif - -#ifndef COMPILE_FOR_SGX -JSON_Value * json_parse_file_with_comments(const char *filename) { - char *file_contents = read_file(filename); - JSON_Value *output_value = NULL; - if (file_contents == NULL) { - return NULL; - } - output_value = json_parse_string_with_comments(file_contents); - parson_free(file_contents); - return output_value; -} -#endif JSON_Value * json_parse_string(const char *string) { if (string == NULL) { @@ -1822,8 +1714,7 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { } size_t json_serialization_size(const JSON_Value *value) { - char num_buf[PARSON_NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ - int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_FALSE, num_buf); + int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_FALSE); return res < 0 ? 0 : (size_t)(res) + 1; } @@ -1833,36 +1724,13 @@ JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { return JSONFailure; } - written = json_serialize_to_buffer_r(value, buf, 0, PARSON_FALSE, NULL); + written = json_serialize_to_buffer_r(value, buf, 0, PARSON_FALSE); if (written < 0) { return JSONFailure; } return JSONSuccess; } -#ifndef COMPILE_FOR_SGX -JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) { - JSON_Status return_code = JSONSuccess; - FILE *fp = NULL; - char *serialized_string = json_serialize_to_string(value); - if (serialized_string == NULL) { - return JSONFailure; - } - fp = fopen(filename, "w"); - if (fp == NULL) { - json_free_serialized_string(serialized_string); - return JSONFailure; - } - if (fputs(serialized_string, fp) == EOF) { - return_code = JSONFailure; - } - if (fclose(fp) == EOF) { - return_code = JSONFailure; - } - json_free_serialized_string(serialized_string); - return return_code; -} -#endif char * json_serialize_to_string(const JSON_Value *value) { JSON_Status serialization_result = JSONFailure; @@ -1884,8 +1752,7 @@ char * json_serialize_to_string(const JSON_Value *value) { } size_t json_serialization_size_pretty(const JSON_Value *value) { - char num_buf[PARSON_NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ - int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_TRUE, num_buf); + int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_TRUE); return res < 0 ? 0 : (size_t)(res) + 1; } @@ -1895,37 +1762,13 @@ JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { return JSONFailure; } - written = json_serialize_to_buffer_r(value, buf, 0, PARSON_TRUE, NULL); + written = json_serialize_to_buffer_r(value, buf, 0, PARSON_TRUE); if (written < 0) { return JSONFailure; } return JSONSuccess; } -#ifndef COMPILE_FOR_SGX -JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) { - JSON_Status return_code = JSONSuccess; - FILE *fp = NULL; - char *serialized_string = json_serialize_to_string_pretty(value); - if (serialized_string == NULL) { - return JSONFailure; - } - fp = fopen(filename, "w"); - if (fp == NULL) { - json_free_serialized_string(serialized_string); - return JSONFailure; - } - if (fputs(serialized_string, fp) == EOF) { - return_code = JSONFailure; - } - if (fclose(fp) == EOF) { - return_code = JSONFailure; - } - json_free_serialized_string(serialized_string); - return return_code; -} -#endif - char * json_serialize_to_string_pretty(const JSON_Value *value) { JSON_Status serialization_result = JSONFailure; size_t buf_size_bytes = json_serialization_size_pretty(value); @@ -2493,23 +2336,3 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu parson_malloc = malloc_fun; parson_free = free_fun; } - -void json_set_escape_slashes(int escape_slashes) { - parson_escape_slashes = escape_slashes; -} - -void json_set_float_serialization_format(const char *format) { - if (parson_float_format) { - parson_free(parson_float_format); - parson_float_format = NULL; - } - if (!format) { - parson_float_format = NULL; - return; - } - parson_float_format = parson_strdup(format); -} - -void json_set_number_serialization_function(JSON_Number_Serialization_Function func) { - parson_number_serialization_function = func; -} diff --git a/common/packages/parson/parson.h b/common/packages/parson/parson.h index 9f6e7538..d37f64ac 100644 --- a/common/packages/parson/parson.h +++ b/common/packages/parson/parson.h @@ -29,8 +29,6 @@ #ifndef parson_parson_h #define parson_parson_h -#define COMPILE_FOR_SGX 1 - #ifdef __cplusplus extern "C" { @@ -72,40 +70,10 @@ typedef int JSON_Status; typedef void * (*JSON_Malloc_Function)(size_t); typedef void (*JSON_Free_Function)(void *); -/* A function used for serializing numbers (see json_set_number_serialization_function). - If 'buf' is null then it should return number of bytes that would've been written - (but not more than PARSON_NUM_BUF_SIZE). -*/ -typedef int (*JSON_Number_Serialization_Function)(double num, char *buf); - /* Call only once, before calling any other function from parson API. If not called, malloc and free from stdlib will be used for all allocations */ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun); -/* Sets if slashes should be escaped or not when serializing JSON. By default slashes are escaped. - This function sets a global setting and is not thread safe. */ -void json_set_escape_slashes(int escape_slashes); - -/* Sets float format used for serialization of numbers. - Make sure it can't serialize to a string longer than PARSON_NUM_BUF_SIZE. - If format is null then the default format is used. */ -void json_set_float_serialization_format(const char *format); - -/* Sets a function that will be used for serialization of numbers. - If function is null then the default serialization function is used. */ -void json_set_number_serialization_function(JSON_Number_Serialization_Function fun); - -/* Parses first JSON value in a file, returns NULL in case of error */ -#ifndef COMPILE_FOR_SGX -JSON_Value * json_parse_file(const char *filename); -#endif - -/* Parses first JSON value in a file and ignores comments (/ * * / and //), - returns NULL in case of error */ -#ifndef COMPILE_FOR_SGX -JSON_Value * json_parse_file_with_comments(const char *filename); -#endif - /* Parses first JSON value in a string, returns NULL in case of error */ JSON_Value * json_parse_string(const char *string); @@ -116,17 +84,11 @@ JSON_Value * json_parse_string_with_comments(const char *string); /* Serialization */ size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */ JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes); -#ifndef COMPILE_FOR_SGX -JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename); -#endif char * json_serialize_to_string(const JSON_Value *value); /* Pretty serialization */ size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */ JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes); -#ifndef COMPILE_FOR_SGX -JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename); -#endif char * json_serialize_to_string_pretty(const JSON_Value *value); void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */ diff --git a/common/state/basic_kv.h b/common/state/basic_kv.h index 4e4b520a..1f478f4a 100644 --- a/common/state/basic_kv.h +++ b/common/state/basic_kv.h @@ -23,9 +23,6 @@ namespace state { class Basic_KV { - protected: - void* handle; - public: virtual ~Basic_KV() {} virtual void Finalize(ByteArray& id) = 0; diff --git a/common/state/cache.h b/common/state/cache.h index b8c65d98..d673659d 100644 --- a/common/state/cache.h +++ b/common/state/cache.h @@ -18,7 +18,7 @@ #include #include -#define CACHE_SIZE (1 << 22) // 4 MB +#define CACHE_SIZE STATE_CACHE_SIZE namespace pdo { diff --git a/common/state/data_node.h b/common/state/data_node.h index 1b1f563d..470a9b73 100644 --- a/common/state/data_node.h +++ b/common/state/data_node.h @@ -15,7 +15,7 @@ #pragma once -#define FIXED_DATA_NODE_BYTE_SIZE (1 << 13) // 8 KB +#define FIXED_DATA_NODE_BYTE_SIZE STATE_DATA_BLOCK_SIZE namespace pdo { diff --git a/common/state/data_node_io.cpp b/common/state/data_node_io.cpp index bca9f66c..ad2c1595 100644 --- a/common/state/data_node_io.cpp +++ b/common/state/data_node_io.cpp @@ -59,8 +59,10 @@ void pstate::data_node_io::init_append_data_node() void pstate::data_node_io::add_and_init_append_data_node() { - pdo::error::ThrowIf(append_dn_->free_bytes() == data_node::data_end_index() - data_node::data_begin_index(), - "appending new data node after empty one"); + pdo::error::ThrowIf( + append_dn_->free_bytes() == data_node::data_end_index() - data_node::data_begin_index(), + "appending new data node after empty one; %u bytes in block %u", + append_dn_->free_bytes(), append_dn_->get_block_num()); unsigned int append_data_node_block_num = block_warehouse_.get_last_block_num(); diff --git a/common/state/data_node_io.h b/common/state/data_node_io.h index 59f73645..d52b3b87 100644 --- a/common/state/data_node_io.h +++ b/common/state/data_node_io.h @@ -28,7 +28,9 @@ namespace state data_node* append_dn_; Cache cache_; - data_node_io(const ByteArray& key) : block_warehouse_(key), cache_(block_warehouse_) {} + data_node_io(const ByteArray& key) : + block_warehouse_(key), cache_(block_warehouse_) { append_dn_ = nullptr; } + void initialize(pdo::state::StateNode& node); void init_append_data_node(); diff --git a/common/tests/state/CMakeLists.txt b/common/tests/state/CMakeLists.txt index f064dd4e..e154dcc6 100644 --- a/common/tests/state/CMakeLists.txt +++ b/common/tests/state/CMakeLists.txt @@ -33,6 +33,8 @@ IF (BUILD_UNTRUSTED) TARGET_INCLUDE_DIRECTORIES(${UNTRUSTED_TEST_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) TARGET_COMPILE_DEFINITIONS(${UNTRUSTED_TEST_NAME} PRIVATE "_UNTRUSTED_=1") + TARGET_COMPILE_DEFINITIONS(${UNTRUSTED_TEST_NAME} PRIVATE "STATE_DATA_BLOCK_SIZE=${STATE_DATA_BLOCK_SIZE}") + TARGET_COMPILE_DEFINITIONS(${UNTRUSTED_TEST_NAME} PRIVATE "STATE_CACHE_SIZE=${STATE_CACHE_SIZE}") # Link the untrusted test application against the untrusted library and openssl TARGET_LINK_LIBRARIES(${UNTRUSTED_TEST_NAME} "-Wl,--start-group") @@ -63,6 +65,8 @@ IF (BUILD_CLIENT) TARGET_COMPILE_DEFINITIONS(${CLIENT_TEST_NAME} PRIVATE "_UNTRUSTED_=1") TARGET_COMPILE_DEFINITIONS(${CLIENT_TEST_NAME} PRIVATE "_CLIENT_ONLY_=1") + TARGET_COMPILE_DEFINITIONS(${CLIENT_TEST_NAME} PRIVATE "STATE_DATA_BLOCK_SIZE=${STATE_DATA_BLOCK_SIZE}") + TARGET_COMPILE_DEFINITIONS(${CLIENT_TEST_NAME} PRIVATE "STATE_CACHE_SIZE=${STATE_CACHE_SIZE}") # Link the untrusted test application against the untrusted library and openssl TARGET_LINK_LIBRARIES(${CLIENT_TEST_NAME} "-Wl,--start-group") diff --git a/contracts/wawaka/common/Dispatch.cpp b/contracts/wawaka/common/Dispatch.cpp index cbef109d..52961c3c 100644 --- a/contracts/wawaka/common/Dispatch.cpp +++ b/contracts/wawaka/common/Dispatch.cpp @@ -100,25 +100,14 @@ static char *initialize_wrapper(const char *environment) #ifdef __cplusplus extern "C" { #endif -extern void __wasm_call_ctors(void); - -// for each of these, we should call both the ctors and -// dtors functions. and that would probably mean making -// sure that we handle atexit correctly. the lack of global -// destructors could become a problem if we attempt to re-use -// an instantiated wamr module or if someone decides to put -// semantically interesting computation in the destructor of -// a global variable (which seems like an incredibly bad idea) char *ww_dispatch(const char *message, const char *environment) { - __wasm_call_ctors(); return dispatch_wrapper(message, environment); } char *ww_initialize(const char *environment) { - __wasm_call_ctors(); return initialize_wrapper(environment); } diff --git a/contracts/wawaka/common/Util.cpp b/contracts/wawaka/common/Util.cpp index fdd3a8e9..3e9bb588 100644 --- a/contracts/wawaka/common/Util.cpp +++ b/contracts/wawaka/common/Util.cpp @@ -66,6 +66,11 @@ void operator delete(void *ptr, std::align_val_t) _NOEXCEPT std::abort(); } +void operator delete(void *ptr, unsigned long _v_) _NOEXCEPT +{ + free(ptr); +} + #include FILE *const stderr = NULL; int vfprintf(FILE *__restrict, const char *__restrict, __isoc_va_list) diff --git a/contracts/wawaka/contract-build.cmake b/contracts/wawaka/contract-build.cmake index ccc828b7..5334544f 100644 --- a/contracts/wawaka/contract-build.cmake +++ b/contracts/wawaka/contract-build.cmake @@ -53,6 +53,21 @@ LIST(APPEND WASM_BUILD_OPTIONS "-DUSE_WASI_SDK=1") SET(WASM_LINK_OPTIONS) LIST(APPEND WASM_LINK_OPTIONS "-Wl,--export=ww_dispatch") LIST(APPEND WASM_LINK_OPTIONS "-Wl,--export=ww_initialize") +LIST(APPEND WASM_LINK_OPTIONS "-Wl,--export=malloc") +LIST(APPEND WASM_LINK_OPTIONS "-Wl,--export=free") +LIST(APPEND WASM_LINK_OPTIONS "-Wl,--export=__data_end") +LIST(APPEND WASM_LINK_OPTIONS "-Wl,--export=__heap_base") + +# Uncomment the following to set stack and memory sizes, these +# are strictly speaking not needed as the runtime will manage +# maximum sizes. However, they can be useful to trap unbounded +# memory usage at compile time rather than at runtime. + +# MATH(EXPR STACK "256*1024") +# MATH(EXPR TOTAL "512*1024") +# LIST(APPEND WASM_LINK_OPTIONS "-z stack-size=${STACK}") +# LIST(APPEND WASM_LINK_OPTIONS "-Wl,--max-memory=${TOTAL}") +# LIST(APPEND WASM_LINK_OPTIONS "-Wl,--initial-memory=${TOTAL}") # To identify undefined symbols, remove the allow-undefined # switch and add the error-limit swith diff --git a/docker/pdo_base.dockerfile b/docker/pdo_base.dockerfile index 5f7701aa..44e4462f 100644 --- a/docker/pdo_base.dockerfile +++ b/docker/pdo_base.dockerfile @@ -70,7 +70,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ # ----------------------------------------------------------------- # Install WASI toolkit # ----------------------------------------------------------------- -ARG WASI_VERSION=24 +ARG WASI_VERSION=27 ARG WASI_PACKAGE="wasi-sdk-${WASI_VERSION}.0-x86_64-linux.deb" WORKDIR /tmp diff --git a/eservice/lib/libpdo_enclave/contract_request.cpp b/eservice/lib/libpdo_enclave/contract_request.cpp index 00cf4ac7..45231e9f 100644 --- a/eservice/lib/libpdo_enclave/contract_request.cpp +++ b/eservice/lib/libpdo_enclave/contract_request.cpp @@ -36,6 +36,45 @@ #include "interpreter_kv.h" +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// This class is used to ensure that the state is always finalized +// after processing a request. Storage reclamation in state appears to +// only happen when state is finalized. If there are too many exceptions +// processed without invoking state we could end up with a significant +// memory leak. +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +class StateFinalizer +{ +private: + ContractState& contract_state_; + bool finalized_ = false; + +public: + StateFinalizer(ContractState& contract_state) : contract_state_(contract_state) {} + + bool Finalize(void) + { + if (!finalized_) + { + try { + contract_state_.Finalize(); + } + catch (std::exception& e) { + SAFE_LOG(PDO_LOG_ERROR, "Failed to finalize state: %s", e.what()); + finalized_ = true; + return false; + } + finalized_ = true; + } + return true; + } + + ~StateFinalizer() + { + Finalize(); + } +}; + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // See ${PDO_SOURCE_ROOT}/eservice/docs/contract.json for format // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -110,6 +149,8 @@ std::shared_ptr UpdateStateRequest::process_request(ContractSt bool state_changed_flag; + StateFinalizer state_finalizer(contract_state); + // Push this into a block to ensure that the interpreter is deallocated // and frees its memory before finalizing the state update { @@ -129,7 +170,8 @@ std::shared_ptr UpdateStateRequest::process_request(ContractSt result); } - contract_state.Finalize(); + if (! state_finalizer.Finalize()) + return std::make_shared(*this, false, "failed to finalize state"); // check for operations that did not modify state if (state_changed_flag) @@ -155,8 +197,6 @@ std::shared_ptr UpdateStateRequest::process_request(ContractSt contract_message_.expression_.c_str(), e.what()); - contract_state.Finalize(); - return std::make_shared(*this, false, e.what()); } catch (pdo::error::Error& e) @@ -239,6 +279,8 @@ std::shared_ptr InitializeStateRequest::process_request(Contra msg.OriginatorID = contract_message_.originator_verifying_key_; msg.MessageHash = ByteArrayToBase64EncodedString(contract_message_.message_hash_); + StateFinalizer state_finalizer(contract_state); + // Push this into a block to ensure that the interpreter is deallocated // and frees its memory before finalizing the state update { @@ -252,7 +294,8 @@ std::shared_ptr InitializeStateRequest::process_request(Contra contract_id_, creator_id_, code, msg, contract_state.state_); } - contract_state.Finalize(); + if (! state_finalizer.Finalize()) + return std::make_shared(*this, false, "failed to finalize state"); return std::make_shared( *this, diff --git a/interpreters/wasm-micro-runtime b/interpreters/wasm-micro-runtime index 3f5e2bd2..b124f703 160000 --- a/interpreters/wasm-micro-runtime +++ b/interpreters/wasm-micro-runtime @@ -1 +1 @@ -Subproject commit 3f5e2bd23bcb8eb3767c8e17789c6a2e3e912a08 +Subproject commit b124f70345d712bead5c0c2393acb2dc583511de