Skip to content

Commit faddd97

Browse files
authored
Merge pull request #772 from wasmx/rich-error-reporting-simple
capi: Reporting error code and message
2 parents 2f102ae + a62544f commit faddd97

File tree

7 files changed

+495
-150
lines changed

7 files changed

+495
-150
lines changed

bindings/rust/src/lib.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@ use std::ptr::NonNull;
4242

4343
/// Parse and validate the input according to WebAssembly 1.0 rules. Returns true if the supplied input is valid.
4444
pub fn validate<T: AsRef<[u8]>>(input: T) -> bool {
45-
unsafe { sys::fizzy_validate(input.as_ref().as_ptr(), input.as_ref().len()) }
45+
unsafe {
46+
sys::fizzy_validate(
47+
input.as_ref().as_ptr(),
48+
input.as_ref().len(),
49+
std::ptr::null_mut(),
50+
)
51+
}
4652
}
4753

4854
/// A parsed and validated WebAssembly 1.0 module.
@@ -68,7 +74,13 @@ impl Clone for Module {
6874

6975
/// Parse and validate the input according to WebAssembly 1.0 rules.
7076
pub fn parse<T: AsRef<[u8]>>(input: &T) -> Result<Module, String> {
71-
let ptr = unsafe { sys::fizzy_parse(input.as_ref().as_ptr(), input.as_ref().len()) };
77+
let ptr = unsafe {
78+
sys::fizzy_parse(
79+
input.as_ref().as_ptr(),
80+
input.as_ref().len(),
81+
std::ptr::null_mut(),
82+
)
83+
};
7284
if ptr.is_null() {
7385
return Err("parsing failure".to_string());
7486
}
@@ -98,6 +110,7 @@ impl Module {
98110
std::ptr::null(),
99111
std::ptr::null(),
100112
0,
113+
std::ptr::null_mut(),
101114
)
102115
};
103116
// Forget Module (and avoid calling drop) because it has been consumed by instantiate (even if it failed).

include/fizzy/fizzy.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,25 @@
1414
extern "C" {
1515
#endif
1616

17+
/// Error codes.
18+
typedef enum FizzyErrorCode
19+
{
20+
FIZZY_SUCCESS = 0,
21+
FIZZY_ERROR_MALFORMED_MODULE,
22+
FIZZY_ERROR_INVALID_MODULE,
23+
FIZZY_ERROR_INSTANTIATION_FAILED,
24+
FIZZY_ERROR_OTHER
25+
} FizzyErrorCode;
26+
27+
/// Error information.
28+
typedef struct FizzyError
29+
{
30+
/// Error code.
31+
FizzyErrorCode code;
32+
/// NULL-terminated error message.
33+
char message[256];
34+
} FizzyError;
35+
1736
/// The opaque data type representing a module.
1837
typedef struct FizzyModule FizzyModule;
1938

@@ -221,15 +240,20 @@ typedef struct FizzyImportedGlobal
221240
///
222241
/// @param wasm_binary Pointer to module binary data.
223242
/// @param wasm_binary_size Size of the module binary data.
243+
/// @param error Pointer to store detailed error information at. Can be NULL if error
244+
/// information is not required.
224245
/// @return true if module is valid, false otherwise.
225-
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size);
246+
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size, FizzyError* error);
226247

227248
/// Parse binary module.
228249
///
229250
/// @param wasm_binary Pointer to module binary data.
230251
/// @param wasm_binary_size Size of the module binary data.
252+
/// @param error Pointer to store detailed error information at. Can be NULL if error
253+
/// information is not required.
231254
/// @return non-NULL pointer to module in case of success, NULL otherwise.
232-
const FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size);
255+
const FizzyModule* fizzy_parse(
256+
const uint8_t* wasm_binary, size_t wasm_binary_size, FizzyError* error);
233257

234258
/// Free resources associated with the module.
235259
///
@@ -374,6 +398,8 @@ bool fizzy_module_has_start_function(const FizzyModule* module);
374398
/// @param imported_globals Pointer to the imported globals array. Can be NULL iff
375399
/// @p imported_globals_size equals 0.
376400
/// @param imported_globals_size Size of the imported global array. Can be zero.
401+
/// @param error Pointer to store detailed error information at. Can be NULL
402+
/// if error information is not required.
377403
/// @return non-NULL pointer to instance in case of success,
378404
/// NULL otherwise.
379405
///
@@ -391,7 +417,7 @@ bool fizzy_module_has_start_function(const FizzyModule* module);
391417
FizzyInstance* fizzy_instantiate(const FizzyModule* module,
392418
const FizzyExternalFunction* imported_functions, size_t imported_functions_size,
393419
const FizzyExternalTable* imported_table, const FizzyExternalMemory* imported_memory,
394-
const FizzyExternalGlobal* imported_globals, size_t imported_globals_size);
420+
const FizzyExternalGlobal* imported_globals, size_t imported_globals_size, FizzyError* error);
395421

396422
/// Instantiate a module resolving imported functions.
397423
///
@@ -415,6 +441,8 @@ FizzyInstance* fizzy_instantiate(const FizzyModule* module,
415441
/// @param imported_globals Pointer to the imported globals array. Can be NULL iff
416442
/// @p imported_globals_size equals 0.
417443
/// @param imported_globals_size Size of the imported global array. Can be zero.
444+
/// @param error Pointer to store detailed error information at. Can be NULL
445+
/// if error information is not required.
418446
/// @return non-NULL pointer to instance in case of success,
419447
/// NULL otherwise.
420448
///
@@ -436,7 +464,7 @@ FizzyInstance* fizzy_instantiate(const FizzyModule* module,
436464
FizzyInstance* fizzy_resolve_instantiate(const FizzyModule* module,
437465
const FizzyImportedFunction* imported_functions, size_t imported_functions_size,
438466
const FizzyExternalTable* imported_table, const FizzyExternalMemory* imported_memory,
439-
const FizzyImportedGlobal* imported_globals, size_t imported_globals_size);
467+
const FizzyImportedGlobal* imported_globals, size_t imported_globals_size, FizzyError* error);
440468

441469
/// Free resources associated with the instance.
442470
///

lib/fizzy/capi.cpp

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,78 @@
77
#include "instantiate.hpp"
88
#include "parser.hpp"
99
#include <fizzy/fizzy.h>
10+
#include <cstring>
1011
#include <memory>
1112

1213
namespace
1314
{
15+
inline void set_success(FizzyError* error) noexcept
16+
{
17+
if (error == nullptr)
18+
return;
19+
20+
error->code = FIZZY_SUCCESS;
21+
error->message[0] = '\0';
22+
}
23+
24+
// Copying a string into a fixed-size static buffer, guaranteed to not overrun it and to always end
25+
// the destination string with a null terminator. Inspired by strlcpy.
26+
template <size_t N>
27+
inline size_t truncating_strlcpy(char (&dest)[N], const char* src) noexcept
28+
{
29+
static_assert(N >= 4);
30+
31+
const auto src_len = strlen(src);
32+
const auto copy_len = std::min(src_len, N - 1);
33+
memcpy(dest, src, copy_len);
34+
if (copy_len < src_len)
35+
{
36+
dest[copy_len - 3] = '.';
37+
dest[copy_len - 2] = '.';
38+
dest[copy_len - 1] = '.';
39+
}
40+
dest[copy_len] = '\0';
41+
return copy_len;
42+
}
43+
44+
inline void set_error_code_and_message(
45+
FizzyErrorCode code, const char* message, FizzyError* error) noexcept
46+
{
47+
error->code = code;
48+
truncating_strlcpy(error->message, message);
49+
}
50+
51+
inline void set_error_from_current_exception(FizzyError* error) noexcept
52+
{
53+
if (error == nullptr)
54+
return;
55+
56+
try
57+
{
58+
throw;
59+
}
60+
catch (const fizzy::parser_error& e)
61+
{
62+
set_error_code_and_message(FIZZY_ERROR_MALFORMED_MODULE, e.what(), error);
63+
}
64+
catch (const fizzy::validation_error& e)
65+
{
66+
set_error_code_and_message(FIZZY_ERROR_INVALID_MODULE, e.what(), error);
67+
}
68+
catch (const fizzy::instantiate_error& e)
69+
{
70+
set_error_code_and_message(FIZZY_ERROR_INSTANTIATION_FAILED, e.what(), error);
71+
}
72+
catch (const std::exception& e)
73+
{
74+
set_error_code_and_message(FIZZY_ERROR_OTHER, e.what(), error);
75+
}
76+
catch (...)
77+
{
78+
set_error_code_and_message(FIZZY_ERROR_OTHER, "unknown error", error);
79+
}
80+
}
81+
1482
inline const FizzyModule* wrap(const fizzy::Module* module) noexcept
1583
{
1684
return reinterpret_cast<const FizzyModule*>(module);
@@ -360,28 +428,33 @@ inline FizzyExportDescription wrap(const fizzy::Export& exp) noexcept
360428
} // namespace
361429

362430
extern "C" {
363-
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size)
431+
bool fizzy_validate(const uint8_t* wasm_binary, size_t wasm_binary_size, FizzyError* error)
364432
{
365433
try
366434
{
367435
fizzy::parse({wasm_binary, wasm_binary_size});
436+
set_success(error);
368437
return true;
369438
}
370439
catch (...)
371440
{
441+
set_error_from_current_exception(error);
372442
return false;
373443
}
374444
}
375445

376-
const FizzyModule* fizzy_parse(const uint8_t* wasm_binary, size_t wasm_binary_size)
446+
const FizzyModule* fizzy_parse(
447+
const uint8_t* wasm_binary, size_t wasm_binary_size, FizzyError* error)
377448
{
378449
try
379450
{
380451
auto module = fizzy::parse({wasm_binary, wasm_binary_size});
452+
set_success(error);
381453
return wrap(module.release());
382454
}
383455
catch (...)
384456
{
457+
set_error_from_current_exception(error);
385458
return nullptr;
386459
}
387460
}
@@ -529,7 +602,7 @@ bool fizzy_module_has_start_function(const FizzyModule* module)
529602
FizzyInstance* fizzy_instantiate(const FizzyModule* module,
530603
const FizzyExternalFunction* imported_functions, size_t imported_functions_size,
531604
const FizzyExternalTable* imported_table, const FizzyExternalMemory* imported_memory,
532-
const FizzyExternalGlobal* imported_globals, size_t imported_globals_size)
605+
const FizzyExternalGlobal* imported_globals, size_t imported_globals_size, FizzyError* error)
533606
{
534607
try
535608
{
@@ -541,18 +614,20 @@ FizzyInstance* fizzy_instantiate(const FizzyModule* module,
541614
auto instance = fizzy::instantiate(std::unique_ptr<const fizzy::Module>(unwrap(module)),
542615
std::move(functions), std::move(table), std::move(memory), std::move(globals));
543616

617+
set_success(error);
544618
return wrap(instance.release());
545619
}
546620
catch (...)
547621
{
622+
set_error_from_current_exception(error);
548623
return nullptr;
549624
}
550625
}
551626

552627
FizzyInstance* fizzy_resolve_instantiate(const FizzyModule* c_module,
553628
const FizzyImportedFunction* c_imported_functions, size_t imported_functions_size,
554629
const FizzyExternalTable* imported_table, const FizzyExternalMemory* imported_memory,
555-
const FizzyImportedGlobal* c_imported_globals, size_t imported_globals_size)
630+
const FizzyImportedGlobal* c_imported_globals, size_t imported_globals_size, FizzyError* error)
556631
{
557632
try
558633
{
@@ -568,10 +643,12 @@ FizzyInstance* fizzy_resolve_instantiate(const FizzyModule* c_module,
568643
auto instance = fizzy::instantiate(std::move(module), std::move(resolved_imports),
569644
std::move(table), std::move(memory), std::move(resolved_globals));
570645

646+
set_success(error);
571647
return wrap(instance.release());
572648
}
573649
catch (...)
574650
{
651+
set_error_from_current_exception(error);
575652
return nullptr;
576653
}
577654
}

test/compilation/compilation_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ bool dummy(void);
88

99
bool dummy()
1010
{
11-
return fizzy_validate(NULL, 0);
11+
return fizzy_validate(NULL, 0, NULL);
1212
}

test/integration/cmake_package/use_fizzy/use_fizzy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66

77
int main()
88
{
9-
return fizzy_validate(nullptr, 0) ? 0 : 1;
9+
return fizzy_validate(nullptr, 0, nullptr) ? 0 : 1;
1010
}

0 commit comments

Comments
 (0)