Skip to content

Commit 3b2e25e

Browse files
committed
Sema: fix missing copy in array multiplication
lead to a Use-After-Free in backend codgen
1 parent 8b73438 commit 3b2e25e

File tree

2 files changed

+18
-11
lines changed

2 files changed

+18
-11
lines changed

src/AstGen.zig

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -634,18 +634,24 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
634634

635635
return simpleBinOp(gz, scope, rl, node, .bit_and);
636636
},
637-
.bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or),
638-
.bit_xor => return simpleBinOp(gz, scope, rl, node, .xor),
639637

638+
.bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or),
639+
.bit_xor => return simpleBinOp(gz, scope, rl, node, .xor),
640640
.bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq),
641641
.equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq),
642642
.greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt),
643643
.greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte),
644644
.less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt),
645645
.less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte),
646-
647646
.array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat),
648-
.array_mult => return simpleBinOp(gz, scope, rl, node, .array_mul),
647+
648+
.array_mult => {
649+
const result = try gz.addPlNode(.array_mul, node, Zir.Inst.Bin{
650+
.lhs = try expr(gz, scope, .none, node_datas[node].lhs),
651+
.rhs = try comptimeExpr(gz, scope, .{ .coerced_ty = .usize_type }, node_datas[node].rhs),
652+
});
653+
return rvalue(gz, rl, result, node);
654+
},
649655

650656
.error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type),
651657
.merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets),

src/Sema.zig

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6945,11 +6945,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
69456945
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
69466946

69476947
// In `**` rhs has to be comptime-known, but lhs can be runtime-known
6948-
const tomulby = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize);
6948+
const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize);
69496949
const mulinfo = getArrayCatInfo(lhs_ty) orelse
69506950
return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty});
69516951

6952-
const final_len = std.math.mul(u64, mulinfo.len, tomulby) catch
6952+
const final_len = std.math.mul(u64, mulinfo.len, factor) catch
69536953
return sema.fail(block, rhs_src, "operation results in overflow", .{});
69546954
const final_len_including_sent = final_len + @boolToInt(mulinfo.sentinel != null);
69556955

@@ -6961,24 +6961,25 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
69616961
const final_ty = if (mulinfo.sentinel) |sent|
69626962
try Type.Tag.array_sentinel.create(anon_decl.arena(), .{
69636963
.len = final_len,
6964-
.elem_type = mulinfo.elem_type,
6965-
.sentinel = sent,
6964+
.elem_type = try mulinfo.elem_type.copy(anon_decl.arena()),
6965+
.sentinel = try sent.copy(anon_decl.arena()),
69666966
})
69676967
else
69686968
try Type.Tag.array.create(anon_decl.arena(), .{
69696969
.len = final_len,
6970-
.elem_type = mulinfo.elem_type,
6970+
.elem_type = try mulinfo.elem_type.copy(anon_decl.arena()),
69716971
});
69726972
const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);
69736973

6974-
// handles the optimisation where arr.len == 0 : [_]T { X } ** N
6974+
// Optimization for the common pattern of a single element repeated N times, such
6975+
// as zero-filling a byte array.
69756976
const val = if (mulinfo.len == 1) blk: {
69766977
const copied_val = try (try lhs_sub_val.elemValue(sema.arena, 0)).copy(anon_decl.arena());
69776978
break :blk try Value.Tag.repeated.create(anon_decl.arena(), copied_val);
69786979
} else blk: {
69796980
// the actual loop
69806981
var i: u64 = 0;
6981-
while (i < tomulby) : (i += 1) {
6982+
while (i < factor) : (i += 1) {
69826983
var j: u64 = 0;
69836984
while (j < mulinfo.len) : (j += 1) {
69846985
const val = try lhs_sub_val.elemValue(sema.arena, j);

0 commit comments

Comments
 (0)