From c3c7ee1d5d1c7028e77f9824fcf4288c66aac0e9 Mon Sep 17 00:00:00 2001 From: Vladiwostok <55026261+Vladiwostok@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:59:26 +0200 Subject: [PATCH] Fix segfault caused by UnusedLabelCheck (#83) * Fix segfault caused by UnusedLabelCheck * Enable debugging for the make/macos-latest build * Revert "Enable debugging for the make/macos-latest build" This reverts commit e66ccb71c092f0669f9ec1b99d773c3603c99ff5. * Fix root cause of segfault * Address feedback --- src/dscanner/analysis/unused_label.d | 63 +++++++++++++++++++--------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/src/dscanner/analysis/unused_label.d b/src/dscanner/analysis/unused_label.d index fcd038f8..37a232da 100644 --- a/src/dscanner/analysis/unused_label.d +++ b/src/dscanner/analysis/unused_label.d @@ -10,12 +10,12 @@ import dmd.tokens; /** * Checks for labels that are never used. */ -extern(C++) class UnusedLabelCheck(AST) : BaseAnalyzerDmd +extern (C++) class UnusedLabelCheck(AST) : BaseAnalyzerDmd { alias visit = BaseAnalyzerDmd.visit; mixin AnalyzerInfo!"unused_label_check"; - extern(D) this(string fileName, bool skipTests = false) + extern (D) this(string fileName, bool skipTests = false) { super(fileName, skipTests); } @@ -30,17 +30,18 @@ extern(C++) class UnusedLabelCheck(AST) : BaseAnalyzerDmd override void visit(AST.LabelStatement ls) { Label* label = ls.ident.toString() in current; - + if (label is null) { - current[ls.ident.toString()] = Label(ls.ident.toString(), ls.loc.linnum, ls.loc.charnum, false); + current[ls.ident.toString()] = Label(ls.ident.toString(), + ls.loc.linnum, ls.loc.charnum, false); } else { label.line = ls.loc.linnum; label.column = ls.loc.charnum; } - + super.visit(ls); } @@ -52,8 +53,6 @@ extern(C++) class UnusedLabelCheck(AST) : BaseAnalyzerDmd override void visit(AST.BreakStatement bs) { - import std.stdio : writeln; - if (bs.ident) labelUsed(bs.ident.toString()); } @@ -86,7 +85,7 @@ extern(C++) class UnusedLabelCheck(AST) : BaseAnalyzerDmd super.visit(fd); popScope(); } - + override void visit(AST.AsmStatement as) { if (!as.tokens) @@ -94,17 +93,30 @@ extern(C++) class UnusedLabelCheck(AST) : BaseAnalyzerDmd // Look for jump instructions bool jmp; - if (as.tokens[0].ident && as.tokens[0].ident.toString()[0] == 'j') + if (getFirstLetterOf(cast(char*) as.tokens[0].ptr) == 'j') jmp = true; // Last argument of the jmp instruction will be the label - Token *label; + Token* label; for (label = as.tokens; label.next; label = label.next) {} if (jmp && label.ident) labelUsed(label.ident.toString()); } + private char getFirstLetterOf(char* str) + { + import std.ascii : isAlpha; + + if (str is null) + return '\0'; + + while (str && !isAlpha(*str)) + str++; + + return *str; + } + private: static struct Label @@ -115,9 +127,9 @@ private: bool used; } - extern(D) Label[const(char)[]][] stack; + extern (D) Label[const(char)[]][] stack; - extern(D) auto ref current() + extern (D) auto ref current() { return stack[$ - 1]; } @@ -146,7 +158,7 @@ private: stack.length--; } - extern(D) void labelUsed(const(char)[] name) + extern (D) void labelUsed(const(char)[] name) { Label* entry = name in current; if (entry is null) @@ -158,13 +170,13 @@ private: unittest { - import dscanner.analysis.helpers : assertAnalyzerWarnings = assertAnalyzerWarningsDMD; + import dscanner.analysis.helpers : assertAnalyzerWarningsDMD; import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig(); sac.unused_label_check = Check.enabled; - assertAnalyzerWarnings(q{ + assertAnalyzerWarningsDMD(q{ int testUnusedLabel() { int x = 0; @@ -203,7 +215,7 @@ unittest } }c, sac); - assertAnalyzerWarnings(q{ + assertAnalyzerWarningsDMD(q{ void testAsm() { asm { jmp lbl;} @@ -211,7 +223,7 @@ unittest } }c, sac); - assertAnalyzerWarnings(q{ + assertAnalyzerWarningsDMD(q{ void testAsm() { asm { mov RAX,1;} @@ -220,7 +232,7 @@ unittest }c, sac); // from std.math - assertAnalyzerWarnings(q{ + assertAnalyzerWarningsDMD(q{ real polyImpl() { asm { jecxz return_ST; @@ -229,7 +241,7 @@ unittest }c, sac); // a label might be hard to find, e.g. in a mixin - assertAnalyzerWarnings(q{ + assertAnalyzerWarningsDMD(q{ real polyImpl() { mixin("return_ST: return 1;"); asm { @@ -238,5 +250,16 @@ unittest } }c, sac); + assertAnalyzerWarningsDMD(q{ + void testAsm() + { + asm nothrow @nogc + { + "movgr2fcsr $r0,%0" : + : "r" (newState & (roundingMask | allExceptions)); + } + } + }c, sac); + stderr.writeln("Unittest for UnusedLabelCheck passed."); -} \ No newline at end of file +}