Split runtime abort/asserts and app abort/assert. Always log and abort normally from native code. Display a dialog and exit silently when aborting/asserting from wasm code or bindings bound checks

This commit is contained in:
martinfouilleul 2023-10-12 20:17:22 +02:00
parent 82e4d0e08b
commit dbc0c0e124
7 changed files with 112 additions and 56 deletions

View File

@ -135,8 +135,8 @@ def bindgen(apiName, spec, **kwargs):
s += retTypeCName + '* __retPtr = (' + retTypeCName + '*)((char*)_mem + *(i32*)&_sp[0]);\n' s += retTypeCName + '* __retPtr = (' + retTypeCName + '*)((char*)_mem + *(i32*)&_sp[0]);\n'
s += '\t{\n' s += '\t{\n'
s += '\t\tOC_ASSERT(((char*)__retPtr >= (char*)_mem) && (((char*)__retPtr - (char*)_mem) < m3_GetMemorySize(runtime)), "return pointer is out of bounds");\n' s += '\t\tOC_ASSERT_DIALOG(((char*)__retPtr >= (char*)_mem) && (((char*)__retPtr - (char*)_mem) < m3_GetMemorySize(runtime)), "return pointer is out of bounds");\n'
s += '\t\tOC_ASSERT((char*)__retPtr + sizeof(' + retTypeCName + ') <= ((char*)_mem + m3_GetMemorySize(runtime)), "return pointer is out of bounds");\n' s += '\t\tOC_ASSERT_DIALOG((char*)__retPtr + sizeof(' + retTypeCName + ') <= ((char*)_mem + m3_GetMemorySize(runtime)), "return pointer is out of bounds");\n'
s += '\t}\n' s += '\t}\n'
for argIndex, arg in enumerate(decl['args']): for argIndex, arg in enumerate(decl['args']):
@ -178,8 +178,8 @@ def bindgen(apiName, spec, **kwargs):
printError("binding '" + name + "' missing pointer length decoration for param '" + argName + "'") printError("binding '" + name + "' missing pointer length decoration for param '" + argName + "'")
else: else:
s += '\t{\n' s += '\t{\n'
s += '\t\tOC_ASSERT(((char*)'+ argName + ' >= (char*)_mem) && (((char*)'+ argName +' - (char*)_mem) < m3_GetMemorySize(runtime)), "parameter \''+argName+'\' is out of bounds");\n' s += '\t\tOC_ASSERT_DIALOG(((char*)'+ argName + ' >= (char*)_mem) && (((char*)'+ argName +' - (char*)_mem) < m3_GetMemorySize(runtime)), "parameter \''+argName+'\' is out of bounds");\n'
s += '\t\tOC_ASSERT((char*)' + argName + ' + ' s += '\t\tOC_ASSERT_DIALOG((char*)' + argName + ' + '
proc = argLen.get('proc') proc = argLen.get('proc')
if proc != None: if proc != None:

View File

@ -7,7 +7,8 @@
**************************************************************************/ **************************************************************************/
#include <stdio.h> #include <stdio.h>
#include "app/app.h" #include "util/memory.h"
#include "util/strings.h"
#include "platform_debug.c" #include "platform_debug.c"
//---------------------------------------------------------------- //----------------------------------------------------------------
// Logging // Logging
@ -102,14 +103,7 @@ _Noreturn void oc_abort_ext(const char* file, const char* function, int line, co
note.ptr); note.ptr);
oc_log_error(msg.ptr); oc_log_error(msg.ptr);
abort();
oc_str8_list options = { 0 };
oc_str8_list_push(scratch.arena, &options, OC_STR8("OK"));
oc_alert_popup(OC_STR8("Fatal Error"), msg, options);
//TODO: could terminate more gracefully?
exit(-1);
} }
_Noreturn void oc_assert_fail(const char* file, const char* function, int line, const char* src, const char* fmt, ...) _Noreturn void oc_assert_fail(const char* file, const char* function, int line, const char* src, const char* fmt, ...)
@ -130,12 +124,5 @@ _Noreturn void oc_assert_fail(const char* file, const char* function, int line,
oc_str8_ip(note)); oc_str8_ip(note));
oc_log_error(msg.ptr); oc_log_error(msg.ptr);
abort();
oc_str8_list options = { 0 };
oc_str8_list_push(scratch.arena, &options, OC_STR8("OK"));
oc_alert_popup(OC_STR8("Assertion Failed"), msg, options);
//TODO: could terminate more gracefully?
exit(-1);
} }

View File

@ -5,6 +5,7 @@
* See LICENSE.txt for licensing information * See LICENSE.txt for licensing information
* *
**************************************************************************/ **************************************************************************/
#include <stdarg.h>
#include "platform_debug.h" #include "platform_debug.h"
typedef struct oc_log_config typedef struct oc_log_config

View File

@ -95,20 +95,6 @@ u64 orca_check_cstring(IM3Runtime runtime, const char* ptr)
return (len + 1); //include null-terminator return (len + 1); //include null-terminator
} }
void orca_wasm3_abort(IM3Runtime runtime, M3Result res, const char* file, const char* function, int line, const char* msg)
{
M3ErrorInfo errInfo = { 0 };
m3_GetErrorInfo(runtime, &errInfo);
if(errInfo.message && res == errInfo.result)
{
oc_abort_ext(file, function, line, "%s: %s (%s)", msg, res, errInfo.message);
}
else
{
oc_abort_ext(file, function, line, "%s: %s", msg, res);
}
}
void oc_bridge_window_set_title(oc_wasm_str8 title) void oc_bridge_window_set_title(oc_wasm_str8 title)
{ {
oc_str8 nativeTitle = oc_wasm_str8_to_native(title); oc_str8 nativeTitle = oc_wasm_str8_to_native(title);
@ -133,6 +119,80 @@ void oc_bridge_clipboard_set_string(oc_wasm_str8 value)
oc_runtime_clipboard_set_string(&__orcaApp.clipboard, value); oc_runtime_clipboard_set_string(&__orcaApp.clipboard, value);
} }
void oc_assert_fail_dialog(const char* file,
const char* function,
int line,
const char* test,
const char* fmt,
...)
{
oc_arena_scope scratch = oc_scratch_begin();
va_list ap;
va_start(ap, fmt);
oc_str8 note = oc_str8_pushfv(scratch.arena, fmt, ap);
va_end(ap);
oc_str8 msg = oc_str8_pushf(scratch.arena,
"Assertion failed in function %s() in file \"%s\", line %i:\n%s\nNote: %.*s\n",
function,
file,
line,
test,
oc_str8_ip(note));
oc_log_error(msg.ptr);
oc_str8_list options = { 0 };
oc_str8_list_push(scratch.arena, &options, OC_STR8("OK"));
oc_alert_popup(OC_STR8("Assertion Failed"), msg, options);
exit(-1);
oc_scratch_end(scratch);
}
void oc_abort_ext_dialog(const char* file, const char* function, int line, const char* fmt, ...)
{
oc_arena_scope scratch = oc_scratch_begin();
va_list ap;
va_start(ap, fmt);
oc_str8 note = oc_str8_pushfv(scratch.arena, fmt, ap);
va_end(ap);
oc_str8 msg = oc_str8_pushf(scratch.arena,
"Fatal error in function %s() in file \"%s\", line %i:\n%.*s\n",
function,
file,
line,
oc_str8_ip(note));
oc_log_error(msg.ptr);
oc_str8_list options = { 0 };
oc_str8_list_push(scratch.arena, &options, OC_STR8("OK"));
oc_alert_popup(OC_STR8("Fatal Error"), msg, options);
exit(-1);
oc_scratch_end(scratch);
}
void oc_wasm3_trap(IM3Runtime runtime, M3Result res, const char* file, const char* function, int line, const char* msg)
{
M3ErrorInfo errInfo = { 0 };
m3_GetErrorInfo(runtime, &errInfo);
if(errInfo.message && res == errInfo.result)
{
oc_abort_ext_dialog(file, function, line, "%s: %s (%s)", msg, res, errInfo.message);
}
else
{
oc_abort_ext_dialog(file, function, line, "%s: %s", msg, res);
}
}
void oc_bridge_log(oc_log_level level, void oc_bridge_log(oc_log_level level,
int functionLen, int functionLen,
char* function, char* function,
@ -441,13 +501,13 @@ i32 orca_runloop(void* user)
M3Result res = m3_ParseModule(app->env.m3Env, &app->env.m3Module, (u8*)app->env.wasmBytecode.ptr, app->env.wasmBytecode.len); M3Result res = m3_ParseModule(app->env.m3Env, &app->env.m3Module, (u8*)app->env.wasmBytecode.ptr, app->env.wasmBytecode.len);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't parse its web assembly module"); OC_WASM3_TRAP(app->env.m3Runtime, res, "The application couldn't parse its web assembly module");
} }
res = m3_LoadModule(app->env.m3Runtime, app->env.m3Module); res = m3_LoadModule(app->env.m3Runtime, app->env.m3Module);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't load its web assembly module into the runtime"); OC_WASM3_TRAP(app->env.m3Runtime, res, "The application couldn't load its web assembly module into the runtime");
} }
m3_SetModuleName(app->env.m3Module, bundleNameCString); m3_SetModuleName(app->env.m3Module, bundleNameCString);
@ -472,7 +532,7 @@ i32 orca_runloop(void* user)
res = m3_CompileModule(app->env.m3Module); res = m3_CompileModule(app->env.m3Module);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't compile its web assembly module"); OC_WASM3_TRAP(app->env.m3Runtime, res, "The application couldn't compile its web assembly module");
} }
//NOTE: Find and type check event handlers. //NOTE: Find and type check event handlers.
@ -558,7 +618,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_ON_INIT], 0, 0); M3Result res = m3_Call(exports[OC_EXPORT_ON_INIT], 0, 0);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
@ -571,7 +631,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_FRAME_RESIZE], 2, args); M3Result res = m3_Call(exports[OC_EXPORT_FRAME_RESIZE], 2, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
@ -616,7 +676,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_RAW_EVENT], 1, args); M3Result res = m3_Call(exports[OC_EXPORT_RAW_EVENT], 1, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
#else #else
oc_log_error("oc_on_raw_event() is not supported on big endian platforms"); oc_log_error("oc_on_raw_event() is not supported on big endian platforms");
@ -647,7 +707,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_FRAME_RESIZE], 2, args); M3Result res = m3_Call(exports[OC_EXPORT_FRAME_RESIZE], 2, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
} }
@ -664,7 +724,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_DOWN], 1, args); M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_DOWN], 1, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
} }
@ -677,7 +737,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_UP], 1, args); M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_UP], 1, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
} }
@ -692,7 +752,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_WHEEL], 2, args); M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_WHEEL], 2, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
} }
@ -706,7 +766,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_MOVE], 4, args); M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_MOVE], 4, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
} }
@ -729,7 +789,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_KEY_DOWN], 2, args); M3Result res = m3_Call(exports[OC_EXPORT_KEY_DOWN], 2, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
} }
@ -741,7 +801,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_KEY_UP], 2, args); M3Result res = m3_Call(exports[OC_EXPORT_KEY_UP], 2, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
} }
@ -760,7 +820,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_FRAME_REFRESH], 0, 0); M3Result res = m3_Call(exports[OC_EXPORT_FRAME_REFRESH], 0, 0);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }
@ -923,7 +983,7 @@ i32 orca_runloop(void* user)
M3Result res = m3_Call(exports[OC_EXPORT_TERMINATE], 0, 0); M3Result res = m3_Call(exports[OC_EXPORT_TERMINATE], 0, 0);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error");
} }
} }

View File

@ -130,7 +130,15 @@ oc_runtime* oc_runtime_get(void);
oc_wasm_env* oc_runtime_get_env(void); oc_wasm_env* oc_runtime_get_env(void);
oc_str8 oc_runtime_get_wasm_memory(void); oc_str8 oc_runtime_get_wasm_memory(void);
void orca_wasm3_abort(IM3Runtime runtime, M3Result res, const char* file, const char* function, int line, const char* msg); void oc_abort_ext_dialog(const char* file, const char* function, int line, const char* fmt, ...);
#define ORCA_WASM3_ABORT(runtime, err, msg) orca_wasm3_abort(runtime, err, __FILE__, __FUNCTION__, __LINE__, msg) void oc_assert_fail_dialog(const char* file, const char* function, int line, const char* test, const char* fmt, ...);
#define _OC_ASSERT_DIALOG_(test, fmt, ...) \
((test) || (oc_assert_fail_dialog(__FILE__, __FUNCTION__, __LINE__, #test, fmt, ##__VA_ARGS__), 0))
#define OC_ASSERT_DIALOG(test, ...) \
_OC_ASSERT_DIALOG_(test, OC_VA_NOPT("", ##__VA_ARGS__) OC_ARG1(__VA_ARGS__) OC_VA_COMMA_TAIL(__VA_ARGS__))
void oc_wasm3_trap(IM3Runtime runtime, M3Result res, const char* file, const char* function, int line, const char* msg);
#define OC_WASM3_TRAP(runtime, err, msg) oc_wasm3_trap(runtime, err, __FILE__, __FUNCTION__, __LINE__, msg)
#endif //__RUNTIME_H_ #endif //__RUNTIME_H_

View File

@ -151,13 +151,13 @@ oc_wasm_addr oc_wasm_arena_push(oc_wasm_addr arena, u64 size)
M3Result res = m3_Call(env->exports[OC_EXPORT_ARENA_PUSH], 2, args); M3Result res = m3_Call(env->exports[OC_EXPORT_ARENA_PUSH], 2, args);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(env->m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(env->m3Runtime, res, "Runtime error");
} }
res = m3_GetResults(env->exports[OC_EXPORT_ARENA_PUSH], 1, retPointers); res = m3_GetResults(env->exports[OC_EXPORT_ARENA_PUSH], 1, retPointers);
if(res) if(res)
{ {
ORCA_WASM3_ABORT(env->m3Runtime, res, "Runtime error"); OC_WASM3_TRAP(env->m3Runtime, res, "Runtime error");
} }
return (retValues[0]); return (retValues[0]);

View File

@ -33,7 +33,7 @@
}, },
{ {
"name": "oc_bridge_assert_fail", "name": "oc_bridge_assert_fail",
"cname": "oc_assert_fail", "cname": "oc_assert_fail_dialog",
"ret": {"name": "void", "tag": "v"}, "ret": {"name": "void", "tag": "v"},
"args": [ {"name": "file", "args": [ {"name": "file",
"type": {"name": "const char*", "tag": "p"}, "type": {"name": "const char*", "tag": "p"},
@ -53,7 +53,7 @@
}, },
{ {
"name": "oc_bridge_abort_ext", "name": "oc_bridge_abort_ext",
"cname": "oc_abort_ext", "cname": "oc_abort_ext_dialog",
"ret": {"name": "void", "tag": "v"}, "ret": {"name": "void", "tag": "v"},
"args": [ {"name": "file", "args": [ {"name": "file",
"type": {"name": "const char*", "tag": "p"}, "type": {"name": "const char*", "tag": "p"},