/* * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include "func_types.h" #include "test_helper.h" #include "wasm_export.h" #include "gtest/gtest.h" #include #include "../interpreter/wasm.h" void *func_ptr; #define CALL_FUNC(name, ...) \ ((name##_func_type)get_func(#name))(dummy_exec_env.get(), ##__VA_ARGS__) extern "C" { extern uint32_t get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis); extern bool wasm_native_lookup_libc_builtin_global(const char *module_name, const char *global_name, WASMGlobalImport *global); } class LibcBuiltinTest : public testing::Test { protected: // You should make the members protected s.t. they can be // accessed from sub-classes. // virtual void SetUp() will be called before each test is run. You // should define it if you need to initialize the varaibles. // Otherwise, this can be skipped. virtual void SetUp() { n_native_symbols = get_libc_builtin_export_apis(&native_symbols); } // virtual void TearDown() will be called after each test is run. // You should define it if there is cleanup work to do. Otherwise, // you don't have to provide it. // virtual void TearDown() {} public: WAMRRuntimeRAII<512 * 1024> runtime; DummyExecEnv dummy_exec_env; static NativeSymbol *native_symbols; static uint32_t n_native_symbols; static void *get_func(const char *name) { int32_t i; for (i = 0; i < n_native_symbols; i++) { if (strcmp(native_symbols[i].symbol, name) == 0) { return native_symbols[i].func_ptr; } } return NULL; } }; NativeSymbol *LibcBuiltinTest::native_symbols; uint32_t LibcBuiltinTest::n_native_symbols; static const char very_long_string[] = R"(2mwa9vxDhuuvO47XePZvc4DAMdR8dzgKrmRNAM3qVoedFhG7GYyhlC4JiuSdrw8G 7vrPoCLGlVlGwMw7ATDL3bA5Filds8krTxS7h8ioq6CY4UmKl1zjHlmnOYRO3Wmp ylp21RrG8LzfHFerFyKFxA1GB93OuTFcasO2n9uQljCx8h5KRolbvjdHVnado4B6 3zNV990V7T7LIJHwZKb0RGg0fFo4GQd6Mfdl6aD3UlpKBIxjbonyeaQBY7hPZB8R J1JV5iw2PWB2BJEGoGhTvlc0a9FxmeqWIjpnU3yNEg2lD3NjZU627pTFcoAy5GCz wDyF5QzcvtAgWBR95kRpDtV21CRyQ6HteorX1aHemoMYWOLIvX52stUTAnOImMD8 tIw6xwkOZx5fs3x9m540pPnRDiihLn2XuQ1PLPwA6orWOGm3dBKthqsycTqaIl0L 0gpycKbVYFHmakfgEyP9fyMziLT11B6EPzomHQAYgTVUdDl9u63P6sQCeaPwAYsY gus28uK9YYjpXgOOziG8ocBddvids1iLJLdbiAqKyHaVY4IBLVWU3F74tKGF7TeI DGAfvpzHls19VM9bKReBfCmDgbib7mCpYEFAQCmu5my0C8QrJlUoOgiljIO0x3sH ByNf4k9OfhzYi1V4cvDnMELVrk0fyZWmIxDvig7nfzI57OltT28pughPBlLxTn8X xyMNVYn1dD6Wpp7sqOBjxWGWmdrjleyin0iQ05UbfioHazvLKHtDfm5P2WwVejm6)"; TEST_F(LibcBuiltinTest, puts) { char ll_string[2048]; /* Capture the stdout */ testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(puts, "Hello Wrold"), strlen("Hello Wrold\n")); EXPECT_EQ(testing::internal::GetCapturedStdout(), "Hello Wrold\n"); testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(puts, "c"), strlen("c\n")); EXPECT_EQ(testing::internal::GetCapturedStdout(), "c\n"); testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(puts, very_long_string), strlen(very_long_string) + 1); EXPECT_EQ(testing::internal::GetCapturedStdout(), std::string(very_long_string) + "\n"); memset(ll_string, 0xAA, sizeof(ll_string)); testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(puts, ll_string), strlen(ll_string) + 1); EXPECT_EQ(testing::internal::GetCapturedStdout(), std::string(ll_string) + "\n"); } TEST_F(LibcBuiltinTest, printf) { WAMRVaList empty_va_list(dummy_exec_env.get()); /* Capture the stdout */ testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(printf, "Hello Wrold", empty_va_list.get()), strlen("Hello Wrold")); EXPECT_EQ(testing::internal::GetCapturedStdout(), "Hello Wrold"); testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(printf, "c", empty_va_list.get()), strlen("c")); EXPECT_EQ(testing::internal::GetCapturedStdout(), "c"); testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(printf, very_long_string, empty_va_list.get()), strlen(very_long_string)); EXPECT_EQ(testing::internal::GetCapturedStdout(), very_long_string); /* type */ { /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); va_list.add(20); //%d 20 va_list.add(65); //%i 65 va_list.add(10); //%O 12 va_list.add(10); //%u 10 va_list.add(255); //%x ff va_list.add(255); //%X FF va_list.add(3.14); //%f 3.14 va_list.add(3.14); //%F 3.14 va_list.add(0.000001); //%e 1.000000e-06 va_list.add(0.000001); //%E 1.000000E-06 va_list.add(0.000001); //%g 1e-06 va_list.add(0.000001); //%G 1E-06 va_list.add("Hello World"); //%s Hello World testing::internal::CaptureStdout(); /* clang-format off */ EXPECT_EQ(CALL_FUNC(printf, "%d, %i, %o, %u, %x, %X, %f, %F, %e, %E, %g, %G, %s", va_list.get()), 97); EXPECT_EQ(testing::internal::GetCapturedStdout(), "20, 65, 12, 10, ff, FF, 3.140000, 3.140000, 1.000000e-06, 1.000000E-06, 1e-06, 1E-06, Hello World"); /* clang-format on */ } /* %c */ { /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); va_list.add('C'); //%c C // va_list.add("Hello"); //%p testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(printf, "%c", va_list.get()), 1); EXPECT_EQ(testing::internal::GetCapturedStdout(), "C"); } /* %p */ { /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); va_list.add("Hello"); testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(printf, "%p", va_list.get()), 7); EXPECT_EQ(testing::internal::GetCapturedStdout(), "0x200a8"); } { /* clang-format off */ /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); va_list.add(20); //%td va_list.add(20); //%zd va_list.add(20); //%ld va_list.add(20L); //%jd testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(printf, "%td, %zd, %ld, %jd", va_list.get()), 14); EXPECT_EQ(testing::internal::GetCapturedStdout(), "20, 20, 20, 20"); /* clang-format on */ } /* %% */ { /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); EXPECT_TRUE(CALL_FUNC(printf, "%%", va_list.get())); } /* %n */ { /* Construct a va_list to call printf */ WAMRVaList empty_va_list(dummy_exec_env.get()); /* Capture the stdout */ testing::internal::CaptureStdout(); CALL_FUNC(printf, "0123%n", empty_va_list.get()); EXPECT_EQ(testing::internal::GetCapturedStdout(), "0123"); } /* flag */ { /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); /*%-*/ va_list.add(20); //%-d 20 va_list.add(20); //%d 20 /*%+*/ va_list.add(20); //%+d +20 va_list.add(-20); //%+d -20 /*% */ va_list.add(20); //% d 20 va_list.add(-20); //% d -20 /*%#*/ va_list.add(20); //%#o 024 va_list.add(255); //%#x 0xff va_list.add(255); //%#X 0xFF va_list.add(3.14); //%#.f 3. va_list.add(3.14); //%#.lf 3. va_list.add(3.14); //%#.e 3.e+00 va_list.add(3.14); //%#.E 3.E+00 va_list.add(3.14); //%#.g 3. va_list.add(3.14); //%#.G 3. va_list.add(20); //%#.a %a va_list.add(20); //%#.A %A /*%0*/ va_list.add(20); //%03d 020 testing::internal::CaptureStdout(); /* clang-format off */ EXPECT_EQ(CALL_FUNC(printf, "%-d, %d, %+d, %+d, % d, % d, %#o, %#x, %#X, %#.f, %#.lf, %#.e, %#.E, %#.g, %#.G, %#.a, %#.A, %03d", va_list.get()), 88); EXPECT_EQ(testing::internal::GetCapturedStdout(), "20, 20, +20, -20, 20, -20, 024, 0xff, 0XFF, 3., 3., 3.e+00, 3.E+00, 3., 3., %a, %A, 020"); /* clang-format on */ } /* precision */ { /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); va_list.add(20); //%d 20 va_list.add(20); //%.1d 20 va_list.add(20); //%.2d 20 va_list.add(20); //%.3d 020 va_list.add(20); //%.4d 0020 va_list.add(20); //%.5d 00020 va_list.add(20); //%.6d 000020 va_list.add(20); //%.7d 0000020 va_list.add(20); //%.8d 00000020 va_list.add(20); //%.9d 000000020 testing::internal::CaptureStdout(); /* clang-format off */ EXPECT_EQ(CALL_FUNC(printf, "%d, %.1d, %.2d, %.3d, %.4d, %.5d, %.6d, %.7d, %.8d, %.9d", va_list.get()), 66); EXPECT_EQ(testing::internal::GetCapturedStdout(), "20, 20, 20, 020, 0020, 00020, 000020, 0000020, 00000020, 000000020"); /* clang-format on */ } /*length*/ { /* clang-format off */ /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); va_list.add(0x7F); //%hhd 127 -char va_list.add(0xFF); //%hhu.1d 255 -unsiged char va_list.add(0x7FFF); //%hd 32767 -sing short int va_list.add(0xFFFF); //%hu 65535 -unsiged short va_list.add(0x7FFFFFFF); //%ld 2147483647 - sing long va_list.add(0xFFFFFFFF); //%lu 4294967295 -unsigned long va_list.add(0x7FFFFFFFFFFFFFFF); //%lld 9223372036854775807 sing long long va_list.add(0xFFFFFFFFFFFFFFFF);//%llu 18446744073709551615 unsiged long long testing::internal::CaptureStdout(); EXPECT_EQ(CALL_FUNC(printf, "%hhd, %hhu, %hd, %hu, %ld, %lu, %lld, %llu", va_list.get()), 89); EXPECT_EQ(testing::internal::GetCapturedStdout(), "127, 255, 32767, 65535, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615"); /* clang-format on */ } EXPECT_EQ(CALL_FUNC(printf, "Hello Wrold", 0), 0); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); EXPECT_EQ(CALL_FUNC(printf, "Hello Wrold", NULL), 0); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); EXPECT_EQ(CALL_FUNC(printf, "Hello Wrold", (char *)-1), 0); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); EXPECT_EQ(CALL_FUNC(printf, (char *)-1, (char *)-1), 0); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); } TEST_F(LibcBuiltinTest, sprintf) { const char *buf; const char *str = "Hello Wrold"; const char *str_sig = "c"; const char *str_f = "20, 3.140000, Hello World"; const char *str_long = "eqwewerwerqwer34were"; // test ok // const char *str_long = "TDSFGAWE%#$TERFQ@$%$@!%$@!RS!$#@$%" // "WAWAAEWAFSDNGFUTKNZDAERQWYNZREWGHAH"; // //fail WAMRVaList empty_va_list(dummy_exec_env.get()); AppData buf_app{ dummy_exec_env.get(), buf }; AppData str_app{ dummy_exec_env.get(), str }; AppData str_sig_app{ dummy_exec_env.get(), str_sig }; AppData str_long_app{ dummy_exec_env.get(), str_long }; EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), (char *)str_app.get_native_addr(), 0), 0); EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), (char *)str_app.get_native_addr(), NULL), 0); EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), (char *)str_app.get_native_addr(), (char *)-1), 0); EXPECT_FALSE(CALL_FUNC(sprintf, (char *)-1, (char *)str_app.get_native_addr(), empty_va_list.get())); EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), (char *)str_app.get_native_addr(), empty_va_list.get()), strlen(str)); EXPECT_EQ(CALL_FUNC(memcmp, buf_app.get_native_addr(), str_app.get_native_addr(), strlen(str)), 0); EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), (char *)str_sig_app.get_native_addr(), empty_va_list.get()), strlen(str_sig)); EXPECT_EQ(CALL_FUNC(memcmp, buf_app.get_native_addr(), str_sig_app.get_native_addr(), strlen(str_sig)), 0); EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), (char *)str_long_app.get_native_addr(), empty_va_list.get()), strlen(str_long)); EXPECT_EQ(CALL_FUNC(memcmp, buf_app.get_native_addr(), str_long_app.get_native_addr(), strlen(str_long)), 0); { /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); va_list.add(20); va_list.add(3.14); va_list.add("Hello World"); /* This is like printf("%d, %f, %s", 20, 3.14, "Hello World") */ EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), "%d, %f, %s", va_list.get()), 25); EXPECT_EQ(CALL_FUNC(memcmp, buf_app.get_native_addr(), str_f, 25), 0); } } TEST_F(LibcBuiltinTest, snprintf) { char buf[1024]; char buf1[10]; WAMRVaList empty_va_list(dummy_exec_env.get()); EXPECT_EQ(CALL_FUNC(snprintf, buf, strlen("Hello Wrold"), "Hello Wrold", 0), 0); EXPECT_EQ( CALL_FUNC(snprintf, buf, strlen("Hello Wrold"), "Hello Wrold", NULL), 0); EXPECT_EQ(CALL_FUNC(snprintf, buf, strlen("Hello Wrold"), "Hello Wrold", (char *)-1), 0); EXPECT_EQ(CALL_FUNC(snprintf, buf, strlen("Hello Wrold"), "Hello Wrold", empty_va_list.get()), strlen("Hello Wrold")); EXPECT_EQ(CALL_FUNC(memcmp, buf, "Hello Wrold", strlen("Hello Wrold")), 0); EXPECT_EQ(CALL_FUNC(snprintf, buf, strlen(very_long_string), very_long_string, empty_va_list.get()), strlen(very_long_string)); { /* Construct a va_list to call printf */ WAMRVaList va_list(dummy_exec_env.get()); va_list.add(20); va_list.add(3.14); va_list.add("Hello World"); EXPECT_EQ(CALL_FUNC(snprintf, buf, 25, "%d, %f, %s", va_list.get()), 25); } } TEST_F(LibcBuiltinTest, putchar) { char ch; for (ch = 'a'; ch <= 'z'; ch++) EXPECT_EQ(CALL_FUNC(putchar, ch), 1); for (ch = '0'; ch <= '9'; ch++) EXPECT_EQ(CALL_FUNC(putchar, ch), 1); for (ch = 0; ch < 127; ch++) EXPECT_EQ(CALL_FUNC(putchar, ch), 1); } TEST_F(LibcBuiltinTest, strdup) { const char *src = "Hello World!"; AppData src_app{ dummy_exec_env.get(), src }; /* exception */ EXPECT_EQ(CALL_FUNC(strdup, NULL), 0); EXPECT_GE(CALL_FUNC(strdup, (char *)src_app.get_native_addr()), 0); } TEST_F(LibcBuiltinTest, _strdup) { const char *src = "Hello World!"; AppData src_app{ dummy_exec_env.get(), src }; /* exception */ EXPECT_EQ(CALL_FUNC(_strdup, NULL), 0); EXPECT_GE(CALL_FUNC(_strdup, (char *)src_app.get_native_addr()), 0); } TEST_F(LibcBuiltinTest, memcmp) { const char *a = "aBcDeF"; const char *b = "AbCdEf"; const char *c = "aacdef"; const char *d = "aBcDeF"; AppData a_app{ dummy_exec_env.get(), a }; AppData b_app{ dummy_exec_env.get(), b }; AppData c_app{ dummy_exec_env.get(), c }; AppData d_app{ dummy_exec_env.get(), d }; /* exception */ EXPECT_EQ(CALL_FUNC(memcmp, (void *)-1, d_app.get_native_addr(), 0), 0); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); /* size = 0 */ EXPECT_EQ( CALL_FUNC(memcmp, a_app.get_native_addr(), d_app.get_native_addr(), 0), 0); // /* s1>s2 */ EXPECT_GT(CALL_FUNC(memcmp, a_app.get_native_addr(), b_app.get_native_addr(), strlen(a)), 0); // /* s1s2*/ EXPECT_GT(CALL_FUNC(strcmp, (char *)b_app.get_native_addr(), (char *)a_app.get_native_addr()), 0); /*s1s2*/ EXPECT_GT(CALL_FUNC(strncmp, (char *)b_app.get_native_addr(), (char *)a_app.get_native_addr(), strlen(a)), 0); /*s1s2*/ EXPECT_GT(CALL_FUNC(strncmp, (char *)b_app.get_native_addr(), (char *)a_app.get_native_addr(), 3), 0); /*s1= UINT32_MAX */ EXPECT_EQ(CALL_FUNC(calloc, 1, 0xffffffff), 0); /* nmemb = 1 size=0xffffffff-1 total_size >= UINT32_MAX-1 */ EXPECT_EQ(CALL_FUNC(calloc, 1, (0xffffffff - 1)), 0); /* nmemb = 1 size = 0 total_size = 0 */ /* According to Linux man page: If nmemb or size is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free() */ EXPECT_GE(CALL_FUNC(calloc, 1, 0), 0); /* nmemb = 10 size = 1024 total_size < UINT32_MAX */ EXPECT_GT(CALL_FUNC(calloc, 10, 1024), 0); } TEST_F(LibcBuiltinTest, realloc) { unsigned int ptr = 0; // ptr = 0; // EXPECT_EQ(CALL_FUNC(realloc, ptr, 1024), 0); // ptr = 1; // EXPECT_GT(CALL_FUNC(realloc, ptr, 1024), 0); // ptr = 3; // EXPECT_GT(CALL_FUNC(realloc, ptr, 1024), 0); /* If ptr is NULL, then the call is equivalent to malloc(size), for all * values of size */ ptr = CALL_FUNC(realloc, ptr, 1024); EXPECT_EQ(ptr, ptr); EXPECT_EQ(CALL_FUNC(realloc, ptr, 10), ptr); EXPECT_EQ(CALL_FUNC(realloc, ptr, 15), ptr); ptr = CALL_FUNC(realloc, ptr, 2048); EXPECT_EQ(ptr, ptr); /* If size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr) */ CALL_FUNC(realloc, ptr, 0); } TEST_F(LibcBuiltinTest, free) { const char *src; const char *s = "Hello World!"; AppMemory src_mem{ dummy_exec_env.get(), 15 }; AppData s_app{ dummy_exec_env.get(), s }; CALL_FUNC(free, (char *)0xFFFFFFFF); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); CALL_FUNC(free, (char *)-1); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); CALL_FUNC(free, NULL); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); memset((char *)src_mem.get_native_addr(), '\0', 15); strcpy((char *)src_mem.get_native_addr(), (char *)s_app.get_native_addr()); EXPECT_EQ(CALL_FUNC(memcmp, (char *)src_mem.get_native_addr(), s_app.get_native_addr(), 15), 0); /* free */ CALL_FUNC(free, (char *)src_mem.get_native_addr()); EXPECT_NE(CALL_FUNC(memcmp, (char *)src_mem.get_native_addr(), s_app.get_native_addr(), 15), 0); } TEST_F(LibcBuiltinTest, atoi) { char *src = (char *)"123"; char *src1 = (char *)"-123"; AppData src_app{ dummy_exec_env.get(), src }; AppData src1_app{ dummy_exec_env.get(), src1 }; EXPECT_EQ(CALL_FUNC(atoi, (char *)src_app.get_native_addr()), 123); EXPECT_EQ(CALL_FUNC(atoi, (char *)src1_app.get_native_addr()), -123); } TEST_F(LibcBuiltinTest, exit) { CALL_FUNC(exit, 3); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: env.exit(3)"); dummy_exec_env.clear_exception(); } TEST_F(LibcBuiltinTest, strtol) { char str[20] = "20"; char str1[20] = "-20"; char buffer[20] = "0x31"; char buffer1[20] = "10379cend$3"; char *ptr; AppData src_app{ dummy_exec_env.get(), str }; AppData src1_app{ dummy_exec_env.get(), str1 }; AppData buffer_app{ dummy_exec_env.get(), buffer }; AppData buffer1_app{ dummy_exec_env.get(), buffer1 }; AppMemory ptr_app{ dummy_exec_env.get(), 20 }; CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 10); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); CALL_FUNC(strtol, (char *)src_app.get_native_addr(), &ptr, 10); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 2), 0); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 8), 0); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 10), 0); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 16), 0); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 32), 0); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 2), 0); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 8), 16); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 10), 20); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 16), 32); EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 32), 64); EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 2), 0); EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 8), -16); EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 10), -20); EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 16), -32); EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 32), -64); EXPECT_EQ(CALL_FUNC(strtol, (char *)buffer_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 0), 49); EXPECT_EQ(CALL_FUNC(strtol, (char *)buffer_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 16), 49); EXPECT_EQ(CALL_FUNC(strtol, (char *)buffer_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 10), 0); EXPECT_EQ(CALL_FUNC(strtol, (char *)buffer1_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 10), 10379); // EXPECT_STREQ((char *)ptr_app.get_native_addr(), "cend$3"); uint32_t str_app_addr = *(uint32_t *)ptr_app.get_native_addr(); EXPECT_GT(str_app_addr, 0); char *str_native_addr = (char *)dummy_exec_env.app_to_native(str_app_addr); EXPECT_NE(str_native_addr, nullptr); EXPECT_STREQ(str_native_addr, "cend$3"); } TEST_F(LibcBuiltinTest, strtoul) { char str[20] = "20"; char buffer[20] = "0x31"; char buffer1[20] = "10379cend$3"; char *ptr; AppData src_app{ dummy_exec_env.get(), str }; AppData buffer_app{ dummy_exec_env.get(), buffer }; AppData buffer1_app{ dummy_exec_env.get(), buffer1 }; AppMemory ptr_app{ dummy_exec_env.get(), 20 }; CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 10); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), &ptr, 10); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 2), 0); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 8), 0); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 10), 0); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 16), 0); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 32), 0); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 2), 0); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 8), 16); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 10), 20); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 16), 32); EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 32), 64); EXPECT_EQ(CALL_FUNC(strtoul, (char *)buffer_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 0), 49); EXPECT_EQ(CALL_FUNC(strtoul, (char *)buffer_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 16), 49); EXPECT_EQ(CALL_FUNC(strtoul, (char *)buffer_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 10), 0); EXPECT_EQ(CALL_FUNC(strtoul, (char *)buffer1_app.get_native_addr(), (char **)ptr_app.get_native_addr(), 10), 10379); uint32_t str_app_addr = *(uint32_t *)ptr_app.get_native_addr(); EXPECT_GT(str_app_addr, 0); char *str_native_addr = (char *)dummy_exec_env.app_to_native(str_app_addr); EXPECT_NE(str_native_addr, nullptr); EXPECT_STREQ(str_native_addr, "cend$3"); } TEST_F(LibcBuiltinTest, memchr) { const char src[] = "Hello World."; char ch = 'o'; AppData src_app{ dummy_exec_env.get(), src }; /* exception */ EXPECT_EQ(CALL_FUNC(memchr, (char *)-1, ch, strlen(src)), 0); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: out of bounds memory access"); dummy_exec_env.clear_exception(); EXPECT_GE(CALL_FUNC(memchr, src_app.get_native_addr(), ch, strlen(src)), 0); } TEST_F(LibcBuiltinTest, strncasecmp) { const char *src1 = "Hello World."; const char *src2 = "hel"; const char *src3 = "HELLO WORLD."; AppData src1_app{ dummy_exec_env.get(), src1 }; AppData src2_app{ dummy_exec_env.get(), src2 }; AppData src3_app{ dummy_exec_env.get(), src3 }; EXPECT_GT(CALL_FUNC(strncasecmp, (char *)src1_app.get_native_addr(), (char *)src2_app.get_native_addr(), 4), 0); EXPECT_LT(CALL_FUNC(strncasecmp, (char *)src2_app.get_native_addr(), (char *)src1_app.get_native_addr(), 4), 0); EXPECT_EQ(CALL_FUNC(strncasecmp, (char *)src1_app.get_native_addr(), (char *)src3_app.get_native_addr(), strlen(src1)), 0); } TEST_F(LibcBuiltinTest, strspn) { const char *src1 = "Hello world!"; const char *src2 = "abcd"; const char *src3 = "l"; const char *src4 = "Hell"; const char *src5 = "Helo"; AppData src1_app{ dummy_exec_env.get(), src1 }; AppData src2_app{ dummy_exec_env.get(), src2 }; AppData src3_app{ dummy_exec_env.get(), src3 }; AppData src4_app{ dummy_exec_env.get(), src4 }; AppData src5_app{ dummy_exec_env.get(), src5 }; EXPECT_EQ(CALL_FUNC(strspn, (char *)src1_app.get_native_addr(), (char *)src2_app.get_native_addr()), 0); EXPECT_EQ(CALL_FUNC(strspn, (char *)src1_app.get_native_addr(), (char *)src3_app.get_native_addr()), 0); EXPECT_EQ(CALL_FUNC(strspn, (char *)src1_app.get_native_addr(), (char *)src4_app.get_native_addr()), 4); EXPECT_EQ(CALL_FUNC(strspn, (char *)src1_app.get_native_addr(), (char *)src5_app.get_native_addr()), 5); } TEST_F(LibcBuiltinTest, strcspn) { const char *src1 = "Hello world!"; const char *src2 = ".?"; const char *src3 = "llo"; const char *src4 = "http://www.baidu.com/"; const char *src5 = "?.,:\"\'-!"; AppData src1_app{ dummy_exec_env.get(), src1 }; AppData src2_app{ dummy_exec_env.get(), src2 }; AppData src3_app{ dummy_exec_env.get(), src3 }; AppData src4_app{ dummy_exec_env.get(), src4 }; AppData src5_app{ dummy_exec_env.get(), src5 }; EXPECT_EQ(CALL_FUNC(strcspn, (char *)src1_app.get_native_addr(), (char *)src2_app.get_native_addr()), 12); EXPECT_EQ(CALL_FUNC(strcspn, (char *)src1_app.get_native_addr(), (char *)src3_app.get_native_addr()), 2); EXPECT_EQ(CALL_FUNC(strcspn, (char *)src4_app.get_native_addr(), (char *)src5_app.get_native_addr()), 4); } TEST_F(LibcBuiltinTest, strstr) { const char *src1 = "Hello world!"; const char *src2 = "abcd"; const char *src3 = "Hello"; const char *src4 = "H"; const char *src5 = "llo"; AppData src1_app{ dummy_exec_env.get(), src1 }; AppData src2_app{ dummy_exec_env.get(), src2 }; AppData src3_app{ dummy_exec_env.get(), src3 }; AppData src4_app{ dummy_exec_env.get(), src4 }; AppData src5_app{ dummy_exec_env.get(), src5 }; EXPECT_EQ(CALL_FUNC(strstr, (char *)src1_app.get_native_addr(), (char *)src2_app.get_native_addr()), 0); EXPECT_EQ(CALL_FUNC(strstr, (char *)src3_app.get_native_addr(), (char *)src1_app.get_native_addr()), 0); EXPECT_GT(CALL_FUNC(strstr, (char *)src1_app.get_native_addr(), (char *)src4_app.get_native_addr()), 0); EXPECT_GT(CALL_FUNC(strstr, (char *)src1_app.get_native_addr(), (char *)src5_app.get_native_addr()), 0); } TEST_F(LibcBuiltinTest, isupper) { EXPECT_FALSE(CALL_FUNC(isupper, 'a')); EXPECT_FALSE(CALL_FUNC(isupper, 97)); EXPECT_FALSE(CALL_FUNC(isupper, '0')); EXPECT_FALSE(CALL_FUNC(isupper, '.')); EXPECT_TRUE(CALL_FUNC(isupper, 'A')); EXPECT_TRUE(CALL_FUNC(isupper, 65)); } TEST_F(LibcBuiltinTest, isalpha) { EXPECT_FALSE(CALL_FUNC(isalpha, '0')); EXPECT_FALSE(CALL_FUNC(isalpha, 0)); EXPECT_FALSE(CALL_FUNC(isalpha, '?')); EXPECT_TRUE(CALL_FUNC(isalpha, 'A')); EXPECT_TRUE(CALL_FUNC(isalpha, 'a')); } TEST_F(LibcBuiltinTest, isspace) { EXPECT_FALSE(CALL_FUNC(isspace, '0')); EXPECT_FALSE(CALL_FUNC(isspace, 0)); EXPECT_FALSE(CALL_FUNC(isspace, '?')); EXPECT_TRUE(CALL_FUNC(isspace, ' ')); EXPECT_TRUE(CALL_FUNC(isspace, '\t')); EXPECT_TRUE(CALL_FUNC(isspace, '\n')); EXPECT_TRUE(CALL_FUNC(isspace, '\v')); EXPECT_TRUE(CALL_FUNC(isspace, '\f')); EXPECT_TRUE(CALL_FUNC(isspace, '\r')); } TEST_F(LibcBuiltinTest, isgraph) { /* ASCII 0x00-0x20 */ EXPECT_FALSE(CALL_FUNC(isgraph, 0x00)); EXPECT_FALSE(CALL_FUNC(isgraph, 0x20)); /* ASCII 0x7F */ EXPECT_FALSE(CALL_FUNC(isgraph, 0x7F)); EXPECT_FALSE(CALL_FUNC(isgraph, 0x80)); /* ASCII 0x21-0x7E */ EXPECT_TRUE(CALL_FUNC(isgraph, 0x21)); EXPECT_TRUE(CALL_FUNC(isgraph, 0x7E)); } TEST_F(LibcBuiltinTest, isprint) { /* ASCII 0x00-0x1F */ EXPECT_FALSE(CALL_FUNC(isprint, 0x00)); EXPECT_FALSE(CALL_FUNC(isprint, 0x1F)); /* ASCII 0x7F */ EXPECT_FALSE(CALL_FUNC(isprint, 0x7F)); EXPECT_FALSE(CALL_FUNC(isprint, 0x80)); /* ASCII 0x20-0x7E */ EXPECT_TRUE(CALL_FUNC(isprint, 0x20)); EXPECT_TRUE(CALL_FUNC(isprint, 0x7E)); } TEST_F(LibcBuiltinTest, isdigit) { /* ASCII 0x00-0x2F */ EXPECT_FALSE(CALL_FUNC(isdigit, 0x00)); EXPECT_FALSE(CALL_FUNC(isdigit, 0x2F)); /* ASCII 0x3A-0x7F */ EXPECT_FALSE(CALL_FUNC(isdigit, 0x3A)); EXPECT_FALSE(CALL_FUNC(isdigit, 0x7F)); /* ASCII 0x30-0x39 */ EXPECT_TRUE(CALL_FUNC(isdigit, 0x30)); EXPECT_TRUE(CALL_FUNC(isdigit, 0x39)); } TEST_F(LibcBuiltinTest, isxdigit) { char str[] = "-FFEE"; char str1[] = "FFEE"; EXPECT_FALSE(CALL_FUNC(isxdigit, str[0])); EXPECT_TRUE(CALL_FUNC(isxdigit, str1[0])); /* ASCII 0x00-0x2F */ EXPECT_FALSE(CALL_FUNC(isxdigit, 0x00)); EXPECT_FALSE(CALL_FUNC(isxdigit, 0x2F)); /* ASCII 0x3A-0x40 */ EXPECT_FALSE(CALL_FUNC(isxdigit, 0x3A)); EXPECT_FALSE(CALL_FUNC(isxdigit, 0x40)); /* ASCII 0x49-0x60 */ EXPECT_FALSE(CALL_FUNC(isxdigit, 0x49)); EXPECT_FALSE(CALL_FUNC(isxdigit, 0x60)); /* ASCII 0x67-0x7F */ EXPECT_FALSE(CALL_FUNC(isxdigit, 0x67)); EXPECT_FALSE(CALL_FUNC(isxdigit, 0x7F)); /* ASCII 0x30-0x39 */ EXPECT_TRUE(CALL_FUNC(isxdigit, 0x30)); EXPECT_TRUE(CALL_FUNC(isxdigit, 0x39)); /* ASCII 0x41-0x46 */ EXPECT_TRUE(CALL_FUNC(isxdigit, 0x41)); EXPECT_TRUE(CALL_FUNC(isxdigit, 0x46)); /* ASCII 0x61-0x66 */ EXPECT_TRUE(CALL_FUNC(isxdigit, 0x61)); EXPECT_TRUE(CALL_FUNC(isxdigit, 0x66)); } TEST_F(LibcBuiltinTest, tolower) { char src[] = "aBcDeFgH12345;!#$"; char dest[sizeof(src)]; int i; for (i = 0; i < sizeof(src); i++) { dest[i] = CALL_FUNC(tolower, (src[i])); } EXPECT_STREQ(dest, "abcdefgh12345;!#$"); } TEST_F(LibcBuiltinTest, toupper) { char src[] = "aBcDeFgH12345;!#$"; char dest[sizeof(src)]; int i; for (i = 0; i < sizeof(src); i++) { dest[i] = CALL_FUNC(toupper, (src[i])); } EXPECT_STREQ(dest, "ABCDEFGH12345;!#$"); } TEST_F(LibcBuiltinTest, isalnum) { char src[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678" "9!\"#$%&'()*+,-./:;<=>?@[^_'{|}~"; int i; int isalnum_cnt = 0; for (i = 0; i < sizeof(src); i++) { if (CALL_FUNC(isalnum, (src[i]))) isalnum_cnt++; } EXPECT_EQ(isalnum_cnt, 62); } TEST_F(LibcBuiltinTest, emscripten_memcpy_big) { const char *src = "Hell World"; char *dest; AppData src_app{ dummy_exec_env.get(), src }; AppData dest_app{ dummy_exec_env.get(), dest }; /* exception */ EXPECT_EQ(CALL_FUNC(emscripten_memcpy_big, (void *)-1, src_app.get_native_addr(), 0), 0); CALL_FUNC(emscripten_memcpy_big, dest_app.get_native_addr(), src_app.get_native_addr(), strlen(src)); EXPECT_EQ(CALL_FUNC(memcmp, dest_app.get_native_addr(), src_app.get_native_addr(), strlen(src)), 0); } TEST_F(LibcBuiltinTest, abort) { CALL_FUNC(abort, 33); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: env.abort(33)"); dummy_exec_env.clear_exception(); } TEST_F(LibcBuiltinTest, abortStackOverflow) { CALL_FUNC(abortStackOverflow, 33); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: env.abortStackOverflow(33)"); dummy_exec_env.clear_exception(); } TEST_F(LibcBuiltinTest, nullFunc_X) { CALL_FUNC(nullFunc_X, 33); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: env.nullFunc_X(33)"); dummy_exec_env.clear_exception(); } TEST_F(LibcBuiltinTest, __cxa_allocate_exception) { EXPECT_NE(CALL_FUNC(__cxa_allocate_exception, 0x0), 0x0); EXPECT_EQ(CALL_FUNC(__cxa_allocate_exception, 0xFFFF), 0x0); } TEST_F(LibcBuiltinTest, __cxa_begin_catch) { /* 无函数原型 */ } TEST_F(LibcBuiltinTest, __cxa_throw) { void *excepton; void *tinfo; CALL_FUNC(__cxa_throw, excepton, tinfo, 1); EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: exception thrown by stdc++"); dummy_exec_env.clear_exception(); } struct timespec_app app; TEST_F(LibcBuiltinTest, clock_gettime) { struct timespec_app *tsapp; tsapp = &app; AppMemory tsapp_app{ dummy_exec_env.get(), sizeof(struct timespec_app) }; /* exception */ EXPECT_EQ(CALL_FUNC(clock_gettime, 0, (struct timespec_app *)-1), -1); EXPECT_EQ(CALL_FUNC(clock_gettime, 100, NULL), -1); EXPECT_EQ(CALL_FUNC(clock_gettime, 100, 0), -1); EXPECT_EQ(CALL_FUNC(clock_gettime, 10, (struct timespec_app *)tsapp_app.get_native_addr()), 0); } TEST_F(LibcBuiltinTest, clock) { EXPECT_GE(CALL_FUNC(clock), 0); } WASMGlobalImport glb; TEST_F(LibcBuiltinTest, wasm_native_lookup_libc_builtin_global) { const char *module_name = "module name"; const char *global_name = "global name"; const char *module_name1 = "global"; const char *global_name1 = "NaN"; const char *global_name2 = "Infinity"; WASMGlobalImport *global = &glb; EXPECT_FALSE( wasm_native_lookup_libc_builtin_global(NULL, global_name, global)); EXPECT_FALSE( wasm_native_lookup_libc_builtin_global(module_name, NULL, global)); EXPECT_FALSE( wasm_native_lookup_libc_builtin_global(module_name, global_name, NULL)); EXPECT_FALSE(wasm_native_lookup_libc_builtin_global(module_name, global_name, global)); EXPECT_FALSE(wasm_native_lookup_libc_builtin_global(module_name, global_name1, global)); EXPECT_TRUE(wasm_native_lookup_libc_builtin_global(module_name1, global_name1, global)); EXPECT_TRUE(wasm_native_lookup_libc_builtin_global(module_name1, global_name2, global)); }