use of org.sonar.java.se.symbolicvalues.SymbolicValue in project sonar-java by SonarSource.
the class ExplodedGraphWalker method startingStates.
private Iterable<ProgramState> startingStates(MethodTree tree, ProgramState currentState) {
Stream<ProgramState> stateStream = Stream.of(currentState);
boolean isEqualsMethod = EQUALS.matches(tree);
boolean nonNullParameters = isGloballyAnnotatedParameterNonNull(methodTree.symbol());
boolean nullableParameters = isGloballyAnnotatedParameterNullable(methodTree.symbol());
boolean hasMethodBehavior = methodBehavior != null;
for (final VariableTree variableTree : tree.parameters()) {
// create
final SymbolicValue sv = constraintManager.createSymbolicValue(variableTree);
Symbol variableSymbol = variableTree.symbol();
if (hasMethodBehavior) {
methodBehavior.addParameter(sv);
}
stateStream = stateStream.map(ps -> ps.put(variableSymbol, sv));
if (isEqualsMethod || parameterCanBeNull(variableSymbol, nullableParameters)) {
stateStream = stateStream.flatMap((ProgramState ps) -> Stream.concat(sv.setConstraint(ps, ObjectConstraint.NULL).stream(), sv.setConstraint(ps, ObjectConstraint.NOT_NULL).stream()));
} else if (nonNullParameters || isAnnotatedNonNull(variableSymbol)) {
stateStream = stateStream.flatMap(ps -> sv.setConstraint(ps, ObjectConstraint.NOT_NULL).stream());
}
}
return stateStream.collect(Collectors.toList());
}
use of org.sonar.java.se.symbolicvalues.SymbolicValue in project sonar-java by SonarSource.
the class ExplodedGraphWalker method executeBinaryExpression.
private void executeBinaryExpression(Tree tree) {
// Consume two and produce one SV.
ProgramState.Pop unstackBinary = programState.unstackValue(2);
programState = unstackBinary.state;
SymbolicValue symbolicValue = constraintManager.createBinarySymbolicValue(tree, unstackBinary.valuesAndSymbols);
programState = programState.addConstraint(symbolicValue, ObjectConstraint.NOT_NULL);
programState = programState.stackValue(symbolicValue);
}
use of org.sonar.java.se.symbolicvalues.SymbolicValue in project sonar-java by SonarSource.
the class ExplodedGraphWalker method executeMethodInvocation.
private void executeMethodInvocation(MethodInvocationTree mit) {
setSymbolicValueOnFields(mit);
// unstack arguments and method identifier
ProgramState.Pop unstack = programState.unstackValue(mit.arguments().size() + 1);
logState(mit);
programState = unstack.state;
// get method behavior for method with known declaration (ie: within the same file)
MethodBehavior methodInvokedBehavior = null;
Symbol methodSymbol = mit.symbol();
if (methodSymbol.isMethodSymbol()) {
methodInvokedBehavior = behaviorCache.get((Symbol.MethodSymbol) methodSymbol);
}
// Enqueue additional exceptional paths corresponding to unchecked exceptions, for instance OutOfMemoryError
enqueueUncheckedExceptionalPaths(methodSymbol);
final SymbolicValue resultValue = constraintManager.createMethodSymbolicValue(mit, unstack.valuesAndSymbols);
if (methodInvokedBehavior != null && methodInvokedBehavior.isComplete() && !EQUALS_METHODS.anyMatch(mit)) {
List<SymbolicValue> invocationArguments = invocationArguments(unstack.values);
List<Type> invocationTypes = mit.arguments().stream().map(ExpressionTree::symbolType).collect(Collectors.toList());
Map<Type, SymbolicValue.ExceptionalSymbolicValue> thrownExceptionsByExceptionType = new HashMap<>();
// Enqueue exceptional paths from exceptional yields
methodInvokedBehavior.exceptionalPathYields().forEach(yield -> yield.statesAfterInvocation(invocationArguments, invocationTypes, programState, () -> thrownExceptionsByExceptionType.computeIfAbsent(yield.exceptionType(semanticModel), constraintManager::createExceptionalSymbolicValue)).forEach(psYield -> enqueueExceptionalPaths(psYield, methodSymbol, yield)));
// Enqueue happy paths
methodInvokedBehavior.happyPathYields().forEach(yield -> yield.statesAfterInvocation(invocationArguments, invocationTypes, programState, () -> resultValue).map(psYield -> handleSpecialMethods(psYield, mit)).forEach(psYield -> enqueueHappyPath(psYield, mit, yield)));
} else {
// Enqueue exceptional paths from thrown exceptions
enqueueThrownExceptionalPaths(methodSymbol);
// Enqueue happy paths
programState = handleSpecialMethods(programState.stackValue(resultValue), mit);
checkerDispatcher.executeCheckPostStatement(mit);
clearStack(mit);
}
}
use of org.sonar.java.se.symbolicvalues.SymbolicValue in project sonar-java by SonarSource.
the class ExplodedGraphWalker method handleBlockExit.
private void handleBlockExit(ProgramPoint programPosition) {
CFG.Block block = (CFG.Block) programPosition.block;
Tree terminator = block.terminator();
cleanUpProgramState(block);
boolean exitPath = node.exitPath;
if (terminator != null) {
switch(terminator.kind()) {
case IF_STATEMENT:
ExpressionTree ifCondition = ((IfStatementTree) terminator).condition();
handleBranch(block, cleanupCondition(ifCondition), verifyCondition(ifCondition));
return;
case CONDITIONAL_OR:
case CONDITIONAL_AND:
handleBranch(block, ((BinaryExpressionTree) terminator).leftOperand());
return;
case CONDITIONAL_EXPRESSION:
handleBranch(block, ((ConditionalExpressionTree) terminator).condition());
return;
case FOR_STATEMENT:
ExpressionTree condition = ((ForStatementTree) terminator).condition();
if (condition != null) {
handleBranch(block, condition, false);
return;
}
break;
case WHILE_STATEMENT:
ExpressionTree whileCondition = ((WhileStatementTree) terminator).condition();
handleBranch(block, cleanupCondition(whileCondition), verifyCondition(whileCondition));
return;
case DO_STATEMENT:
ExpressionTree doCondition = ((DoWhileStatementTree) terminator).condition();
handleBranch(block, cleanupCondition(doCondition), verifyCondition(doCondition));
return;
case SYNCHRONIZED_STATEMENT:
resetFieldValues(false);
break;
case RETURN_STATEMENT:
ExpressionTree returnExpression = ((ReturnStatementTree) terminator).expression();
if (returnExpression != null) {
programState.storeExitValue();
}
break;
case THROW_STATEMENT:
ProgramState.Pop unstack = programState.unstackValue(1);
SymbolicValue sv = unstack.values.get(0);
if (sv instanceof SymbolicValue.CaughtExceptionSymbolicValue) {
// retrowing the exception from a catch block
sv = ((SymbolicValue.CaughtExceptionSymbolicValue) sv).exception();
} else {
sv = constraintManager.createExceptionalSymbolicValue(((ThrowStatementTree) terminator).expression().symbolType());
}
programState = unstack.state.stackValue(sv);
programState.storeExitValue();
break;
default:
}
}
// unconditional jumps, for-statement, switch-statement, synchronized:
if (exitPath) {
if (block.exitBlock() != null) {
enqueue(new ProgramPoint(block.exitBlock()), programState, true);
} else {
for (CFG.Block successor : block.successors()) {
enqueue(new ProgramPoint(successor), programState, true);
}
}
} else {
for (CFG.Block successor : block.successors()) {
if (!block.isFinallyBlock() || isDirectFlowSuccessorOf(successor, block)) {
enqueue(new ProgramPoint(successor), programState, successor == block.exitBlock());
}
}
}
}
use of org.sonar.java.se.symbolicvalues.SymbolicValue in project sonar-java by SonarSource.
the class ExplodedGraphWalker method enqueueExceptionalPaths.
private void enqueueExceptionalPaths(ProgramState ps, Symbol methodSymbol, @Nullable MethodYield methodYield) {
Set<CFG.Block> exceptionBlocks = ((CFG.Block) node.programPoint.block).exceptions();
List<CFG.Block> catchBlocks = exceptionBlocks.stream().filter(CFG.Block.IS_CATCH_BLOCK).collect(Collectors.toList());
SymbolicValue peekValue = ps.peekValue();
Preconditions.checkState(peekValue instanceof SymbolicValue.ExceptionalSymbolicValue, "Top of stack should always contains exceptional SV");
SymbolicValue.ExceptionalSymbolicValue exceptionSV = (SymbolicValue.ExceptionalSymbolicValue) peekValue;
// only consider the first match, as order of catch block is important
List<CFG.Block> caughtBlocks = catchBlocks.stream().filter(b -> isCaughtByBlock(exceptionSV.exceptionType(), b)).sorted((b1, b2) -> Integer.compare(b2.id(), b1.id())).collect(Collectors.toList());
if (!caughtBlocks.isEmpty()) {
caughtBlocks.forEach(b -> enqueue(new ProgramPoint(b), ps, methodYield));
return;
}
// branch to any unchecked exception catch
catchBlocks.stream().filter(ExplodedGraphWalker::isCatchingUncheckedException).forEach(b -> enqueue(new ProgramPoint(b), ps, methodYield));
// store the exception as exit value in case of method exit in next block
ps.storeExitValue();
// use other exceptional blocks, i.e. finally block and exit blocks
List<CFG.Block> otherBlocks = exceptionBlocks.stream().filter(CFG.Block.IS_CATCH_BLOCK.negate().or(b -> methodSymbol.isUnknown())).collect(Collectors.toList());
if (otherBlocks.isEmpty()) {
// explicitly add the exception branching to method exit
CFG.Block methodExit = node.programPoint.block.successors().stream().map(b -> (CFG.Block) b).filter(CFG.Block::isMethodExitBlock).findFirst().orElse(exitBlock);
enqueue(new ProgramPoint(methodExit), ps, true, methodYield);
} else {
otherBlocks.forEach(b -> enqueue(new ProgramPoint(b), ps, true, methodYield));
}
}
Aggregations