From 3b2e25ed8718d8aee085497886967fa21a9697cc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 20 Oct 2021 17:02:15 -0700 Subject: [PATCH] Sema: fix missing copy in array multiplication lead to a Use-After-Free in backend codgen --- src/AstGen.zig | 14 ++++++++++---- src/Sema.zig | 15 ++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index a17bcc16bd..e98e04f7d4 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -634,18 +634,24 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr return simpleBinOp(gz, scope, rl, node, .bit_and); }, - .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), - .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), + .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), + .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq), .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq), .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt), .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte), .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt), .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte), - .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat), - .array_mult => return simpleBinOp(gz, scope, rl, node, .array_mul), + + .array_mult => { + const result = try gz.addPlNode(.array_mul, node, Zir.Inst.Bin{ + .lhs = try expr(gz, scope, .none, node_datas[node].lhs), + .rhs = try comptimeExpr(gz, scope, .{ .coerced_ty = .usize_type }, node_datas[node].rhs), + }); + return rvalue(gz, rl, result, node); + }, .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type), .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets), diff --git a/src/Sema.zig b/src/Sema.zig index f34b078af5..39e4dfe368 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6945,11 +6945,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; // In `**` rhs has to be comptime-known, but lhs can be runtime-known - const tomulby = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize); + const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize); const mulinfo = getArrayCatInfo(lhs_ty) orelse return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty}); - const final_len = std.math.mul(u64, mulinfo.len, tomulby) catch + const final_len = std.math.mul(u64, mulinfo.len, factor) catch return sema.fail(block, rhs_src, "operation results in overflow", .{}); const final_len_including_sent = final_len + @boolToInt(mulinfo.sentinel != null); @@ -6961,24 +6961,25 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const final_ty = if (mulinfo.sentinel) |sent| try Type.Tag.array_sentinel.create(anon_decl.arena(), .{ .len = final_len, - .elem_type = mulinfo.elem_type, - .sentinel = sent, + .elem_type = try mulinfo.elem_type.copy(anon_decl.arena()), + .sentinel = try sent.copy(anon_decl.arena()), }) else try Type.Tag.array.create(anon_decl.arena(), .{ .len = final_len, - .elem_type = mulinfo.elem_type, + .elem_type = try mulinfo.elem_type.copy(anon_decl.arena()), }); const buf = try anon_decl.arena().alloc(Value, final_len_including_sent); - // handles the optimisation where arr.len == 0 : [_]T { X } ** N + // Optimization for the common pattern of a single element repeated N times, such + // as zero-filling a byte array. const val = if (mulinfo.len == 1) blk: { const copied_val = try (try lhs_sub_val.elemValue(sema.arena, 0)).copy(anon_decl.arena()); break :blk try Value.Tag.repeated.create(anon_decl.arena(), copied_val); } else blk: { // the actual loop var i: u64 = 0; - while (i < tomulby) : (i += 1) { + while (i < factor) : (i += 1) { var j: u64 = 0; while (j < mulinfo.len) : (j += 1) { const val = try lhs_sub_val.elemValue(sema.arena, j);