authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-20 17:02:15-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-20 17:02:15-07:00
log3b2e25ed8718d8aee085497886967fa21a9697cc
tree1596615c3300c979757de0127f42554f73ffc267
parent8b734380f9e900826b1a9cb9804887035f2fe085

Sema: fix missing copy in array multiplication

lead to a Use-After-Free in backend codgen

2 files changed, 18 insertions(+), 11 deletions(-)

src/AstGen.zig+10-4
...@@ -634,18 +634,24 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -634,18 +634,24 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
634634
635 return simpleBinOp(gz, scope, rl, node, .bit_and);635 return simpleBinOp(gz, scope, rl, node, .bit_and);
636 },636 },
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),
640 .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq),640 .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq),
641 .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq),641 .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq),
642 .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt),642 .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt),
643 .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte),643 .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte),
644 .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt),644 .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt),
645 .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte),645 .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte),
646
647 .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat),646 .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
650 .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type),656 .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type),
651 .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets),657 .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets),
src/Sema.zig+8-7
...@@ -6945,11 +6945,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -6945,11 +6945,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
6945 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };6945 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
69466946
6947 // In `**` rhs has to be comptime-known, but lhs can be runtime-known6947 // 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);
6949 const mulinfo = getArrayCatInfo(lhs_ty) orelse6949 const mulinfo = getArrayCatInfo(lhs_ty) orelse
6950 return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty});6950 return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty});
69516951
6952 const final_len = std.math.mul(u64, mulinfo.len, tomulby) catch6952 const final_len = std.math.mul(u64, mulinfo.len, factor) catch
6953 return sema.fail(block, rhs_src, "operation results in overflow", .{});6953 return sema.fail(block, rhs_src, "operation results in overflow", .{});
6954 const final_len_including_sent = final_len + @boolToInt(mulinfo.sentinel != null);6954 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...@@ -6961,24 +6961,25 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
6961 const final_ty = if (mulinfo.sentinel) |sent|6961 const final_ty = if (mulinfo.sentinel) |sent|
6962 try Type.Tag.array_sentinel.create(anon_decl.arena(), .{6962 try Type.Tag.array_sentinel.create(anon_decl.arena(), .{
6963 .len = final_len,6963 .len = final_len,
6964 .elem_type = mulinfo.elem_type,6964 .elem_type = try mulinfo.elem_type.copy(anon_decl.arena()),
6965 .sentinel = sent,6965 .sentinel = try sent.copy(anon_decl.arena()),
6966 })6966 })
6967 else6967 else
6968 try Type.Tag.array.create(anon_decl.arena(), .{6968 try Type.Tag.array.create(anon_decl.arena(), .{
6969 .len = final_len,6969 .len = final_len,
6970 .elem_type = mulinfo.elem_type,6970 .elem_type = try mulinfo.elem_type.copy(anon_decl.arena()),
6971 });6971 });
6972 const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);6972 const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);
69736973
6974 // handles the optimisation where arr.len == 0 : [_]T { X } ** N6974 // Optimization for the common pattern of a single element repeated N times, such
6975 // as zero-filling a byte array.
6975 const val = if (mulinfo.len == 1) blk: {6976 const val = if (mulinfo.len == 1) blk: {
6976 const copied_val = try (try lhs_sub_val.elemValue(sema.arena, 0)).copy(anon_decl.arena());6977 const copied_val = try (try lhs_sub_val.elemValue(sema.arena, 0)).copy(anon_decl.arena());
6977 break :blk try Value.Tag.repeated.create(anon_decl.arena(), copied_val);6978 break :blk try Value.Tag.repeated.create(anon_decl.arena(), copied_val);
6978 } else blk: {6979 } else blk: {
6979 // the actual loop6980 // the actual loop
6980 var i: u64 = 0;6981 var i: u64 = 0;
6981 while (i < tomulby) : (i += 1) {6982 while (i < factor) : (i += 1) {
6982 var j: u64 = 0;6983 var j: u64 = 0;
6983 while (j < mulinfo.len) : (j += 1) {6984 while (j < mulinfo.len) : (j += 1) {
6984 const val = try lhs_sub_val.elemValue(sema.arena, j);6985 const val = try lhs_sub_val.elemValue(sema.arena, j);