Przeglądaj źródła

Random improvements to samples/native-stack-overflow (#3353)

YAMAMOTO Takashi 1 rok temu
rodzic
commit
a36c7d5aa9

+ 8 - 1
samples/native-stack-overflow/CMakeLists.txt

@@ -11,6 +11,9 @@ else()
   project (native-stack-overflow C ASM)
   project (native-stack-overflow C ASM)
 endif()
 endif()
 
 
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_C_EXTENSIONS YES)
+
 ################  runtime settings  ################
 ################  runtime settings  ################
 string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
 string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
 if (APPLE)
 if (APPLE)
@@ -43,7 +46,7 @@ if (NOT DEFINED WAMR_BUILD_TARGET)
 endif ()
 endif ()
 
 
 if (NOT CMAKE_BUILD_TYPE)
 if (NOT CMAKE_BUILD_TYPE)
-  set (CMAKE_BUILD_TYPE Debug)
+  set (CMAKE_BUILD_TYPE Release)
 endif ()
 endif ()
 
 
 set (WAMR_BUILD_INTERP 1)
 set (WAMR_BUILD_INTERP 1)
@@ -65,6 +68,10 @@ if (NOT MSVC)
   endif ()
   endif ()
 endif ()
 endif ()
 
 
+if (CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 13.0.0)
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-usage")
+endif ()
+
 # build out vmlib
 # build out vmlib
 set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
 set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
 include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
 include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)

+ 2 - 2
samples/native-stack-overflow/build.sh

@@ -1,10 +1,10 @@
+#! /bin/sh
+
 #
 #
 # Copyright (C) 2019 Intel Corporation.  All rights reserved.
 # Copyright (C) 2019 Intel Corporation.  All rights reserved.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 #
 #
 
 
-#!/bin/bash
-
 CURR_DIR=$PWD
 CURR_DIR=$PWD
 WAMR_DIR=${PWD}/../..
 WAMR_DIR=${PWD}/../..
 OUT_DIR=${PWD}/out
 OUT_DIR=${PWD}/out

+ 1 - 1
samples/native-stack-overflow/clean.sh

@@ -1 +1 @@
-rm -r cmake_build cmake_build_disable_hw_bound out
+rm -rf cmake_build cmake_build_disable_hw_bound out

+ 15 - 7
samples/native-stack-overflow/run.sh

@@ -1,12 +1,20 @@
-#!/bin/bash
+#! /bin/sh
 
 
-echo "====== Interpreter"
-out/native-stack-overflow out/wasm-apps/testapp.wasm
+set -e
+
+NAME=${1:-test1}
+
+echo "====== Interpreter ${NAME}"
+out/native-stack-overflow out/wasm-apps/testapp.wasm ${NAME}
+
+echo
+echo "====== Interpreter WAMR_DISABLE_HW_BOUND_CHECK=1 ${NAME}"
+out/native-stack-overflow.WAMR_DISABLE_HW_BOUND_CHECK out/wasm-apps/testapp.wasm ${NAME}
 
 
 echo
 echo
-echo "====== AOT"
-out/native-stack-overflow out/wasm-apps/testapp.wasm.aot
+echo "====== AOT ${NAME}"
+out/native-stack-overflow out/wasm-apps/testapp.wasm.aot ${NAME}
 
 
 echo
 echo
-echo "====== AOT WAMR_DISABLE_HW_BOUND_CHECK=1"
-out/native-stack-overflow.WAMR_DISABLE_HW_BOUND_CHECK out/wasm-apps/testapp.wasm.aot.bounds-checks
+echo "====== AOT WAMR_DISABLE_HW_BOUND_CHECK=1 ${NAME}"
+out/native-stack-overflow.WAMR_DISABLE_HW_BOUND_CHECK out/wasm-apps/testapp.wasm.aot.bounds-checks ${NAME}

+ 39 - 5
samples/native-stack-overflow/src/main.c

@@ -20,6 +20,34 @@ static NativeSymbol native_symbols[] = {
     { "host_consume_stack", host_consume_stack, "(i)i", NULL },
     { "host_consume_stack", host_consume_stack, "(i)i", NULL },
 };
 };
 
 
+void *
+canary_addr()
+{
+    uint8_t *p = os_thread_get_stack_boundary();
+#if defined(OS_ENABLE_HW_BOUND_CHECK) && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+    uint32_t page_size = os_getpagesize();
+    uint32_t guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
+    return p + page_size * guard_page_count;
+#else
+    return p;
+#endif
+}
+
+void
+canary_init(void)
+{
+    uint32_t *canary = canary_addr();
+    *canary = 0xaabbccdd;
+}
+
+bool
+canary_check(void)
+{
+    /* assume an overflow if the first uint32_t on the stack was modified */
+    const uint32_t *canary = (void *)canary_addr();
+    return *canary == 0xaabbccdd;
+}
+
 struct record {
 struct record {
     bool failed;
     bool failed;
     bool leaked;
     bool leaked;
@@ -40,10 +68,11 @@ main(int argc, char **argv)
     char *buffer;
     char *buffer;
     char error_buf[128];
     char error_buf[128];
 
 
-    if (argc != 2) {
+    if (argc != 3) {
         return 2;
         return 2;
     }
     }
-    char *module_path = argv[1];
+    const char *module_path = argv[1];
+    const char *funcname = argv[2];
 
 
     wasm_module_t module = NULL;
     wasm_module_t module = NULL;
     uint32 buf_size;
     uint32 buf_size;
@@ -101,6 +130,7 @@ main(int argc, char **argv)
         const char *exception = NULL;
         const char *exception = NULL;
         nest = 0;
         nest = 0;
 
 
+        canary_init();
         module_inst = wasm_runtime_instantiate(module, stack_size, heap_size,
         module_inst = wasm_runtime_instantiate(module, stack_size, heap_size,
                                                error_buf, sizeof(error_buf));
                                                error_buf, sizeof(error_buf));
         if (!module_inst) {
         if (!module_inst) {
@@ -114,7 +144,6 @@ main(int argc, char **argv)
             goto fail2;
             goto fail2;
         }
         }
 
 
-        const char *funcname = "test";
         wasm_function_inst_t func =
         wasm_function_inst_t func =
             wasm_runtime_lookup_function(module_inst, funcname);
             wasm_runtime_lookup_function(module_inst, funcname);
         if (!func) {
         if (!func) {
@@ -124,8 +153,8 @@ main(int argc, char **argv)
 
 
         /* note: the function type is (ii)i */
         /* note: the function type is (ii)i */
         uint32_t wasm_argv[] = {
         uint32_t wasm_argv[] = {
-            stack,
-            30,
+            stack, /* native_stack */
+            30,    /* recurse_count */
         };
         };
         uint32_t wasm_argc = 2;
         uint32_t wasm_argc = 2;
         if (!wasm_runtime_call_wasm(exec_env, func, wasm_argc, wasm_argv)) {
         if (!wasm_runtime_call_wasm(exec_env, func, wasm_argc, wasm_argv)) {
@@ -134,6 +163,11 @@ main(int argc, char **argv)
         }
         }
         failed = false;
         failed = false;
     fail2:
     fail2:
+        if (!canary_check()) {
+            printf("stack overurn detected for stack=%u\n", stack);
+            abort();
+        }
+
         /*
         /*
          * note: non-zero "nest" here demonstrates resource leak on longjmp
          * note: non-zero "nest" here demonstrates resource leak on longjmp
          * from signal handler.
          * from signal handler.

+ 28 - 1
samples/native-stack-overflow/src/native_impl.c

@@ -3,8 +3,15 @@
  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  */
  */
 
 
+#define __STDC_WANT_LIB_EXT1__ 1
+
 #include <inttypes.h>
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <string.h>
+
+#if defined(__APPLE__)
+#include <Availability.h>
+#endif
 
 
 #include "wasm_export.h"
 #include "wasm_export.h"
 #include "bh_platform.h"
 #include "bh_platform.h"
@@ -38,6 +45,11 @@ host_consume_stack_and_call_indirect(wasm_exec_env_t exec_env, uint32_t funcidx,
     void *boundary = os_thread_get_stack_boundary();
     void *boundary = os_thread_get_stack_boundary();
     void *fp = __builtin_frame_address(0);
     void *fp = __builtin_frame_address(0);
     ptrdiff_t diff = fp - boundary;
     ptrdiff_t diff = fp - boundary;
+    if ((unsigned char *)fp < (unsigned char *)boundary + 1024 * 5) {
+        wasm_runtime_set_exception(wasm_runtime_get_module_inst(exec_env),
+                                   "native stack overflow 2");
+        return 0;
+    }
     if (diff > stack) {
     if (diff > stack) {
         prev_diff = diff;
         prev_diff = diff;
         nest++;
         nest++;
@@ -49,14 +61,29 @@ host_consume_stack_and_call_indirect(wasm_exec_env_t exec_env, uint32_t funcidx,
     return call_indirect(exec_env, funcidx, x);
     return call_indirect(exec_env, funcidx, x);
 }
 }
 
 
-static uint32_t
+__attribute__((noinline)) static uint32_t
 consume_stack1(wasm_exec_env_t exec_env, void *base, uint32_t stack)
 consume_stack1(wasm_exec_env_t exec_env, void *base, uint32_t stack)
+    __attribute__((disable_tail_calls))
 {
 {
     void *fp = __builtin_frame_address(0);
     void *fp = __builtin_frame_address(0);
     ptrdiff_t diff = (unsigned char *)base - (unsigned char *)fp;
     ptrdiff_t diff = (unsigned char *)base - (unsigned char *)fp;
     assert(diff > 0);
     assert(diff > 0);
     char buf[16];
     char buf[16];
+    /*
+     * note: we prefer to use memset_s here because, unlike memset,
+     * memset_s is not allowed to be optimized away.
+     *
+     * memset_s is available for macOS 10.13+ according to:
+     * https://developer.apple.com/documentation/kernel/2876438-memset_s
+     */
+#if defined(__STDC_LIB_EXT1__)                  \
+    || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) \
+        && __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3)
     memset_s(buf, sizeof(buf), 0, sizeof(buf));
     memset_s(buf, sizeof(buf), 0, sizeof(buf));
+#else
+#warning memset_s is not available
+    memset(buf, 0, sizeof(buf));
+#endif
     if (diff > stack) {
     if (diff > stack) {
         return diff;
         return diff;
     }
     }

+ 31 - 11
samples/native-stack-overflow/wasm-apps/testapp.c

@@ -17,7 +17,7 @@ cb(int x)
 }
 }
 
 
 int
 int
-consume_stack_cb(int x)
+consume_stack_cb(int x) __attribute__((disable_tail_calls))
 {
 {
     /*
     /*
      * intentions:
      * intentions:
@@ -39,16 +39,36 @@ host_consume_stack_cb(int x)
     return host_consume_stack(x);
     return host_consume_stack(x);
 }
 }
 
 
-__attribute__((export_name("test"))) uint32_t
-test(uint32_t native_stack, uint32_t recurse_count)
+__attribute__((export_name("test1"))) uint32_t
+test1(uint32_t native_stack, uint32_t recurse_count)
 {
 {
-    uint32_t ret;
-    ret = host_consume_stack_and_call_indirect(cb, 321, native_stack);
-    ret = host_consume_stack_and_call_indirect(consume_stack_cb, recurse_count,
-                                               native_stack);
-#if 0 /* notyet */
-    ret = host_consume_stack_and_call_indirect(host_consume_stack_cb, 1000000,
-                                          native_stack);
-#endif
+    /*
+     * ------ os_thread_get_stack_boundary
+     * ^
+     * |
+     * | "native_stack" bytes of stack left by
+     * | host_consume_stack_and_call_indirect
+     * |
+     * | ^
+     * | |
+     * | | consume_stack_cb (interpreter or aot)
+     * v |
+     *   ^
+     *   |
+     *   | host_consume_stack_and_call_indirect
+     *   |
+     *
+     *
+     */
+    uint32_t ret = host_consume_stack_and_call_indirect(
+        consume_stack_cb, recurse_count, native_stack);
+    return 42;
+}
+
+__attribute__((export_name("test2"))) uint32_t
+test2(uint32_t native_stack, uint32_t recurse_count)
+{
+    uint32_t ret = host_consume_stack_and_call_indirect(host_consume_stack_cb,
+                                                        6000, native_stack);
     return 42;
     return 42;
 }
 }