Skip to content

Commit db110f9

Browse files
authored
Fixes for fuzzing-discovered crashes (#17)
Fixes for fuzzing discovered crashes Signed-off-by: garyschulte <garyschulte@gmail.com>
1 parent baecc20 commit db110f9

File tree

4 files changed

+23
-25
lines changed

4 files changed

+23
-25
lines changed

src/interpreter/opcodes/environment.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ pub fn opCalldatacopy(ctx: *InstructionContext) void {
140140
return;
141141
};
142142

143-
// Dynamic: copy cost
144-
const num_words = (size_usize + 31) / 32;
143+
// Dynamic: copy cost — use divCeil to avoid (size + 31) overflow when size = maxInt(usize)
144+
const num_words = std.math.divCeil(usize, size_usize, 32) catch unreachable;
145145
const copy_cost: u64 = gas_costs.G_COPY * @as(u64, @intCast(num_words));
146146
if (!ctx.interpreter.gas.spend(copy_cost)) {
147147
ctx.interpreter.halt(.out_of_gas);
@@ -211,8 +211,8 @@ pub fn opCodecopy(ctx: *InstructionContext) void {
211211
return;
212212
};
213213

214-
// Dynamic: copy cost
215-
const num_words = (size_usize + 31) / 32;
214+
// Dynamic: copy cost — use divCeil to avoid (size + 31) overflow when size = maxInt(usize)
215+
const num_words = std.math.divCeil(usize, size_usize, 32) catch unreachable;
216216
const copy_cost: u64 = gas_costs.G_COPY * @as(u64, @intCast(num_words));
217217
if (!ctx.interpreter.gas.spend(copy_cost)) {
218218
ctx.interpreter.halt(.out_of_gas);
@@ -303,8 +303,8 @@ pub fn opReturndatacopy(ctx: *InstructionContext) void {
303303
return;
304304
};
305305

306-
// Dynamic: copy cost
307-
const num_words = (size_usize + 31) / 32;
306+
// Dynamic: copy cost — use divCeil to avoid (size + 31) overflow when size = maxInt(usize)
307+
const num_words = std.math.divCeil(usize, size_usize, 32) catch unreachable;
308308
const copy_cost: u64 = gas_costs.G_COPY * @as(u64, @intCast(num_words));
309309
if (!ctx.interpreter.gas.spend(copy_cost)) {
310310
ctx.interpreter.halt(.out_of_gas);

src/interpreter/opcodes/host_ops.zig

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ pub fn opExtcodecopy(ctx: *InstructionContext) void {
159159
}
160160
const mem_off_u: usize = @intCast(mem_off);
161161
const size_u: usize = @intCast(size);
162-
const num_words = (size_u + 31) / 32;
162+
const num_words = std.math.divCeil(usize, size_u, 32) catch unreachable;
163163
if (!ctx.interpreter.gas.spend(gas_costs.G_COPY * @as(u64, @intCast(num_words)))) {
164164
ctx.interpreter.halt(.out_of_gas);
165165
return;
@@ -199,8 +199,8 @@ pub fn opExtcodecopy(ctx: *InstructionContext) void {
199199
return;
200200
};
201201

202-
// Dynamic: copy cost
203-
const num_words = (size_u + 31) / 32;
202+
// Dynamic: copy cost — use divCeil to avoid (size + 31) overflow when size = maxInt(usize)
203+
const num_words = std.math.divCeil(usize, size_u, 32) catch unreachable;
204204
if (!ctx.interpreter.gas.spend(gas_costs.G_COPY * @as(u64, @intCast(num_words)))) {
205205
ctx.interpreter.halt(.out_of_gas);
206206
return;
@@ -489,9 +489,18 @@ pub fn makeLogFn(comptime n: u8) *const fn (ctx: *InstructionContext) void {
489489
const offset_u: usize = if (size_u == 0) 0 else @intCast(offset);
490490

491491
// Dynamic: data cost + topic cost
492-
const data_cost: u64 = gas_costs.G_LOGDATA * @as(u64, @intCast(size_u));
492+
// Use checked arithmetic: size_u can be maxInt(usize) on 64-bit systems,
493+
// making G_LOGDATA * size_u overflow a u64.
494+
const data_cost: u64 = std.math.mul(u64, gas_costs.G_LOGDATA, @as(u64, @intCast(size_u))) catch {
495+
ctx.interpreter.halt(.out_of_gas);
496+
return;
497+
};
493498
const topic_cost: u64 = gas_costs.G_LOGTOPIC * @as(u64, n);
494-
if (!ctx.interpreter.gas.spend(data_cost + topic_cost)) {
499+
const log_gas = std.math.add(u64, data_cost, topic_cost) catch {
500+
ctx.interpreter.halt(.out_of_gas);
501+
return;
502+
};
503+
if (!ctx.interpreter.gas.spend(log_gas)) {
495504
ctx.interpreter.halt(.out_of_gas);
496505
return;
497506
}

src/interpreter/opcodes/memory.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ pub fn opMstore8(ctx: *InstructionContext) void {
112112
const value = stack.peekUnsafe(1);
113113
stack.shrinkUnsafe(2);
114114

115-
if (offset > std.math.maxInt(usize)) {
115+
// Guard must use >= maxInt(usize) so that offset = maxInt(usize) doesn't slip through
116+
// and cause offset_usize + 1 to overflow in ReleaseSafe mode.
117+
if (offset >= std.math.maxInt(usize)) {
116118
ctx.interpreter.halt(.memory_limit_oog);
117119
return;
118120
}

src/spec_test/main.zig

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,24 +88,11 @@ pub fn main() !void {
8888
const root = parsed.value;
8989
if (root != .object) continue;
9090

91-
// If any top-level key contains "fork_Osaka", skip matching "fork_Prague" entries
92-
var has_osaka = false;
93-
{
94-
var it = root.object.iterator();
95-
while (it.next()) |kv| {
96-
if (std.mem.indexOf(u8, kv.key_ptr.*, "fork_Osaka") != null) {
97-
has_osaka = true;
98-
break;
99-
}
100-
}
101-
}
102-
10391
var test_iter = root.object.iterator();
10492
while (test_iter.next()) |test_entry| {
10593
const test_name = test_entry.key_ptr.*;
10694
const test_obj = test_entry.value_ptr.*;
10795
if (test_obj != .object) continue;
108-
if (has_osaka and std.mem.indexOf(u8, test_name, "fork_Prague") != null) continue;
10996

11097
var cases: std.ArrayList(types.TestCase) = .{};
11198
parseTestCases(a, test_name, &test_obj.object, &cases) catch |err| {

0 commit comments

Comments
 (0)