From e8c848352e89809d997f1a3fe6ad7d873278f7a2 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Sat, 24 Dec 2016 06:05:57 +0100 Subject: [PATCH 1/3] fix #392 - Usage of labels in asm blocks is not detected --- src/analysis/unused_label.d | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/analysis/unused_label.d b/src/analysis/unused_label.d index cc19779..be51701 100644 --- a/src/analysis/unused_label.d +++ b/src/analysis/unused_label.d @@ -89,6 +89,30 @@ class UnusedLabelCheck : BaseAnalyzer labelUsed(gotoStatement.label.text); } + override void visit(const AsmInstruction instr) + { + instr.accept(this); + + bool jmp; + if (instr.identifierOrIntegerOrOpcode.text.length) + jmp = instr.identifierOrIntegerOrOpcode.text[0] == 'j'; + + if (!jmp || instr.operands.operands.length != 1) + return; + + const AsmExp e = cast(AsmExp) instr.operands.operands[0]; + if (e.left && cast(const(AsmBrExp)) e.left) + { + const AsmBrExp b = cast(AsmBrExp) e.left; + if (b.asmUnaExp && b.asmUnaExp.asmPrimaryExp) + { + const AsmPrimaryExp p = b.asmUnaExp.asmPrimaryExp; + if (p && p.identifierChain && p.identifierChain.identifiers.length == 1) + labelUsed(p.identifierChain.identifiers[0].text); + } + } + } + private: static struct Label @@ -181,5 +205,21 @@ unittest } }c, sac); + assertAnalyzerWarnings(q{ + void testAsm() + { + asm { jmp lbl;} + lbl: + } + }c, sac); + + assertAnalyzerWarnings(q{ + void testAsm() + { + asm { mov RAX,1;} + lbl: // [warn]: Label "lbl" is not used. + } + }c, sac); + stderr.writeln("Unittest for UnusedLabelCheck passed."); } From e5708325c195c92df7858148b92477dbed7a51b6 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Sat, 24 Dec 2016 07:35:06 +0100 Subject: [PATCH 2/3] apply Dscanner on the label ana module --- src/analysis/unused_label.d | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/analysis/unused_label.d b/src/analysis/unused_label.d index be51701..59fd817 100644 --- a/src/analysis/unused_label.d +++ b/src/analysis/unused_label.d @@ -4,16 +4,20 @@ module analysis.unused_label; -import dparse.ast; -import dparse.lexer; import analysis.base; import analysis.helpers; +import dparse.ast; +import dparse.lexer; import dsymbol.scope_ : Scope; -class UnusedLabelCheck : BaseAnalyzer +/** + * Checks for labels that are never used. + */ +final class UnusedLabelCheck : BaseAnalyzer { alias visit = BaseAnalyzer.visit; + /// this(string fileName, const(Scope)* sc, bool skipTests = false) { super(fileName, sc, skipTests); @@ -101,10 +105,10 @@ class UnusedLabelCheck : BaseAnalyzer return; const AsmExp e = cast(AsmExp) instr.operands.operands[0]; - if (e.left && cast(const(AsmBrExp)) e.left) + if (e.left && cast(AsmBrExp) e.left) { const AsmBrExp b = cast(AsmBrExp) e.left; - if (b.asmUnaExp && b.asmUnaExp.asmPrimaryExp) + if (b && b.asmUnaExp && b.asmUnaExp.asmPrimaryExp) { const AsmPrimaryExp p = b.asmUnaExp.asmPrimaryExp; if (p && p.identifierChain && p.identifierChain.identifiers.length == 1) @@ -125,7 +129,7 @@ private: Label[string][] stack; - auto ref current() @property + auto ref current() { return stack[$ - 1]; } @@ -161,7 +165,7 @@ private: unittest { - import analysis.config : StaticAnalysisConfig, Check; + import analysis.config : Check, StaticAnalysisConfig; import std.stdio : stderr; StaticAnalysisConfig sac; From 92037b5e7c4979584624aaa50f45f9309dd20c95 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Sat, 24 Dec 2016 19:55:33 +0100 Subject: [PATCH 3/3] prevent possible segfault with instructions without params, like RDTSC --- src/analysis/unused_label.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/unused_label.d b/src/analysis/unused_label.d index 59fd817..fe9ddad 100644 --- a/src/analysis/unused_label.d +++ b/src/analysis/unused_label.d @@ -101,7 +101,7 @@ final class UnusedLabelCheck : BaseAnalyzer if (instr.identifierOrIntegerOrOpcode.text.length) jmp = instr.identifierOrIntegerOrOpcode.text[0] == 'j'; - if (!jmp || instr.operands.operands.length != 1) + if (!jmp || !instr.operands || instr.operands.operands.length != 1) return; const AsmExp e = cast(AsmExp) instr.operands.operands[0];