Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix quadratic runtime for duplicate export name detection #3861

Merged
merged 1 commit into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 50 additions & 11 deletions core/iwasm/aot/aot_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
*/

#include "aot_runtime.h"
#include "bh_common.h"
#include "bh_log.h"
#include "aot_reloc.h"
#include "bh_platform.h"
#include "../common/wasm_runtime_common.h"
#include "../common/wasm_native.h"
#include "../common/wasm_loader_common.h"
Expand Down Expand Up @@ -2753,14 +2752,56 @@ destroy_exports(AOTExport *exports)
wasm_runtime_free(exports);
}

static int
cmp_export_name(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}

static bool
check_duplicate_exports(AOTModule *module, char *error_buf,
uint32 error_buf_size)
{
uint32 i;
bool result = false;
char *names_buf[32], **names = names_buf;
if (module->export_count > 32) {
names = loader_malloc(module->export_count * sizeof(char *), error_buf,
error_buf_size);
if (!names) {
return result;
}
}

for (i = 0; i < module->export_count; i++) {
names[i] = module->exports[i].name;
}

qsort(names, module->export_count, sizeof(char *), cmp_export_name);

for (i = 1; i < module->export_count; i++) {
if (!strcmp(names[i], names[i - 1])) {
set_error_buf(error_buf, error_buf_size, "duplicate export name");
goto cleanup;
}
}

result = true;
cleanup:
if (module->export_count > 32) {
wasm_runtime_free(names);
}
return result;
}

static bool
load_exports(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
bool is_load_from_file_buf, char *error_buf, uint32 error_buf_size)
{
const uint8 *buf = *p_buf;
AOTExport *exports;
uint64 size;
uint32 i, j;
uint32 i;

/* Allocate memory */
size = sizeof(AOTExport) * (uint64)module->export_count;
Expand All @@ -2775,14 +2816,6 @@ load_exports(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
read_uint8(buf, buf_end, exports[i].kind);
read_string(buf, buf_end, exports[i].name);

for (j = 0; j < i; j++) {
if (!strcmp(exports[i].name, exports[j].name)) {
set_error_buf(error_buf, error_buf_size,
"duplicate export name");
return false;
}
}

/* Check export kind and index */
switch (exports[i].kind) {
case EXPORT_KIND_FUNC:
Expand Down Expand Up @@ -2830,6 +2863,12 @@ load_exports(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
}
}

if (module->export_count > 0) {
if (!check_duplicate_exports(module, error_buf, error_buf_size)) {
return false;
}
}

*p_buf = buf;
return true;
fail:
Expand Down
62 changes: 49 additions & 13 deletions core/iwasm/interpreter/wasm_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
*/

#include "wasm_loader.h"
#include "bh_common.h"
#include "bh_log.h"
#include "bh_platform.h"
#include "wasm.h"
#include "wasm_opcode.h"
#include "wasm_runtime.h"
Expand Down Expand Up @@ -3184,6 +3183,12 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
return false;
}

static int
cmp_export_name(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}

static bool
load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
bool is_load_from_file_buf, bool no_resolve,
Expand Down Expand Up @@ -4054,17 +4059,53 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
return false;
}

static bool
check_duplicate_exports(WASMModule *module, char *error_buf,
uint32 error_buf_size)
{
uint32 i;
bool result = false;
char *names_buf[32], **names = names_buf;

if (module->export_count > 32) {
names = loader_malloc(module->export_count * sizeof(char *), error_buf,
error_buf_size);
if (!names) {
return result;
}
}

for (i = 0; i < module->export_count; i++) {
names[i] = module->exports[i].name;
}

qsort(names, module->export_count, sizeof(char *), cmp_export_name);

for (i = 1; i < module->export_count; i++) {
if (!strcmp(names[i], names[i - 1])) {
set_error_buf(error_buf, error_buf_size, "duplicate export name");
goto cleanup;
}
}
wenyongh marked this conversation as resolved.
Show resolved Hide resolved

result = true;
cleanup:
if (module->export_count > 32) {
wasm_runtime_free(names);
}
return result;
}

static bool
load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
bool is_load_from_file_buf, char *error_buf,
uint32 error_buf_size)
{
const uint8 *p = buf, *p_end = buf_end;
uint32 export_count, i, j, index;
uint32 export_count, i, index;
uint64 total_size;
uint32 str_len;
WASMExport *export;
const char *name;

read_leb_uint32(p, p_end, export_count);

Expand All @@ -4090,15 +4131,6 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
read_leb_uint32(p, p_end, str_len);
CHECK_BUF(p, p_end, str_len);

for (j = 0; j < i; j++) {
name = module->exports[j].name;
if (strlen(name) == str_len && memcmp(name, p, str_len) == 0) {
set_error_buf(error_buf, error_buf_size,
"duplicate export name");
return false;
}
}

if (!(export->name = wasm_const_str_list_insert(
p, str_len, module, is_load_from_file_buf, error_buf,
error_buf_size))) {
Expand Down Expand Up @@ -4171,6 +4203,10 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
return false;
}
}

if (!check_duplicate_exports(module, error_buf, error_buf_size)) {
return false;
}
}
wenyongh marked this conversation as resolved.
Show resolved Hide resolved

if (p != p_end) {
Expand Down
Loading