aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-09-07 22:05:01 +0300
committerVeikka Tuominen <git@vexu.eu>2022-09-08 00:37:11 +0300
commit99826a2ba89ccd80caaa4eeb47c59a71ddfe76b6 (patch)
tree1e769aff2edca88474f60f28846da7a4a62e18f0 /src
parent37afab2addab5809e1419a09e3be5ea4f3ee5501 (diff)
downloadzig-99826a2ba89ccd80caaa4eeb47c59a71ddfe76b6.tar.gz
zig-99826a2ba89ccd80caaa4eeb47c59a71ddfe76b6.zip
Sema: fix UAF in zirClosureGet
Previously if a decl failed its capture scope would be deallocated and set to undefined which would then lead to invalid dereference in `zirClosureGet`. To avoid this set the capture scope to a special failed state and fail the current decl with dependency failure if the failed state is encountered in `zirClosureGet`. Closes #12433 Closes #12530 Closes #12593
Diffstat (limited to 'src')
-rw-r--r--src/Module.zig10
-rw-r--r--src/Sema.zig11
2 files changed, 20 insertions, 1 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 3ae6c48edd..ea89225537 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -345,6 +345,15 @@ pub const CaptureScope = struct {
/// During sema, this map is backed by the gpa. Once sema completes,
/// it is reallocated using the value_arena.
captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, TypedValue) = .{},
+
+ pub fn failed(noalias self: *const @This()) bool {
+ return self.captures.available == 0 and self.captures.size == std.math.maxInt(u32);
+ }
+
+ pub fn fail(noalias self: *@This()) void {
+ self.captures.available = 0;
+ self.captures.size = std.math.maxInt(u32);
+ }
};
pub const WipCaptureScope = struct {
@@ -383,6 +392,7 @@ pub const WipCaptureScope = struct {
pub fn deinit(noalias self: *@This()) void {
if (!self.finalized) {
self.scope.captures.deinit(self.gpa);
+ self.scope.fail();
}
self.* = undefined;
}
diff --git a/src/Sema.zig b/src/Sema.zig
index 8d25a7c93e..15e891ef87 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -5956,7 +5956,6 @@ fn analyzeCall(
error.NeededSourceLocation => {
_ = sema.inst_map.remove(inst);
const decl = sema.mod.declPtr(block.src_decl);
- child_block.src_decl = block.src_decl;
try sema.analyzeInlineCallArg(
block,
&child_block,
@@ -13740,6 +13739,16 @@ fn zirClosureGet(
const tv = while (true) {
// Note: We don't need to add a dependency here, because
// decls always depend on their lexical parents.
+
+ // Fail this decl if a scope it depended on failed.
+ if (scope.failed()) {
+ if (sema.owner_func) |owner_func| {
+ owner_func.state = .dependency_failure;
+ } else {
+ sema.owner_decl.analysis = .dependency_failure;
+ }
+ return error.AnalysisFail;
+ }
if (scope.captures.getPtr(inst_data.inst)) |tv| {
break tv;
}