protected override void VisitSimpleBlock(SimpleBlock block, ExplodedGraphNode node) { var newProgramState = node.ProgramState; if (block is UsingEndBlock usingFinalizerBlock) { newProgramState = InvokeChecks(newProgramState, (ps, check) => check.PreProcessUsingStatement(node.ProgramPoint, ps)); newProgramState = CleanStateAfterBlock(newProgramState, block); EnqueueAllSuccessors(block, newProgramState); return; } newProgramState = CleanStateAfterBlock(newProgramState, block); if (block is ForeachCollectionProducerBlock) { newProgramState = newProgramState.PopValue(); EnqueueAllSuccessors(block, newProgramState); return; } if (block is ForInitializerBlock forInitializerBlock) { newProgramState = newProgramState.PopValues( forInitializerBlock.ForNode.Initializers.Count); newProgramState = newProgramState.PushValues( Enumerable .Range(0, forInitializerBlock.ForNode.Incrementors.Count) .Select(i => new SymbolicValue())); EnqueueAllSuccessors(forInitializerBlock, newProgramState); return; } if (block is LockBlock lockBlock) { newProgramState = newProgramState.PopValue(); newProgramState = newProgramState.RemoveSymbols(IsFieldSymbol); EnqueueAllSuccessors(block, newProgramState); return; } if (block is JumpBlock jumpBlock && jumpBlock.JumpNode.IsKind(SyntaxKind.YieldReturnStatement)) { newProgramState = newProgramState.RemoveSymbols(IsFieldSymbol); } base.VisitSimpleBlock(block, node); }
protected virtual void VisitSimpleBlock(SimpleBlock block, ExplodedGraphNode node) { var newProgramState = CleanStateAfterBlock(node.ProgramState, block); if (block is JumpBlock jumpBlock && IsValueConsumingStatement(jumpBlock.JumpNode)) { newProgramState = newProgramState.PopValue(); } EnqueueAllSuccessors(block, newProgramState); }
private void VisitBinaryBranch(BinaryBranchBlock binaryBranchBlock, ExplodedGraphNode node, SyntaxNode instruction) { var ps = node.ProgramState; SymbolicValue sv; var forStatement = binaryBranchBlock.BranchingNode as ForStatementSyntax; if (forStatement != null) { if (forStatement.Condition == null) { ps = ps.PushValue(SymbolicValue.True); } ps = ps.PopValue(out sv); ps = ps.PopValues(forStatement.Incrementors.Count); } else { ps = ps.PopValue(out sv); } foreach (var newProgramState in sv.TrySetConstraint(BoolConstraint.True, ps)) { OnConditionEvaluated(instruction, evaluationValue: true); var nps = binaryBranchBlock.BranchingNode.IsKind(SyntaxKind.LogicalOrExpression) ? newProgramState.PushValue(SymbolicValue.True) : newProgramState; EnqueueNewNode(new ProgramPoint(binaryBranchBlock.TrueSuccessorBlock), CleanStateAfterBlock(nps, node.ProgramPoint.Block)); } foreach (var newProgramState in sv.TrySetConstraint(BoolConstraint.False, ps)) { OnConditionEvaluated(instruction, evaluationValue: false); var nps = binaryBranchBlock.BranchingNode.IsKind(SyntaxKind.LogicalAndExpression) ? newProgramState.PushValue(SymbolicValue.False) : newProgramState; EnqueueNewNode(new ProgramPoint(binaryBranchBlock.FalseSuccessorBlock), CleanStateAfterBlock(nps, node.ProgramPoint.Block)); } }
protected void EnqueueNewNode(ProgramPoint programPoint, ProgramState programState) { if (programState == null) { return; } var pos = programPoint; if (this.programPoints.ContainsKey(programPoint)) { pos = this.programPoints[programPoint]; } else { this.programPoints[pos] = pos; } ExplodedGraphNode newNode = null; if (programState.GetVisitedCount(pos) >= MaxProgramPointExecutionCount) { OnProgramPointVisitCountExceedLimit(pos, programState); // reached the max number of visit by program point, in the case of ForEach blocks, we take the foreach loop false branch with current program state, // if it is not a foreach loop, newNode will be null and we will stop exploring the path if (GetForEachExitBlock(programPoint.Block) is Block forEachExitBlock) { newNode = new ExplodedGraphNode(new ProgramPoint(forEachExitBlock), programState); } } else { newNode = new ExplodedGraphNode(pos, programState.AddVisit(pos)); } if (newNode != null && this.nodesAlreadyInGraph.Add(newNode)) { this.workList.Enqueue(newNode); } }
protected virtual void VisitSingleSuccessorBinaryBranch(BinaryBranchingSimpleBlock block, ExplodedGraphNode node) { var programState = node.ProgramState.PopValue(out var sv); foreach (var newProgramState in sv.TrySetConstraint(BoolConstraint.True, programState)) { OnConditionEvaluated(block.BranchingInstruction, evaluationValue: true); var nps = newProgramState.PushValue(SymbolicValue.True); EnqueueNewNode(new ProgramPoint(block.SuccessorBlock), nps); } foreach (var newProgramState in sv.TrySetConstraint(BoolConstraint.False, programState)) { OnConditionEvaluated(block.BranchingInstruction, evaluationValue: false); var nps = newProgramState.PushValue(SymbolicValue.False); EnqueueNewNode(new ProgramPoint(block.SuccessorBlock), nps); } }
protected abstract void VisitInstruction(ExplodedGraphNode node);
protected abstract void VisitBinaryBranch(BinaryBranchBlock binaryBranchBlock, ExplodedGraphNode node);
protected override void VisitInstruction(ExplodedGraphNode node) { var instruction = node.ProgramPoint.Block.Instructions[node.ProgramPoint.Offset]; var expression = instruction as ExpressionSyntax; var parenthesizedExpression = expression?.GetSelfOrTopParenthesizedExpression(); var newProgramPoint = new ProgramPoint(node.ProgramPoint.Block, node.ProgramPoint.Offset + 1); var newProgramState = node.ProgramState; newProgramState = InvokeChecks(newProgramState, (ps, check) => check.PreProcessInstruction(node.ProgramPoint, ps)); if (newProgramState == null) { return; } switch (instruction.Kind()) { case SyntaxKind.VariableDeclarator: newProgramState = VisitVariableDeclarator((VariableDeclaratorSyntax)instruction, newProgramState); break; case SyntaxKind.SimpleAssignmentExpression: newProgramState = VisitSimpleAssignment((AssignmentExpressionSyntax)instruction, newProgramState); break; case SyntaxKind.OrAssignmentExpression: newProgramState = VisitBooleanBinaryOpAssignment(newProgramState, (AssignmentExpressionSyntax)instruction, (l, r) => new OrSymbolicValue(l, r)); break; case SyntaxKind.AndAssignmentExpression: newProgramState = VisitBooleanBinaryOpAssignment(newProgramState, (AssignmentExpressionSyntax)instruction, (l, r) => new AndSymbolicValue(l, r)); break; case SyntaxKind.ExclusiveOrAssignmentExpression: newProgramState = VisitBooleanBinaryOpAssignment(newProgramState, (AssignmentExpressionSyntax)instruction, (l, r) => new XorSymbolicValue(l, r)); break; case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.DivideAssignmentExpression: case SyntaxKind.MultiplyAssignmentExpression: case SyntaxKind.ModuloAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: newProgramState = VisitOpAssignment((AssignmentExpressionSyntax)instruction, newProgramState); break; case SyntaxKind.PreIncrementExpression: case SyntaxKind.PreDecrementExpression: newProgramState = VisitPrefixIncrement((PrefixUnaryExpressionSyntax)instruction, newProgramState); break; case SyntaxKind.PostIncrementExpression: case SyntaxKind.PostDecrementExpression: newProgramState = VisitPostfixIncrement((PostfixUnaryExpressionSyntax)instruction, newProgramState); break; case SyntaxKind.IdentifierName: newProgramState = VisitIdentifier((IdentifierNameSyntax)instruction, newProgramState); break; case SyntaxKind.BitwiseOrExpression: newProgramState = VisitBinaryOperator(newProgramState, (l, r) => new OrSymbolicValue(l, r)); break; case SyntaxKind.BitwiseAndExpression: newProgramState = VisitBinaryOperator(newProgramState, (l, r) => new AndSymbolicValue(l, r)); break; case SyntaxKind.ExclusiveOrExpression: newProgramState = VisitBinaryOperator(newProgramState, (l, r) => new XorSymbolicValue(l, r)); break; case SyntaxKind.LessThanExpression: newProgramState = VisitComparisonBinaryOperator(newProgramState, (BinaryExpressionSyntax)instruction, (l, r) => new ComparisonSymbolicValue(ComparisonKind.Less, l, r)); break; case SyntaxKind.LessThanOrEqualExpression: newProgramState = VisitComparisonBinaryOperator(newProgramState, (BinaryExpressionSyntax)instruction, (l, r) => new ComparisonSymbolicValue(ComparisonKind.LessOrEqual, l, r)); break; case SyntaxKind.GreaterThanExpression: newProgramState = VisitComparisonBinaryOperator(newProgramState, (BinaryExpressionSyntax)instruction, (l, r) => new ComparisonSymbolicValue(ComparisonKind.Less, r, l)); break; case SyntaxKind.GreaterThanOrEqualExpression: newProgramState = VisitComparisonBinaryOperator(newProgramState, (BinaryExpressionSyntax)instruction, (l, r) => new ComparisonSymbolicValue(ComparisonKind.LessOrEqual, r, l)); break; case SyntaxKind.SubtractExpression: case SyntaxKind.AddExpression: case SyntaxKind.DivideExpression: case SyntaxKind.MultiplyExpression: case SyntaxKind.ModuloExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: newProgramState = newProgramState.PopValues(2); newProgramState = newProgramState.PushValue(new SymbolicValue()); break; case SyntaxKind.EqualsExpression: var binary = (BinaryExpressionSyntax)instruction; newProgramState = IsOperatorOnObject(instruction) ? VisitReferenceEquals(binary, newProgramState) : VisitValueEquals(newProgramState); break; case SyntaxKind.NotEqualsExpression: newProgramState = IsOperatorOnObject(instruction) ? VisitBinaryOperator(newProgramState, (l, r) => new ReferenceNotEqualsSymbolicValue(l, r)) : VisitBinaryOperator(newProgramState, (l, r) => new ValueNotEqualsSymbolicValue(l, r)); break; case SyntaxKind.BitwiseNotExpression: case SyntaxKind.UnaryMinusExpression: case SyntaxKind.UnaryPlusExpression: case SyntaxKind.AddressOfExpression: case SyntaxKind.PointerIndirectionExpression: case SyntaxKind.MakeRefExpression: case SyntaxKind.RefTypeExpression: case SyntaxKind.RefValueExpression: case SyntaxKind.MemberBindingExpression: case SyntaxKind.AwaitExpression: newProgramState = newProgramState.PopValue(); newProgramState = newProgramState.PushValue(new SymbolicValue()); break; case SyntaxKind.AsExpression: case SyntaxKind.IsExpression: newProgramState = VisitSafeCastExpression((BinaryExpressionSyntax)instruction, newProgramState); break; case SyntaxKind.SimpleMemberAccessExpression: { var memberAccess = (MemberAccessExpressionSyntax)instruction; var check = explodedGraphChecks.OfType <EmptyNullableValueAccess.NullValueAccessedCheck>().FirstOrDefault(); if (check == null || !check.TryProcessInstruction(memberAccess, newProgramState, out newProgramState)) { // Default behavior newProgramState = VisitMemberAccess(memberAccess, newProgramState); } } break; case SyntaxKind.PointerMemberAccessExpression: { newProgramState = VisitMemberAccess((MemberAccessExpressionSyntax)instruction, newProgramState); } break; case SyntaxKind.GenericName: case SyntaxKind.AliasQualifiedName: case SyntaxKind.QualifiedName: case SyntaxKind.PredefinedType: case SyntaxKind.NullableType: case SyntaxKind.OmittedArraySizeExpression: case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.QueryExpression: case SyntaxKind.ArgListExpression: newProgramState = newProgramState.PushValue(new SymbolicValue()); break; case SyntaxKind.LogicalNotExpression: { newProgramState = newProgramState.PopValue(out var sv); newProgramState = newProgramState.PushValue(new LogicalNotSymbolicValue(sv)); } break; case SyntaxKind.TrueLiteralExpression: newProgramState = newProgramState.PushValue(SymbolicValue.True); break; case SyntaxKind.FalseLiteralExpression: newProgramState = newProgramState.PushValue(SymbolicValue.False); break; case SyntaxKind.NullLiteralExpression: newProgramState = newProgramState.PushValue(SymbolicValue.Null); break; case SyntaxKind.ThisExpression: newProgramState = newProgramState.PushValue(SymbolicValue.This); break; case SyntaxKind.BaseExpression: newProgramState = newProgramState.PushValue(SymbolicValue.Base); break; case SyntaxKind.CharacterLiteralExpression: case SyntaxKind.StringLiteralExpression: case SyntaxKind.NumericLiteralExpression: case SyntaxKind.SizeOfExpression: case SyntaxKind.TypeOfExpression: case SyntaxKind.ArrayCreationExpression: case SyntaxKind.ImplicitArrayCreationExpression: case SyntaxKind.StackAllocArrayCreationExpression: { var sv = new SymbolicValue(); newProgramState = newProgramState.SetConstraint(sv, ObjectConstraint.NotNull); newProgramState = newProgramState.PushValue(sv); newProgramState = InvokeChecks(newProgramState, (ps, check) => check.ObjectCreated(ps, sv, instruction)); } break; case SyntaxKind.DefaultExpression: newProgramState = VisitDefaultExpression((DefaultExpressionSyntax)instruction, newProgramState); break; case SyntaxKind.AnonymousObjectCreationExpression: { var creation = (AnonymousObjectCreationExpressionSyntax)instruction; newProgramState = newProgramState.PopValues(creation.Initializers.Count); var sv = new SymbolicValue(); newProgramState = newProgramState.SetConstraint(sv, ObjectConstraint.NotNull); newProgramState = newProgramState.PushValue(sv); newProgramState = InvokeChecks(newProgramState, (ps, check) => check.ObjectCreated(ps, sv, instruction)); } break; case SyntaxKind.CastExpression: case SyntaxKind.CheckedExpression: case SyntaxKind.UncheckedExpression: // Do nothing break; case SyntaxKind.InterpolatedStringExpression: newProgramState = newProgramState.PopValues(((InterpolatedStringExpressionSyntax)instruction).Contents.OfType <InterpolationSyntax>().Count()); newProgramState = newProgramState.PushValue(new SymbolicValue()); break; case SyntaxKind.ObjectCreationExpression: newProgramState = VisitObjectCreation((ObjectCreationExpressionSyntax)instruction, newProgramState); break; case SyntaxKind.ElementAccessExpression: newProgramState = newProgramState.PopValues((((ElementAccessExpressionSyntax)instruction).ArgumentList?.Arguments.Count ?? 0) + 1); newProgramState = newProgramState.PushValue(new SymbolicValue()); break; case SyntaxKind.ImplicitElementAccess: newProgramState = newProgramState .PopValues(((ImplicitElementAccessSyntax)instruction).ArgumentList?.Arguments.Count ?? 0) .PushValue(new SymbolicValue()); break; case SyntaxKind.ObjectInitializerExpression: case SyntaxKind.ArrayInitializerExpression: case SyntaxKind.CollectionInitializerExpression: case SyntaxKind.ComplexElementInitializerExpression: newProgramState = VisitInitializer(instruction, parenthesizedExpression, newProgramState); break; case SyntaxKind.ArrayType: newProgramState = newProgramState.PopValues(((ArrayTypeSyntax)instruction).RankSpecifiers.SelectMany(rs => rs.Sizes).Count()); break; case SyntaxKind.ElementBindingExpression: newProgramState = newProgramState.PopValues(((ElementBindingExpressionSyntax)instruction).ArgumentList?.Arguments.Count ?? 0); newProgramState = newProgramState.PushValue(new SymbolicValue()); break; case SyntaxKind.InvocationExpression: { var invocation = (InvocationExpressionSyntax)instruction; var invocationVisitor = new InvocationVisitor(invocation, SemanticModel, newProgramState); newProgramState = invocationVisitor.ProcessInvocation(); if (invocation.Expression.IsOnThis() && !invocation.IsNameof(SemanticModel)) { newProgramState = newProgramState.RemoveSymbols(IsFieldSymbol); } } break; default: throw new NotImplementedException($"{instruction.Kind()}"); } newProgramState = EnsureStackState(parenthesizedExpression, newProgramState); OnInstructionProcessed(instruction, node.ProgramPoint, newProgramState); EnqueueNewNode(newProgramPoint, newProgramState); }
protected override void VisitBinaryBranch(BinaryBranchBlock binaryBranchBlock, ExplodedGraphNode node) { var newProgramState = CleanStateAfterBlock(node.ProgramState, node.ProgramPoint.Block); switch (binaryBranchBlock.BranchingNode.Kind()) { case SyntaxKind.ForEachStatement: VisitForeachBinaryBranch(binaryBranchBlock, newProgramState); return; case SyntaxKind.CoalesceExpression: VisitCoalesceExpressionBinaryBranch(binaryBranchBlock, newProgramState); return; case SyntaxKind.ConditionalAccessExpression: VisitConditionalAccessBinaryBranch(binaryBranchBlock, newProgramState); return; case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: VisitBinaryBranch(binaryBranchBlock, node, ((BinaryExpressionSyntax)binaryBranchBlock.BranchingNode).Left); return; case SyntaxKind.WhileStatement: VisitBinaryBranch(binaryBranchBlock, node, ((WhileStatementSyntax)binaryBranchBlock.BranchingNode).Condition); return; case SyntaxKind.DoStatement: VisitBinaryBranch(binaryBranchBlock, node, ((DoStatementSyntax)binaryBranchBlock.BranchingNode).Condition); return; case SyntaxKind.ForStatement: VisitBinaryBranch(binaryBranchBlock, node, ((ForStatementSyntax)binaryBranchBlock.BranchingNode).Condition); return; case SyntaxKind.IfStatement: VisitBinaryBranch(binaryBranchBlock, node, ((IfStatementSyntax)binaryBranchBlock.BranchingNode).Condition); return; case SyntaxKind.ConditionalExpression: VisitBinaryBranch(binaryBranchBlock, node, ((ConditionalExpressionSyntax)binaryBranchBlock.BranchingNode).Condition); return; default: System.Diagnostics.Debug.Fail($"Branch kind '{binaryBranchBlock.BranchingNode.Kind()}' not handled"); VisitBinaryBranch(binaryBranchBlock, node, null); return; } }
protected override void VisitBinaryBranch(BinaryBranchBlock binaryBranchBlock, ExplodedGraphNode node) { var newProgramState = CleanStateAfterBlock(node.ProgramState, node.ProgramPoint.Block); switch (binaryBranchBlock.BranchingNode.Kind()) { case SyntaxKind.ForEachStatement: VisitForeachBinaryBranch(binaryBranchBlock, newProgramState); return; case SyntaxKind.CoalesceExpression: VisitCoalesceExpressionBinaryBranch(binaryBranchBlock, newProgramState); return; case SyntaxKind.ConditionalAccessExpression: VisitConditionalAccessBinaryBranch(binaryBranchBlock, newProgramState); return; case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: VisitBinaryBranch(binaryBranchBlock, node, ((BinaryExpressionSyntax)binaryBranchBlock.BranchingNode).Left); return; case SyntaxKind.ForStatement: VisitBinaryBranch(binaryBranchBlock, node, ((ForStatementSyntax)binaryBranchBlock.BranchingNode).Condition); return; case SyntaxKind.ConditionalExpression: VisitBinaryBranch(binaryBranchBlock, node, ((ConditionalExpressionSyntax)binaryBranchBlock.BranchingNode).Condition); return; case SyntaxKind.CatchFilterClause: VisitBinaryBranch(binaryBranchBlock, node, ((CatchFilterClauseSyntax)binaryBranchBlock.BranchingNode).FilterExpression); return; default: VisitBinaryBranch(binaryBranchBlock, node, binaryBranchBlock.BranchingNode); return; } }
protected virtual void VisitBranchBlock(ExplodedGraphNode node, ProgramPoint programPoint) { var newProgramState = node.ProgramState.PopValue(); newProgramState = CleanStateAfterBlock(newProgramState, node.ProgramPoint.Block); EnqueueAllSuccessors(programPoint.Block, newProgramState); }