Bug Description
Memory leak detected in examples/04_smart_contracts when using ABI encoding functions. The leak occurs in the AbiType.toString() method which allocates memory for type strings but doesn't properly clean them up.
Error Output
error(gpa): memory address 0x105140000 leaked:
/Users/partha/.local/share/zigup/0.14.1/files/lib/std/mem/Allocator.zig:423:40: 0x104f756fb in dupe__anon_8621 (04_smart_contracts)
const new_buf = try allocator.alloc(T, m.len);
^
/Users/partha/zig/zigeth/src/abi/types.zig:110:43: 0x104ffa6ff in toString (04_smart_contracts)
.address => try allocator.dupe(u8, "address"),
^
Stack Trace
/Users/partha/zig/zigeth/src/abi/types.zig:110:43: in toString
.address => try allocator.dupe(u8, "address"),
^
/Users/partha/zig/zigeth/src/abi/types.zig:189:56: in getSignature
try sig.appendSlice(try param.type.toString(allocator));
^
/Users/partha/zig/zigeth/src/abi/types.zig:170:48: in getSelector
const signature = try self.getSignature(allocator);
^
/Users/partha/zig/zigeth/src/abi/encode.zig:115:46: in encodeFunctionCall
const selector = try function.getSelector(allocator);
^
/Users/partha/zig/zigeth/examples/04_smart_contracts.zig:73:58: in main
const encoded = try zigeth.abi.encodeFunctionCall(
Steps to Reproduce
-
Build examples with Zig's debug mode (includes GPA leak detection):
zig build -Dexamples examples
-
Run example 04:
./zig-out/examples/04_smart_contracts
-
Example runs successfully but reports memory leak at exit
Expected Behavior
Example should run without any memory leaks. All allocated memory should be properly freed.
Environment
- Zig Version: 0.14.1
- OS: macOS (darwin 23.6.0)
- Architecture: ARM64 (Apple Silicon)
Code Context
The leak is in src/abi/types.zig in the toString() method:
pub fn toString(self: AbiType, allocator: std.mem.Allocator) ![]u8 {
return switch (self) {
.uint256 => try allocator.dupe(u8, "uint256"),
.address => try allocator.dupe(u8, "address"), // <-- LEAK HERE
.bool_type => try allocator.dupe(u8, "bool"),
// ... more cases
};
}
This is called from getSignature():
pub fn getSignature(self: Function, allocator: std.mem.Allocator) ![]u8 {
// ...
for (self.inputs) |param| {
if (first) { first = false; } else { try sig.append(','); }
try sig.appendSlice(try param.type.toString(allocator)); // <-- Never freed!
}
// ...
}
Root Cause
The toString() method allocates memory for the type string, but the caller (getSignature()) appends it to an ArrayList and never frees the original allocation. The string is duplicated into the ArrayList, creating a leak.
Suggested Fix
Option 1: Use stack allocation for known strings
pub fn toString(self: AbiType, allocator: std.mem.Allocator) ![]u8 {
_ = allocator; // Don't allocate for static strings
return switch (self) {
.uint256 => "uint256",
.address => "address",
.bool_type => "bool",
// ... return const string literals
};
}
Then update callers to handle const strings (no need to free).
Option 2: Fix the caller to free
pub fn getSignature(self: Function, allocator: std.mem.Allocator) ![]u8 {
// ...
for (self.inputs) |param| {
if (first) { first = false; } else { try sig.append(','); }
const type_str = try param.type.toString(allocator);
defer allocator.free(type_str); // <-- Free after use
try sig.appendSlice(type_str);
}
// ...
}
Recommended: Option 1 is cleaner since these are constant string literals.
Impact
- Severity: Low - Example runs successfully, just leaks small amounts of memory
- Scope: Affects all code using
encodeFunctionCall() and ABI type signatures
- Performance: Minimal - only leaks a few bytes per function call
- User Impact: Only visible with leak detection enabled (debug builds)
Related Files
src/abi/types.zig - Contains the leaking toString() method
src/abi/encode.zig - Uses getSelector() which triggers the leak
examples/04_smart_contracts.zig - Example that demonstrates the leak
Testing
After fix, verify with:
zig build -Dexamples examples
./zig-out/examples/04_smart_contracts
# Should show no memory leaks
Additional Context
- Detected by Zig's GeneralPurposeAllocator leak detection
- Examples complete successfully despite the leak
- This is a pre-existing issue, not caused by the u256 migration
Bug Description
Memory leak detected in
examples/04_smart_contractswhen using ABI encoding functions. The leak occurs in theAbiType.toString()method which allocates memory for type strings but doesn't properly clean them up.Error Output
Stack Trace
Steps to Reproduce
Build examples with Zig's debug mode (includes GPA leak detection):
Run example 04:
Example runs successfully but reports memory leak at exit
Expected Behavior
Example should run without any memory leaks. All allocated memory should be properly freed.
Environment
Code Context
The leak is in
src/abi/types.zigin thetoString()method:This is called from
getSignature():Root Cause
The
toString()method allocates memory for the type string, but the caller (getSignature()) appends it to an ArrayList and never frees the original allocation. The string is duplicated into the ArrayList, creating a leak.Suggested Fix
Option 1: Use stack allocation for known strings
Then update callers to handle const strings (no need to free).
Option 2: Fix the caller to free
Recommended: Option 1 is cleaner since these are constant string literals.
Impact
encodeFunctionCall()and ABI type signaturesRelated Files
src/abi/types.zig- Contains the leakingtoString()methodsrc/abi/encode.zig- UsesgetSelector()which triggers the leakexamples/04_smart_contracts.zig- Example that demonstrates the leakTesting
After fix, verify with:
zig build -Dexamples examples ./zig-out/examples/04_smart_contracts # Should show no memory leaksAdditional Context