88//! layout. Error messages are stored in a thread-local buffer accessible
99//! via `zwasm_last_error_message()`.
1010//!
11- //! Allocator strategy: Each CApiModule owns a GeneralPurposeAllocator,
12- //! heap-allocated via page_allocator so its address is stable. The GPA
13- //! provides the allocator for WasmModule and all its internal state .
11+ //! Allocator strategy: The C API uses libc malloc (c_allocator) as the
12+ //! default backing allocator for WasmModule and all its internal state.
13+ //! Custom allocators can be injected via zwasm_config_t .
1414
1515const std = @import ("std" );
1616const types = @import ("types.zig" );
@@ -97,20 +97,22 @@ const CApiConfig = struct {
9797pub const zwasm_config_t = CApiConfig ;
9898
9999// ============================================================
100- // Internal wrapper — GPA + WasmModule co-located
100+ // Internal wrapper — allocator + WasmModule co-located
101101// ============================================================
102102
103- const Gpa = std .heap .GeneralPurposeAllocator (.{});
103+ // Zig 0.15's GeneralPurposeAllocator crashes in Debug-mode shared
104+ // libraries on Linux x86_64 (PIC codegen issue, see GitHub #11).
105+ // The C API uses libc malloc (c_allocator) as the default backing
106+ // allocator, which is correct for a library loaded via dlopen/ctypes.
107+ // GPA is only used when running Zig tests (leak detection).
108+ const default_allocator = std .heap .c_allocator ;
104109
105- /// Internal wrapper owning both the GPA and WasmModule.
110+ /// Internal wrapper owning a WasmModule.
106111/// Heap-allocated via page_allocator for address stability.
107112///
108- /// When a custom allocator is injected via zwasm_config_t, gpa is unused
109- /// and the custom allocator handles all allocations. The `owns_gpa` flag
110- /// tracks whether we need to deinit gpa.
113+ /// When a custom allocator is injected via zwasm_config_t, that
114+ /// allocator is used instead of the default.
111115const CApiModule = struct {
112- gpa : Gpa ,
113- owns_gpa : bool ,
114116 module : * WasmModule ,
115117
116118 fn create (wasm_bytes : []const u8 , wasi : bool ) ! * CApiModule {
@@ -121,15 +123,7 @@ const CApiModule = struct {
121123 const self = try std .heap .page_allocator .create (CApiModule );
122124 errdefer std .heap .page_allocator .destroy (self );
123125
124- const allocator = if (custom_alloc ) | ca | blk : {
125- self .gpa = .{};
126- self .owns_gpa = false ;
127- break :blk ca ;
128- } else blk : {
129- self .gpa = .{};
130- self .owns_gpa = true ;
131- break :blk self .gpa .allocator ();
132- };
126+ const allocator = custom_alloc orelse default_allocator ;
133127
134128 self .module = if (wasi )
135129 try WasmModule .loadWasi (allocator , wasm_bytes )
@@ -146,15 +140,7 @@ const CApiModule = struct {
146140 const self = try std .heap .page_allocator .create (CApiModule );
147141 errdefer std .heap .page_allocator .destroy (self );
148142
149- const allocator = if (custom_alloc ) | ca | blk : {
150- self .gpa = .{};
151- self .owns_gpa = false ;
152- break :blk ca ;
153- } else blk : {
154- self .gpa = .{};
155- self .owns_gpa = true ;
156- break :blk self .gpa .allocator ();
157- };
143+ const allocator = custom_alloc orelse default_allocator ;
158144
159145 self .module = try WasmModule .loadWasiWithOptions (allocator , wasm_bytes , opts );
160146 return self ;
@@ -163,16 +149,12 @@ const CApiModule = struct {
163149 fn createWithImports (wasm_bytes : []const u8 , imports : []const types.ImportEntry ) ! * CApiModule {
164150 const self = try std .heap .page_allocator .create (CApiModule );
165151 errdefer std .heap .page_allocator .destroy (self );
166- self .gpa = .{};
167- self .owns_gpa = true ;
168- const allocator = self .gpa .allocator ();
169- self .module = try WasmModule .loadWithImports (allocator , wasm_bytes , imports );
152+ self .module = try WasmModule .loadWithImports (default_allocator , wasm_bytes , imports );
170153 return self ;
171154 }
172155
173156 fn destroy (self : * CApiModule ) void {
174157 self .module .deinit ();
175- if (self .owns_gpa ) _ = self .gpa .deinit ();
176158 std .heap .page_allocator .destroy (self );
177159 }
178160};
@@ -392,9 +374,7 @@ export fn zwasm_module_delete(module: *zwasm_module_t) void {
392374/// Returns true if valid, false if invalid or malformed.
393375export fn zwasm_module_validate (wasm_ptr : [* ]const u8 , len : usize ) bool {
394376 clearError ();
395- var gpa = Gpa {};
396- defer _ = gpa .deinit ();
397- const allocator = gpa .allocator ();
377+ const allocator = default_allocator ;
398378 const validate = types .runtime .validateModule ;
399379 var module = types .runtime .Module .init (allocator , wasm_ptr [0.. len ]);
400380 defer module .deinit ();
@@ -906,7 +886,7 @@ const MEMORY_WASM = "\x00\x61\x73\x6d\x01\x00\x00\x00" ++
906886 "\x01\x04\x01\x60\x00\x00 " ++ // type: () -> ()
907887 "\x03\x02\x01\x00 " ++ // func section
908888 "\x05\x03\x01\x00\x01 " ++ // memory: min=0, max=1
909- "\x07\x0d \x02\x01\x6d\x02\x00 " ++ // export "m" = memory 0
889+ "\x07\x09 \x02\x01\x6d\x02\x00 " ++ // export "m" = memory 0
910890 "\x01\x66\x00\x00 " ++ // export "f" = func 0
911891 "\x0a\x0b\x01\x09\x00\x41\x00\x41\x2a\x36\x02\x00\x0b " ; // code: i32.const 0, i32.const 42, i32.store, end
912892
0 commit comments