优化准则:在访问文件或目录前对路径名进行验证

master
wuhaoyang 10 months ago
parent 576eec8ba0
commit 65ed9f4927
  1. 100
      sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.java
  2. 2
      sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/FileAccessCheckerTest.java
  3. 2
      sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.cc

@ -6,7 +6,9 @@
*/ */
package com.keyware.sonar.cxx.rules.checkers; package com.keyware.sonar.cxx.rules.checkers;
import com.sonar.cxx.sslr.api.AstNode; import com.sonar.cxx.sslr.api.AstNode;
import com.sonar.cxx.sslr.api.GenericTokenType;
import com.sonar.cxx.sslr.api.Grammar; import com.sonar.cxx.sslr.api.Grammar;
import org.sonar.check.Priority; import org.sonar.check.Priority;
import org.sonar.check.Rule; import org.sonar.check.Rule;
@ -15,6 +17,9 @@ import org.sonar.cxx.squidbridge.annotations.ActivatedByDefault;
import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation; import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation;
import org.sonar.cxx.squidbridge.checks.SquidCheck; import org.sonar.cxx.squidbridge.checks.SquidCheck;
import java.util.HashSet;
import java.util.Set;
/** /**
* 在访问文件或目录前对路径名进行验证 * 在访问文件或目录前对路径名进行验证
@ -27,68 +32,85 @@ import org.sonar.cxx.squidbridge.checks.SquidCheck;
@ActivatedByDefault @ActivatedByDefault
@SqaleConstantRemediation("5min") @SqaleConstantRemediation("5min")
public class FileAccessChecker extends SquidCheck<Grammar> { public class FileAccessChecker extends SquidCheck<Grammar> {
private boolean filePathChecked = false;
private boolean filePathUsedInIf = false; private Set<String> conditionVariables;
@Override @Override
public void init() { public void init() {
subscribeTo(CxxGrammarImpl.selectionStatement, CxxGrammarImpl.declaration, CxxGrammarImpl.statement); subscribeTo(CxxGrammarImpl.selectionStatement);
subscribeTo(CxxGrammarImpl.declaration);
conditionVariables = new HashSet<>();
} }
@Override @Override
public void visitNode(AstNode astNode) { public void visitNode(AstNode node) {
if (astNode.is(CxxGrammarImpl.selectionStatement)) { if (node.is(CxxGrammarImpl.selectionStatement)) {
checkIfStatement(astNode); handleIfStatement(node);
} else if (astNode.is(CxxGrammarImpl.declaration)) { } else if (node.is(CxxGrammarImpl.declaration)) {
checkDeclaration(astNode); addAllIdentifiers(node);
} else if (astNode.is(CxxGrammarImpl.statement)) { handleDeclaration(node);
checkStatement(astNode);
} }
} }
private void checkIfStatement(AstNode ifStatement) {
AstNode condition = ifStatement.getFirstChild(CxxGrammarImpl.condition); private void handleDeclaration(AstNode node) {
filePathUsedInIf = containsFilePathCheck(condition); AstNode ifstreamNode = findIfstreamNode(node);
if (!filePathUsedInIf) { if (ifstreamNode != null) {
createViolation(ifStatement, "在访问文件或目录前需要对路径名进行验证"); handleIfstreamDeclaration(ifstreamNode);
} }
filePathUsedInIf = false;
} }
private void checkDeclaration(AstNode declaration) { private AstNode findIfstreamNode(AstNode node) {
AstNode declaratorNode = declaration.getFirstDescendant(CxxGrammarImpl.declarator); if (node.getToken() != null && "ifstream".equals(node.getTokenOriginalValue())) {
filePathChecked = containsFilePathCheck(declaratorNode); return node;
if (declaratorNode != null && !filePathChecked) { }
String variableName = declaratorNode.getTokenOriginalValue(); for (AstNode child : node.getChildren()) {
if (variableName != null && variableName.equals("filePath")) { AstNode result = findIfstreamNode(child);
System.out.println(variableName); if (result != null) {
getContext().createLineViolation(this, "在访问文件或目录前需要对路径名进行验证", declaratorNode); return result;
} }
} }
return null;
} }
private void checkStatement(AstNode statement) {
AstNode condition = statement.getFirstChild(CxxGrammarImpl.condition);
filePathChecked = containsFilePathCheck(condition);
}
private boolean containsFilePathCheck(AstNode node) { private void handleIfStatement(AstNode node) {
if (node != null && node.getTokenOriginalValue().equals("filePath")) { AstNode conditionNode = node.getFirstDescendant(CxxGrammarImpl.condition);
return true; if (conditionNode != null) {
addAllIdentifiers(conditionNode);
} }
if (node != null) { }
for (AstNode child : node.getChildren()) {
// 如果 if 中使用了 filePath,则停止递归并跳过 ifstream file(filePath) 检查 private void addAllIdentifiers(AstNode node) {
if (containsFilePathCheck(child)) { for (AstNode child : node.getChildren()) {
return true; if (child.getType().equals(CxxGrammarImpl.selectionStatement)) {
// 找到 if 语句节点
AstNode conditionNode = child.getFirstDescendant(CxxGrammarImpl.condition);
// 找到条件部分的节点
AstNode identifierNode = conditionNode.getFirstDescendant(GenericTokenType.IDENTIFIER);
// 找到代表标识符的节点
if (identifierNode != null) {
String codeInsideIf = identifierNode.getTokenValue();
// 获取标识符节点的值
conditionVariables.add(codeInsideIf);
} }
} else {
addAllIdentifiers(child);
} }
} }
return false; // 节点或其任何子节点中找不到“filePath”
} }
private void createViolation(AstNode node, String message) { private void handleIfstreamDeclaration(AstNode ifstreamNode) {
getContext().createLineViolation(this, message, node); AstNode parameterDeclarationNode = ifstreamNode.getFirstDescendant(CxxGrammarImpl.parameterDeclaration);
if (parameterDeclarationNode != null) {
AstNode identifierNode = parameterDeclarationNode.getFirstDescendant(GenericTokenType.IDENTIFIER);
if (identifierNode != null) {
String ifstreamParam = identifierNode.getTokenOriginalValue();
if (!conditionVariables.contains(ifstreamParam)) {
getContext().createLineViolation(this, "在访问文件或目录前需要对路径名进行验证", ifstreamNode);
}
}
}
} }
} }

@ -27,7 +27,7 @@ public class FileAccessCheckerTest {
var tester = CxxFileTesterHelper.create("FileAccessChecker.cc"); var tester = CxxFileTesterHelper.create("FileAccessChecker.cc");
SourceFile file = CxxAstScanner.scanSingleInputFile(tester.asInputFile(), checker); SourceFile file = CxxAstScanner.scanSingleInputFile(tester.asInputFile(), checker);
CheckMessagesVerifier.verify(file.getCheckMessages()) CheckMessagesVerifier.verify(file.getCheckMessages())
.next().atLine(13).withMessage("在访问文件或目录前需要对路径名进行验证") .next().atLine(14).withMessage("在访问文件或目录前需要对路径名进行验证")
.noMore(); .noMore();
} }
} }

@ -10,7 +10,7 @@ int main() {
int a = 5; int a = 5;
if (a<5) { if (a<4) {
ifstream file(filePath); ifstream file(filePath);
cout << "File opened successfully." << endl; cout << "File opened successfully." << endl;

Loading…
Cancel
Save