authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-10 17:03:17+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-19 20:19:00+02:00
log43e89026ac90ee6e8c2cb066068eb8ff10352ac1
tree5652c5820a1649275d7b252bdd2b650ca8bd75df
parent8be69f41328ebc0331434fd9d4008985463188c9
signaturelock-open Commit is signed but in an unrecognized format.

wasm: fix double free of locals

A copy was being made of a WValue variable, which meant the call to `free` would insert the local that was being held by said WValue was appended to the free list twice. This led to the same local being reused even though it wasn't free and would lead to it being over- written by a new value.

1 files changed, 17 insertions(+), 10 deletions(-)

src/arch/wasm/CodeGen.zig+17-10
......@@ -127,6 +127,7 @@ const WValue = union(enum) {
127127 .f64 => gen.free_locals_f64.append(gen.gpa, local_value) catch return,
128128 .v128 => gen.free_locals_v128.append(gen.gpa, local_value) catch return,
129129 }
130 log.debug("freed local ({d}) of type {}", .{ local_value, valtype });
130131 value.* = .dead;
131132 }
132133};
......@@ -1092,27 +1093,27 @@ fn allocLocal(func: *CodeGen, ty: Type) InnerError!WValue {
10921093 const valtype = typeToValtype(ty, func.target);
10931094 switch (valtype) {
10941095 .i32 => if (func.free_locals_i32.popOrNull()) |index| {
1095 log.debug("reusing local ({d}) of type {}\n", .{ index, valtype });
1096 log.debug("reusing local ({d}) of type {}", .{ index, valtype });
10961097 return WValue{ .local = .{ .value = index, .references = 1 } };
10971098 },
10981099 .i64 => if (func.free_locals_i64.popOrNull()) |index| {
1099 log.debug("reusing local ({d}) of type {}\n", .{ index, valtype });
1100 log.debug("reusing local ({d}) of type {}", .{ index, valtype });
11001101 return WValue{ .local = .{ .value = index, .references = 1 } };
11011102 },
11021103 .f32 => if (func.free_locals_f32.popOrNull()) |index| {
1103 log.debug("reusing local ({d}) of type {}\n", .{ index, valtype });
1104 log.debug("reusing local ({d}) of type {}", .{ index, valtype });
11041105 return WValue{ .local = .{ .value = index, .references = 1 } };
11051106 },
11061107 .f64 => if (func.free_locals_f64.popOrNull()) |index| {
1107 log.debug("reusing local ({d}) of type {}\n", .{ index, valtype });
1108 log.debug("reusing local ({d}) of type {}", .{ index, valtype });
11081109 return WValue{ .local = .{ .value = index, .references = 1 } };
11091110 },
11101111 .v128 => if (func.free_locals_v128.popOrNull()) |index| {
1111 log.debug("reusing local ({d}) of type {}\n", .{ index, valtype });
1112 log.debug("reusing local ({d}) of type {}", .{ index, valtype });
11121113 return WValue{ .local = .{ .value = index, .references = 1 } };
11131114 },
11141115 }
1115 log.debug("new local of type {}\n", .{valtype});
1116 log.debug("new local of type {}", .{valtype});
11161117 // no local was free to be re-used, so allocate a new local instead
11171118 return func.ensureAllocLocal(ty);
11181119}
......@@ -4948,8 +4949,15 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
49484949 else => unreachable,
49494950 }
49504951 };
4951 // TODO: this is incorrect Liveness handling code
4952 func.finishAir(inst, result, &.{});
4952
4953 if (elements.len <= Liveness.bpi - 1) {
4954 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
4955 @memcpy(buf[0..elements.len], elements);
4956 return func.finishAir(inst, result, &buf);
4957 }
4958 var bt = try func.iterateBigTomb(inst, elements.len);
4959 for (elements) |arg| bt.feed(arg);
4960 return bt.finishAir(result);
49534961}
49544962
49554963fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
......@@ -5436,11 +5444,10 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro
54365444 };
54375445
54385446 var bin_op = try (try func.binOp(lhs, rhs, lhs_ty, op)).toLocal(func, lhs_ty);
5439 defer bin_op.free(func);
54405447 var result = if (wasm_bits != int_info.bits) blk: {
54415448 break :blk try (try func.wrapOperand(bin_op, lhs_ty)).toLocal(func, lhs_ty);
54425449 } else bin_op;
5443 defer result.free(func); // no-op when wasm_bits == int_info.bits
5450 defer result.free(func);
54445451
54455452 const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt;
54465453 const overflow_bit: WValue = if (is_signed) blk: {