|
|
@ -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); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|