From 9dc3d0d1d1f7635505c22b09e3a57eee6ae98162 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sat, 27 Dec 2025 18:17:28 +0100 Subject: [PATCH] fix attempted OOB access with broken swtich/case syntax --- src/dscanner/analysis/base.d | 62 ++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/src/dscanner/analysis/base.d b/src/dscanner/analysis/base.d index a9baca0..1a7a097 100644 --- a/src/dscanner/analysis/base.d +++ b/src/dscanner/analysis/base.d @@ -1,7 +1,7 @@ module dscanner.analysis.base; import dparse.ast; -import dparse.lexer : IdType, str, Token, tok; +import dparse.lexer : IdType, str, tok, Token; import dscanner.analysis.nolint; import dsymbol.scope_ : Scope; import std.array; @@ -639,12 +639,13 @@ public: { // case and default statements always open new scopes and close // previous case scopes - bool close = switchStack.length && switchStack[$ - 1].inCase; - bool b = switchStack[$ - 1].inCase; - switchStack[$ - 1].inCase = true; + bool wasInCase = switchStack.length && switchStack[$ - 1].inCase; + if (switchStack.length) + switchStack[$ - 1].inCase = true; scope (exit) - switchStack[$ - 1].inCase = b; - if (close) + if (switchStack.length) + switchStack[$ - 1].inCase = wasInCase; + if (wasInCase) { popScope(); pushScope(); @@ -897,3 +898,52 @@ unittest auto isOldScope = void; }); } + +// test previous segfault +unittest +{ + import dparse.lexer : getTokensForParser, LexerConfig, StringCache; + import dparse.parser : parseModule; + import dparse.rollback_allocator : RollbackAllocator; + + StringCache cache = StringCache(4096); + LexerConfig config; + RollbackAllocator rba; + auto tokens = getTokensForParser(q{ + module derp; + + void main(string[] args) + { + foreach + switch (x) + { + case 1: + if (y) { + continue; + } + break; + default: + break; + } + } + }, config, &cache); + auto m = parseModule(tokens, "stdin", &rba); + + class TestScopedAnalyzer : ScopedBaseAnalyzer + { + this() + { + super(BaseAnalyzerArguments("stdin")); + } + + override protected void pushScope() + { + } + + override protected void popScope() + { + } + } + + new TestScopedAnalyzer().visit(m); +}