From 61b71807dfe77c668a6bbd3e475fddedf8ad5dc0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Nov 2021 14:14:17 +0100 Subject: [PATCH] Add codeql sources (6c2713dd8bf76ae1207e3123900a04d6f89b5162) --- repo-tests/codeql.txt | 2 +- .../cpp/security/PrivateCleartextWrite.qll | 7 +- .../semmle/code/cpp/security/PrivateData.qll | 39 +- .../cpp/ql/lib/external/ExternalArtifact.qll | 18 +- .../cpp/ql/lib/semmle/code/cpp/Class.qll | 39 +- .../ql/lib/semmle/code/cpp/Declaration.qll | 43 +- .../cpp/ql/lib/semmle/code/cpp/Element.qll | 8 +- .../cpp/ql/lib/semmle/code/cpp/Enum.qll | 2 +- .../cpp/ql/lib/semmle/code/cpp/File.qll | 22 +- .../cpp/ql/lib/semmle/code/cpp/Function.qll | 79 +- .../cpp/ql/lib/semmle/code/cpp/Include.qll | 6 +- .../ql/lib/semmle/code/cpp/Initializer.qll | 4 +- .../cpp/ql/lib/semmle/code/cpp/Location.qll | 12 +- .../cpp/ql/lib/semmle/code/cpp/Macro.qll | 18 +- .../ql/lib/semmle/code/cpp/MemberFunction.qll | 58 +- .../cpp/ql/lib/semmle/code/cpp/Namespace.qll | 14 +- .../cpp/ql/lib/semmle/code/cpp/Parameter.qll | 30 +- .../ql/lib/semmle/code/cpp/Preprocessor.qll | 12 +- .../cpp/ql/lib/semmle/code/cpp/Print.qll | 133 +- .../cpp/ql/lib/semmle/code/cpp/Specifier.qll | 44 +- .../cpp/ql/lib/semmle/code/cpp/Struct.qll | 2 +- .../cpp/ql/lib/semmle/code/cpp/TestFile.qll | 14 +- .../cpp/ql/lib/semmle/code/cpp/Type.qll | 62 +- .../ql/lib/semmle/code/cpp/TypedefType.qll | 10 +- .../cpp/ql/lib/semmle/code/cpp/Union.qll | 2 +- .../cpp/ql/lib/semmle/code/cpp/UserType.qll | 20 +- .../cpp/ql/lib/semmle/code/cpp/Variable.qll | 43 +- .../codeql/cpp/ql/lib/semmle/code/cpp/XML.qll | 12 +- .../semmle/code/cpp/commons/CommonType.qll | 16 +- .../semmle/code/cpp/commons/Dependency.qll | 10 +- .../semmle/code/cpp/commons/Exclusions.qll | 41 +- .../code/cpp/commons/NullTermination.qll | 53 +- .../ql/lib/semmle/code/cpp/commons/Printf.qll | 208 +- .../ql/lib/semmle/code/cpp/commons/Scanf.qll | 44 +- .../code/cpp/commons/Synchronization.qll | 18 +- .../code/cpp/controlflow/BasicBlocks.qll | 6 +- .../code/cpp/controlflow/ControlFlowGraph.qll | 4 +- .../cpp/controlflow/DefinitionsAndUses.qll | 2 +- .../semmle/code/cpp/controlflow/IRGuards.qll | 22 +- .../LocalScopeVariableReachability.qll | 62 +- .../lib/semmle/code/cpp/controlflow/SSA.qll | 4 +- .../semmle/code/cpp/controlflow/SSAUtils.qll | 2 +- .../controlflow/StackVariableReachability.qll | 62 +- .../code/cpp/controlflow/SubBasicBlocks.qll | 4 +- .../code/cpp/controlflow/internal/CFG.qll | 4 +- .../controlflow/internal/ConstantExprs.qll | 265 +- .../cpp/dataflow/internal/DataFlowImpl.qll | 250 +- .../cpp/dataflow/internal/DataFlowImpl2.qll | 250 +- .../cpp/dataflow/internal/DataFlowImpl3.qll | 250 +- .../cpp/dataflow/internal/DataFlowImpl4.qll | 250 +- .../dataflow/internal/DataFlowImplCommon.qll | 49 +- .../internal/DataFlowImplConsistency.qll | 13 +- .../dataflow/internal/DataFlowImplLocal.qll | 250 +- .../cpp/dataflow/internal/DataFlowPrivate.qll | 15 + .../cpp/dataflow/internal/DataFlowUtil.qll | 36 +- .../code/cpp/dataflow/internal/FlowVar.qll | 8 +- .../cpp/dataflow/internal/SubBasicBlocks.qll | 4 +- .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- .../ql/lib/semmle/code/cpp/exprs/Access.qll | 6 +- .../code/cpp/exprs/ArithmeticOperation.qll | 4 +- .../code/cpp/exprs/BuiltInOperations.qll | 12 +- .../cpp/ql/lib/semmle/code/cpp/exprs/Call.qll | 58 +- .../cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll | 52 +- .../cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll | 60 +- .../ql/lib/semmle/code/cpp/exprs/Lambda.qll | 8 +- .../ql/lib/semmle/code/cpp/exprs/Literal.qll | 32 +- .../internal/AddressConstantExpression.qll | 2 +- .../code/cpp/internal/QualifiedName.qll | 2 +- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 18 + .../ir/dataflow/internal/DataFlowDispatch.qll | 7 +- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 250 +- .../ir/dataflow/internal/DataFlowImpl2.qll | 250 +- .../ir/dataflow/internal/DataFlowImpl3.qll | 250 +- .../ir/dataflow/internal/DataFlowImpl4.qll | 250 +- .../dataflow/internal/DataFlowImplCommon.qll | 49 +- .../internal/DataFlowImplConsistency.qll | 13 +- .../ir/dataflow/internal/DataFlowPrivate.qll | 243 +- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 714 ++- .../ir/dataflow/internal/SsaImplCommon.qll | 636 +++ .../ir/dataflow/internal/SsaImplSpecific.qll | 18 + .../cpp/ir/dataflow/internal/SsaInternals.qll | 600 +++ .../dataflow/internal/TaintTrackingUtil.qll | 4 - .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- .../tainttracking3/TaintTrackingImpl.qll | 12 +- .../ir/implementation/aliased_ssa/IRBlock.qll | 30 +- .../aliased_ssa/Instruction.qll | 461 +- .../ir/implementation/aliased_ssa/Operand.qll | 56 +- .../cpp/ir/implementation/raw/IRBlock.qll | 30 +- .../cpp/ir/implementation/raw/Instruction.qll | 461 +- .../cpp/ir/implementation/raw/Operand.qll | 56 +- .../raw/internal/TranslatedExpr.qll | 847 +-- .../raw/internal/TranslatedStmt.qll | 4 +- .../implementation/unaliased_ssa/IRBlock.qll | 30 +- .../unaliased_ssa/Instruction.qll | 461 +- .../implementation/unaliased_ssa/Operand.qll | 56 +- .../semmle/code/cpp/metrics/MetricClass.qll | 2 +- .../semmle/code/cpp/metrics/MetricFile.qll | 2 +- .../code/cpp/metrics/MetricFunction.qll | 4 +- .../cpp/models/implementations/Allocation.qll | 54 +- .../cpp/models/implementations/GetDelim.qll | 2 +- .../code/cpp/models/implementations/Gets.qll | 6 +- .../cpp/models/implementations/Iterator.qll | 10 + .../cpp/models/implementations/Memcpy.qll | 36 +- .../cpp/models/implementations/Memset.qll | 10 +- .../code/cpp/models/implementations/Pure.qll | 56 +- .../models/implementations/SmartPointer.qll | 10 +- .../cpp/models/implementations/Sscanf.qll | 14 +- .../models/implementations/StdContainer.qll | 34 +- .../cpp/models/implementations/StdMap.qll | 14 +- .../cpp/models/implementations/StdPair.qll | 6 +- .../cpp/models/implementations/StdSet.qll | 10 +- .../cpp/models/implementations/StdString.qll | 46 +- .../cpp/models/implementations/Strcat.qll | 6 +- .../cpp/models/implementations/Strcpy.qll | 50 +- .../cpp/models/implementations/Strcrement.qll | 6 +- .../code/cpp/models/implementations/Swap.qll | 2 +- .../interfaces/FunctionInputsAndOutputs.qll | 18 +- .../lib/semmle/code/cpp/padding/Padding.qll | 119 +- .../code/cpp/rangeanalysis/RangeSSA.qll | 4 +- .../cpp/rangeanalysis/SimpleRangeAnalysis.qll | 17 +- .../semmle/code/cpp/security/BufferWrite.qll | 80 +- .../code/cpp/security/CommandExecution.qll | 76 +- .../semmle/code/cpp/security/FileWrite.qll | 38 +- .../semmle/code/cpp/security/FlowSources.qll | 8 +- .../cpp/security/FunctionWithWrappers.qll | 6 +- .../semmle/code/cpp/security/OutputWrite.qll | 19 +- .../lib/semmle/code/cpp/security/Security.qll | 2 +- .../code/cpp/security/SensitiveExprs.qll | 17 +- .../cpp/security/boostorg/asio/protocols.qll | 2 +- .../ql/lib/semmle/code/cpp/stmts/Block.qll | 6 +- .../cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll | 44 +- .../code/cpp/valuenumbering/HashCons.qll | 4 +- .../ClassesWithManyFields.ql | 24 +- .../Likely Errors/EmptyBlock.ql | 5 +- .../Magic Constants/MagicConstants.qll | 10 +- .../Unused Entities/UnusedStaticFunctions.ql | 2 +- .../ql/src/JPL_C/LOC-2/Rule 09/Semaphores.qll | 6 +- .../Conversion/NonzeroValueCastToPointer.ql | 17 +- .../Likely Bugs/Format/NonConstantFormat.ql | 4 +- .../ql/src/Likely Bugs/Leap Year/LeapYear.qll | 2 +- .../Likely Typos/ExprHasNoEffect.ql | 2 +- .../ImproperNullTermination.ql | 1 - .../Memory Management/NtohlArrayNoBound.qll | 8 +- .../Memory Management/StrncpyFlippedArgs.ql | 28 +- .../Metrics/Files/FCyclomaticComplexity.ql | 2 +- .../cpp/ql/src/Power of 10/Rule 1/UseOfJmp.ql | 5 +- .../src/Security/CWE/CWE-022/TaintedPath.ql | 13 +- .../CWE-170/ImproperNullTerminationTainted.ql | 7 +- .../ql/src/Security/CWE/CWE-319/UseOfHttp.ql | 90 + .../Security/CWE/CWE-497/ExposedSystemData.ql | 129 +- .../IncorrectChangingWorkingDirectory.ql | 69 + .../CWE-273/PrivilegeDroppingOutoforder.ql | 15 +- .../CWE/CWE-377/InsecureTemporaryFile.ql | 112 + ...cErrorWhenUseBitwiseOrLogicalOperations.ql | 5 +- .../cpp/ql/src/external/CodeDuplication.qll | 20 +- .../cpp/ql/src/external/MetricFilter.qll | 4 +- .../cpp/ql/src/jsf/4.09 Style/AV Rule 53.1.ql | 9 +- .../cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql | 2 +- .../AV Rule 135.ql | 2 +- .../AV Rule 173.ql | 2 +- .../src/jsf/4.28 Portable Code/AV Rule 209.ql | 8 +- .../src/jsf/4.28 Portable Code/AV Rule 210.ql | 6 +- .../ql/consistency-queries/CfgConsistency.ql | 64 + .../csharp/ql/consistency-queries/qlpack.yml | 6 + .../ql/lib/semmle/code/asp/WebConfig.qll | 22 +- .../csharp/ql/lib/semmle/code/cil/Access.qll | 10 +- .../ql/lib/semmle/code/cil/BasicBlock.qll | 38 +- .../lib/semmle/code/cil/ConsistencyChecks.qll | 67 +- .../ql/lib/semmle/code/cil/ControlFlow.qll | 16 +- .../ql/lib/semmle/code/cil/Declaration.qll | 17 +- .../ql/lib/semmle/code/cil/Generics.qll | 2 +- .../ql/lib/semmle/code/cil/Instruction.qll | 16 +- .../lib/semmle/code/cil/InstructionGroups.qll | 54 +- .../ql/lib/semmle/code/cil/Instructions.qll | 103 +- .../csharp/ql/lib/semmle/code/cil/Method.qll | 72 +- .../csharp/ql/lib/semmle/code/cil/Type.qll | 8 +- .../csharp/ql/lib/semmle/code/cil/Types.qll | 18 +- .../ql/lib/semmle/code/cil/Variable.qll | 39 +- .../code/cil/internal/SsaImplCommon.qll | 33 +- .../lib/semmle/code/csharp/AnnotatedType.qll | 14 +- .../ql/lib/semmle/code/csharp/Attribute.qll | 2 +- .../ql/lib/semmle/code/csharp/Callable.qll | 28 +- .../ql/lib/semmle/code/csharp/Comments.qll | 2 +- .../ql/lib/semmle/code/csharp/Conversion.qll | 7 +- .../ql/lib/semmle/code/csharp/Element.qll | 2 +- .../ql/lib/semmle/code/csharp/Event.qll | 12 +- .../csharp/ql/lib/semmle/code/csharp/File.qll | 30 +- .../ql/lib/semmle/code/csharp/Generics.qll | 36 +- .../ql/lib/semmle/code/csharp/Member.qll | 45 +- .../ql/lib/semmle/code/csharp/Modifier.qll | 7 +- .../lib/semmle/code/csharp/Preprocessor.qll | 2 +- .../ql/lib/semmle/code/csharp/PrintAst.ql | 20 - .../ql/lib/semmle/code/csharp/PrintAst.qll | 6 +- .../ql/lib/semmle/code/csharp/Property.qll | 46 +- .../csharp/ql/lib/semmle/code/csharp/Stmt.qll | 70 +- .../csharp/ql/lib/semmle/code/csharp/Type.qll | 98 +- .../ql/lib/semmle/code/csharp/Unification.qll | 2 +- .../ql/lib/semmle/code/csharp/Variable.qll | 10 +- .../csharp/ql/lib/semmle/code/csharp/XML.qll | 12 +- .../semmle/code/csharp/commons/Assertions.qll | 4 +- .../code/csharp/commons/Collections.qll | 103 +- .../code/csharp/commons/GeneratedCode.qll | 4 +- .../code/csharp/controlflow/BasicBlocks.qll | 32 +- .../csharp/controlflow/ControlFlowElement.qll | 5 +- .../csharp/controlflow/ControlFlowGraph.qll | 24 +- .../semmle/code/csharp/controlflow/Guards.qll | 6 +- .../internal/ControlFlowGraphImpl.qll | 10 +- .../internal/ControlFlowGraphImplShared.qll | 3 +- .../controlflow/internal/PreBasicBlocks.qll | 6 +- .../csharp/controlflow/internal/Splitting.qll | 10 +- .../controlflow/internal/SuccessorType.qll | 4 +- .../internal/pressa/SsaImplCommon.qll | 33 +- .../code/csharp/dataflow/ExternalFlow.qll | 2 +- .../code/csharp/dataflow/FlowSummary.qll | 17 + .../csharp/dataflow/LibraryTypeDataFlow.qll | 150 +- .../lib/semmle/code/csharp/dataflow/SSA.qll | 26 +- .../csharp/dataflow/internal/DataFlowImpl.qll | 250 +- .../dataflow/internal/DataFlowImpl2.qll | 250 +- .../dataflow/internal/DataFlowImpl3.qll | 250 +- .../dataflow/internal/DataFlowImpl4.qll | 250 +- .../dataflow/internal/DataFlowImpl5.qll | 250 +- .../dataflow/internal/DataFlowImplCommon.qll | 49 +- .../internal/DataFlowImplConsistency.qll | 13 +- .../dataflow/internal/DataFlowPrivate.qll | 57 +- .../dataflow/internal/FlowSummaryImpl.qll | 106 +- .../dataflow/internal/SsaImplCommon.qll | 33 +- .../internal/basessa/SsaImplCommon.qll | 33 +- .../internal/rangeanalysis/RangeUtils.qll | 4 +- .../rangeanalysis/SsaReadPositionCommon.qll | 6 +- .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- .../tainttracking3/TaintTrackingImpl.qll | 12 +- .../tainttracking4/TaintTrackingImpl.qll | 12 +- .../tainttracking5/TaintTrackingImpl.qll | 12 +- .../semmle/code/csharp/dispatch/Dispatch.qll | 75 +- .../csharp/dispatch/OverridableCallable.qll | 24 +- .../lib/semmle/code/csharp/exprs/Access.qll | 18 +- .../code/csharp/exprs/ArithmeticOperation.qll | 4 +- .../semmle/code/csharp/exprs/Assignment.qll | 6 +- .../ql/lib/semmle/code/csharp/exprs/Call.qll | 52 +- .../lib/semmle/code/csharp/exprs/Creation.qll | 12 +- .../lib/semmle/code/csharp/exprs/Dynamic.qll | 12 +- .../ql/lib/semmle/code/csharp/exprs/Expr.qll | 38 +- .../lib/semmle/code/csharp/exprs/Literal.qll | 6 +- .../csharp/frameworks/EntityFramework.qll | 16 +- .../semmle/code/csharp/frameworks/Format.qll | 4 +- .../semmle/code/csharp/frameworks/JsonNET.qll | 32 +- .../lib/semmle/code/csharp/frameworks/Moq.qll | 2 +- .../code/csharp/frameworks/NHibernate.qll | 10 +- .../semmle/code/csharp/frameworks/System.qll | 14 +- .../lib/semmle/code/csharp/frameworks/WCF.qll | 2 +- .../frameworks/microsoft/AspNetCore.qll | 100 +- .../frameworks/system/collections/Generic.qll | 8 +- .../frameworks/system/data/SqlClient.qll | 2 +- .../system/text/RegularExpressions.qll | 2 +- .../code/csharp/frameworks/system/web/Mvc.qll | 6 +- .../csharp/frameworks/system/web/WebPages.qll | 12 +- .../code/csharp/security/PrivateData.qll | 36 +- .../code/csharp/security/SensitiveActions.qll | 2 +- .../HardcodedSymmetricEncryptionKey.qll | 6 +- .../security/dataflow/ExternalAPIsQuery.qll | 4 +- .../csharp/security/dataflow/XSSSinks.qll | 4 +- .../flowsinks/ExternalLocationSink.qll | 7 +- .../security/dataflow/flowsources/Remote.qll | 15 +- .../csharp/security/xml/InsecureXMLQuery.qll | 8 +- .../ql/lib/semmle/code/dotnet/Callable.qll | 2 +- .../ql/lib/semmle/code/dotnet/Declaration.qll | 2 +- .../ql/lib/semmle/code/dotnet/Element.qll | 6 +- .../csharp/ql/lib/semmle/code/dotnet/Expr.qll | 2 +- .../ql/lib/semmle/code/dotnet/Generics.qll | 4 +- .../ql/lib/semmle/code/dotnet/Namespace.qll | 2 +- .../csharp/ql/lib/semmle/code/dotnet/Type.qll | 18 +- .../ql/lib/semmle/code/dotnet/Variable.qll | 4 +- .../ExposeRepresentation.ql | 17 +- .../Magic Constants/MagicConstants.qll | 207 +- .../Naming Conventions/DefaultControlNames.ql | 15 +- .../VariableNameTooShort.ql | 11 +- .../ql/src/Dead Code/DeadStoreOfLocal.ql | 27 +- .../Diagnostics/DiagnosticExtractionErrors.ql | 4 +- .../ExternalAPIsUsedWithUntrustedData.ql | 2 +- .../CWE-020/UntrustedDataToExternalAPI.ql | 2 +- .../codeql/csharp/ql/src/Stubs/Stubs.qll | 109 +- .../experimental/CWE-918/RequestForgery.ql | 19 + .../experimental/CWE-918/RequestForgery.qll | 234 + .../ql/src/experimental/ir/IRConsistency.ql | 2 +- .../csharp/ql/src/experimental/ir/PrintIR.ql | 2 +- .../ir/implementation/raw/IRBlock.qll | 30 +- .../ir/implementation/raw/IRConsistency.ql | 2 +- .../ir/implementation/raw/Instruction.qll | 461 +- .../ir/implementation/raw/Operand.qll | 56 +- .../ir/implementation/raw/PrintIR.ql | 2 +- .../raw/internal/TranslatedCondition.qll | 4 +- .../raw/internal/TranslatedDeclaration.qll | 4 +- .../raw/internal/TranslatedElement.qll | 4 +- .../raw/internal/TranslatedExpr.qll | 64 +- .../raw/internal/TranslatedFunction.qll | 20 +- .../raw/internal/TranslatedInitialization.qll | 50 +- .../raw/internal/TranslatedStmt.qll | 96 +- .../implementation/unaliased_ssa/IRBlock.qll | 30 +- .../unaliased_ssa/Instruction.qll | 461 +- .../implementation/unaliased_ssa/Operand.qll | 56 +- .../internal/AliasAnalysisImports.qll | 14 +- .../unaliased_ssa/internal/SSAConsistency.ql | 2 +- .../src/experimental/ir/internal/IRGuards.qll | 16 +- repo-tests/codeql/csharp/ql/src/printAst.ql | 2 +- .../java/ql/lib/config/semmlecode.dbscheme | 11 +- .../java/ql/lib/external/ExternalArtifact.qll | 19 +- .../java/ql/lib/semmle/code/FileSystem.qll | 34 +- .../java/ql/lib/semmle/code/Location.qll | 6 +- .../codeql/java/ql/lib/semmle/code/SMAP.qll | 2 +- .../ql/lib/semmle/code/java/Annotation.qll | 10 +- .../lib/semmle/code/java/ControlFlowGraph.qll | 12 +- .../ql/lib/semmle/code/java/Conversions.qll | 2 +- .../java/ql/lib/semmle/code/java/Element.qll | 4 +- .../java/ql/lib/semmle/code/java/Expr.qll | 157 +- .../java/ql/lib/semmle/code/java/Generics.qll | 40 +- .../java/ql/lib/semmle/code/java/Import.qll | 8 +- .../java/ql/lib/semmle/code/java/JDK.qll | 63 +- .../lib/semmle/code/java/JDKAnnotations.qll | 2 +- .../java/ql/lib/semmle/code/java/JMX.qll | 20 +- .../java/ql/lib/semmle/code/java/Javadoc.qll | 12 +- .../java/ql/lib/semmle/code/java/Maps.qll | 6 +- .../java/ql/lib/semmle/code/java/Member.qll | 74 +- .../java/ql/lib/semmle/code/java/Modifier.qll | 20 +- .../lib/semmle/code/java/PrettyPrintAst.qll | 58 +- .../java/ql/lib/semmle/code/java/PrintAst.qll | 18 +- .../ql/lib/semmle/code/java/Reflection.qll | 58 +- .../ql/lib/semmle/code/java/Statement.qll | 64 +- .../ql/lib/semmle/code/java/StringFormat.qll | 40 +- .../java/ql/lib/semmle/code/java/Type.qll | 292 +- .../ql/lib/semmle/code/java/UnitTests.qll | 55 +- .../java/ql/lib/semmle/code/java/Variable.qll | 10 +- .../semmle/code/java/arithmetic/Overflow.qll | 4 +- .../code/java/controlflow/BasicBlocks.qll | 10 +- .../java/controlflow/UnreachableBlocks.qll | 34 +- .../ExcludeDebuggingProfilingLogging.qll | 15 +- .../code/java/dataflow/ExternalFlow.qll | 35 +- .../semmle/code/java/dataflow/FlowSources.qll | 4 +- .../semmle/code/java/dataflow/FlowSteps.qll | 15 + .../ql/lib/semmle/code/java/dataflow/SSA.qll | 53 +- .../code/java/dataflow/StringPrefixes.qll | 178 + .../code/java/dataflow/internal/BaseSSA.qll | 25 +- .../java/dataflow/internal/ContainerFlow.qll | 4 + .../dataflow/internal/DataFlowDispatch.qll | 17 +- .../java/dataflow/internal/DataFlowImpl.qll | 250 +- .../java/dataflow/internal/DataFlowImpl2.qll | 250 +- .../java/dataflow/internal/DataFlowImpl3.qll | 250 +- .../java/dataflow/internal/DataFlowImpl4.qll | 250 +- .../java/dataflow/internal/DataFlowImpl5.qll | 250 +- .../java/dataflow/internal/DataFlowImpl6.qll | 250 +- .../dataflow/internal/DataFlowImplCommon.qll | 49 +- .../internal/DataFlowImplConsistency.qll | 13 +- .../DataFlowImplForSerializability.qll | 250 +- .../java/dataflow/internal/DataFlowNodes.qll | 60 +- .../dataflow/internal/DataFlowPrivate.qll | 78 +- .../java/dataflow/internal/DataFlowUtil.qll | 9 +- .../dataflow/internal/FlowSummaryImpl.qll | 106 +- .../internal/FlowSummaryImplSpecific.qll | 6 +- .../dataflow/internal/TaintTrackingUtil.qll | 43 +- .../rangeanalysis/SignAnalysisSpecific.qll | 2 +- .../rangeanalysis/SsaReadPositionCommon.qll | 6 +- .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- .../semmle/code/java/deadcode/DeadCode.qll | 36 +- .../semmle/code/java/deadcode/DeadField.qll | 32 +- .../semmle/code/java/deadcode/EntryPoints.qll | 34 +- .../code/java/deadcode/StrutsEntryPoints.qll | 2 +- .../code/java/deadcode/TestEntryPoints.qll | 20 +- .../code/java/deadcode/WebEntryPoints.qll | 4 +- .../code/java/dispatch/DispatchFlow.qll | 7 +- .../lib/semmle/code/java/dispatch/ObjFlow.qll | 9 +- .../code/java/dispatch/WrappedInvocation.qll | 5 +- .../lib/semmle/code/java/frameworks/Camel.qll | 2 +- .../lib/semmle/code/java/frameworks/Guice.qll | 2 +- .../lib/semmle/code/java/frameworks/JAXB.qll | 42 +- .../code/java/frameworks/JUnitAnnotations.qll | 2 +- .../semmle/code/java/frameworks/Jackson.qll | 12 +- .../lib/semmle/code/java/frameworks/JaxWS.qll | 25 +- .../lib/semmle/code/java/frameworks/Jndi.qll | 20 +- .../lib/semmle/code/java/frameworks/Kryo.qll | 26 +- .../semmle/code/java/frameworks/Mockito.qll | 100 +- .../code/java/frameworks/Networking.qll | 20 +- .../semmle/code/java/frameworks/Optional.qll | 9 + .../semmle/code/java/frameworks/Protobuf.qll | 10 +- .../lib/semmle/code/java/frameworks/Rmi.qll | 2 +- .../semmle/code/java/frameworks/Servlets.qll | 16 +- .../semmle/code/java/frameworks/SnakeYaml.qll | 8 +- .../code/java/frameworks/SpringLdap.qll | 48 +- .../semmle/code/java/frameworks/Strings.qll | 3 +- .../semmle/code/java/frameworks/Thrift.qll | 2 +- .../semmle/code/java/frameworks/UnboundId.qll | 40 +- .../code/java/frameworks/android/Android.qll | 14 +- .../java/frameworks/android/AsyncTask.qll | 52 + .../code/java/frameworks/android/Intent.qll | 113 +- .../code/java/frameworks/android/WebView.qll | 6 +- .../semmle/code/java/frameworks/apache/IO.qll | 34 + .../java/frameworks/gigaspaces/GigaSpaces.qll | 6 +- .../frameworks/google/GoogleHttpClientApi.qll | 4 +- .../semmle/code/java/frameworks/gwt/GWT.qll | 4 +- .../code/java/frameworks/gwt/GwtUiBinder.qll | 33 +- .../java/frameworks/gwt/GwtUiBinderXml.qll | 4 +- .../code/java/frameworks/gwt/GwtXml.qll | 28 +- .../code/java/frameworks/j2objc/J2ObjC.qll | 8 +- .../lib/semmle/code/java/frameworks/jOOQ.qll | 8 +- .../jackson/JacksonSerializability.qll | 47 +- .../java/frameworks/javaee/Persistence.qll | 12 +- .../java/frameworks/javaee/PersistenceXML.qll | 4 +- .../code/java/frameworks/javaee/ejb/EJB.qll | 36 +- .../java/frameworks/javaee/ejb/EJBJarXML.qll | 8 +- .../javaee/jsf/JSFFacesContextXML.qll | 18 +- .../frameworks/javaee/jsf/JSFRenderer.qll | 12 +- .../code/java/frameworks/javase/Http.qll | 4 +- .../semmle/code/java/frameworks/play/Play.qll | 2 +- .../code/java/frameworks/ratpack/Ratpack.qll | 87 + .../java/frameworks/ratpack/RatpackExec.qll | 79 + .../java/frameworks/spring/SpringAutowire.qll | 104 +- .../java/frameworks/spring/SpringBean.qll | 10 +- .../java/frameworks/spring/SpringBeanFile.qll | 7 +- .../frameworks/spring/SpringComponentScan.qll | 41 +- .../frameworks/spring/SpringController.qll | 114 +- .../frameworks/spring/SpringExpression.qll | 8 +- .../java/frameworks/spring/SpringFlex.qll | 20 +- .../java/frameworks/spring/SpringHttp.qll | 2 +- .../java/frameworks/spring/SpringProfile.qll | 10 +- .../code/java/frameworks/spring/SpringWeb.qll | 6 +- .../java/frameworks/struts/StrutsActions.qll | 8 +- .../frameworks/struts/StrutsAnnotations.qll | 2 +- .../frameworks/struts/StrutsConventions.qll | 8 +- .../code/java/frameworks/struts/StrutsXML.qll | 38 +- .../code/java/metrics/MetricRefType.qll | 26 +- .../security/AndroidIntentRedirection.qll | 82 + .../AndroidIntentRedirectionQuery.qll | 115 + .../AndroidSensitiveCommunicationQuery.qll | 150 + .../code/java/security/CommandArguments.qll | 28 +- .../code/java/security/ControlledString.qll | 2 +- .../semmle/code/java/security/Encryption.qll | 36 +- .../code/java/security/ExternalAPIs.qll | 46 +- .../semmle/code/java/security/HttpsUrls.qll | 4 +- .../code/java/security/InformationLeak.qll | 4 +- .../code/java/security/InsecureBasicAuth.qll | 2 +- .../code/java/security/JexlInjectionQuery.qll | 35 +- .../code/java/security/MvelInjection.qll | 24 +- .../code/java/security/RelativePaths.qll | 49 +- .../code/java/security/RequestForgery.qll | 147 +- .../code/java/security/SecurityFlag.qll | 2 +- .../code/java/security/SensitiveActions.qll | 10 +- .../code/java/security/SpelInjectionQuery.qll | 4 +- .../security/UnsafeDeserializationQuery.qll | 8 +- .../ql/lib/semmle/code/java/security/XSS.qll | 2 +- .../lib/semmle/code/xml/AndroidManifest.qll | 23 +- .../java/ql/lib/semmle/code/xml/MavenPom.qll | 110 +- .../java/ql/lib/semmle/code/xml/WebXML.qll | 46 +- .../java/ql/lib/semmle/code/xml/XML.qll | 12 +- .../Compatibility/JDK9/JdkInternalAccess.ql | 15 +- .../src/Compatibility/JDK9/JdkInternals.qll | 1506 ++---- .../ql/src/Language Abuse/UselessUpcast.ql | 2 +- .../Likely Bugs/Arithmetic/InformationLoss.ql | 2 +- .../Concurrency/NonSynchronizedOverride.ql | 1 - .../Concurrency/SynchSetUnsynchGet.ql | 1 + .../Inheritance/NoNonFinalInConstructor.ql | 2 +- .../Likely Bugs/Resource Leaks/CloseType.qll | 6 +- .../Performance/InefficientEmptyStringTest.ql | 4 +- .../Security/CWE/CWE-190/ArithmeticCommon.qll | 4 +- .../CWE/CWE-327/BrokenCryptoAlgorithm.ql | 8 +- .../CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql | 8 +- .../CWE/CWE-681/NumericCastCommon.qll | 2 +- .../CWE/CWE-798/HardcodedCredentials.qll | 2 +- .../src/Security/CWE/CWE-798/SensitiveApi.qll | 849 ++- .../CWE/CWE-833/LockOrderInconsistency.ql | 2 +- .../CWE/CWE-927/SensitiveCommunication.ql | 21 + .../CWE/CWE-940/AndroidIntentRedirection.ql | 24 + .../java/ql/src/Telemetry/ExternalAPI.qll | 2 +- .../Dead Code/NonAssignedFields.ql | 4 +- .../Magic Constants/MagicConstants.qll | 197 +- .../Magic Constants/MagicConstantsString.ql | 37 +- .../CWE-016/InsecureSpringActuatorConfig.ql | 4 +- .../CWE/CWE-094/SpringViewManipulationLib.qll | 4 +- .../CWE/CWE-200/AndroidFileIntentSource.qll | 6 +- .../CWE/CWE-326/InsufficientKeySize.ql | 2 +- ...nsafeSpringExporterInConfigurationClass.ql | 2 +- .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 2 +- .../Security/CWE/CWE-552/UnsafeUrlForward.ql | 58 + .../Security/CWE/CWE-552/UnsafeUrlForward.qll | 72 + .../CWE/CWE-927/SensitiveBroadcast.ql | 175 - .../CWE/CWE-939/IncorrectURLVerification.ql | 13 +- .../codeql/java/ql/src/external/Clover.qll | 2 +- .../model-generator/CaptureSinkModels.ql | 57 + .../model-generator/CaptureSourceModels.ql | 53 + .../model-generator/CaptureSummaryModels.ql | 232 + .../model-generator/ModelGeneratorUtils.qll | 173 + .../adaptivethreatmodeling/ATMConfig.qll | 112 + .../AdaptiveThreatModeling.qll | 125 + .../adaptivethreatmodeling/BaseScoring.qll | 121 + .../adaptivethreatmodeling/CodeToFeatures.qll | 444 ++ .../adaptivethreatmodeling/CoreKnowledge.qll | 208 + .../EndpointFeatures.qll | 289 + .../EndpointScoring.qll | 223 + .../adaptivethreatmodeling/EndpointTypes.qll | 57 + .../FilteringReasons.qll | 196 + .../NosqlInjectionATM.qll | 175 + .../SqlInjectionATM.qll | 94 + .../StandardEndpointFilters.qll | 137 + .../adaptivethreatmodeling/TaintedPathATM.qll | 123 + .../adaptivethreatmodeling/XssATM.qll | 103 + .../adaptivethreatmodeling/lib/qlpack.yml | 6 + .../src/NosqlInjectionATM.ql | 30 + .../src/SqlInjectionATM.ql | 30 + .../src/TaintedPathATM.ql | 30 + .../adaptivethreatmodeling/src/XssATM.ql | 31 + .../adaptivethreatmodeling/src/qlpack.yml | 7 + .../codeql/javascript/ql/lib/javascript.qll | 1 + .../ql/lib/semmle/javascript/AST.qll | 2 + .../ql/lib/semmle/javascript/ApiGraphs.qll | 103 +- .../ql/lib/semmle/javascript/DOM.qll | 63 +- .../javascript/DynamicPropertyAccess.qll | 2 +- .../lib/semmle/javascript/ES2015Modules.qll | 2 +- .../ql/lib/semmle/javascript/Expr.qll | 8 + .../ql/lib/semmle/javascript/Files.qll | 8 +- .../semmle/javascript/GlobalAccessPaths.qll | 11 + .../ql/lib/semmle/javascript/JSDoc.qll | 8 +- .../lib/semmle/javascript/PackageExports.qll | 42 +- .../ql/lib/semmle/javascript/PrintAst.qll | 2 +- .../ql/lib/semmle/javascript/Promises.qll | 8 + .../ql/lib/semmle/javascript/Regexp.qll | 29 +- .../lib/semmle/javascript/StandardLibrary.qll | 8 +- .../ql/lib/semmle/javascript/XML.qll | 12 +- .../dataflow/AbstractProperties.qll | 1 + .../javascript/dataflow/Configuration.qll | 7 +- .../semmle/javascript/dataflow/DataFlow.qll | 9 +- .../javascript/dataflow/InferredTypes.qll | 8 +- .../lib/semmle/javascript/dataflow/Nodes.qll | 32 +- .../javascript/dataflow/Refinements.qll | 11 +- .../javascript/dataflow/TaintTracking.qll | 12 +- .../dataflow/internal/AnalyzedParameters.qll | 2 +- .../internal/BasicExprTypeInference.qll | 4 +- .../dataflow/internal/CallGraphs.qll | 38 +- .../javascript/filters/ClassifyFiles.qll | 73 +- .../semmle/javascript/frameworks/Angular2.qll | 2 +- .../frameworks/AngularJS/AngularJSCore.qll | 103 +- .../AngularJS/AngularJSExpressions.qll | 23 +- .../javascript/frameworks/AsyncPackage.qll | 30 +- .../javascript/frameworks/ClientRequests.qll | 9 +- .../frameworks/ComposedFunctions.qll | 2 +- .../javascript/frameworks/CookieLibraries.qll | 283 +- .../javascript/frameworks/CryptoLibraries.qll | 185 +- .../javascript/frameworks/EventEmitter.qll | 8 +- .../semmle/javascript/frameworks/Express.qll | 22 +- .../semmle/javascript/frameworks/Files.qll | 7 +- .../lib/semmle/javascript/frameworks/HTTP.qll | 46 +- .../semmle/javascript/frameworks/LdapJS.qll | 71 + .../frameworks/LodashUnderscore.qll | 463 +- .../semmle/javascript/frameworks/Logging.qll | 18 +- .../semmle/javascript/frameworks/MooTools.qll | 2 +- .../semmle/javascript/frameworks/NoSQL.qll | 152 +- .../javascript/frameworks/NodeJSLib.qll | 31 +- .../semmle/javascript/frameworks/PkgCloud.qll | 16 +- .../semmle/javascript/frameworks/ShellJS.qll | 20 +- .../frameworks/StringFormatters.qll | 9 +- .../frameworks/SystemCommandExecutors.qll | 4 +- .../javascript/frameworks/Templating.qll | 25 +- .../semmle/javascript/frameworks/jQuery.qll | 28 +- .../javascript/internal/CachedStages.qll | 2 + .../lib/semmle/javascript/linters/JSLint.qll | 98 +- .../javascript/security/BadTagFilterQuery.qll | 306 ++ .../javascript/security/CryptoAlgorithms.qll | 79 +- .../javascript/security/SensitiveActions.qll | 3 + .../javascript/security/TaintedUrlSuffix.qll | 19 +- .../javascript/security/UselessUseOfCat.qll | 9 +- .../ClientSideUrlRedirectCustomizations.qll | 16 +- .../javascript/security/dataflow/DOM.qll | 9 +- .../LoopBoundInjectionCustomizations.qll | 72 +- ...otypePollutingAssignmentCustomizations.qll | 22 +- .../PrototypePollutingAssignmentQuery.qll | 74 +- .../dataflow/SqlInjectionCustomizations.qll | 31 + .../security/dataflow/SqlInjectionQuery.qll | 7 + .../dataflow/TaintedPathCustomizations.qll | 38 +- ...hroughParameterTamperingCustomizations.qll | 6 +- ...ShellCommandConstructionCustomizations.qll | 6 +- .../javascript/security/dataflow/Xss.qll | 4 +- .../internal/SensitiveDataHeuristics.qll | 2 +- .../PolynomialReDoSCustomizations.qll | 17 +- .../security/performance/ReDoSUtil.qll | 31 +- .../security/performance/RegExpTreeView.qll | 18 +- .../ql/lib/semmlecode.javascript.dbscheme | 2 +- .../ql/src/AngularJS/IncompatibleService.ql | 8 +- .../MixedStaticInstanceThisAccess.ql | 6 +- ...UnsupportedStateUpdateInLifecycleMethod.ql | 12 +- .../ql/src/Security/CWE-089/SqlInjection.ql | 2 + .../Security/CWE-1004/ClientExposedCookie.ql | 20 + .../ql/src/Security/CWE-116/BadTagFilter.ql | 19 + .../CWE-116/IncompleteSanitization.ql | 13 +- .../Security/CWE-209/StackTraceExposure.ql | 1 + .../CWE-295/DisablingCertificateValidation.ql | 1 + .../src/Security/CWE-312/CleartextLogging.ql | 1 + .../Security/CWE-326/InsufficientKeySize.ql | 36 + .../CorsMisconfigurationForCredentials.ql | 1 + .../src/Security/CWE-384/SessionFixation.ql | 58 + .../src/Security/CWE-598/SensitiveGetQuery.ql | 27 + .../src/Security/CWE-614/ClearTextCookie.ql | 21 + .../ql/src/Security/CWE-730/ServerCrash.ql | 2 +- .../CWE-915/PrototypePollutingAssignment.ql | 2 +- .../src/Statements/UseOfReturnlessFunction.ql | 15 +- .../Security/CWE-090/LdapInjection.ql | 20 - .../Security/CWE-090/LdapInjection.qll | 25 - .../CWE-090/LdapInjectionCustomizations.qll | 73 - .../experimental/Security/CWE-090/Ldapjs.qll | 92 - .../CWE-1004/CookieWithoutHttpOnly.ql | 20 - .../Security/CWE-614/InsecureCookie.ql | 18 - .../src/experimental/Security/CWE-918/SSRF.ql | 19 + .../experimental/Security/CWE-918/SSRF.qll | 154 + .../javascript/security/InsecureCookie.qll | 323 -- .../javascript/ql/src/meta/Consistency.ql | 22 +- .../python/ql/lib/semmle/python/ApiGraphs.qll | 39 +- .../python/ql/lib/semmle/python/Concepts.qll | 99 + .../python/ql/lib/semmle/python/Exprs.qll | 4 +- .../python/ql/lib/semmle/python/Files.qll | 10 +- .../python/ql/lib/semmle/python/Flow.qll | 6 +- .../ql/lib/semmle/python/Frameworks.qll | 10 + .../python/ql/lib/semmle/python/Import.qll | 18 +- .../python/ql/lib/semmle/python/Module.qll | 4 +- .../python/ql/lib/semmle/python/PrintAst.qll | 3 +- .../ql/lib/semmle/python/RegexTreeView.qll | 90 +- .../ql/lib/semmle/python/SpecialMethods.qll | 2 +- .../python/ql/lib/semmle/python/Stmts.qll | 4 +- .../python/concepts/CryptoAlgorithms.qll | 79 +- .../dataflow/new/internal/DataFlowImpl.qll | 250 +- .../dataflow/new/internal/DataFlowImpl2.qll | 250 +- .../dataflow/new/internal/DataFlowImpl3.qll | 250 +- .../dataflow/new/internal/DataFlowImpl4.qll | 250 +- .../new/internal/DataFlowImplCommon.qll | 49 +- .../new/internal/DataFlowImplConsistency.qll | 13 +- .../dataflow/new/internal/DataFlowPrivate.qll | 39 +- .../dataflow/new/internal/LocalSources.qll | 8 +- .../dataflow/new/internal/PrintNode.qll | 1 - .../new/internal/TaintTrackingPrivate.qll | 23 + .../dataflow/new/internal/TypeTracker.qll | 45 +- .../tainttracking1/TaintTrackingImpl.qll | 12 +- .../tainttracking2/TaintTrackingImpl.qll | 12 +- .../tainttracking3/TaintTrackingImpl.qll | 12 +- .../tainttracking4/TaintTrackingImpl.qll | 12 +- .../python/dataflow/old/TaintTracking.qll | 8 +- .../python/dependencies/TechInventory.qll | 8 +- .../ql/lib/semmle/python/essa/Definitions.qll | 29 +- .../python/ql/lib/semmle/python/essa/Essa.qll | 4 +- .../lib/semmle/python/frameworks/Aiohttp.qll | 6 +- .../lib/semmle/python/frameworks/Aiomysql.qll | 145 + .../ql/lib/semmle/python/frameworks/Aiopg.qll | 141 + .../lib/semmle/python/frameworks/Asyncpg.qll | 162 + .../semmle/python/frameworks/Cryptodome.qll | 22 +- .../lib/semmle/python/frameworks/Django.qll | 100 +- .../lib/semmle/python/frameworks/FastApi.qll | 352 ++ .../ql/lib/semmle/python/frameworks/Flask.qll | 58 +- .../semmle/python/frameworks/FlaskAdmin.qll | 79 + .../lib/semmle/python/frameworks/Pydantic.qll | 108 + .../python/frameworks/RestFramework.qll | 369 ++ .../semmle/python/frameworks/RuamelYaml.qll | 57 + .../semmle/python/frameworks/SqlAlchemy.qll | 4 +- .../semmle/python/frameworks/Starlette.qll | 162 + .../lib/semmle/python/frameworks/Stdlib.qll | 256 +- .../ql/lib/semmle/python/frameworks/Toml.qll | 101 + .../lib/semmle/python/frameworks/Tornado.qll | 2 +- .../lib/semmle/python/frameworks/Werkzeug.qll | 2 +- .../ql/lib/semmle/python/frameworks/Yaml.qll | 19 +- .../ql/lib/semmle/python/frameworks/Yarl.qll | 2 +- .../frameworks/internal/SubclassFinder.qll | 209 + .../ql/lib/semmle/python/internal/Awaited.qll | 47 + .../lib/semmle/python/objects/Constants.qll | 4 +- .../lib/semmle/python/objects/ObjectAPI.qll | 36 +- .../ql/lib/semmle/python/objects/TObject.qll | 29 +- .../lib/semmle/python/pointsto/PointsTo.qll | 10 +- .../python/ql/lib/semmle/python/regex.qll | 20 +- .../python/security/BadTagFilterQuery.qll | 306 ++ .../lib/semmle/python/security/ClearText.qll | 6 +- .../lib/semmle/python/security/Exceptions.qll | 11 +- .../security/dataflow/PathInjection.qll | 10 +- .../dataflow/PathInjectionCustomizations.qll | 10 + .../PolynomialReDoSCustomizations.qll | 138 +- .../dataflow/ReflectedXSSCustomizations.qll | 2 +- .../dataflow/SqlInjectionCustomizations.qll | 14 +- .../python/security/injection/Command.qll | 14 +- .../security/injection/RegexInjection.qll | 37 + .../RegexInjectionCustomizations.qll | 62 + .../internal/SensitiveDataHeuristics.qll | 2 +- .../python/security/performance/ReDoSUtil.qll | 31 +- .../lib/semmle/python/templates/PyxlTags.qll | 2 +- .../ql/lib/semmle/python/types/Extensions.qll | 15 +- .../semmle/python/types/FunctionObject.qll | 1 + .../ql/lib/semmle/python/types/Properties.qll | 4 +- .../semmle/python/values/StringAttributes.qll | 2 +- .../python/ql/lib/semmle/python/web/Http.qll | 2 +- .../lib/semmle/python/web/HttpConstants.qll | 10 +- .../ql/lib/semmle/python/web/django/Model.qll | 30 +- .../lib/semmle/python/web/falcon/Request.qll | 8 +- .../lib/semmle/python/web/flask/Request.qll | 7 +- .../python/ql/lib/semmle/python/xml/XML.qll | 12 +- .../python/ql/src/Classes/UselessClass.ql | 6 +- .../ql/src/Diagnostics/ExtractionErrors.ql | 23 - .../ql/src/Diagnostics/ExtractionWarnings.ql | 36 + .../python/ql/src/Expressions/CallArgs.qll | 4 +- .../IncorrectRaiseInSpecialMethod.ql | 51 +- .../Functions/SignatureOverriddenMethod.ql | 1 - .../src/Functions/SignatureSpecialMethods.ql | 103 +- .../ql/src/Lexical/CommentedOutCode.qll | 40 +- .../ql/src/Security/CWE-116/BadTagFilter.ql | 19 + .../CWE-295/RequestWithoutValidation.ql | 49 +- .../Security/CWE-730/RegexInjection.ql | 15 +- .../Security/CWE-798/HardcodedCredentials.ql | 2 +- .../ql/src/Statements/RedundantAssignment.ql | 7 +- .../ql/src/Statements/SideEffectInAssert.ql | 13 +- .../python/ql/src/analysis/Consistency.ql | 15 +- .../Security/CWE-113/HeaderInjection.ql | 21 + .../CWE-347/JWTEmptyKeyOrAlgorithm.ql | 22 + ...JWTMissingSecretOrPublicKeyVerification.ql | 17 + .../experimental/semmle/python/Concepts.qll | 248 +- .../experimental/semmle/python/Frameworks.qll | 7 + .../semmle/python/frameworks/Django.qll | 93 + .../semmle/python/frameworks/Flask.qll | 84 + .../semmle/python/frameworks/JWT.qll | 23 + .../semmle/python/frameworks/Stdlib.qll | 88 - .../semmle/python/frameworks/Werkzeug.qll | 33 + .../semmle/python/libraries/Authlib.qll | 87 + .../semmle/python/libraries/PyJWT.qll | 108 + .../semmle/python/libraries/PythonJose.qll | 105 + .../python/security/injection/HTTPHeaders.qll | 20 + .../security/injection/RegexInjection.qll | 53 - .../ql/src/meta/alerts/RequestHandlers.ql | 23 + .../ql/consistency-queries/AstConsistency.ql | 25 + .../ql/consistency-queries/CfgConsistency.ql | 1 + .../DataFlowConsistency.ql | 1 + .../ql/consistency-queries/SsaConsistency.ql | 22 + .../VariablesConsistency.ql | 6 + .../ruby/ql/consistency-queries/qlpack.yml | 5 + repo-tests/codeql/ruby/ql/examples/qlpack.yml | 4 + .../ruby/ql/examples/snippets/emptythen.ql | 18 + .../ruby/ql/lib/codeql/IDEContextual.qll | 19 + .../codeql/ruby/ql/lib/codeql/Locations.qll | 66 + .../ruby/ql/lib/codeql/files/FileSystem.qll | 177 + .../codeql/ruby/ql/lib/codeql/ruby/AST.qll | 141 + .../ruby/ql/lib/codeql/ruby/ApiGraphs.qll | 423 ++ .../codeql/ruby/ql/lib/codeql/ruby/CFG.qll | 5 + .../ruby/ql/lib/codeql/ruby/Concepts.qll | 603 +++ .../ruby/ql/lib/codeql/ruby/DataFlow.qll | 7 + .../ruby/ql/lib/codeql/ruby/DataFlow2.qll | 7 + .../ruby/ql/lib/codeql/ruby/Diagnostics.qll | 52 + .../ruby/ql/lib/codeql/ruby/Frameworks.qll | 12 + .../ruby/ql/lib/codeql/ruby/TaintTracking.qll | 7 + .../ruby/ql/lib/codeql/ruby/ast/Call.qll | 215 + .../ruby/ql/lib/codeql/ruby/ast/Constant.qll | 210 + .../ruby/ql/lib/codeql/ruby/ast/Control.qll | 611 +++ .../ruby/ql/lib/codeql/ruby/ast/Erb.qll | 313 ++ .../ruby/ql/lib/codeql/ruby/ast/Expr.qll | 456 ++ .../ruby/ql/lib/codeql/ruby/ast/Literal.qll | 892 ++++ .../ruby/ql/lib/codeql/ruby/ast/Method.qll | 228 + .../ruby/ql/lib/codeql/ruby/ast/Module.qll | 365 ++ .../ruby/ql/lib/codeql/ruby/ast/Operation.qll | 620 +++ .../ruby/ql/lib/codeql/ruby/ast/Parameter.qll | 248 + .../ruby/ql/lib/codeql/ruby/ast/Pattern.qll | 96 + .../ruby/ql/lib/codeql/ruby/ast/Scope.qll | 24 + .../ruby/ql/lib/codeql/ruby/ast/Statement.qll | 251 + .../ruby/ql/lib/codeql/ruby/ast/Variable.qll | 204 + .../ql/lib/codeql/ruby/ast/internal/AST.qll | 754 +++ .../ql/lib/codeql/ruby/ast/internal/Call.qll | 186 + .../ql/lib/codeql/ruby/ast/internal/Erb.qll | 43 + .../lib/codeql/ruby/ast/internal/Module.qll | 414 ++ .../codeql/ruby/ast/internal/Operation.qll | 198 + .../codeql/ruby/ast/internal/Parameter.qll | 19 + .../lib/codeql/ruby/ast/internal/Pattern.qll | 32 + .../ql/lib/codeql/ruby/ast/internal/Scope.qll | 130 + .../codeql/ruby/ast/internal/Synthesis.qll | 816 +++ .../codeql/ruby/ast/internal/TreeSitter.qll | 1999 +++++++ .../lib/codeql/ruby/ast/internal/Variable.qll | 642 +++ .../codeql/ruby/controlflow/BasicBlocks.qll | 414 ++ .../lib/codeql/ruby/controlflow/CfgNodes.qll | 496 ++ .../ruby/controlflow/ControlFlowGraph.qll | 341 ++ .../ruby/controlflow/internal/Completion.qll | 507 ++ .../internal/ControlFlowGraphImpl.qll | 1173 +++++ .../internal/ControlFlowGraphImplShared.qll | 946 ++++ .../internal/ControlFlowGraphImplSpecific.qll | 74 + .../controlflow/internal/NonReturning.qll | 22 + .../ruby/controlflow/internal/Splitting.qll | 336 ++ .../codeql/ruby/dataflow/BarrierGuards.qll | 75 + .../lib/codeql/ruby/dataflow/FlowSummary.qll | 127 + .../ruby/dataflow/RemoteFlowSources.qll | 37 + .../ruby/ql/lib/codeql/ruby/dataflow/SSA.qll | 403 ++ .../dataflow/internal/DataFlowDispatch.qll | 459 ++ .../ruby/dataflow/internal/DataFlowImpl.qll | 4667 +++++++++++++++++ .../ruby/dataflow/internal/DataFlowImpl2.qll | 4667 +++++++++++++++++ .../dataflow/internal/DataFlowImplCommon.qll | 1331 +++++ .../internal/DataFlowImplConsistency.qll | 182 + .../internal/DataFlowImplSpecific.qll | 11 + .../dataflow/internal/DataFlowPrivate.qll | 824 +++ .../ruby/dataflow/internal/DataFlowPublic.qll | 213 + .../dataflow/internal/FlowSummaryImpl.qll | 1020 ++++ .../internal/FlowSummaryImplSpecific.qll | 120 + .../codeql/ruby/dataflow/internal/SsaImpl.qll | 289 + .../ruby/dataflow/internal/SsaImplCommon.qll | 636 +++ .../dataflow/internal/SsaImplSpecific.qll | 47 + .../internal/TaintTrackingPrivate.qll | 41 + .../dataflow/internal/TaintTrackingPublic.qll | 31 + .../tainttracking1/TaintTrackingImpl.qll | 122 + .../tainttracking1/TaintTrackingParameter.qll | 6 + .../lib/codeql/ruby/filters/GeneratedCode.qll | 43 + .../ruby/frameworks/ActionController.qll | 259 + .../lib/codeql/ruby/frameworks/ActionView.qll | 138 + .../codeql/ruby/frameworks/ActiveRecord.qll | 319 ++ .../codeql/ruby/frameworks/ActiveStorage.qll | 55 + .../ql/lib/codeql/ruby/frameworks/Files.qll | 339 ++ .../codeql/ruby/frameworks/HttpClients.qll | 12 + .../ruby/frameworks/StandardLibrary.qll | 335 ++ .../lib/codeql/ruby/frameworks/XmlParsing.qll | 182 + .../ruby/frameworks/http_clients/Excon.qll | 130 + .../ruby/frameworks/http_clients/Faraday.qll | 140 + .../frameworks/http_clients/HttpClient.qll | 55 + .../ruby/frameworks/http_clients/Httparty.qll | 95 + .../ruby/frameworks/http_clients/NetHttp.qll | 69 + .../ruby/frameworks/http_clients/OpenURI.qll | 113 + .../frameworks/http_clients/RestClient.qll | 71 + .../ruby/frameworks/http_clients/Typhoeus.qll | 74 + .../ruby/ql/lib/codeql/ruby/printAst.qll | 203 + .../ruby/security/BadTagFilterQuery.qll | 306 ++ .../security/CodeInjectionCustomizations.qll | 40 + .../ruby/security/CodeInjectionQuery.qll | 29 + .../CommandInjectionCustomizations.qll | 54 + .../ruby/security/CommandInjectionQuery.qll | 32 + .../security/PathInjectionCustomizations.qll | 54 + .../ruby/security/PathInjectionQuery.qll | 31 + .../ruby/security/ReflectedXSSQuery.qll | 39 + .../codeql/ruby/security/StoredXSSQuery.qll | 40 + .../UnsafeDeserializationCustomizations.qll | 190 + .../security/UnsafeDeserializationQuery.qll | 34 + .../security/UrlRedirectCustomizations.qll | 127 + .../codeql/ruby/security/UrlRedirectQuery.qll | 34 + .../ruby/ql/lib/codeql/ruby/security/XSS.qll | 369 ++ .../performance/ExponentialBackTracking.qll | 343 ++ .../ruby/security/performance/ParseRegExp.qll | 891 ++++ .../PolynomialReDoSCustomizations.qll | 131 + .../performance/PolynomialReDoSQuery.qll | 37 + .../ruby/security/performance/ReDoSUtil.qll | 1241 +++++ .../security/performance/RegExpTreeView.qll | 771 +++ .../performance/SuperlinearBackTracking.qll | 420 ++ .../codeql/ruby/typetracking/TypeTracker.qll | 489 ++ .../ruby/typetracking/TypeTrackerSpecific.qll | 146 + repo-tests/codeql/ruby/ql/lib/qlpack.yml | 6 + repo-tests/codeql/ruby/ql/lib/ruby.dbscheme | 1318 +++++ repo-tests/codeql/ruby/ql/lib/ruby.qll | 1 + repo-tests/codeql/ruby/ql/lib/tutorial.qll | 1207 +++++ .../codeql/ruby/ql/src/AlertSuppression.ql | 82 + .../src/experimental/performance/UseDetect.ql | 64 + .../ruby/ql/src/filters/ClassifyFiles.ql | 20 + .../localDefinitions.ql | 20 + .../ide-contextual-queries/localReferences.ql | 21 + .../ql/src/ide-contextual-queries/printAst.ql | 27 + repo-tests/codeql/ruby/ql/src/qlpack.yml | 7 + .../ql/src/queries/analysis/Definitions.ql | 88 + .../queries/diagnostics/ExtractionErrors.ql | 18 + .../diagnostics/SuccessfullyExtractedFiles.ql | 16 + .../ruby/ql/src/queries/metrics/FLines.ql | 13 + .../ql/src/queries/metrics/FLinesOfCode.ql | 14 + .../src/queries/metrics/FLinesOfComments.ql | 13 + .../queries/security/cwe-022/PathInjection.ql | 26 + .../security/cwe-078/CommandInjection.ql | 25 + .../queries/security/cwe-078/KernelOpen.ql | 76 + .../queries/security/cwe-079/ReflectedXSS.ql | 24 + .../src/queries/security/cwe-079/StoredXSS.ql | 23 + .../queries/security/cwe-089/SqlInjection.ql | 39 + .../queries/security/cwe-094/CodeInjection.ql | 27 + .../queries/security/cwe-116/BadTagFilter.ql | 19 + .../security/cwe-1333/PolynomialReDoS.ql | 31 + .../ql/src/queries/security/cwe-1333/ReDoS.ql | 25 + .../cwe-295/RequestWithoutValidation.ql | 20 + .../security/cwe-502/UnsafeDeserialization.ql | 21 + .../queries/security/cwe-601/UrlRedirect.ql | 22 + .../ql/src/queries/security/cwe-611/Xxe.ql | 43 + .../security/cwe-732/WeakFilePermissions.ql | 64 + .../security/cwe-798/HardcodedCredentials.ql | 155 + .../ql/src/queries/summary/LinesOfCode.ql | 15 + .../ql/src/queries/summary/LinesOfUserCode.ql | 19 + .../NumberOfFilesExtractedWithErrors.ql | 15 + .../NumberOfSuccessfullyExtractedFiles.ql | 15 + .../src/queries/variables/DeadStoreOfLocal.ql | 28 + .../queries/variables/UninitializedLocal.ql | 32 + .../src/queries/variables/UnusedParameter.ql | 27 + 884 files changed, 68391 insertions(+), 13667 deletions(-) create mode 100644 repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll create mode 100644 repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplSpecific.qll create mode 100644 repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll create mode 100644 repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-319/UseOfHttp.ql create mode 100644 repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-243/IncorrectChangingWorkingDirectory.ql create mode 100644 repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-377/InsecureTemporaryFile.ql create mode 100644 repo-tests/codeql/csharp/ql/consistency-queries/CfgConsistency.ql create mode 100644 repo-tests/codeql/csharp/ql/consistency-queries/qlpack.yml delete mode 100644 repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/PrintAst.ql create mode 100644 repo-tests/codeql/csharp/ql/src/experimental/CWE-918/RequestForgery.ql create mode 100644 repo-tests/codeql/csharp/ql/src/experimental/CWE-918/RequestForgery.qll create mode 100644 repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/StringPrefixes.qll create mode 100644 repo-tests/codeql/java/ql/lib/semmle/code/java/frameworks/android/AsyncTask.qll create mode 100644 repo-tests/codeql/java/ql/lib/semmle/code/java/frameworks/apache/IO.qll create mode 100644 repo-tests/codeql/java/ql/lib/semmle/code/java/frameworks/ratpack/Ratpack.qll create mode 100644 repo-tests/codeql/java/ql/lib/semmle/code/java/frameworks/ratpack/RatpackExec.qll create mode 100644 repo-tests/codeql/java/ql/lib/semmle/code/java/security/AndroidIntentRedirection.qll create mode 100644 repo-tests/codeql/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll create mode 100644 repo-tests/codeql/java/ql/lib/semmle/code/java/security/AndroidSensitiveCommunicationQuery.qll create mode 100644 repo-tests/codeql/java/ql/src/Security/CWE/CWE-927/SensitiveCommunication.ql create mode 100644 repo-tests/codeql/java/ql/src/Security/CWE/CWE-940/AndroidIntentRedirection.ql create mode 100644 repo-tests/codeql/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.ql create mode 100644 repo-tests/codeql/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qll delete mode 100644 repo-tests/codeql/java/ql/src/experimental/Security/CWE/CWE-927/SensitiveBroadcast.ql create mode 100644 repo-tests/codeql/java/ql/src/utils/model-generator/CaptureSinkModels.ql create mode 100644 repo-tests/codeql/java/ql/src/utils/model-generator/CaptureSourceModels.ql create mode 100644 repo-tests/codeql/java/ql/src/utils/model-generator/CaptureSummaryModels.ql create mode 100644 repo-tests/codeql/java/ql/src/utils/model-generator/ModelGeneratorUtils.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/ATMConfig.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/AdaptiveThreatModeling.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/BaseScoring.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/CodeToFeatures.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/CoreKnowledge.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointScoring.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointTypes.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/FilteringReasons.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/SqlInjectionATM.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/StandardEndpointFilters.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/TaintedPathATM.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/XssATM.qll create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/src/NosqlInjectionATM.ql create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/src/SqlInjectionATM.ql create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/src/TaintedPathATM.ql create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/src/XssATM.ql create mode 100644 repo-tests/codeql/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml create mode 100644 repo-tests/codeql/javascript/ql/lib/semmle/javascript/frameworks/LdapJS.qll create mode 100644 repo-tests/codeql/javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll create mode 100644 repo-tests/codeql/javascript/ql/src/Security/CWE-1004/ClientExposedCookie.ql create mode 100644 repo-tests/codeql/javascript/ql/src/Security/CWE-116/BadTagFilter.ql create mode 100644 repo-tests/codeql/javascript/ql/src/Security/CWE-326/InsufficientKeySize.ql create mode 100644 repo-tests/codeql/javascript/ql/src/Security/CWE-384/SessionFixation.ql create mode 100644 repo-tests/codeql/javascript/ql/src/Security/CWE-598/SensitiveGetQuery.ql create mode 100644 repo-tests/codeql/javascript/ql/src/Security/CWE-614/ClearTextCookie.ql delete mode 100644 repo-tests/codeql/javascript/ql/src/experimental/Security/CWE-090/LdapInjection.ql delete mode 100644 repo-tests/codeql/javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qll delete mode 100644 repo-tests/codeql/javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll delete mode 100644 repo-tests/codeql/javascript/ql/src/experimental/Security/CWE-090/Ldapjs.qll delete mode 100644 repo-tests/codeql/javascript/ql/src/experimental/Security/CWE-1004/CookieWithoutHttpOnly.ql delete mode 100644 repo-tests/codeql/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql create mode 100644 repo-tests/codeql/javascript/ql/src/experimental/Security/CWE-918/SSRF.ql create mode 100644 repo-tests/codeql/javascript/ql/src/experimental/Security/CWE-918/SSRF.qll delete mode 100644 repo-tests/codeql/javascript/ql/src/experimental/semmle/javascript/security/InsecureCookie.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/Aiomysql.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/Aiopg.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/Asyncpg.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/FastApi.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/FlaskAdmin.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/Pydantic.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/RestFramework.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/RuamelYaml.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/Starlette.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/Toml.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/frameworks/internal/SubclassFinder.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/internal/Awaited.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/security/BadTagFilterQuery.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/security/injection/RegexInjection.qll create mode 100644 repo-tests/codeql/python/ql/lib/semmle/python/security/injection/RegexInjectionCustomizations.qll delete mode 100644 repo-tests/codeql/python/ql/src/Diagnostics/ExtractionErrors.ql create mode 100644 repo-tests/codeql/python/ql/src/Diagnostics/ExtractionWarnings.ql create mode 100644 repo-tests/codeql/python/ql/src/Security/CWE-116/BadTagFilter.ql rename repo-tests/codeql/python/ql/src/{experimental => }/Security/CWE-730/RegexInjection.ql (58%) create mode 100644 repo-tests/codeql/python/ql/src/experimental/Security/CWE-113/HeaderInjection.ql create mode 100644 repo-tests/codeql/python/ql/src/experimental/Security/CWE-347/JWTEmptyKeyOrAlgorithm.ql create mode 100644 repo-tests/codeql/python/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql create mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/frameworks/Django.qll create mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/frameworks/Flask.qll create mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/frameworks/JWT.qll create mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/frameworks/Werkzeug.qll create mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/libraries/Authlib.qll create mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/libraries/PyJWT.qll create mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/libraries/PythonJose.qll create mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/security/injection/HTTPHeaders.qll delete mode 100644 repo-tests/codeql/python/ql/src/experimental/semmle/python/security/injection/RegexInjection.qll create mode 100644 repo-tests/codeql/python/ql/src/meta/alerts/RequestHandlers.ql create mode 100644 repo-tests/codeql/ruby/ql/consistency-queries/AstConsistency.ql create mode 100644 repo-tests/codeql/ruby/ql/consistency-queries/CfgConsistency.ql create mode 100644 repo-tests/codeql/ruby/ql/consistency-queries/DataFlowConsistency.ql create mode 100644 repo-tests/codeql/ruby/ql/consistency-queries/SsaConsistency.ql create mode 100644 repo-tests/codeql/ruby/ql/consistency-queries/VariablesConsistency.ql create mode 100644 repo-tests/codeql/ruby/ql/consistency-queries/qlpack.yml create mode 100644 repo-tests/codeql/ruby/ql/examples/qlpack.yml create mode 100644 repo-tests/codeql/ruby/ql/examples/snippets/emptythen.ql create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/IDEContextual.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/Locations.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/files/FileSystem.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/AST.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ApiGraphs.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/CFG.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/Concepts.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/DataFlow.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/DataFlow2.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/Diagnostics.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/Frameworks.qll create mode 100755 repo-tests/codeql/ruby/ql/lib/codeql/ruby/TaintTracking.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Call.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Constant.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Control.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Erb.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Expr.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Literal.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Method.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Module.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Operation.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Parameter.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Pattern.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Scope.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Statement.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/Variable.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Erb.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Module.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Operation.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Pattern.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Scope.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/BasicBlocks.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/ControlFlowGraph.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/internal/Completion.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplSpecific.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/internal/NonReturning.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/controlflow/internal/Splitting.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/BarrierGuards.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/FlowSummary.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/RemoteFlowSources.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/SSA.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplSpecific.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplSpecific.qll create mode 100755 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/TaintTrackingPrivate.qll create mode 100755 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/TaintTrackingPublic.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingParameter.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/filters/GeneratedCode.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/ActionView.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/ActiveStorage.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/Files.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/HttpClients.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/StandardLibrary.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/XmlParsing.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Excon.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Faraday.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/http_clients/HttpClient.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Httparty.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/http_clients/NetHttp.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/http_clients/OpenURI.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/http_clients/RestClient.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/frameworks/http_clients/Typhoeus.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/printAst.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/CodeInjectionCustomizations.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/CodeInjectionQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/CommandInjectionQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/PathInjectionCustomizations.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/PathInjectionQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/ReflectedXSSQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/StoredXSSQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/UrlRedirectCustomizations.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/UrlRedirectQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/XSS.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/performance/ParseRegExp.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/performance/PolynomialReDoSCustomizations.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/performance/PolynomialReDoSQuery.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/performance/RegExpTreeView.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/qlpack.yml create mode 100644 repo-tests/codeql/ruby/ql/lib/ruby.dbscheme create mode 100644 repo-tests/codeql/ruby/ql/lib/ruby.qll create mode 100644 repo-tests/codeql/ruby/ql/lib/tutorial.qll create mode 100644 repo-tests/codeql/ruby/ql/src/AlertSuppression.ql create mode 100644 repo-tests/codeql/ruby/ql/src/experimental/performance/UseDetect.ql create mode 100644 repo-tests/codeql/ruby/ql/src/filters/ClassifyFiles.ql create mode 100644 repo-tests/codeql/ruby/ql/src/ide-contextual-queries/localDefinitions.ql create mode 100644 repo-tests/codeql/ruby/ql/src/ide-contextual-queries/localReferences.ql create mode 100644 repo-tests/codeql/ruby/ql/src/ide-contextual-queries/printAst.ql create mode 100644 repo-tests/codeql/ruby/ql/src/qlpack.yml create mode 100644 repo-tests/codeql/ruby/ql/src/queries/analysis/Definitions.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/diagnostics/ExtractionErrors.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/metrics/FLines.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/metrics/FLinesOfCode.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/metrics/FLinesOfComments.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-022/PathInjection.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-078/CommandInjection.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-078/KernelOpen.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-089/SqlInjection.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-094/CodeInjection.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-116/BadTagFilter.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-1333/PolynomialReDoS.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-1333/ReDoS.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-295/RequestWithoutValidation.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-601/UrlRedirect.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-611/Xxe.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-732/WeakFilePermissions.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/security/cwe-798/HardcodedCredentials.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/summary/LinesOfCode.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/summary/LinesOfUserCode.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/variables/DeadStoreOfLocal.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/variables/UninitializedLocal.ql create mode 100644 repo-tests/codeql/ruby/ql/src/queries/variables/UnusedParameter.ql diff --git a/repo-tests/codeql.txt b/repo-tests/codeql.txt index 869ad93732c..56db311862a 100644 --- a/repo-tests/codeql.txt +++ b/repo-tests/codeql.txt @@ -1 +1 @@ -a2371370ff8260e789342e0ac759bc67ed401702 +6c2713dd8bf76ae1207e3123900a04d6f89b5162 diff --git a/repo-tests/codeql/cpp/ql/lib/experimental/semmle/code/cpp/security/PrivateCleartextWrite.qll b/repo-tests/codeql/cpp/ql/lib/experimental/semmle/code/cpp/security/PrivateCleartextWrite.qll index 922dadaa20e..5438722fd08 100644 --- a/repo-tests/codeql/cpp/ql/lib/experimental/semmle/code/cpp/security/PrivateCleartextWrite.qll +++ b/repo-tests/codeql/cpp/ql/lib/experimental/semmle/code/cpp/security/PrivateCleartextWrite.qll @@ -52,11 +52,8 @@ module PrivateCleartextWrite { class WriteSink extends Sink { WriteSink() { - exists(FileWrite f, BufferWrite b | - this.asExpr() = f.getASource() - or - this.asExpr() = b.getAChild() - ) + this.asExpr() = any(FileWrite f).getASource() or + this.asExpr() = any(BufferWrite b).getAChild() } } } diff --git a/repo-tests/codeql/cpp/ql/lib/experimental/semmle/code/cpp/security/PrivateData.qll b/repo-tests/codeql/cpp/ql/lib/experimental/semmle/code/cpp/security/PrivateData.qll index 621e8aad707..ec37e8ce86c 100644 --- a/repo-tests/codeql/cpp/ql/lib/experimental/semmle/code/cpp/security/PrivateData.qll +++ b/repo-tests/codeql/cpp/ql/lib/experimental/semmle/code/cpp/security/PrivateData.qll @@ -13,26 +13,25 @@ import cpp /** A string for `match` that identifies strings that look like they represent private data. */ private string privateNames() { - // Inspired by the list on https://cwe.mitre.org/data/definitions/359.html - // Government identifiers, such as Social Security Numbers - result = "%social%security%number%" or - // Contact information, such as home addresses and telephone numbers - result = "%postcode%" or - result = "%zipcode%" or - // result = "%telephone%" or - // Geographic location - where the user is (or was) - result = "%latitude%" or - result = "%longitude%" or - // Financial data - such as credit card numbers, salary, bank accounts, and debts - result = "%creditcard%" or - result = "%salary%" or - result = "%bankaccount%" or - // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. - // result = "%email%" or - // result = "%mobile%" or - result = "%employer%" or - // Health - medical conditions, insurance status, prescription records - result = "%medical%" + result = + [ + // Inspired by the list on https://cwe.mitre.org/data/definitions/359.html + // Government identifiers, such as Social Security Numbers + "%social%security%number%", + // Contact information, such as home addresses and telephone numbers + "%postcode%", "%zipcode%", + // result = "%telephone%" or + // Geographic location - where the user is (or was) + "%latitude%", "%longitude%", + // Financial data - such as credit card numbers, salary, bank accounts, and debts + "%creditcard%", "%salary%", "%bankaccount%", + // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. + // result = "%email%" or + // result = "%mobile%" or + "%employer%", + // Health - medical conditions, insurance status, prescription records + "%medical%" + ] } /** An expression that might contain private data. */ diff --git a/repo-tests/codeql/cpp/ql/lib/external/ExternalArtifact.qll b/repo-tests/codeql/cpp/ql/lib/external/ExternalArtifact.qll index abbc96a7b47..1034f1c9ecc 100644 --- a/repo-tests/codeql/cpp/ql/lib/external/ExternalArtifact.qll +++ b/repo-tests/codeql/cpp/ql/lib/external/ExternalArtifact.qll @@ -15,7 +15,7 @@ class ExternalData extends @externalDataElement { * Gets the path of the file this data was loaded from, with its * extension replaced by `.ql`. */ - string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } + string getQueryPath() { result = this.getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } /** Gets the number of fields in this data item. */ int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } @@ -24,22 +24,22 @@ class ExternalData extends @externalDataElement { string getField(int i) { externalData(this, _, i, result) } /** Gets the integer value of the `i`th field of this data item. */ - int getFieldAsInt(int i) { result = getField(i).toInt() } + int getFieldAsInt(int i) { result = this.getField(i).toInt() } /** Gets the floating-point value of the `i`th field of this data item. */ - float getFieldAsFloat(int i) { result = getField(i).toFloat() } + float getFieldAsFloat(int i) { result = this.getField(i).toFloat() } /** Gets the value of the `i`th field of this data item, interpreted as a date. */ - date getFieldAsDate(int i) { result = getField(i).toDate() } + date getFieldAsDate(int i) { result = this.getField(i).toDate() } /** Gets a textual representation of this data item. */ - string toString() { result = getQueryPath() + ": " + buildTupleString(0) } + string toString() { result = this.getQueryPath() + ": " + this.buildTupleString(0) } /** Gets a textual representation of this data item, starting with the `n`th field. */ private string buildTupleString(int n) { - n = getNumFields() - 1 and result = getField(n) + n = this.getNumFields() - 1 and result = this.getField(n) or - n < getNumFields() - 1 and result = getField(n) + "," + buildTupleString(n + 1) + n < this.getNumFields() - 1 and result = this.getField(n) + "," + this.buildTupleString(n + 1) } } @@ -53,8 +53,8 @@ class DefectExternalData extends ExternalData { } /** Gets the URL associated with this data item. */ - string getURL() { result = getField(0) } + string getURL() { result = this.getField(0) } /** Gets the message associated with this data item. */ - string getMessage() { result = getField(1) } + string getMessage() { result = this.getField(1) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Class.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Class.qll index 987ec7ffa3d..4fe1b07e32a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Class.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Class.qll @@ -237,7 +237,7 @@ class Class extends UserType { exists(ClassDerivation cd | cd.getBaseClass() = base | result = this.accessOfBaseMemberMulti(cd.getDerivedClass(), - fieldInBase.accessInDirectDerived(cd.getASpecifier().(AccessSpecifier))) + fieldInBase.accessInDirectDerived(cd.getASpecifier())) ) } @@ -261,21 +261,20 @@ class Class extends UserType { * includes the case of `base` = `this`. */ AccessSpecifier accessOfBaseMember(Declaration member) { - result = - this.accessOfBaseMember(member.getDeclaringType(), member.getASpecifier().(AccessSpecifier)) + result = this.accessOfBaseMember(member.getDeclaringType(), member.getASpecifier()) } /** * DEPRECATED: name changed to `hasImplicitCopyConstructor` to reflect that * `= default` members are no longer included. */ - deprecated predicate hasGeneratedCopyConstructor() { hasImplicitCopyConstructor() } + deprecated predicate hasGeneratedCopyConstructor() { this.hasImplicitCopyConstructor() } /** * DEPRECATED: name changed to `hasImplicitCopyAssignmentOperator` to * reflect that `= default` members are no longer included. */ - deprecated predicate hasGeneratedCopyAssignmentOperator() { hasImplicitCopyConstructor() } + deprecated predicate hasGeneratedCopyAssignmentOperator() { this.hasImplicitCopyConstructor() } /** * Holds if this class, struct or union has an implicitly-declared copy @@ -319,7 +318,7 @@ class Class extends UserType { exists(Type t | t = this.getAFieldSubobjectType().getUnspecifiedType() | // Note: Overload resolution is not implemented -- all copy // constructors are considered equal. - this.cannotAccessCopyConstructorOnAny(t.(Class)) + this.cannotAccessCopyConstructorOnAny(t) ) or // - T has direct or virtual base class that cannot be copied (has deleted, @@ -392,7 +391,7 @@ class Class extends UserType { exists(Type t | t = this.getAFieldSubobjectType().getUnspecifiedType() | // Note: Overload resolution is not implemented -- all copy assignment // operators are considered equal. - this.cannotAccessCopyAssignmentOperatorOnAny(t.(Class)) + this.cannotAccessCopyAssignmentOperatorOnAny(t) ) or exists(Class c | c = this.getADirectOrVirtualBase() | @@ -487,7 +486,7 @@ class Class extends UserType { exists(ClassDerivation cd | // Add the offset of the direct base class and the offset of `baseClass` // within that direct base class. - cd = getADerivation() and + cd = this.getADerivation() and result = cd.getBaseClass().getANonVirtualBaseClassByteOffset(baseClass) + cd.getByteOffset() ) } @@ -502,12 +501,12 @@ class Class extends UserType { */ int getABaseClassByteOffset(Class baseClass) { // Handle the non-virtual case. - result = getANonVirtualBaseClassByteOffset(baseClass) + result = this.getANonVirtualBaseClassByteOffset(baseClass) or exists(Class virtualBaseClass, int virtualBaseOffset, int offsetFromVirtualBase | // Look for the base class as a non-virtual base of a direct or indirect // virtual base, adding the two offsets. - getVirtualBaseClassByteOffset(virtualBaseClass) = virtualBaseOffset and + this.getVirtualBaseClassByteOffset(virtualBaseClass) = virtualBaseOffset and offsetFromVirtualBase = virtualBaseClass.getANonVirtualBaseClassByteOffset(baseClass) and result = virtualBaseOffset + offsetFromVirtualBase ) @@ -623,11 +622,11 @@ class Class extends UserType { * inherits one). */ predicate isPolymorphic() { - exists(MemberFunction f | f.getDeclaringType() = getABaseClass*() and f.isVirtual()) + exists(MemberFunction f | f.getDeclaringType() = this.getABaseClass*() and f.isVirtual()) } override predicate involvesTemplateParameter() { - getATemplateArgument().(Type).involvesTemplateParameter() + this.getATemplateArgument().(Type).involvesTemplateParameter() } /** Holds if this class, struct or union was declared 'final'. */ @@ -765,7 +764,7 @@ class ClassDerivation extends Locatable, @derivation { * }; * ``` */ - Class getBaseClass() { result = getBaseType().getUnderlyingType() } + Class getBaseClass() { result = this.getBaseType().getUnderlyingType() } override string getAPrimaryQlClass() { result = "ClassDerivation" } @@ -818,7 +817,7 @@ class ClassDerivation extends Locatable, @derivation { predicate hasSpecifier(string s) { this.getASpecifier().hasName(s) } /** Holds if the derivation is for a virtual base class. */ - predicate isVirtual() { hasSpecifier("virtual") } + predicate isVirtual() { this.hasSpecifier("virtual") } /** Gets the location of the derivation. */ override Location getLocation() { derivations(underlyingElement(this), _, _, _, result) } @@ -846,7 +845,7 @@ class ClassDerivation extends Locatable, @derivation { * ``` */ class LocalClass extends Class { - LocalClass() { isLocal() } + LocalClass() { this.isLocal() } override string getAPrimaryQlClass() { not this instanceof LocalStruct and result = "LocalClass" } @@ -989,9 +988,9 @@ class ClassTemplateSpecialization extends Class { TemplateClass getPrimaryTemplate() { // Ignoring template arguments, the primary template has the same name // as each of its specializations. - result.getSimpleName() = getSimpleName() and + result.getSimpleName() = this.getSimpleName() and // It is in the same namespace as its specializations. - result.getNamespace() = getNamespace() and + result.getNamespace() = this.getNamespace() and // It is distinguished by the fact that each of its template arguments // is a distinct template parameter. count(TemplateParameter tp | tp = result.getATemplateArgument()) = @@ -1108,7 +1107,7 @@ deprecated class Interface extends Class { * ``` */ class VirtualClassDerivation extends ClassDerivation { - VirtualClassDerivation() { hasSpecifier("virtual") } + VirtualClassDerivation() { this.hasSpecifier("virtual") } override string getAPrimaryQlClass() { result = "VirtualClassDerivation" } } @@ -1136,7 +1135,7 @@ class VirtualBaseClass extends Class { VirtualClassDerivation getAVirtualDerivation() { result.getBaseClass() = this } /** A class/struct that is derived from this one using virtual inheritance. */ - Class getAVirtuallyDerivedClass() { result = getAVirtualDerivation().getDerivedClass() } + Class getAVirtuallyDerivedClass() { result = this.getAVirtualDerivation().getDerivedClass() } } /** @@ -1155,7 +1154,7 @@ class ProxyClass extends UserType { override string getAPrimaryQlClass() { result = "ProxyClass" } /** Gets the location of the proxy class. */ - override Location getLocation() { result = getTemplateParameter().getDefinitionLocation() } + override Location getLocation() { result = this.getTemplateParameter().getDefinitionLocation() } /** Gets the template parameter for which this is the proxy class. */ TemplateParameter getTemplateParameter() { diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Declaration.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Declaration.qll index b1422aa6342..8def15e8c13 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Declaration.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Declaration.qll @@ -184,7 +184,7 @@ class Declaration extends Locatable, @declaration { predicate hasDefinition() { exists(this.getDefinition()) } /** DEPRECATED: Use `hasDefinition` instead. */ - predicate isDefined() { hasDefinition() } + predicate isDefined() { this.hasDefinition() } /** Gets the preferred location of this declaration, if any. */ override Location getLocation() { none() } @@ -209,7 +209,7 @@ class Declaration extends Locatable, @declaration { predicate isStatic() { this.hasSpecifier("static") } /** Holds if this declaration is a member of a class/struct/union. */ - predicate isMember() { hasDeclaringType() } + predicate isMember() { this.hasDeclaringType() } /** Holds if this declaration is a member of a class/struct/union. */ predicate hasDeclaringType() { exists(this.getDeclaringType()) } @@ -226,14 +226,14 @@ class Declaration extends Locatable, @declaration { * When called on a template, this will return a template parameter type for * both typed and non-typed parameters. */ - final Locatable getATemplateArgument() { result = getTemplateArgument(_) } + final Locatable getATemplateArgument() { result = this.getTemplateArgument(_) } /** * Gets a template argument used to instantiate this declaration from a template. * When called on a template, this will return a non-typed template * parameter value. */ - final Locatable getATemplateArgumentKind() { result = getTemplateArgumentKind(_) } + final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) } /** * Gets the `i`th template argument used to instantiate this declaration from a @@ -252,9 +252,9 @@ class Declaration extends Locatable, @declaration { * `getTemplateArgument(1)` return `1`. */ final Locatable getTemplateArgument(int index) { - if exists(getTemplateArgumentValue(index)) - then result = getTemplateArgumentValue(index) - else result = getTemplateArgumentType(index) + if exists(this.getTemplateArgumentValue(index)) + then result = this.getTemplateArgumentValue(index) + else result = this.getTemplateArgumentType(index) } /** @@ -275,13 +275,13 @@ class Declaration extends Locatable, @declaration { * `getTemplateArgumentKind(0)`. */ final Locatable getTemplateArgumentKind(int index) { - exists(getTemplateArgumentValue(index)) and - result = getTemplateArgumentType(index) + exists(this.getTemplateArgumentValue(index)) and + result = this.getTemplateArgumentType(index) } /** Gets the number of template arguments for this declaration. */ final int getNumberOfTemplateArguments() { - result = count(int i | exists(getTemplateArgument(i))) + result = count(int i | exists(this.getTemplateArgument(i))) } private Type getTemplateArgumentType(int index) { @@ -327,9 +327,9 @@ class DeclarationEntry extends Locatable, TDeclarationEntry { * available), or the name declared by this entry otherwise. */ string getCanonicalName() { - if getDeclaration().hasDefinition() - then result = getDeclaration().getDefinition().getName() - else result = getName() + if this.getDeclaration().hasDefinition() + then result = this.getDeclaration().getDefinition().getName() + else result = this.getName() } /** @@ -370,18 +370,18 @@ class DeclarationEntry extends Locatable, TDeclarationEntry { /** * Holds if this declaration entry has a specifier with the given name. */ - predicate hasSpecifier(string specifier) { getASpecifier() = specifier } + predicate hasSpecifier(string specifier) { this.getASpecifier() = specifier } /** Holds if this declaration entry is a definition. */ predicate isDefinition() { none() } // overridden in subclasses override string toString() { - if isDefinition() - then result = "definition of " + getName() + if this.isDefinition() + then result = "definition of " + this.getName() else - if getName() = getCanonicalName() - then result = "declaration of " + getName() - else result = "declaration of " + getCanonicalName() + " as " + getName() + if this.getName() = this.getCanonicalName() + then result = "declaration of " + this.getName() + else result = "declaration of " + this.getCanonicalName() + " as " + this.getName() } } @@ -490,8 +490,7 @@ class AccessHolder extends Declaration, TAccessHolder { */ pragma[inline] predicate canAccessMember(Declaration member, Class derived) { - this.couldAccessMember(member.getDeclaringType(), member.getASpecifier().(AccessSpecifier), - derived) + this.couldAccessMember(member.getDeclaringType(), member.getASpecifier(), derived) } /** @@ -580,7 +579,7 @@ private class DirectAccessHolder extends Element { // transitive closure with a restricted base case. this.thisCanAccessClassStep(base, derived) or - exists(Class between | thisCanAccessClassTrans(base, between) | + exists(Class between | this.thisCanAccessClassTrans(base, between) | isDirectPublicBaseOf(between, derived) or this.thisCanAccessClassStep(between, derived) ) diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Element.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Element.qll index 1f547adccaa..9273d1b31bf 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Element.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Element.qll @@ -61,7 +61,7 @@ class ElementBase extends @element { /** * Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. */ - final string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") } + final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } /** * Gets the name of a primary CodeQL class to which this element belongs. @@ -206,9 +206,9 @@ class Element extends ElementBase { /** Gets the closest `Element` enclosing this one. */ cached Element getEnclosingElement() { - result = getEnclosingElementPref() + result = this.getEnclosingElementPref() or - not exists(getEnclosingElementPref()) and + not exists(this.getEnclosingElementPref()) and ( this = result.(Class).getAMember() or @@ -281,7 +281,7 @@ private predicate isFromUninstantiatedTemplateRec(Element e, Element template) { * ``` */ class StaticAssert extends Locatable, @static_assert { - override string toString() { result = "static_assert(..., \"" + getMessage() + "\")" } + override string toString() { result = "static_assert(..., \"" + this.getMessage() + "\")" } /** * Gets the expression which this static assertion ensures is true. diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Enum.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Enum.qll index 9cddeb78f9b..38263dacf7a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Enum.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Enum.qll @@ -85,7 +85,7 @@ class Enum extends UserType, IntegralOrEnumType { * ``` */ class LocalEnum extends Enum { - LocalEnum() { isLocal() } + LocalEnum() { this.isLocal() } override string getAPrimaryQlClass() { result = "LocalEnum" } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/File.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/File.qll index f486dd8d3c5..3b72533b4f4 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/File.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/File.qll @@ -52,7 +52,7 @@ class Container extends Locatable, @container { */ string getRelativePath() { exists(string absPath, string pref | - absPath = getAbsolutePath() and sourceLocationPrefix(pref) + absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) | absPath = pref and result = "" or @@ -79,7 +79,7 @@ class Container extends Locatable, @container { * */ string getBaseName() { - result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) + result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) } /** @@ -105,7 +105,9 @@ class Container extends Locatable, @container { * "/tmp/x.tar.gz""gz" * */ - string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) } + string getExtension() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) + } /** * Gets the stem of this container, that is, the prefix of its base name up to @@ -124,7 +126,9 @@ class Container extends Locatable, @container { * "/tmp/x.tar.gz""x.tar" * */ - string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) } + string getStem() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) + } /** Gets the parent container of this file or folder, if any. */ Container getParentContainer() { @@ -135,20 +139,20 @@ class Container extends Locatable, @container { Container getAChildContainer() { this = result.getParentContainer() } /** Gets a file in this container. */ - File getAFile() { result = getAChildContainer() } + File getAFile() { result = this.getAChildContainer() } /** Gets the file in this container that has the given `baseName`, if any. */ File getFile(string baseName) { - result = getAFile() and + result = this.getAFile() and result.getBaseName() = baseName } /** Gets a sub-folder in this container. */ - Folder getAFolder() { result = getAChildContainer() } + Folder getAFolder() { result = this.getAChildContainer() } /** Gets the sub-folder in this container that has the given `baseName`, if any. */ Folder getFolder(string baseName) { - result = getAFolder() and + result = this.getAFolder() and result.getBaseName() = baseName } @@ -157,7 +161,7 @@ class Container extends Locatable, @container { * * This is the absolute path of the container. */ - override string toString() { result = getAbsolutePath() } + override string toString() { result = this.getAbsolutePath() } } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Function.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Function.qll index 6cae134645f..0f1de2b512c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Function.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Function.qll @@ -43,26 +43,26 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { */ string getFullSignature() { exists(string name, string templateArgs, string args | - result = name + templateArgs + args + " -> " + getType().toString() and - name = getQualifiedName() and + result = name + templateArgs + args + " -> " + this.getType().toString() and + name = this.getQualifiedName() and ( - if exists(getATemplateArgument()) + if exists(this.getATemplateArgument()) then templateArgs = "<" + concat(int i | - exists(getTemplateArgument(i)) + exists(this.getTemplateArgument(i)) | - getTemplateArgument(i).toString(), ", " order by i + this.getTemplateArgument(i).toString(), ", " order by i ) + ">" else templateArgs = "" ) and args = "(" + concat(int i | - exists(getParameter(i)) + exists(this.getParameter(i)) | - getParameter(i).getType().toString(), ", " order by i + this.getParameter(i).getType().toString(), ", " order by i ) + ")" ) } @@ -70,7 +70,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { /** Gets a specifier of this function. */ override Specifier getASpecifier() { funspecifiers(underlyingElement(this), unresolveElement(result)) or - result.hasName(getADeclarationEntry().getASpecifier()) + result.hasName(this.getADeclarationEntry().getASpecifier()) } /** Gets an attribute of this function. */ @@ -149,7 +149,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * Holds if this function is declared with `__attribute__((naked))` or * `__declspec(naked)`. */ - predicate isNaked() { getAnAttribute().hasName("naked") } + predicate isNaked() { this.getAnAttribute().hasName("naked") } /** * Holds if this function has a trailing return type. @@ -172,7 +172,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * Gets the return type of this function after specifiers have been deeply * stripped and typedefs have been resolved. */ - Type getUnspecifiedType() { result = getType().getUnspecifiedType() } + Type getUnspecifiedType() { result = this.getType().getUnspecifiedType() } /** * Gets the nth parameter of this function. There is no result for the @@ -206,7 +206,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { int getEffectiveNumberOfParameters() { // This method is overridden in `MemberFunction`, where the result is // adjusted to account for the implicit `this` parameter. - result = getNumberOfParameters() + result = this.getNumberOfParameters() } /** @@ -216,7 +216,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * return `int p1, int p2`. */ string getParameterString() { - result = concat(int i | | min(getParameter(i).getTypedName()), ", " order by i) + result = concat(int i | | min(this.getParameter(i).getTypedName()), ", " order by i) } /** Gets a call to this function. */ @@ -229,7 +229,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { */ override FunctionDeclarationEntry getADeclarationEntry() { if fun_decls(_, underlyingElement(this), _, _, _) - then declEntry(result) + then this.declEntry(result) else exists(Function f | this.isConstructedFrom(f) and @@ -250,7 +250,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * Gets the location of a `FunctionDeclarationEntry` corresponding to this * declaration. */ - override Location getADeclarationLocation() { result = getADeclarationEntry().getLocation() } + override Location getADeclarationLocation() { result = this.getADeclarationEntry().getLocation() } /** Holds if this Function is a Template specialization. */ predicate isSpecialization() { @@ -265,14 +265,14 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * definition, if any. */ override FunctionDeclarationEntry getDefinition() { - result = getADeclarationEntry() and + result = this.getADeclarationEntry() and result.isDefinition() } /** Gets the location of the definition, if any. */ override Location getDefinitionLocation() { - if exists(getDefinition()) - then result = getDefinition().getLocation() + if exists(this.getDefinition()) + then result = this.getDefinition().getLocation() else exists(Function f | this.isConstructedFrom(f) and result = f.getDefinition().getLocation()) } @@ -281,7 +281,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * definition, if possible.) */ override Location getLocation() { - if exists(getDefinition()) + if exists(this.getDefinition()) then result = this.getDefinitionLocation() else result = this.getADeclarationLocation() } @@ -299,7 +299,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { BlockStmt getBlock() { result.getParentScope() = this } /** Holds if this function has an entry point. */ - predicate hasEntryPoint() { exists(getEntryPoint()) } + predicate hasEntryPoint() { exists(this.getEntryPoint()) } /** * Gets the first node in this function's control flow graph. @@ -392,7 +392,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * Holds if this function has C linkage, as specified by one of its * declaration entries. For example: `extern "C" void foo();`. */ - predicate hasCLinkage() { getADeclarationEntry().hasCLinkage() } + predicate hasCLinkage() { this.getADeclarationEntry().hasCLinkage() } /** * Holds if this function is constructed from `f` as a result @@ -409,27 +409,27 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * several functions that are not linked together have been compiled. An * example would be a project with many 'main' functions. */ - predicate isMultiplyDefined() { strictcount(getFile()) > 1 } + predicate isMultiplyDefined() { strictcount(this.getFile()) > 1 } /** Holds if this function is a varargs function. */ - predicate isVarargs() { hasSpecifier("varargs") } + predicate isVarargs() { this.hasSpecifier("varargs") } /** Gets a type that is specified to be thrown by the function. */ - Type getAThrownType() { result = getADeclarationEntry().getAThrownType() } + Type getAThrownType() { result = this.getADeclarationEntry().getAThrownType() } /** * Gets the `i`th type specified to be thrown by the function. */ - Type getThrownType(int i) { result = getADeclarationEntry().getThrownType(i) } + Type getThrownType(int i) { result = this.getADeclarationEntry().getThrownType(i) } /** Holds if the function has an exception specification. */ - predicate hasExceptionSpecification() { getADeclarationEntry().hasExceptionSpecification() } + predicate hasExceptionSpecification() { this.getADeclarationEntry().hasExceptionSpecification() } /** Holds if this function has a `throw()` exception specification. */ - predicate isNoThrow() { getADeclarationEntry().isNoThrow() } + predicate isNoThrow() { this.getADeclarationEntry().isNoThrow() } /** Holds if this function has a `noexcept` exception specification. */ - predicate isNoExcept() { getADeclarationEntry().isNoExcept() } + predicate isNoExcept() { this.getADeclarationEntry().isNoExcept() } /** * Gets a function that overloads this one. @@ -539,7 +539,7 @@ private predicate candGetAnOverloadNonMember(string name, Namespace namespace, F */ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { /** Gets the function which is being declared or defined. */ - override Function getDeclaration() { result = getFunction() } + override Function getDeclaration() { result = this.getFunction() } override string getAPrimaryQlClass() { result = "FunctionDeclarationEntry" } @@ -586,7 +586,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { * case, catch) plus the number of branching expressions (`?`, `&&`, * `||`) plus one. */ - int getCyclomaticComplexity() { result = 1 + cyclomaticComplexityBranches(getBlock()) } + int getCyclomaticComplexity() { result = 1 + cyclomaticComplexityBranches(this.getBlock()) } /** * If this is a function definition, get the block containing the @@ -594,7 +594,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { */ BlockStmt getBlock() { this.isDefinition() and - result = getFunction().getBlock() and + result = this.getFunction().getBlock() and result.getFile() = this.getFile() } @@ -604,7 +604,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { */ pragma[noopt] int getNumberOfLines() { - exists(BlockStmt b, Location l, int start, int end, int diff | b = getBlock() | + exists(BlockStmt b, Location l, int start, int end, int diff | b = this.getBlock() | l = b.getLocation() and start = l.getStartLine() and end = l.getEndLine() and @@ -618,7 +618,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { * declaration. */ ParameterDeclarationEntry getAParameterDeclarationEntry() { - result = getParameterDeclarationEntry(_) + result = this.getParameterDeclarationEntry(_) } /** @@ -639,7 +639,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { * return 'int p1, int p2'. */ string getParameterString() { - result = concat(int i | | min(getParameterDeclarationEntry(i).getTypedName()), ", " order by i) + result = + concat(int i | | min(this.getParameterDeclarationEntry(i).getTypedName()), ", " order by i) } /** @@ -647,10 +648,10 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { * * `extern "C" void foo();` */ - predicate hasCLinkage() { getASpecifier() = "c_linkage" } + predicate hasCLinkage() { this.getASpecifier() = "c_linkage" } /** Holds if this declaration entry has a void parameter list. */ - predicate hasVoidParamList() { getASpecifier() = "void_param_list" } + predicate hasVoidParamList() { this.getASpecifier() = "void_param_list" } /** Holds if this declaration is also a definition of its function. */ override predicate isDefinition() { fun_def(underlyingElement(this)) } @@ -665,7 +666,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { predicate isImplicit() { fun_implicit(underlyingElement(this)) } /** Gets a type that is specified to be thrown by the declared function. */ - Type getAThrownType() { result = getThrownType(_) } + Type getAThrownType() { result = this.getThrownType(_) } /** * Gets the `i`th type specified to be thrown by the declared function @@ -690,8 +691,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { predicate hasExceptionSpecification() { fun_decl_throws(underlyingElement(this), _, _) or fun_decl_noexcept(underlyingElement(this), _) or - isNoThrow() or - isNoExcept() + this.isNoThrow() or + this.isNoExcept() } /** @@ -763,7 +764,7 @@ class Operator extends Function { */ class TemplateFunction extends Function { TemplateFunction() { - is_function_template(underlyingElement(this)) and exists(getATemplateArgument()) + is_function_template(underlyingElement(this)) and exists(this.getATemplateArgument()) } override string getAPrimaryQlClass() { result = "TemplateFunction" } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Include.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Include.qll index f21edb2651d..9a120b1013c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Include.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Include.qll @@ -23,7 +23,7 @@ class Include extends PreprocessorDirective, @ppd_include { * Gets the token which occurs after `#include`, for example `"filename"` * or ``. */ - string getIncludeText() { result = getHead() } + string getIncludeText() { result = this.getHead() } /** Gets the file directly included by this `#include`. */ File getIncludedFile() { includes(underlyingElement(this), unresolveElement(result)) } @@ -53,7 +53,7 @@ class Include extends PreprocessorDirective, @ppd_include { * ``` */ class IncludeNext extends Include, @ppd_include_next { - override string toString() { result = "#include_next " + getIncludeText() } + override string toString() { result = "#include_next " + this.getIncludeText() } } /** @@ -65,5 +65,5 @@ class IncludeNext extends Include, @ppd_include_next { * ``` */ class Import extends Include, @ppd_objc_import { - override string toString() { result = "#import " + getIncludeText() } + override string toString() { result = "#import " + this.getIncludeText() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Initializer.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Initializer.qll index 64607af3393..62af72c1803 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Initializer.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Initializer.qll @@ -34,8 +34,8 @@ class Initializer extends ControlFlowNode, @initialiser { override predicate fromSource() { not this.getLocation() instanceof UnknownLocation } override string toString() { - if exists(getDeclaration()) - then result = "initializer for " + max(getDeclaration().getName()) + if exists(this.getDeclaration()) + then result = "initializer for " + max(this.getDeclaration().getName()) else result = "initializer" } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Location.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Location.qll index 15ae2121255..92b358d474c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Location.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Location.qll @@ -79,8 +79,8 @@ class Location extends @location { /** Holds if location `l` is completely contained within this one. */ predicate subsumes(Location l) { - exists(File f | f = getFile() | - exists(int thisStart, int thisEnd | charLoc(f, thisStart, thisEnd) | + exists(File f | f = this.getFile() | + exists(int thisStart, int thisEnd | this.charLoc(f, thisStart, thisEnd) | exists(int lStart, int lEnd | l.charLoc(f, lStart, lEnd) | thisStart <= lStart and lEnd <= thisEnd ) @@ -97,10 +97,10 @@ class Location extends @location { * see `subsumes`. */ predicate charLoc(File f, int start, int end) { - f = getFile() and + f = this.getFile() and exists(int maxCols | maxCols = maxCols(f) | - start = getStartLine() * maxCols + getStartColumn() and - end = getEndLine() * maxCols + getEndColumn() + start = this.getStartLine() * maxCols + this.getStartColumn() and + end = this.getEndLine() * maxCols + this.getEndColumn() ) } } @@ -144,7 +144,7 @@ class Locatable extends Element { } * expressions, one for statements and one for other program elements. */ class UnknownLocation extends Location { - UnknownLocation() { getFile().getAbsolutePath() = "" } + UnknownLocation() { this.getFile().getAbsolutePath() = "" } } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Macro.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Macro.qll index aa4b8d41999..6d61ae7be7c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Macro.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Macro.qll @@ -44,10 +44,10 @@ class Macro extends PreprocessorDirective, @ppd_define { * Gets the name of the macro. For example, `MAX` in * `#define MAX(x,y) (((x)>(y))?(x):(y))`. */ - string getName() { result = getHead().splitAt("(", 0) } + string getName() { result = this.getHead().splitAt("(", 0) } /** Holds if the macro has name `name`. */ - predicate hasName(string name) { getName() = name } + predicate hasName(string name) { this.getName() = name } } /** @@ -130,7 +130,7 @@ class MacroAccess extends Locatable, @macroinvocation { override string toString() { result = this.getMacro().getHead() } /** Gets the name of the accessed macro. */ - string getMacroName() { result = getMacro().getName() } + string getMacroName() { result = this.getMacro().getName() } } /** @@ -197,8 +197,8 @@ class MacroInvocation extends MacroAccess { * expression. In other cases, it may have multiple results or no results. */ Expr getExpr() { - result = getAnExpandedElement() and - not result.getParent() = getAnExpandedElement() and + result = this.getAnExpandedElement() and + not result.getParent() = this.getAnExpandedElement() and not result instanceof Conversion } @@ -208,8 +208,8 @@ class MacroInvocation extends MacroAccess { * element is not a statement (for example if it is an expression). */ Stmt getStmt() { - result = getAnExpandedElement() and - not result.getParent() = getAnExpandedElement() + result = this.getAnExpandedElement() and + not result.getParent() = this.getAnExpandedElement() } /** @@ -278,7 +278,7 @@ deprecated class MacroInvocationExpr extends Expr { MacroInvocation getInvocation() { result.getExpr() = this } /** Gets the name of the invoked macro. */ - string getMacroName() { result = getInvocation().getMacroName() } + string getMacroName() { result = this.getInvocation().getMacroName() } } /** @@ -298,7 +298,7 @@ deprecated class MacroInvocationStmt extends Stmt { MacroInvocation getInvocation() { result.getStmt() = this } /** Gets the name of the invoked macro. */ - string getMacroName() { result = getInvocation().getMacroName() } + string getMacroName() { result = this.getInvocation().getMacroName() } } /** Holds if `l` is the location of a macro. */ diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/MemberFunction.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/MemberFunction.qll index 63c1406d8a5..03b1704549f 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/MemberFunction.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/MemberFunction.qll @@ -36,7 +36,9 @@ class MemberFunction extends Function { * `this` parameter. */ override int getEffectiveNumberOfParameters() { - if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1 + if this.isStatic() + then result = this.getNumberOfParameters() + else result = this.getNumberOfParameters() + 1 } /** Holds if this member is private. */ @@ -49,13 +51,13 @@ class MemberFunction extends Function { predicate isPublic() { this.hasSpecifier("public") } /** Holds if this declaration has the lvalue ref-qualifier */ - predicate isLValueRefQualified() { hasSpecifier("&") } + predicate isLValueRefQualified() { this.hasSpecifier("&") } /** Holds if this declaration has the rvalue ref-qualifier */ - predicate isRValueRefQualified() { hasSpecifier("&&") } + predicate isRValueRefQualified() { this.hasSpecifier("&&") } /** Holds if this declaration has a ref-qualifier */ - predicate isRefQualified() { isLValueRefQualified() or isRValueRefQualified() } + predicate isRefQualified() { this.isLValueRefQualified() or this.isRValueRefQualified() } /** Holds if this function overrides that function. */ predicate overrides(MemberFunction that) { @@ -73,10 +75,10 @@ class MemberFunction extends Function { * class body. */ FunctionDeclarationEntry getClassBodyDeclarationEntry() { - if strictcount(getADeclarationEntry()) = 1 - then result = getDefinition() + if strictcount(this.getADeclarationEntry()) = 1 + then result = this.getDefinition() else ( - result = getADeclarationEntry() and result != getDefinition() + result = this.getADeclarationEntry() and result != this.getDefinition() ) } @@ -198,7 +200,7 @@ class Constructor extends MemberFunction { * compiler-generated action which initializes a base class or member * variable. */ - ConstructorInit getAnInitializer() { result = getInitializer(_) } + ConstructorInit getAnInitializer() { result = this.getInitializer(_) } /** * Gets an entry in the constructor's initializer list, or a @@ -220,8 +222,8 @@ class ImplicitConversionFunction extends MemberFunction { functions(underlyingElement(this), _, 4) or // ConversionConstructor (deprecated) - strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and - not hasSpecifier("explicit") + strictcount(Parameter p | p = this.getAParameter() and not p.hasInitializer()) = 1 and + not this.hasSpecifier("explicit") } /** Gets the type this `ImplicitConversionFunction` takes as input. */ @@ -248,8 +250,8 @@ class ImplicitConversionFunction extends MemberFunction { */ deprecated class ConversionConstructor extends Constructor, ImplicitConversionFunction { ConversionConstructor() { - strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and - not hasSpecifier("explicit") + strictcount(Parameter p | p = this.getAParameter() and not p.hasInitializer()) = 1 and + not this.hasSpecifier("explicit") } override string getAPrimaryQlClass() { @@ -301,15 +303,15 @@ class CopyConstructor extends Constructor { hasCopySignature(this) and ( // The rest of the parameters all have default values - forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) + forall(int i | i > 0 and exists(this.getParameter(i)) | this.getParameter(i).hasInitializer()) or // or this is a template class, in which case the default values have // not been extracted even if they exist. In that case, we assume that // there are default values present since that is the most common case // in real-world code. - getDeclaringType() instanceof TemplateClass + this.getDeclaringType() instanceof TemplateClass ) and - not exists(getATemplateArgument()) + not exists(this.getATemplateArgument()) } override string getAPrimaryQlClass() { result = "CopyConstructor" } @@ -325,8 +327,8 @@ class CopyConstructor extends Constructor { // type-checked for each template instantiation; if an argument in an // instantiation fails to type-check then the corresponding parameter has // no default argument in the instantiation. - getDeclaringType() instanceof TemplateClass and - getNumberOfParameters() > 1 + this.getDeclaringType() instanceof TemplateClass and + this.getNumberOfParameters() > 1 } } @@ -358,15 +360,15 @@ class MoveConstructor extends Constructor { hasMoveSignature(this) and ( // The rest of the parameters all have default values - forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) + forall(int i | i > 0 and exists(this.getParameter(i)) | this.getParameter(i).hasInitializer()) or // or this is a template class, in which case the default values have // not been extracted even if they exist. In that case, we assume that // there are default values present since that is the most common case // in real-world code. - getDeclaringType() instanceof TemplateClass + this.getDeclaringType() instanceof TemplateClass ) and - not exists(getATemplateArgument()) + not exists(this.getATemplateArgument()) } override string getAPrimaryQlClass() { result = "MoveConstructor" } @@ -382,8 +384,8 @@ class MoveConstructor extends Constructor { // type-checked for each template instantiation; if an argument in an // instantiation fails to type-check then the corresponding parameter has // no default argument in the instantiation. - getDeclaringType() instanceof TemplateClass and - getNumberOfParameters() > 1 + this.getDeclaringType() instanceof TemplateClass and + this.getNumberOfParameters() > 1 } } @@ -426,7 +428,7 @@ class Destructor extends MemberFunction { * Gets a compiler-generated action which destructs a base class or member * variable. */ - DestructorDestruction getADestruction() { result = getDestruction(_) } + DestructorDestruction getADestruction() { result = this.getDestruction(_) } /** * Gets a compiler-generated action which destructs a base class or member @@ -475,16 +477,16 @@ class ConversionOperator extends MemberFunction, ImplicitConversionFunction { */ class CopyAssignmentOperator extends Operator { CopyAssignmentOperator() { - hasName("operator=") and + this.hasName("operator=") and ( hasCopySignature(this) or // Unlike CopyConstructor, this member allows a non-reference // parameter. - getParameter(0).getUnspecifiedType() = getDeclaringType() + this.getParameter(0).getUnspecifiedType() = this.getDeclaringType() ) and not exists(this.getParameter(1)) and - not exists(getATemplateArgument()) + not exists(this.getATemplateArgument()) } override string getAPrimaryQlClass() { result = "CopyAssignmentOperator" } @@ -507,10 +509,10 @@ class CopyAssignmentOperator extends Operator { */ class MoveAssignmentOperator extends Operator { MoveAssignmentOperator() { - hasName("operator=") and + this.hasName("operator=") and hasMoveSignature(this) and not exists(this.getParameter(1)) and - not exists(getATemplateArgument()) + not exists(this.getATemplateArgument()) } override string getAPrimaryQlClass() { result = "MoveAssignmentOperator" } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Namespace.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Namespace.qll index d46abc6b4db..47ebc9d35c5 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Namespace.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Namespace.qll @@ -38,8 +38,8 @@ class Namespace extends NameQualifyingElement, @namespace { * unless the namespace has exactly one declaration entry. */ override Location getLocation() { - if strictcount(getADeclarationEntry()) = 1 - then result = getADeclarationEntry().getLocation() + if strictcount(this.getADeclarationEntry()) = 1 + then result = this.getADeclarationEntry().getLocation() else result instanceof UnknownDefaultLocation } @@ -50,7 +50,7 @@ class Namespace extends NameQualifyingElement, @namespace { predicate hasName(string name) { name = this.getName() } /** Holds if this namespace is anonymous. */ - predicate isAnonymous() { hasName("(unnamed namespace)") } + predicate isAnonymous() { this.hasName("(unnamed namespace)") } /** Gets the name of the parent namespace, if it exists. */ private string getParentName() { @@ -60,9 +60,9 @@ class Namespace extends NameQualifyingElement, @namespace { /** Gets the qualified name of this namespace. For example: `a::b`. */ string getQualifiedName() { - if exists(getParentName()) - then result = getParentNamespace().getQualifiedName() + "::" + getName() - else result = getName() + if exists(this.getParentName()) + then result = this.getParentNamespace().getQualifiedName() + "::" + this.getName() + else result = this.getName() } /** Gets the parent namespace, if any. */ @@ -99,7 +99,7 @@ class Namespace extends NameQualifyingElement, @namespace { /** Gets a version of the `QualifiedName` that is more suitable for display purposes. */ string getFriendlyName() { result = this.getQualifiedName() } - final override string toString() { result = getFriendlyName() } + final override string toString() { result = this.getFriendlyName() } /** Gets a declaration of (part of) this namespace. */ NamespaceDeclarationEntry getADeclarationEntry() { result.getNamespace() = this } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Parameter.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Parameter.qll index b87bfe6a4c7..47b77b542c1 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Parameter.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Parameter.qll @@ -40,12 +40,12 @@ class Parameter extends LocalScopeVariable, @parameter { */ override string getName() { exists(VariableDeclarationEntry vde | - vde = getANamedDeclarationEntry() and result = vde.getName() + vde = this.getANamedDeclarationEntry() and result = vde.getName() | - vde.isDefinition() or not getANamedDeclarationEntry().isDefinition() + vde.isDefinition() or not this.getANamedDeclarationEntry().isDefinition() ) or - not exists(getANamedDeclarationEntry()) and + not exists(this.getANamedDeclarationEntry()) and result = "(unnamed parameter " + this.getIndex().toString() + ")" } @@ -58,8 +58,12 @@ class Parameter extends LocalScopeVariable, @parameter { */ string getTypedName() { exists(string typeString, string nameString | - (if exists(getType().getName()) then typeString = getType().getName() else typeString = "") and - (if exists(getName()) then nameString = getName() else nameString = "") and + ( + if exists(this.getType().getName()) + then typeString = this.getType().getName() + else typeString = "" + ) and + (if exists(this.getName()) then nameString = this.getName() else nameString = "") and ( if typeString != "" and nameString != "" then result = typeString + " " + nameString @@ -69,7 +73,7 @@ class Parameter extends LocalScopeVariable, @parameter { } private VariableDeclarationEntry getANamedDeclarationEntry() { - result = getAnEffectiveDeclarationEntry() and result.getName() != "" + result = this.getAnEffectiveDeclarationEntry() and result.getName() != "" } /** @@ -82,13 +86,13 @@ class Parameter extends LocalScopeVariable, @parameter { * own). */ private VariableDeclarationEntry getAnEffectiveDeclarationEntry() { - if getFunction().isConstructedFrom(_) + if this.getFunction().isConstructedFrom(_) then exists(Function prototypeInstantiation | - prototypeInstantiation.getParameter(getIndex()) = result.getVariable() and - getFunction().isConstructedFrom(prototypeInstantiation) + prototypeInstantiation.getParameter(this.getIndex()) = result.getVariable() and + this.getFunction().isConstructedFrom(prototypeInstantiation) ) - else result = getADeclarationEntry() + else result = this.getADeclarationEntry() } /** @@ -114,7 +118,7 @@ class Parameter extends LocalScopeVariable, @parameter { * `getName()` is not "(unnamed parameter i)" (where `i` is the index * of the parameter). */ - predicate isNamed() { exists(getANamedDeclarationEntry()) } + predicate isNamed() { exists(this.getANamedDeclarationEntry()) } /** * Gets the function to which this parameter belongs, if it is a function @@ -157,9 +161,9 @@ class Parameter extends LocalScopeVariable, @parameter { */ override Location getLocation() { exists(VariableDeclarationEntry vde | - vde = getAnEffectiveDeclarationEntry() and result = vde.getLocation() + vde = this.getAnEffectiveDeclarationEntry() and result = vde.getLocation() | - vde.isDefinition() or not getAnEffectiveDeclarationEntry().isDefinition() + vde.isDefinition() or not this.getAnEffectiveDeclarationEntry().isDefinition() ) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Preprocessor.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Preprocessor.qll index 2389db07f2a..91b7aa1aab9 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Preprocessor.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Preprocessor.qll @@ -29,8 +29,8 @@ class PreprocessorDirective extends Locatable, @preprocdirect { PreprocessorBranch getAGuard() { exists(PreprocessorEndif e, int line | result.getEndIf() = e and - e.getFile() = getFile() and - result.getFile() = getFile() and + e.getFile() = this.getFile() and + result.getFile() = this.getFile() and line = this.getLocation().getStartLine() and result.getLocation().getStartLine() < line and line < e.getLocation().getEndLine() @@ -69,7 +69,9 @@ class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBr * directives in different translation units, then there can be more than * one result. */ - PreprocessorEndif getEndIf() { preprocpair(unresolveElement(getIf()), unresolveElement(result)) } + PreprocessorEndif getEndIf() { + preprocpair(unresolveElement(this.getIf()), unresolveElement(result)) + } /** * Gets the next `#elif`, `#else` or `#endif` matching this branching @@ -137,7 +139,7 @@ class PreprocessorBranch extends PreprocessorBranchDirective, @ppd_branch { * which evaluated it, or was not taken by any translation unit which * evaluated it. */ - predicate wasPredictable() { not (wasTaken() and wasNotTaken()) } + predicate wasPredictable() { not (this.wasTaken() and this.wasNotTaken()) } } /** @@ -268,7 +270,7 @@ class PreprocessorUndef extends PreprocessorDirective, @ppd_undef { /** * Gets the name of the macro that is undefined. */ - string getName() { result = getHead() } + string getName() { result = this.getHead() } } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Print.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Print.qll index f8d30f55a88..64ae5b960d1 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Print.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Print.qll @@ -105,8 +105,8 @@ private class DumpType extends Type { // for a `SpecifiedType`, insert the qualifiers after // `getDeclaratorSuffixBeforeQualifiers()`. result = - getTypeSpecifier() + getDeclaratorPrefix() + getDeclaratorSuffixBeforeQualifiers() + - getDeclaratorSuffix() + this.getTypeSpecifier() + this.getDeclaratorPrefix() + + this.getDeclaratorSuffixBeforeQualifiers() + this.getDeclaratorSuffix() } /** @@ -147,29 +147,35 @@ private class DumpType extends Type { } private class BuiltInDumpType extends DumpType, BuiltInType { - override string getTypeSpecifier() { result = toString() } + override string getTypeSpecifier() { result = this.toString() } } private class IntegralDumpType extends BuiltInDumpType, IntegralType { - override string getTypeSpecifier() { result = getCanonicalArithmeticType().toString() } + override string getTypeSpecifier() { result = this.getCanonicalArithmeticType().toString() } } private class DerivedDumpType extends DumpType, DerivedType { - override string getTypeSpecifier() { result = getBaseType().(DumpType).getTypeSpecifier() } + override string getTypeSpecifier() { result = this.getBaseType().(DumpType).getTypeSpecifier() } override string getDeclaratorSuffixBeforeQualifiers() { - result = getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + result = this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() } - override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() } + override string getDeclaratorSuffix() { + result = this.getBaseType().(DumpType).getDeclaratorSuffix() + } } private class DecltypeDumpType extends DumpType, Decltype { - override string getTypeSpecifier() { result = getBaseType().(DumpType).getTypeSpecifier() } + override string getTypeSpecifier() { result = this.getBaseType().(DumpType).getTypeSpecifier() } - override string getDeclaratorPrefix() { result = getBaseType().(DumpType).getDeclaratorPrefix() } + override string getDeclaratorPrefix() { + result = this.getBaseType().(DumpType).getDeclaratorPrefix() + } - override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() } + override string getDeclaratorSuffix() { + result = this.getBaseType().(DumpType).getDeclaratorSuffix() + } } private class PointerIshDumpType extends DerivedDumpType { @@ -180,10 +186,10 @@ private class PointerIshDumpType extends DerivedDumpType { override string getDeclaratorPrefix() { exists(string declarator | - result = getBaseType().(DumpType).getDeclaratorPrefix() + declarator and - if getBaseType().getUnspecifiedType() instanceof ArrayType - then declarator = "(" + getDeclaratorToken() + ")" - else declarator = getDeclaratorToken() + result = this.getBaseType().(DumpType).getDeclaratorPrefix() + declarator and + if this.getBaseType().getUnspecifiedType() instanceof ArrayType + then declarator = "(" + this.getDeclaratorToken() + ")" + else declarator = this.getDeclaratorToken() ) } @@ -206,13 +212,13 @@ private class RValueReferenceDumpType extends PointerIshDumpType, RValueReferenc } private class PointerToMemberDumpType extends DumpType, PointerToMemberType { - override string getTypeSpecifier() { result = getBaseType().(DumpType).getTypeSpecifier() } + override string getTypeSpecifier() { result = this.getBaseType().(DumpType).getTypeSpecifier() } override string getDeclaratorPrefix() { exists(string declarator, string parenDeclarator, Type baseType | - declarator = getClass().(DumpType).getTypeIdentityString() + "::*" and - result = getBaseType().(DumpType).getDeclaratorPrefix() + " " + parenDeclarator and - baseType = getBaseType().getUnspecifiedType() and + declarator = this.getClass().(DumpType).getTypeIdentityString() + "::*" and + result = this.getBaseType().(DumpType).getDeclaratorPrefix() + " " + parenDeclarator and + baseType = this.getBaseType().getUnspecifiedType() and if baseType instanceof ArrayType or baseType instanceof RoutineType then parenDeclarator = "(" + declarator else parenDeclarator = declarator @@ -221,38 +227,44 @@ private class PointerToMemberDumpType extends DumpType, PointerToMemberType { override string getDeclaratorSuffixBeforeQualifiers() { exists(Type baseType | - baseType = getBaseType().getUnspecifiedType() and + baseType = this.getBaseType().getUnspecifiedType() and if baseType instanceof ArrayType or baseType instanceof RoutineType - then result = ")" + getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() - else result = getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + then result = ")" + this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + else result = this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() ) } - override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() } + override string getDeclaratorSuffix() { + result = this.getBaseType().(DumpType).getDeclaratorSuffix() + } } private class ArrayDumpType extends DerivedDumpType, ArrayType { - override string getDeclaratorPrefix() { result = getBaseType().(DumpType).getDeclaratorPrefix() } + override string getDeclaratorPrefix() { + result = this.getBaseType().(DumpType).getDeclaratorPrefix() + } override string getDeclaratorSuffixBeforeQualifiers() { - if exists(getArraySize()) + if exists(this.getArraySize()) then result = - "[" + getArraySize().toString() + "]" + - getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() - else result = "[]" + getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + "[" + this.getArraySize().toString() + "]" + + this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + else result = "[]" + this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() } } private class FunctionPointerIshDumpType extends DerivedDumpType, FunctionPointerIshType { override string getDeclaratorSuffixBeforeQualifiers() { - result = ")" + getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + result = ")" + this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() } - override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() } + override string getDeclaratorSuffix() { + result = this.getBaseType().(DumpType).getDeclaratorSuffix() + } override string getDeclaratorPrefix() { - result = getBaseType().(DumpType).getDeclaratorPrefix() + "(" + getDeclaratorToken() + result = this.getBaseType().(DumpType).getDeclaratorPrefix() + "(" + this.getDeclaratorToken() } /** @@ -274,10 +286,10 @@ private class BlockDumpType extends FunctionPointerIshDumpType, BlockType { } private class RoutineDumpType extends DumpType, RoutineType { - override string getTypeSpecifier() { result = getReturnType().(DumpType).getTypeSpecifier() } + override string getTypeSpecifier() { result = this.getReturnType().(DumpType).getTypeSpecifier() } override string getDeclaratorPrefix() { - result = getReturnType().(DumpType).getDeclaratorPrefix() + result = this.getReturnType().(DumpType).getDeclaratorPrefix() } language[monotonicAggregates] @@ -285,39 +297,41 @@ private class RoutineDumpType extends DumpType, RoutineType { result = "(" + concat(int i | - exists(getParameterType(i)) + exists(this.getParameterType(i)) | - getParameterTypeString(getParameterType(i)), ", " order by i + getParameterTypeString(this.getParameterType(i)), ", " order by i ) + ")" } override string getDeclaratorSuffix() { result = - getReturnType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + - getReturnType().(DumpType).getDeclaratorSuffix() + this.getReturnType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + + this.getReturnType().(DumpType).getDeclaratorSuffix() } } private class SpecifiedDumpType extends DerivedDumpType, SpecifiedType { override string getDeclaratorPrefix() { exists(string basePrefix | - basePrefix = getBaseType().(DumpType).getDeclaratorPrefix() and - if getBaseType().getUnspecifiedType() instanceof RoutineType + basePrefix = this.getBaseType().(DumpType).getDeclaratorPrefix() and + if this.getBaseType().getUnspecifiedType() instanceof RoutineType then result = basePrefix - else result = basePrefix + " " + getSpecifierString() + else result = basePrefix + " " + this.getSpecifierString() ) } override string getDeclaratorSuffixBeforeQualifiers() { exists(string baseSuffix | - baseSuffix = getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() and - if getBaseType().getUnspecifiedType() instanceof RoutineType - then result = baseSuffix + " " + getSpecifierString() + baseSuffix = this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() and + if this.getBaseType().getUnspecifiedType() instanceof RoutineType + then result = baseSuffix + " " + this.getSpecifierString() else result = baseSuffix ) } - override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() } + override string getDeclaratorSuffix() { + result = this.getBaseType().(DumpType).getDeclaratorSuffix() + } } private class UserDumpType extends DumpType, DumpDeclaration, UserType { @@ -330,18 +344,18 @@ private class UserDumpType extends DumpType, DumpDeclaration, UserType { // "lambda [] type at line 12, col. 40" // Use `min(getSimpleName())` to work around an extractor bug where a lambda can have different names // from different compilation units. - simpleName = "(" + min(getSimpleName()) + ")" - else simpleName = getSimpleName() + simpleName = "(" + min(this.getSimpleName()) + ")" + else simpleName = this.getSimpleName() ) and - result = getScopePrefix(this) + simpleName + getTemplateArgumentsString() + result = getScopePrefix(this) + simpleName + this.getTemplateArgumentsString() ) } - override string getTypeSpecifier() { result = getIdentityString() } + override string getTypeSpecifier() { result = this.getIdentityString() } } private class DumpProxyClass extends UserDumpType, ProxyClass { - override string getIdentityString() { result = getName() } + override string getIdentityString() { result = this.getName() } } private class DumpVariable extends DumpDeclaration, Variable { @@ -360,9 +374,9 @@ private class DumpVariable extends DumpDeclaration, Variable { private class DumpFunction extends DumpDeclaration, Function { override string getIdentityString() { result = - getType().(DumpType).getTypeSpecifier() + getType().(DumpType).getDeclaratorPrefix() + " " + - getScopePrefix(this) + getName() + getTemplateArgumentsString() + - getDeclaratorSuffixBeforeQualifiers() + getDeclaratorSuffix() + this.getType().(DumpType).getTypeSpecifier() + this.getType().(DumpType).getDeclaratorPrefix() + + " " + getScopePrefix(this) + this.getName() + this.getTemplateArgumentsString() + + this.getDeclaratorSuffixBeforeQualifiers() + this.getDeclaratorSuffix() } language[monotonicAggregates] @@ -370,28 +384,29 @@ private class DumpFunction extends DumpDeclaration, Function { result = "(" + concat(int i | - exists(getParameter(i).getType()) + exists(this.getParameter(i).getType()) | - getParameterTypeString(getParameter(i).getType()), ", " order by i - ) + ")" + getQualifierString() + getParameterTypeString(this.getParameter(i).getType()), ", " order by i + ) + ")" + this.getQualifierString() } private string getQualifierString() { - if exists(getACVQualifier()) + if exists(this.getACVQualifier()) then - result = " " + strictconcat(string qualifier | qualifier = getACVQualifier() | qualifier, " ") + result = + " " + strictconcat(string qualifier | qualifier = this.getACVQualifier() | qualifier, " ") else result = "" } private string getACVQualifier() { - result = getASpecifier().getName() and + result = this.getASpecifier().getName() and result = ["const", "volatile"] } private string getDeclaratorSuffix() { result = - getType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + - getType().(DumpType).getDeclaratorSuffix() + this.getType().(DumpType).getDeclaratorSuffixBeforeQualifiers() + + this.getType().(DumpType).getDeclaratorSuffix() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Specifier.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Specifier.qll index 4a425b690f4..fe2919c3ed6 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Specifier.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Specifier.qll @@ -31,11 +31,7 @@ class Specifier extends Element, @specifier { * A C/C++ function specifier: `inline`, `virtual`, or `explicit`. */ class FunctionSpecifier extends Specifier { - FunctionSpecifier() { - this.hasName("inline") or - this.hasName("virtual") or - this.hasName("explicit") - } + FunctionSpecifier() { this.hasName(["inline", "virtual", "explicit"]) } override string getAPrimaryQlClass() { result = "FunctionSpecifier" } } @@ -45,13 +41,7 @@ class FunctionSpecifier extends Specifier { * or `mutable". */ class StorageClassSpecifier extends Specifier { - StorageClassSpecifier() { - this.hasName("auto") or - this.hasName("register") or - this.hasName("static") or - this.hasName("extern") or - this.hasName("mutable") - } + StorageClassSpecifier() { this.hasName(["auto", "register", "static", "extern", "mutable"]) } override string getAPrimaryQlClass() { result = "StorageClassSpecifier" } } @@ -60,11 +50,7 @@ class StorageClassSpecifier extends Specifier { * A C++ access specifier: `public`, `protected`, or `private`. */ class AccessSpecifier extends Specifier { - AccessSpecifier() { - this.hasName("public") or - this.hasName("protected") or - this.hasName("private") - } + AccessSpecifier() { this.hasName(["public", "protected", "private"]) } /** * Gets the visibility of a field with access specifier `this` if it is @@ -140,7 +126,7 @@ class Attribute extends Element, @attribute { AttributeArgument getArgument(int i) { result.getAttribute() = this and result.getIndex() = i } /** Gets an argument of the attribute. */ - AttributeArgument getAnArgument() { result = getArgument(_) } + AttributeArgument getAnArgument() { result = this.getArgument(_) } } /** @@ -166,7 +152,7 @@ class StdAttribute extends Attribute, @stdattribute { * Holds if this attribute has the given namespace and name. */ predicate hasQualifiedName(string namespace, string name) { - namespace = getNamespace() and hasName(name) + namespace = this.getNamespace() and this.hasName(name) } } @@ -184,7 +170,7 @@ class Declspec extends Attribute, @declspec { } */ class MicrosoftAttribute extends Attribute, @msattribute { AttributeArgument getNamedArgument(string name) { - result = getAnArgument() and result.getName() = name + result = this.getAnArgument() and result.getName() = name } } @@ -212,13 +198,13 @@ class AlignAs extends Attribute, @alignas { * ``` */ class FormatAttribute extends GnuAttribute { - FormatAttribute() { getName() = "format" } + FormatAttribute() { this.getName() = "format" } /** * Gets the archetype of this format attribute, for example * `"printf"`. */ - string getArchetype() { result = getArgument(0).getValueText() } + string getArchetype() { result = this.getArgument(0).getValueText() } /** * Gets the index in (1-based) format attribute notation associated @@ -236,7 +222,7 @@ class FormatAttribute extends GnuAttribute { * Gets the (0-based) index of the format string, * according to this attribute. */ - int getFormatIndex() { result = getArgument(1).getValueInt() - firstArgumentNumber() } + int getFormatIndex() { result = this.getArgument(1).getValueInt() - this.firstArgumentNumber() } /** * Gets the (0-based) index of the first format argument (if any), @@ -244,8 +230,8 @@ class FormatAttribute extends GnuAttribute { */ int getFirstFormatArgIndex() { exists(int val | - val = getArgument(2).getValueInt() and - result = val - firstArgumentNumber() and + val = this.getArgument(2).getValueInt() and + result = val - this.firstArgumentNumber() and not val = 0 // indicates a `vprintf` style format function with arguments not directly available. ) } @@ -277,7 +263,7 @@ class AttributeArgument extends Element, @attribute_arg { /** * Gets the value of this argument, if its value is integral. */ - int getValueInt() { result = getValueText().toInt() } + int getValueInt() { result = this.getValueText().toInt() } /** * Gets the value of this argument, if its value is a type. @@ -304,11 +290,11 @@ class AttributeArgument extends Element, @attribute_arg { then result = "empty argument" else exists(string prefix, string tail | - (if exists(getName()) then prefix = getName() + "=" else prefix = "") and + (if exists(this.getName()) then prefix = this.getName() + "=" else prefix = "") and ( if exists(@attribute_arg_type self | self = underlyingElement(this)) - then tail = getValueType().getName() - else tail = getValueText() + then tail = this.getValueType().getName() + else tail = this.getValueText() ) and result = prefix + tail ) diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Struct.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Struct.qll index 50a208894b4..5465472374f 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Struct.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Struct.qll @@ -41,7 +41,7 @@ class Struct extends Class { * ``` */ class LocalStruct extends Struct { - LocalStruct() { isLocal() } + LocalStruct() { this.isLocal() } override string getAPrimaryQlClass() { not this instanceof LocalUnion and result = "LocalStruct" } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/TestFile.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/TestFile.qll index b9e3fe3a614..a2e496ab019 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/TestFile.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/TestFile.qll @@ -10,8 +10,8 @@ import semmle.code.cpp.File */ private class GoogleTestHeader extends File { GoogleTestHeader() { - getBaseName() = "gtest.h" and - getParentContainer().getBaseName() = "gtest" + this.getBaseName() = "gtest.h" and + this.getParentContainer().getBaseName() = "gtest" } } @@ -30,8 +30,8 @@ private class GoogleTest extends MacroInvocation { */ private class BoostTestFolder extends Folder { BoostTestFolder() { - getBaseName() = "test" and - getParentContainer().getBaseName() = "boost" + this.getBaseName() = "test" and + this.getParentContainer().getBaseName() = "boost" } } @@ -49,7 +49,7 @@ private class BoostTest extends MacroInvocation { * The `cppunit` directory. */ private class CppUnitFolder extends Folder { - CppUnitFolder() { getBaseName() = "cppunit" } + CppUnitFolder() { this.getBaseName() = "cppunit" } } /** @@ -57,8 +57,8 @@ private class CppUnitFolder extends Folder { */ private class CppUnitClass extends Class { CppUnitClass() { - getFile().getParentContainer+() instanceof CppUnitFolder and - getNamespace().getParentNamespace*().getName() = "CppUnit" + this.getFile().getParentContainer+() instanceof CppUnitFolder and + this.getNamespace().getParentNamespace*().getName() = "CppUnit" } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Type.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Type.qll index bf3defd4f40..f8552144ea8 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Type.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Type.qll @@ -81,7 +81,7 @@ class Type extends Locatable, @type { * Holds if this type refers to type `t` (by default, * a type always refers to itself). */ - predicate refersTo(Type t) { refersToDirectly*(t) } + predicate refersTo(Type t) { this.refersToDirectly*(t) } /** * Holds if this type refers to type `t` directly. @@ -1080,11 +1080,11 @@ class DerivedType extends Type, @derivedtype { override predicate refersToDirectly(Type t) { t = this.getBaseType() } - override predicate involvesReference() { getBaseType().involvesReference() } + override predicate involvesReference() { this.getBaseType().involvesReference() } - override predicate involvesTemplateParameter() { getBaseType().involvesTemplateParameter() } + override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() } - override Type stripType() { result = getBaseType().stripType() } + override Type stripType() { result = this.getBaseType().stripType() } /** * Holds if this type has the `__autoreleasing` specifier or if it points to @@ -1165,33 +1165,35 @@ class Decltype extends Type, @decltype { */ predicate parenthesesWouldChangeMeaning() { decltypes(underlyingElement(this), _, _, true) } - override Type getUnderlyingType() { result = getBaseType().getUnderlyingType() } + override Type getUnderlyingType() { result = this.getBaseType().getUnderlyingType() } - override Type stripTopLevelSpecifiers() { result = getBaseType().stripTopLevelSpecifiers() } + override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() } - override Type stripType() { result = getBaseType().stripType() } + override Type stripType() { result = this.getBaseType().stripType() } - override Type resolveTypedefs() { result = getBaseType().resolveTypedefs() } + override Type resolveTypedefs() { result = this.getBaseType().resolveTypedefs() } - override Location getLocation() { result = getExpr().getLocation() } + override Location getLocation() { result = this.getExpr().getLocation() } override string toString() { result = "decltype(...)" } override string getName() { none() } - override int getSize() { result = getBaseType().getSize() } + override int getSize() { result = this.getBaseType().getSize() } - override int getAlignment() { result = getBaseType().getAlignment() } + override int getAlignment() { result = this.getBaseType().getAlignment() } - override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } + override int getPointerIndirectionLevel() { + result = this.getBaseType().getPointerIndirectionLevel() + } override string explain() { result = "decltype resulting in {" + this.getBaseType().explain() + "}" } - override predicate involvesReference() { getBaseType().involvesReference() } + override predicate involvesReference() { this.getBaseType().involvesReference() } - override predicate involvesTemplateParameter() { getBaseType().involvesTemplateParameter() } + override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() } override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() } @@ -1223,7 +1225,7 @@ class PointerType extends DerivedType { override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() } override Type resolveTypedefs() { - result.(PointerType).getBaseType() = getBaseType().resolveTypedefs() + result.(PointerType).getBaseType() = this.getBaseType().resolveTypedefs() } } @@ -1240,7 +1242,9 @@ class ReferenceType extends DerivedType { override string getAPrimaryQlClass() { result = "ReferenceType" } - override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } + override int getPointerIndirectionLevel() { + result = this.getBaseType().getPointerIndirectionLevel() + } override string explain() { result = "reference to {" + this.getBaseType().explain() + "}" } @@ -1251,7 +1255,7 @@ class ReferenceType extends DerivedType { override predicate involvesReference() { any() } override Type resolveTypedefs() { - result.(ReferenceType).getBaseType() = getBaseType().resolveTypedefs() + result.(ReferenceType).getBaseType() = this.getBaseType().resolveTypedefs() } } @@ -1330,11 +1334,11 @@ class SpecifiedType extends DerivedType { } override Type resolveTypedefs() { - result.(SpecifiedType).getBaseType() = getBaseType().resolveTypedefs() and - result.getASpecifier() = getASpecifier() + result.(SpecifiedType).getBaseType() = this.getBaseType().resolveTypedefs() and + result.getASpecifier() = this.getASpecifier() } - override Type stripTopLevelSpecifiers() { result = getBaseType().stripTopLevelSpecifiers() } + override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() } } /** @@ -1433,7 +1437,8 @@ class GNUVectorType extends DerivedType { override int getAlignment() { arraysizes(underlyingElement(this), _, _, result) } override string explain() { - result = "GNU " + getNumElements() + " element vector of {" + this.getBaseType().explain() + "}" + result = + "GNU " + this.getNumElements() + " element vector of {" + this.getBaseType().explain() + "}" } override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() } @@ -1468,7 +1473,9 @@ class FunctionReferenceType extends FunctionPointerIshType { override string getAPrimaryQlClass() { result = "FunctionReferenceType" } - override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } + override int getPointerIndirectionLevel() { + result = this.getBaseType().getPointerIndirectionLevel() + } override string explain() { result = "reference to {" + this.getBaseType().(RoutineType).explain() + "}" @@ -1535,8 +1542,8 @@ class FunctionPointerIshType extends DerivedType { int getNumberOfParameters() { result = count(int i | exists(this.getParameterType(i))) } override predicate involvesTemplateParameter() { - getReturnType().involvesTemplateParameter() or - getAParameterType().involvesTemplateParameter() + this.getReturnType().involvesTemplateParameter() or + this.getAParameterType().involvesTemplateParameter() } override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() } @@ -1581,7 +1588,7 @@ class PointerToMemberType extends Type, @ptrtomember { this.getBaseType().explain() + "}" } - override predicate involvesTemplateParameter() { getBaseType().involvesTemplateParameter() } + override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() } override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() } } @@ -1650,7 +1657,6 @@ class RoutineType extends Type, @routinetype { i = 0 and result = "" and not exists(this.getAParameterType()) or ( - exists(this.getParameterType(i)) and if i < max(int j | exists(this.getParameterType(j))) then // Not the last one @@ -1671,8 +1677,8 @@ class RoutineType extends Type, @routinetype { override predicate isDeeplyConstBelow() { none() } // Current limitation: no such thing as a const routine type override predicate involvesTemplateParameter() { - getReturnType().involvesTemplateParameter() or - getAParameterType().involvesTemplateParameter() + this.getReturnType().involvesTemplateParameter() or + this.getAParameterType().involvesTemplateParameter() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/TypedefType.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/TypedefType.qll index aaf452ce4bb..51bcf6f6127 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/TypedefType.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/TypedefType.qll @@ -25,7 +25,7 @@ class TypedefType extends UserType { override Type getUnderlyingType() { result = this.getBaseType().getUnderlyingType() } - override Type stripTopLevelSpecifiers() { result = getBaseType().stripTopLevelSpecifiers() } + override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() } override int getSize() { result = this.getBaseType().getSize() } @@ -43,11 +43,11 @@ class TypedefType extends UserType { result = this.getBaseType().getASpecifier() } - override predicate involvesReference() { getBaseType().involvesReference() } + override predicate involvesReference() { this.getBaseType().involvesReference() } - override Type resolveTypedefs() { result = getBaseType().resolveTypedefs() } + override Type resolveTypedefs() { result = this.getBaseType().resolveTypedefs() } - override Type stripType() { result = getBaseType().stripType() } + override Type stripType() { result = this.getBaseType().stripType() } } /** @@ -90,7 +90,7 @@ class UsingAliasTypedefType extends TypedefType { * ``` */ class LocalTypedefType extends TypedefType { - LocalTypedefType() { isLocal() } + LocalTypedefType() { this.isLocal() } override string getAPrimaryQlClass() { result = "LocalTypedefType" } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Union.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Union.qll index 6dcb2f0796c..2f1b5b07b25 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Union.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Union.qll @@ -37,7 +37,7 @@ class Union extends Struct { * ``` */ class LocalUnion extends Union { - LocalUnion() { isLocal() } + LocalUnion() { this.isLocal() } override string getAPrimaryQlClass() { result = "LocalUnion" } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/UserType.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/UserType.qll index 2ab0603f06c..13697722190 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/UserType.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/UserType.qll @@ -30,19 +30,19 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ * Gets the simple name of this type, without any template parameters. For example * if the name of the type is `"myType"`, the simple name is just `"myType"`. */ - string getSimpleName() { result = getName().regexpReplaceAll("<.*", "") } + string getSimpleName() { result = this.getName().regexpReplaceAll("<.*", "") } override predicate hasName(string name) { usertypes(underlyingElement(this), name, _) } /** Holds if this type is anonymous. */ - predicate isAnonymous() { getName().matches("(unnamed%") } + predicate isAnonymous() { this.getName().matches("(unnamed%") } override predicate hasSpecifier(string s) { Type.super.hasSpecifier(s) } override Specifier getASpecifier() { result = Type.super.getASpecifier() } override Location getLocation() { - if hasDefinition() + if this.hasDefinition() then result = this.getDefinitionLocation() else result = this.getADeclarationLocation() } @@ -53,16 +53,16 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ else exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getADeclarationEntry()) } - override Location getADeclarationLocation() { result = getADeclarationEntry().getLocation() } + override Location getADeclarationLocation() { result = this.getADeclarationEntry().getLocation() } override TypeDeclarationEntry getDefinition() { - result = getADeclarationEntry() and + result = this.getADeclarationEntry() and result.isDefinition() } override Location getDefinitionLocation() { - if exists(getDefinition()) - then result = getDefinition().getLocation() + if exists(this.getDefinition()) + then result = this.getDefinition().getLocation() else exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getDefinition().getLocation() @@ -80,7 +80,7 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ * Holds if this is a local type (that is, a type that has a directly-enclosing * function). */ - predicate isLocal() { exists(getEnclosingFunction()) } + predicate isLocal() { exists(this.getEnclosingFunction()) } /* * Dummy implementations of inherited methods. This class must not be @@ -107,9 +107,9 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ * ``` */ class TypeDeclarationEntry extends DeclarationEntry, @type_decl { - override UserType getDeclaration() { result = getType() } + override UserType getDeclaration() { result = this.getType() } - override string getName() { result = getType().getName() } + override string getName() { result = this.getType().getName() } override string getAPrimaryQlClass() { result = "TypeDeclarationEntry" } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Variable.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Variable.qll index 12e25f33afe..b0c9bac7f66 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Variable.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/Variable.qll @@ -104,17 +104,17 @@ class Variable extends Declaration, @variable { override VariableDeclarationEntry getADeclarationEntry() { result.getDeclaration() = this } - override Location getADeclarationLocation() { result = getADeclarationEntry().getLocation() } + override Location getADeclarationLocation() { result = this.getADeclarationEntry().getLocation() } override VariableDeclarationEntry getDefinition() { - result = getADeclarationEntry() and + result = this.getADeclarationEntry() and result.isDefinition() } - override Location getDefinitionLocation() { result = getDefinition().getLocation() } + override Location getDefinitionLocation() { result = this.getDefinition().getLocation() } override Location getLocation() { - if exists(getDefinition()) + if exists(this.getDefinition()) then result = this.getDefinitionLocation() else result = this.getADeclarationLocation() } @@ -199,7 +199,7 @@ class Variable extends Declaration, @variable { * ``` */ class VariableDeclarationEntry extends DeclarationEntry, @var_decl { - override Variable getDeclaration() { result = getVariable() } + override Variable getDeclaration() { result = this.getVariable() } override string getAPrimaryQlClass() { result = "VariableDeclarationEntry" } @@ -276,32 +276,33 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { int getIndex() { param_decl_bind(underlyingElement(this), result, _) } private string getAnonymousParameterDescription() { - not exists(getName()) and + not exists(this.getName()) and exists(string idx | idx = - ((getIndex() + 1).toString() + "th") + ((this.getIndex() + 1).toString() + "th") .replaceAll("1th", "1st") .replaceAll("2th", "2nd") .replaceAll("3th", "3rd") .replaceAll("11st", "11th") .replaceAll("12nd", "12th") .replaceAll("13rd", "13th") and - if exists(getCanonicalName()) - then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter" + if exists(this.getCanonicalName()) + then + result = "declaration of " + this.getCanonicalName() + " as anonymous " + idx + " parameter" else result = "declaration of " + idx + " parameter" ) } override string toString() { - isDefinition() and - result = "definition of " + getName() + this.isDefinition() and + result = "definition of " + this.getName() or - not isDefinition() and - if getName() = getCanonicalName() - then result = "declaration of " + getName() - else result = "declaration of " + getCanonicalName() + " as " + getName() + not this.isDefinition() and + if this.getName() = this.getCanonicalName() + then result = "declaration of " + this.getName() + else result = "declaration of " + this.getCanonicalName() + " as " + this.getName() or - result = getAnonymousParameterDescription() + result = this.getAnonymousParameterDescription() } /** @@ -311,8 +312,12 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ string getTypedName() { exists(string typeString, string nameString | - (if exists(getType().getName()) then typeString = getType().getName() else typeString = "") and - (if exists(getName()) then nameString = getName() else nameString = "") and + ( + if exists(this.getType().getName()) + then typeString = this.getType().getName() + else typeString = "" + ) and + (if exists(this.getName()) then nameString = this.getName() else nameString = "") and if typeString != "" and nameString != "" then result = typeString + " " + nameString else result = typeString + nameString @@ -540,7 +545,7 @@ class MemberVariable extends Variable, @membervariable { } /** Holds if this member is mutable. */ - predicate isMutable() { getADeclarationEntry().hasSpecifier("mutable") } + predicate isMutable() { this.getADeclarationEntry().hasSpecifier("mutable") } private Type getAType() { membervariables(underlyingElement(this), unresolveElement(result), _) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/XML.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/XML.qll index 4c762f4bf65..76f3b3cb022 100755 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/XML.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/XML.qll @@ -108,7 +108,7 @@ class XMLParent extends @xmlparent { } /** Gets the text value contained in this XML parent. */ - string getTextValue() { result = allCharactersString() } + string getTextValue() { result = this.allCharactersString() } /** Gets a printable representation of this XML parent. */ string toString() { result = this.getName() } @@ -119,7 +119,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = getName() } + override string toString() { result = this.getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -129,14 +129,14 @@ class XMLFile extends XMLParent, File { * * Gets the path of this XML file. */ - deprecated string getPath() { result = getAbsolutePath() } + deprecated string getPath() { result = this.getAbsolutePath() } /** * DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead. * * Gets the path of the folder that contains this XML file. */ - deprecated string getFolder() { result = getParentContainer().getAbsolutePath() } + deprecated string getFolder() { result = this.getParentContainer().getAbsolutePath() } /** Gets the encoding of this XML file. */ string getEncoding() { xmlEncoding(this, result) } @@ -200,7 +200,7 @@ class XMLDTD extends XMLLocatable, @xmldtd { */ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { /** Holds if this XML element has the given `name`. */ - predicate hasName(string name) { name = getName() } + predicate hasName(string name) { name = this.getName() } /** Gets the name of this XML element. */ override string getName() { xmlElements(this, result, _, _, _) } @@ -239,7 +239,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = getName() } + override string toString() { result = this.getName() } } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/CommonType.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/CommonType.qll index 5d6c64630a6..26e60538ec6 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/CommonType.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/CommonType.qll @@ -375,8 +375,8 @@ class Wchar_t extends Type { class MicrosoftInt8Type extends IntegralType { MicrosoftInt8Type() { this instanceof CharType and - not isExplicitlyUnsigned() and - not isExplicitlySigned() + not this.isExplicitlyUnsigned() and + not this.isExplicitlySigned() } } @@ -391,8 +391,8 @@ class MicrosoftInt8Type extends IntegralType { class MicrosoftInt16Type extends IntegralType { MicrosoftInt16Type() { this instanceof ShortType and - not isExplicitlyUnsigned() and - not isExplicitlySigned() + not this.isExplicitlyUnsigned() and + not this.isExplicitlySigned() } } @@ -407,8 +407,8 @@ class MicrosoftInt16Type extends IntegralType { class MicrosoftInt32Type extends IntegralType { MicrosoftInt32Type() { this instanceof IntType and - not isExplicitlyUnsigned() and - not isExplicitlySigned() + not this.isExplicitlyUnsigned() and + not this.isExplicitlySigned() } } @@ -423,8 +423,8 @@ class MicrosoftInt32Type extends IntegralType { class MicrosoftInt64Type extends IntegralType { MicrosoftInt64Type() { this instanceof LongLongType and - not isExplicitlyUnsigned() and - not isExplicitlySigned() + not this.isExplicitlyUnsigned() and + not this.isExplicitlySigned() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll index 1b885fb8f5f..ec95b29177b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll @@ -33,7 +33,7 @@ DependencyOptions getDependencyOptions() { any() } class DependsSource extends Element { DependsSource() { // not inside a template instantiation - not exists(Element other | isFromTemplateInstantiation(other)) or + not exists(Element other | this.isFromTemplateInstantiation(other)) or // allow DeclarationEntrys of template specializations this.(DeclarationEntry).getDeclaration().(Function).isConstructedFrom(_) or this.(DeclarationEntry).getDeclaration().(Class).isConstructedFrom(_) @@ -275,7 +275,7 @@ private predicate dependsOnDeclarationEntry(Element src, DeclarationEntry dest) dependsOnTransitive(src, mid) and not mid instanceof Type and not mid instanceof EnumConstant and - getDeclarationEntries(mid, dest.(DeclarationEntry)) and + getDeclarationEntries(mid, dest) and not dest instanceof TypeDeclarationEntry ) or @@ -283,9 +283,9 @@ private predicate dependsOnDeclarationEntry(Element src, DeclarationEntry dest) // dependency from a Type / Variable / Function use -> any (visible) definition dependsOnTransitive(src, mid) and not mid instanceof EnumConstant and - getDeclarationEntries(mid, dest.(DeclarationEntry)) and + getDeclarationEntries(mid, dest) and // must be definition - dest.(DeclarationEntry).isDefinition() + dest.isDefinition() ) } @@ -307,7 +307,7 @@ private predicate dependsOnFull(DependsSource src, Symbol dest, int category) { // dependency from a Variable / Function use -> non-visible definition (link time) dependsOnTransitive(src, mid) and not mid instanceof EnumConstant and - getDeclarationEntries(mid, dest.(DeclarationEntry)) and + getDeclarationEntries(mid, dest) and not dest instanceof TypeDeclarationEntry and // must be definition dest.(DeclarationEntry).isDefinition() and diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Exclusions.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Exclusions.qll index a0dfea20046..ad60bb3288a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Exclusions.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Exclusions.qll @@ -81,8 +81,8 @@ predicate functionContainsPreprocCode(Function f) { } /** - * Holds if `e` is completely or partially from a macro definition, as opposed - * to being passed in as an argument. + * Holds if `e` is completely or partially from a macro invocation `mi`, as + * opposed to being passed in as an argument. * * In the following example, the call to `f` is from a macro definition, * while `y`, `+`, `1`, and `;` are not. This assumes that no identifier apart @@ -93,8 +93,8 @@ predicate functionContainsPreprocCode(Function f) { * M(y + 1); * ``` */ -predicate isFromMacroDefinition(Element e) { - exists(MacroInvocation mi, Location eLocation, Location miLocation | +private predicate isFromMacroInvocation(Element e, MacroInvocation mi) { + exists(Location eLocation, Location miLocation | mi.getAnExpandedElement() = e and eLocation = e.getLocation() and miLocation = mi.getLocation() and @@ -109,3 +109,36 @@ predicate isFromMacroDefinition(Element e) { eLocation.getEndColumn() >= miLocation.getEndColumn() ) } + +/** + * Holds if `e` is completely or partially from a macro definition, as opposed + * to being passed in as an argument. + * + * In the following example, the call to `f` is from a macro definition, + * while `y`, `+`, `1`, and `;` are not. This assumes that no identifier apart + * from `M` refers to a macro. + * ``` + * #define M(x) f(x) + * ... + * M(y + 1); + * ``` + */ +predicate isFromMacroDefinition(Element e) { isFromMacroInvocation(e, _) } + +/** + * Holds if `e` is completely or partially from a _system macro_ definition, as + * opposed to being passed in as an argument. A system macro is a macro whose + * definition is outside the source directory of the database. + * + * If the system macro is invoked through a non-system macro, then this + * predicate does not hold. + * + * See also `isFromMacroDefinition`. + */ +predicate isFromSystemMacroDefinition(Element e) { + exists(MacroInvocation mi | + isFromMacroInvocation(e, mi) and + // Has no relative path in the database, meaning it's a system file. + not exists(mi.getMacro().getFile().getRelativePath()) + ) +} diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll index 2f811ab83a0..71effe7906f 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll @@ -3,17 +3,33 @@ private import semmle.code.cpp.models.interfaces.ArrayFunction private import semmle.code.cpp.models.implementations.Strcat import semmle.code.cpp.dataflow.DataFlow -private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0) { - exists(StackVariable v0, Expr val | - exprDefinition(v0, e, val) and - val.getAChild*() = va and - mayAddNullTerminator(e0, v0.getAnAccess()) +/** + * Holds if the expression `e` assigns something including `va` to a + * stack variable `v0`. + */ +private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, StackVariable v0) { + exists(Expr val | + exprDefinition(v0, e, val) and // `e` is `v0 := val` + val.getAChild*() = va + ) +} + +bindingset[n1, n2] +private predicate controlFlowNodeSuccessorTransitive(ControlFlowNode n1, ControlFlowNode n2) { + exists(BasicBlock bb1, int pos1, BasicBlock bb2, int pos2 | + pragma[only_bind_into](bb1).getNode(pos1) = n1 and + pragma[only_bind_into](bb2).getNode(pos2) = n2 and + ( + bb1 = bb2 and pos1 < pos2 + or + bb1.getASuccessor+() = bb2 + ) ) } /** - * Holds if the expression `e` may add a null terminator to the string in - * variable `v`. + * Holds if the expression `e` may add a null terminator to the string + * accessed by `va`. */ predicate mayAddNullTerminator(Expr e, VariableAccess va) { // Assignment: dereferencing or array access @@ -30,14 +46,10 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) { ) or // Assignment to another stack variable - exists(Expr e0, BasicBlock bb, int pos, BasicBlock bb0, int pos0 | - mayAddNullTerminatorHelper(e, va, e0) and - bb.getNode(pos) = e and - bb0.getNode(pos0) = e0 - | - bb = bb0 and pos < pos0 - or - bb.getASuccessor+() = bb0 + exists(StackVariable v0, Expr e0 | + mayAddNullTerminatorHelper(e, va, v0) and + mayAddNullTerminator(pragma[only_bind_into](e0), pragma[only_bind_into](v0.getAnAccess())) and + controlFlowNodeSuccessorTransitive(e, e0) ) or // Assignment to non-stack variable @@ -119,14 +131,9 @@ predicate variableMustBeNullTerminated(VariableAccess va) { variableMustBeNullTerminated(use) and // Simplified: check that `p` may not be null terminated on *any* // path to `use` (including the one found via `parameterUsePair`) - not exists(Expr e, BasicBlock bb1, int pos1, BasicBlock bb2, int pos2 | - mayAddNullTerminator(e, p.getAnAccess()) and - bb1.getNode(pos1) = e and - bb2.getNode(pos2) = use - | - bb1 = bb2 and pos1 < pos2 - or - bb1.getASuccessor+() = bb2 + not exists(Expr e | + mayAddNullTerminator(pragma[only_bind_into](e), p.getAnAccess()) and + controlFlowNodeSuccessorTransitive(e, use) ) ) ) diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll index 46ca9ccf009..54de9df553b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll @@ -6,9 +6,11 @@ import semmle.code.cpp.Type import semmle.code.cpp.commons.CommonType import semmle.code.cpp.commons.StringAnalysis import semmle.code.cpp.models.interfaces.FormattingFunction +private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils class PrintfFormatAttribute extends FormatAttribute { - PrintfFormatAttribute() { getArchetype() = ["printf", "__printf__"] } + PrintfFormatAttribute() { this.getArchetype() = ["printf", "__printf__"] } } /** @@ -20,13 +22,13 @@ class AttributeFormattingFunction extends FormattingFunction { AttributeFormattingFunction() { exists(PrintfFormatAttribute printf_attrib | - printf_attrib = getAnAttribute() and + printf_attrib = this.getAnAttribute() and exists(printf_attrib.getFirstFormatArgIndex()) // exclude `vprintf` style format functions ) } override int getFormatParameterIndex() { - forex(PrintfFormatAttribute printf_attrib | printf_attrib = getAnAttribute() | + forex(PrintfFormatAttribute printf_attrib | printf_attrib = this.getAnAttribute() | result = printf_attrib.getFormatIndex() ) } @@ -132,7 +134,7 @@ deprecated predicate variadicFormatter(Function f, int formatParamIndex) { class UserDefinedFormattingFunction extends FormattingFunction { override string getAPrimaryQlClass() { result = "UserDefinedFormattingFunction" } - UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _, _, _) } + UserDefinedFormattingFunction() { this.isVarargs() and callsVariadicFormatter(this, _, _, _) } override int getFormatParameterIndex() { callsVariadicFormatter(this, _, result, _) } @@ -175,9 +177,7 @@ class FormattingFunctionCall extends Expr { /** * Gets the index at which the format string occurs in the argument list. */ - int getFormatParameterIndex() { - result = this.getTarget().(FormattingFunction).getFormatParameterIndex() - } + int getFormatParameterIndex() { result = this.getTarget().getFormatParameterIndex() } /** * Gets the format expression used in this call. @@ -191,7 +191,7 @@ class FormattingFunctionCall extends Expr { exists(int i | result = this.getArgument(i) and n >= 0 and - n = i - getTarget().(FormattingFunction).getFirstFormatArgumentIndex() + n = i - this.getTarget().getFirstFormatArgumentIndex() ) } @@ -251,7 +251,7 @@ class FormattingFunctionCall extends Expr { int getNumFormatArgument() { result = count(this.getFormatArgument(_)) and // format arguments must be known - exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex()) + exists(this.getTarget().getFirstFormatArgumentIndex()) } /** @@ -270,6 +270,18 @@ class FormattingFunctionCall extends Expr { } } +/** + * Gets the number of digits required to represent the integer represented by `f`. + * + * `f` is assumed to be nonnegative. + */ +bindingset[f] +private int lengthInBase10(float f) { + f = 0 and result = 1 + or + result = f.log10().floor() + 1 +} + /** * A class to represent format strings that occur as arguments to invocations of formatting functions. */ @@ -289,33 +301,27 @@ class FormatLiteral extends Literal { * a `char *` (either way, `%S` will have the opposite meaning). * DEPRECATED: Use getDefaultCharType() instead. */ - deprecated predicate isWideCharDefault() { - getUse().getTarget().(FormattingFunction).isWideCharDefault() - } + deprecated predicate isWideCharDefault() { this.getUse().getTarget().isWideCharDefault() } /** * Gets the default character type expected for `%s` by this format literal. Typically * `char` or `wchar_t`. */ - Type getDefaultCharType() { - result = getUse().getTarget().(FormattingFunction).getDefaultCharType() - } + Type getDefaultCharType() { result = this.getUse().getTarget().getDefaultCharType() } /** * Gets the non-default character type expected for `%S` by this format literal. Typically * `wchar_t` or `char`. On some snapshots there may be multiple results where we can't tell * which is correct for a particular function. */ - Type getNonDefaultCharType() { - result = getUse().getTarget().(FormattingFunction).getNonDefaultCharType() - } + Type getNonDefaultCharType() { result = this.getUse().getTarget().getNonDefaultCharType() } /** * Gets the wide character type for this format literal. This is usually `wchar_t`. On some * snapshots there may be multiple results where we can't tell which is correct for a * particular function. */ - Type getWideCharType() { result = getUse().getTarget().(FormattingFunction).getWideCharType() } + Type getWideCharType() { result = this.getUse().getTarget().getWideCharType() } /** * Holds if this `FormatLiteral` is in a context that supports @@ -353,7 +359,7 @@ class FormatLiteral extends Literal { } private string getFlagRegexp() { - if isMicrosoft() then result = "[-+ #0']*" else result = "[-+ #0'I]*" + if this.isMicrosoft() then result = "[-+ #0']*" else result = "[-+ #0'I]*" } private string getFieldWidthRegexp() { result = "(?:[1-9][0-9]*|\\*|\\*[0-9]+\\$)?" } @@ -361,13 +367,13 @@ class FormatLiteral extends Literal { private string getPrecRegexp() { result = "(?:\\.(?:[0-9]*|\\*|\\*[0-9]+\\$))?" } private string getLengthRegexp() { - if isMicrosoft() + if this.isMicrosoft() then result = "(?:hh?|ll?|L|q|j|z|t|w|I32|I64|I)?" else result = "(?:hh?|ll?|L|q|j|z|Z|t)?" } private string getConvCharRegexp() { - if isMicrosoft() + if this.isMicrosoft() then result = "[aAcCdeEfFgGimnopsSuxXZ@]" else result = "[aAcCdeEfFgGimnopsSuxX@]" } @@ -747,16 +753,16 @@ class FormatLiteral extends Literal { * Gets the argument type required by the nth conversion specifier. */ Type getConversionType(int n) { - result = getConversionType1(n) or - result = getConversionType1b(n) or - result = getConversionType2(n) or - result = getConversionType3(n) or - result = getConversionType4(n) or - result = getConversionType6(n) or - result = getConversionType7(n) or - result = getConversionType8(n) or - result = getConversionType9(n) or - result = getConversionType10(n) + result = this.getConversionType1(n) or + result = this.getConversionType1b(n) or + result = this.getConversionType2(n) or + result = this.getConversionType3(n) or + result = this.getConversionType4(n) or + result = this.getConversionType6(n) or + result = this.getConversionType7(n) or + result = this.getConversionType8(n) or + result = this.getConversionType9(n) or + result = this.getConversionType10(n) } private Type getConversionType1(int n) { @@ -786,15 +792,15 @@ class FormatLiteral extends Literal { or conv = ["c", "C"] and len = ["l", "w"] and - result = getWideCharType() + result = this.getWideCharType() or conv = "c" and (len != "l" and len != "w" and len != "h") and - result = getDefaultCharType() + result = this.getDefaultCharType() or conv = "C" and (len != "l" and len != "w" and len != "h") and - result = getNonDefaultCharType() + result = this.getNonDefaultCharType() ) ) } @@ -831,15 +837,15 @@ class FormatLiteral extends Literal { or conv = ["s", "S"] and len = ["l", "w"] and - result.(PointerType).getBaseType() = getWideCharType() + result.(PointerType).getBaseType() = this.getWideCharType() or conv = "s" and (len != "l" and len != "w" and len != "h") and - result.(PointerType).getBaseType() = getDefaultCharType() + result.(PointerType).getBaseType() = this.getDefaultCharType() or conv = "S" and (len != "l" and len != "w" and len != "h") and - result.(PointerType).getBaseType() = getNonDefaultCharType() + result.(PointerType).getBaseType() = this.getNonDefaultCharType() ) ) } @@ -894,19 +900,19 @@ class FormatLiteral extends Literal { exists(string len, string conv | this.parseConvSpec(n, _, _, _, _, _, len, conv) and (len != "l" and len != "w" and len != "h") and - getUse().getTarget().(FormattingFunction).getFormatCharType().getSize() > 1 and // wide function + this.getUse().getTarget().getFormatCharType().getSize() > 1 and // wide function ( conv = "c" and - result = getNonDefaultCharType() + result = this.getNonDefaultCharType() or conv = "C" and - result = getDefaultCharType() + result = this.getDefaultCharType() or conv = "s" and - result.(PointerType).getBaseType() = getNonDefaultCharType() + result.(PointerType).getBaseType() = this.getNonDefaultCharType() or conv = "S" and - result.(PointerType).getBaseType() = getDefaultCharType() + result.(PointerType).getBaseType() = this.getDefaultCharType() ) ) } @@ -939,9 +945,13 @@ class FormatLiteral extends Literal { * not account for positional arguments (`$`). */ int getFormatArgumentIndexFor(int n, int mode) { - hasFormatArgumentIndexFor(n, mode) and + this.hasFormatArgumentIndexFor(n, mode) and (3 * n) + mode = - rank[result + 1](int n2, int mode2 | hasFormatArgumentIndexFor(n2, mode2) | (3 * n2) + mode2) + rank[result + 1](int n2, int mode2 | + this.hasFormatArgumentIndexFor(n2, mode2) + | + (3 * n2) + mode2 + ) } /** @@ -951,7 +961,7 @@ class FormatLiteral extends Literal { int getNumArgNeeded(int n) { exists(this.getConvSpecOffset(n)) and exists(this.getConversionChar(n)) and - result = count(int mode | hasFormatArgumentIndexFor(n, mode)) + result = count(int mode | this.hasFormatArgumentIndexFor(n, mode)) } /** @@ -963,7 +973,7 @@ class FormatLiteral extends Literal { // At least one conversion specifier has a parameter field, in which case, // they all should have. result = max(string s | this.getParameterField(_) = s + "$" | s.toInt()) - else result = count(int n, int mode | hasFormatArgumentIndexFor(n, mode)) + else result = count(int n, int mode | this.hasFormatArgumentIndexFor(n, mode)) } /** @@ -1050,65 +1060,89 @@ class FormatLiteral extends Literal { or this.getConversionChar(n).toLowerCase() = ["d", "i"] and // e.g. -2^31 = "-2147483648" - exists(int sizeBits | - sizeBits = - min(int bits | - bits = getIntegralDisplayType(n).getSize() * 8 - or - exists(IntegralType t | - t = getUse().getConversionArgument(n).getType().getUnderlyingType() - | - t.isSigned() and bits = t.getSize() * 8 - ) - ) and - len = 1 + ((sizeBits - 1) / 10.0.log2()).ceil() - // this calculation is as %u (below) only we take out the sign bit (- 1) and allow a whole - // character for it to be expressed as '-'. - ) + len = + min(float cand | + // The first case handles length sub-specifiers + // Subtract one in the exponent because one bit is for the sign. + // Add 1 to account for the possible sign in the output. + cand = 1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1)) + or + // The second case uses range analysis to deduce a length that's shorter than the length + // of the number -2^31. + exists(Expr arg, float lower, float upper | + arg = this.getUse().getConversionArgument(n) and + lower = lowerBound(arg.getFullyConverted()) and + upper = upperBound(arg.getFullyConverted()) + | + cand = + max(int cand0 | + // Include the sign bit in the length if it can be negative + ( + if lower < 0 + then cand0 = 1 + lengthInBase10(lower.abs()) + else cand0 = lengthInBase10(lower) + ) + or + ( + if upper < 0 + then cand0 = 1 + lengthInBase10(upper.abs()) + else cand0 = lengthInBase10(upper) + ) + ) + ) + ) or this.getConversionChar(n).toLowerCase() = "u" and // e.g. 2^32 - 1 = "4294967295" - exists(int sizeBits | - sizeBits = - min(int bits | - bits = getIntegralDisplayType(n).getSize() * 8 - or - exists(IntegralType t | - t = getUse().getConversionArgument(n).getType().getUnderlyingType() - | - t.isUnsigned() and bits = t.getSize() * 8 - ) - ) and - len = (sizeBits / 10.0.log2()).ceil() - // convert the size from bits to decimal characters, and round up as you can't have - // fractional characters (10.0.log2() is the number of bits expressed per decimal character) - ) + len = + min(float cand | + // The first case handles length sub-specifiers + cand = 2.pow(this.getIntegralDisplayType(n).getSize() * 8) + or + // The second case uses range analysis to deduce a length that's shorter than + // the length of the number 2^31 - 1. + exists(Expr arg, float lower | + arg = this.getUse().getConversionArgument(n) and + lower = lowerBound(arg.getFullyConverted()) + | + cand = + max(float cand0 | + // If lower can be negative we use `(unsigned)-1` as the candidate value. + lower < 0 and + cand0 = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8) + or + cand0 = upperBound(arg.getFullyConverted()) + ) + ) + | + lengthInBase10(cand) + ) or this.getConversionChar(n).toLowerCase() = "x" and // e.g. "12345678" exists(int sizeBytes, int baseLen | sizeBytes = min(int bytes | - bytes = getIntegralDisplayType(n).getSize() + bytes = this.getIntegralDisplayType(n).getSize() or exists(IntegralType t | - t = getUse().getConversionArgument(n).getType().getUnderlyingType() + t = this.getUse().getConversionArgument(n).getType().getUnderlyingType() | t.isUnsigned() and bytes = t.getSize() ) ) and baseLen = sizeBytes * 2 and ( - if hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x" + if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x" ) ) or this.getConversionChar(n).toLowerCase() = "p" and exists(PointerType ptrType, int baseLen | - ptrType = getFullyConverted().getType() and + ptrType = this.getFullyConverted().getType() and baseLen = max(ptrType.getSize() * 2) and // e.g. "0x1234567812345678"; exact format is platform dependent ( - if hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x" + if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x" ) ) or @@ -1117,17 +1151,17 @@ class FormatLiteral extends Literal { exists(int sizeBits, int baseLen | sizeBits = min(int bits | - bits = getIntegralDisplayType(n).getSize() * 8 + bits = this.getIntegralDisplayType(n).getSize() * 8 or exists(IntegralType t | - t = getUse().getConversionArgument(n).getType().getUnderlyingType() + t = this.getUse().getConversionArgument(n).getType().getUnderlyingType() | t.isUnsigned() and bits = t.getSize() * 8 ) ) and baseLen = (sizeBits / 3.0).ceil() and ( - if hasAlternateFlag(n) then len = 1 + baseLen else len = baseLen // "0" + if this.hasAlternateFlag(n) then len = 1 + baseLen else len = baseLen // "0" ) ) or @@ -1150,8 +1184,8 @@ class FormatLiteral extends Literal { */ int getMaxConvertedLengthLimited(int n) { if this.getConversionChar(n).toLowerCase() = "f" - then result = getMaxConvertedLength(n).minimum(8) - else result = getMaxConvertedLength(n) + then result = this.getMaxConvertedLength(n).minimum(8) + else result = this.getMaxConvertedLength(n) } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll index 461030f389d..58d980318d9 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll @@ -24,7 +24,7 @@ abstract class ScanfFunction extends Function { * Holds if the default meaning of `%s` is a `wchar_t*` string * (rather than a `char*`). */ - predicate isWideCharDefault() { exists(getName().indexOf("wscanf")) } + predicate isWideCharDefault() { exists(this.getName().indexOf("wscanf")) } } /** @@ -34,10 +34,10 @@ class Scanf extends ScanfFunction { Scanf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...) - hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...) - hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...) - hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...) + this.hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...) + this.hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...) + this.hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...) + this.hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...) ) } @@ -53,10 +53,10 @@ class Fscanf extends ScanfFunction { Fscanf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...) - hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...) - hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...) - hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...) + this.hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...) + this.hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...) + this.hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...) + this.hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...) ) } @@ -72,10 +72,10 @@ class Sscanf extends ScanfFunction { Sscanf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...) - hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...) - hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...) - hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...) + this.hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...) + this.hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...) + this.hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...) + this.hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...) ) } @@ -91,10 +91,10 @@ class Snscanf extends ScanfFunction { Snscanf() { this instanceof TopLevelFunction and ( - hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...) - hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...) - hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...) - hasGlobalName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...) + this.hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...) + this.hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...) + this.hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...) + this.hasGlobalName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...) // note that the max_amount is not a limit on the output length, it's an input length // limit used with non null-terminated strings. ) @@ -120,18 +120,18 @@ class ScanfFunctionCall extends FunctionCall { /** * Gets the `scanf`-like function that is called. */ - ScanfFunction getScanfFunction() { result = getTarget() } + ScanfFunction getScanfFunction() { result = this.getTarget() } /** * Gets the position at which the input string or stream parameter occurs, * if this function call does not read from standard input. */ - int getInputParameterIndex() { result = getScanfFunction().getInputParameterIndex() } + int getInputParameterIndex() { result = this.getScanfFunction().getInputParameterIndex() } /** * Gets the position at which the format parameter occurs. */ - int getFormatParameterIndex() { result = getScanfFunction().getFormatParameterIndex() } + int getFormatParameterIndex() { result = this.getScanfFunction().getFormatParameterIndex() } /** * Gets the format expression used in this call. @@ -142,7 +142,7 @@ class ScanfFunctionCall extends FunctionCall { * Holds if the default meaning of `%s` is a `wchar_t*` string * (rather than a `char*`). */ - predicate isWideCharDefault() { getScanfFunction().isWideCharDefault() } + predicate isWideCharDefault() { this.getScanfFunction().isWideCharDefault() } } /** @@ -158,7 +158,7 @@ class ScanfFormatLiteral extends Expr { ScanfFunctionCall getUse() { result.getFormat() = this } /** Holds if the default meaning of `%s` is a `wchar_t*` (rather than a `char*`). */ - predicate isWideCharDefault() { getUse().getTarget().(ScanfFunction).isWideCharDefault() } + predicate isWideCharDefault() { this.getUse().getTarget().(ScanfFunction).isWideCharDefault() } /** * Gets the format string itself, transformed as follows: diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Synchronization.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Synchronization.qll index 92955ae3580..f1b9cf80d64 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Synchronization.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/commons/Synchronization.qll @@ -40,8 +40,8 @@ abstract class MutexType extends Type { * Gets a call that locks or tries to lock any mutex of this type. */ FunctionCall getLockAccess() { - result = getMustlockAccess() or - result = getTrylockAccess() + result = this.getMustlockAccess() or + result = this.getTrylockAccess() } /** @@ -63,22 +63,22 @@ abstract class MutexType extends Type { /** * DEPRECATED: use mustlockAccess(fc, arg) instead. */ - deprecated Function getMustlockFunction() { result = getMustlockAccess().getTarget() } + deprecated Function getMustlockFunction() { result = this.getMustlockAccess().getTarget() } /** * DEPRECATED: use trylockAccess(fc, arg) instead. */ - deprecated Function getTrylockFunction() { result = getTrylockAccess().getTarget() } + deprecated Function getTrylockFunction() { result = this.getTrylockAccess().getTarget() } /** * DEPRECATED: use lockAccess(fc, arg) instead. */ - deprecated Function getLockFunction() { result = getLockAccess().getTarget() } + deprecated Function getLockFunction() { result = this.getLockAccess().getTarget() } /** * DEPRECATED: use unlockAccess(fc, arg) instead. */ - deprecated Function getUnlockFunction() { result = getUnlockAccess().getTarget() } + deprecated Function getUnlockFunction() { result = this.getUnlockAccess().getTarget() } } /** @@ -155,17 +155,17 @@ class DefaultMutexType extends MutexType { override predicate mustlockAccess(FunctionCall fc, Expr arg) { fc.getTarget() = mustlockCandidate() and - lockArgType(fc, arg) + this.lockArgType(fc, arg) } override predicate trylockAccess(FunctionCall fc, Expr arg) { fc.getTarget() = trylockCandidate() and - lockArgType(fc, arg) + this.lockArgType(fc, arg) } override predicate unlockAccess(FunctionCall fc, Expr arg) { fc.getTarget() = unlockCandidate() and - lockArgType(fc, arg) + this.lockArgType(fc, arg) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/BasicBlocks.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/BasicBlocks.qll index e235eba355b..34373d943af 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/BasicBlocks.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/BasicBlocks.qll @@ -201,7 +201,7 @@ class BasicBlock extends ControlFlowNodeBase { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - hasLocationInfoInternal(filepath, startline, startcolumn, filepath, endline, endcolumn) + this.hasLocationInfoInternal(filepath, startline, startcolumn, filepath, endline, endcolumn) } pragma[noinline] @@ -276,7 +276,7 @@ class EntryBasicBlock extends BasicBlock { */ class ExitBasicBlock extends BasicBlock { ExitBasicBlock() { - getEnd() instanceof Function or - aborting(getEnd()) + this.getEnd() instanceof Function or + aborting(this.getEnd()) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/ControlFlowGraph.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/ControlFlowGraph.qll index bac051f6474..c7b3d1dc16f 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/ControlFlowGraph.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/ControlFlowGraph.qll @@ -66,7 +66,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase { */ ControlFlowNode getATrueSuccessor() { qlCFGTrueSuccessor(this, result) and - result = getASuccessor() + result = this.getASuccessor() } /** @@ -75,7 +75,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase { */ ControlFlowNode getAFalseSuccessor() { qlCFGFalseSuccessor(this, result) and - result = getASuccessor() + result = this.getASuccessor() } /** Gets the `BasicBlock` containing this control-flow node. */ diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/DefinitionsAndUses.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/DefinitionsAndUses.qll index f6eb0a8a645..dcabba51ce2 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/DefinitionsAndUses.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/DefinitionsAndUses.qll @@ -25,7 +25,7 @@ predicate definitionUsePair(SemanticStackVariable var, Expr def, Expr use) { * Holds if the definition `def` of some stack variable can reach `node`, which * is a definition or use, without crossing definitions of the same variable. */ -predicate definitionReaches(Expr def, Expr node) { def.(Def).reaches(true, _, node.(DefOrUse)) } +predicate definitionReaches(Expr def, Expr node) { def.(Def).reaches(true, _, node) } private predicate hasAddressOfAccess(SemanticStackVariable var) { var.getAnAccess().isAddressOfAccessNonConst() diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll index d96fc34259c..9aee2556c1d 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll @@ -121,7 +121,7 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition { override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { exists(boolean testIsTrue | - comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) + this.comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) ) } @@ -135,7 +135,7 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition { override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { exists(boolean testIsTrue | - comparesEq(left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue) + this.comparesEq(left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue) ) } } @@ -147,27 +147,29 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition { private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr { GuardConditionFromShortCircuitNot() { not exists(Instruction inst | this.getFullyConverted() = inst.getAST()) and - exists(IRGuardCondition ir | getOperand() = ir.getAST()) + exists(IRGuardCondition ir | this.getOperand() = ir.getAST()) } override predicate controls(BasicBlock controlled, boolean testIsTrue) { - getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot()) + this.getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot()) } override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { - getOperand().(GuardCondition).comparesLt(left, right, k, isLessThan, testIsTrue.booleanNot()) + this.getOperand() + .(GuardCondition) + .comparesLt(left, right, k, isLessThan, testIsTrue.booleanNot()) } override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { - getOperand().(GuardCondition).ensuresLt(left, right, k, block, isLessThan.booleanNot()) + this.getOperand().(GuardCondition).ensuresLt(left, right, k, block, isLessThan.booleanNot()) } override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { - getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot()) + this.getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot()) } override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { - getOperand().(GuardCondition).ensuresEq(left, right, k, block, areEqual.booleanNot()) + this.getOperand().(GuardCondition).ensuresEq(left, right, k, block, areEqual.booleanNot()) } } @@ -303,9 +305,9 @@ class IRGuardCondition extends Instruction { cached predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) { pred.getASuccessor() = succ and - controls(pred, testIsTrue) + this.controls(pred, testIsTrue) or - succ = getBranchSuccessor(testIsTrue) and + succ = this.getBranchSuccessor(testIsTrue) and branch.getCondition() = this and branch.getBlock() = pred } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll index 32857146029..f6685865830 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll @@ -73,19 +73,19 @@ abstract deprecated class LocalScopeVariableReachability extends string { */ exists(BasicBlock bb, int i | - isSource(source, v) and + this.isSource(source, v) and bb.getNode(i) = source and not bb.isUnreachable() | exists(int j | j > i and sink = bb.getNode(j) and - isSink(sink, v) and - not exists(int k | isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1]) + this.isSink(sink, v) and + not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1]) ) or - not exists(int k | isBarrier(bb.getNode(k), v) | k > i) and - bbSuccessorEntryReaches(bb, v, sink, _) + not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and + this.bbSuccessorEntryReaches(bb, v, sink, _) ) } @@ -97,11 +97,11 @@ abstract deprecated class LocalScopeVariableReachability extends string { bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry, succSkipsFirstLoopAlwaysTrueUponEntry) | - bbEntryReachesLocally(succ, v, node) and + this.bbEntryReachesLocally(succ, v, node) and succSkipsFirstLoopAlwaysTrueUponEntry = false or - not isBarrier(succ.getNode(_), v) and - bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry) + not this.isBarrier(succ.getNode(_), v) and + this.bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry) ) } @@ -110,7 +110,7 @@ abstract deprecated class LocalScopeVariableReachability extends string { ) { exists(int n | node = bb.getNode(n) and - isSink(node, v) + this.isSink(node, v) | not exists(this.firstBarrierIndexIn(bb, v)) or @@ -119,7 +119,7 @@ abstract deprecated class LocalScopeVariableReachability extends string { } private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) { - result = min(int m | isBarrier(bb.getNode(m), v)) + result = min(int m | this.isBarrier(bb.getNode(m), v)) } } @@ -271,7 +271,7 @@ abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends * accounts for loops where the condition is provably true upon entry. */ override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { - reachesTo(source, v, sink, _) + this.reachesTo(source, v, sink, _) } /** @@ -281,21 +281,21 @@ abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0 ) { exists(ControlFlowNode def | - actualSourceReaches(source, v, def, v0) and + this.actualSourceReaches(source, v, def, v0) and LocalScopeVariableReachability.super.reaches(def, v0, sink) and - isSinkActual(sink, v0) + this.isSinkActual(sink, v0) ) } private predicate actualSourceReaches( ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0 ) { - isSourceActual(source, v) and def = source and v0 = v + this.isSourceActual(source, v) and def = source and v0 = v or exists(ControlFlowNode source1, SemanticStackVariable v1 | - actualSourceReaches(source, v, source1, v1) + this.actualSourceReaches(source, v, source1, v1) | - reassignment(source1, v1, def, v0) + this.reassignment(source1, v1, def, v0) ) } @@ -307,14 +307,14 @@ abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends } final override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { - isSourceActual(node, v) + this.isSourceActual(node, v) or // Reassignment generates a new (non-actual) source - reassignment(_, _, node, v) + this.reassignment(_, _, node, v) } final override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { - isSinkActual(node, v) + this.isSinkActual(node, v) or // Reassignment generates a new (non-actual) sink exprDefinition(_, node, v.getAnAccess()) @@ -347,21 +347,21 @@ abstract deprecated class LocalScopeVariableReachabilityExt extends string { /** See `LocalScopeVariableReachability.reaches`. */ predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { exists(BasicBlock bb, int i | - isSource(source, v) and + this.isSource(source, v) and bb.getNode(i) = source and not bb.isUnreachable() | exists(int j | j > i and sink = bb.getNode(j) and - isSink(sink, v) and - not exists(int k | isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | + this.isSink(sink, v) and + not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k in [i .. j - 1] ) ) or - not exists(int k | isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and - bbSuccessorEntryReaches(source, bb, v, sink, _) + not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and + this.bbSuccessorEntryReaches(source, bb, v, sink, _) ) } @@ -372,22 +372,22 @@ abstract deprecated class LocalScopeVariableReachabilityExt extends string { exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry | bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry, succSkipsFirstLoopAlwaysTrueUponEntry) and - not isBarrier(source, bb.getEnd(), succ.getStart(), v) + not this.isBarrier(source, bb.getEnd(), succ.getStart(), v) | - bbEntryReachesLocally(source, succ, v, node) and + this.bbEntryReachesLocally(source, succ, v, node) and succSkipsFirstLoopAlwaysTrueUponEntry = false or - not exists(int k | isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and - bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry) + not exists(int k | this.isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and + this.bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry) ) } private predicate bbEntryReachesLocally( ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node ) { - isSource(source, v) and - exists(int n | node = bb.getNode(n) and isSink(node, v) | - not exists(int m | m < n | isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v)) + this.isSource(source, v) and + exists(int n | node = bb.getNode(n) and this.isSink(node, v) | + not exists(int m | m < n | this.isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v)) ) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll index 5c0f6b3ac14..c7af3fe4326 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll @@ -59,10 +59,10 @@ class SsaDefinition extends ControlFlowNodeBase { ControlFlowNode getDefinition() { result = this } /** Gets the `BasicBlock` containing this definition. */ - BasicBlock getBasicBlock() { result.contains(getDefinition()) } + BasicBlock getBasicBlock() { result.contains(this.getDefinition()) } /** Holds if this definition is a phi node for variable `v`. */ - predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) } + predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this)) } /** Gets the location of this definition. */ Location getLocation() { result = this.(ControlFlowNode).getLocation() } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll index caae23c3bbd..3b02a0c828f 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll @@ -292,7 +292,7 @@ library class SSAHelper extends int { */ cached string toString(ControlFlowNode node, StackVariable v) { - if phi_node(v, node.(BasicBlock)) + if phi_node(v, node) then result = "SSA phi(" + v.getName() + ")" else ( ssa_defn(v, node, _, _) and result = "SSA def(" + v.getName() + ")" diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/StackVariableReachability.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/StackVariableReachability.qll index 6c50d254faa..7b5fcd504b1 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/StackVariableReachability.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/StackVariableReachability.qll @@ -72,19 +72,19 @@ abstract class StackVariableReachability extends string { */ exists(BasicBlock bb, int i | - isSource(source, v) and + this.isSource(source, v) and bb.getNode(i) = source and not bb.isUnreachable() | exists(int j | j > i and sink = bb.getNode(j) and - isSink(sink, v) and - not exists(int k | isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1]) + this.isSink(sink, v) and + not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1]) ) or - not exists(int k | isBarrier(bb.getNode(k), v) | k > i) and - bbSuccessorEntryReaches(bb, v, sink, _) + not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and + this.bbSuccessorEntryReaches(bb, v, sink, _) ) } @@ -96,11 +96,11 @@ abstract class StackVariableReachability extends string { bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry, succSkipsFirstLoopAlwaysTrueUponEntry) | - bbEntryReachesLocally(succ, v, node) and + this.bbEntryReachesLocally(succ, v, node) and succSkipsFirstLoopAlwaysTrueUponEntry = false or - not isBarrier(succ.getNode(_), v) and - bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry) + not this.isBarrier(succ.getNode(_), v) and + this.bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry) ) } @@ -109,7 +109,7 @@ abstract class StackVariableReachability extends string { ) { exists(int n | node = bb.getNode(n) and - isSink(node, v) + this.isSink(node, v) | not exists(this.firstBarrierIndexIn(bb, v)) or @@ -118,7 +118,7 @@ abstract class StackVariableReachability extends string { } private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) { - result = min(int m | isBarrier(bb.getNode(m), v)) + result = min(int m | this.isBarrier(bb.getNode(m), v)) } } @@ -268,7 +268,7 @@ abstract class StackVariableReachabilityWithReassignment extends StackVariableRe * accounts for loops where the condition is provably true upon entry. */ override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { - reachesTo(source, v, sink, _) + this.reachesTo(source, v, sink, _) } /** @@ -278,21 +278,21 @@ abstract class StackVariableReachabilityWithReassignment extends StackVariableRe ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0 ) { exists(ControlFlowNode def | - actualSourceReaches(source, v, def, v0) and + this.actualSourceReaches(source, v, def, v0) and StackVariableReachability.super.reaches(def, v0, sink) and - isSinkActual(sink, v0) + this.isSinkActual(sink, v0) ) } private predicate actualSourceReaches( ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0 ) { - isSourceActual(source, v) and def = source and v0 = v + this.isSourceActual(source, v) and def = source and v0 = v or exists(ControlFlowNode source1, SemanticStackVariable v1 | - actualSourceReaches(source, v, source1, v1) + this.actualSourceReaches(source, v, source1, v1) | - reassignment(source1, v1, def, v0) + this.reassignment(source1, v1, def, v0) ) } @@ -304,14 +304,14 @@ abstract class StackVariableReachabilityWithReassignment extends StackVariableRe } final override predicate isSource(ControlFlowNode node, StackVariable v) { - isSourceActual(node, v) + this.isSourceActual(node, v) or // Reassignment generates a new (non-actual) source - reassignment(_, _, node, v) + this.reassignment(_, _, node, v) } final override predicate isSink(ControlFlowNode node, StackVariable v) { - isSinkActual(node, v) + this.isSinkActual(node, v) or // Reassignment generates a new (non-actual) sink exprDefinition(_, node, v.getAnAccess()) @@ -342,21 +342,21 @@ abstract class StackVariableReachabilityExt extends string { /** See `StackVariableReachability.reaches`. */ predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { exists(BasicBlock bb, int i | - isSource(source, v) and + this.isSource(source, v) and bb.getNode(i) = source and not bb.isUnreachable() | exists(int j | j > i and sink = bb.getNode(j) and - isSink(sink, v) and - not exists(int k | isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | + this.isSink(sink, v) and + not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k in [i .. j - 1] ) ) or - not exists(int k | isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and - bbSuccessorEntryReaches(source, bb, v, sink, _) + not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and + this.bbSuccessorEntryReaches(source, bb, v, sink, _) ) } @@ -367,22 +367,22 @@ abstract class StackVariableReachabilityExt extends string { exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry | bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry, succSkipsFirstLoopAlwaysTrueUponEntry) and - not isBarrier(source, bb.getEnd(), succ.getStart(), v) + not this.isBarrier(source, bb.getEnd(), succ.getStart(), v) | - bbEntryReachesLocally(source, succ, v, node) and + this.bbEntryReachesLocally(source, succ, v, node) and succSkipsFirstLoopAlwaysTrueUponEntry = false or - not exists(int k | isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and - bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry) + not exists(int k | this.isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and + this.bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry) ) } private predicate bbEntryReachesLocally( ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node ) { - isSource(source, v) and - exists(int n | node = bb.getNode(n) and isSink(node, v) | - not exists(int m | m < n | isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v)) + this.isSource(source, v) and + exists(int n | node = bb.getNode(n) and this.isSink(node, v) | + not exists(int m | m < n | this.isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v)) ) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SubBasicBlocks.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SubBasicBlocks.qll index fa9d2e94081..4fbea43b805 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SubBasicBlocks.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/SubBasicBlocks.qll @@ -80,7 +80,7 @@ class SubBasicBlock extends ControlFlowNodeBase { * returns a 0-based position, while `getRankInBasicBlock` returns a 1-based * position. */ - deprecated int getPosInBasicBlock(BasicBlock bb) { result = getRankInBasicBlock(bb) - 1 } + deprecated int getPosInBasicBlock(BasicBlock bb) { result = this.getRankInBasicBlock(bb) - 1 } pragma[noinline] private int getIndexInBasicBlock(BasicBlock bb) { this = bb.getNode(result) } @@ -102,7 +102,7 @@ class SubBasicBlock extends ControlFlowNodeBase { exists(BasicBlock bb | exists(int outerIndex | result = bb.getNode(outerIndex) and - index = outerToInnerIndex(bb, outerIndex) + index = this.outerToInnerIndex(bb, outerIndex) ) ) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll index 31ef5570451..ca1964a43c3 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll @@ -231,7 +231,7 @@ private class PostOrderInitializer extends Initializer { or this.getDeclaration() = for.getRangeVariable() or - this.getDeclaration() = for.getBeginEndDeclaration().(DeclStmt).getADeclaration() + this.getDeclaration() = for.getBeginEndDeclaration().getADeclaration() ) } } @@ -1143,7 +1143,7 @@ private class ExceptionSource extends Node { this.reachesParent(mid) and not mid = any(TryStmt try).getStmt() and not mid = any(MicrosoftTryStmt try).getStmt() and - parent = mid.(Node).getParentNode() + parent = mid.getParentNode() ) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/internal/ConstantExprs.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/internal/ConstantExprs.qll index ff27baae965..d2b24db0938 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/internal/ConstantExprs.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/controlflow/internal/ConstantExprs.qll @@ -385,7 +385,7 @@ library class ExprEvaluator extends int { abstract predicate interesting(Expr e); /** Gets the value of (interesting) expression `e`, if any. */ - int getValue(Expr e) { result = getValueInternal(e, e) } + int getValue(Expr e) { result = this.getValueInternal(e, e) } /** * When evaluating a syntactic subexpression of `e`, we may @@ -425,9 +425,9 @@ library class ExprEvaluator extends int { * calculates the values bottom-up. */ predicate interestingInternal(Expr e, Expr req, boolean sub) { - interesting(e) and req = e and sub = true + this.interesting(e) and req = e and sub = true or - exists(Expr mid | interestingInternal(e, mid, sub) | + exists(Expr mid | this.interestingInternal(e, mid, sub) | req = mid.(NotExpr).getOperand() or req = mid.(BinaryLogicalOperation).getAnOperand() or req = mid.(RelationalOperation).getAnOperand() or @@ -442,36 +442,36 @@ library class ExprEvaluator extends int { ) or exists(VariableAccess va, Variable v, boolean sub1 | - interestingVariableAccess(e, va, v, sub1) and + this.interestingVariableAccess(e, va, v, sub1) and req = v.getAnAssignedValue() and - (sub1 = true implies not ignoreVariableAssignment(e, v, req)) and + (sub1 = true implies not this.ignoreVariableAssignment(e, v, req)) and sub = false ) or exists(Function f | - interestingFunction(e, f) and + this.interestingFunction(e, f) and returnStmt(f, req) and sub = false ) } private predicate interestingVariableAccess(Expr e, VariableAccess va, Variable v, boolean sub) { - interestingInternal(e, va, sub) and + this.interestingInternal(e, va, sub) and v = getVariableTarget(va) and ( v.hasInitializer() or - sub = true and allowVariableWithoutInitializer(e, v) + sub = true and this.allowVariableWithoutInitializer(e, v) ) and tractableVariable(v) and forall(StmtParent def | nonAnalyzableVariableDefinition(v, def) | sub = true and - ignoreNonAnalyzableVariableDefinition(e, v, def) + this.ignoreNonAnalyzableVariableDefinition(e, v, def) ) } private predicate interestingFunction(Expr e, Function f) { - exists(FunctionCall fc | interestingInternal(e, fc, _) | + exists(FunctionCall fc | this.interestingInternal(e, fc, _) | f = fc.getTarget() and not obviouslyNonConstant(f) and not f.getUnspecifiedType() instanceof VoidType @@ -481,10 +481,10 @@ library class ExprEvaluator extends int { /** Gets the value of subexpressions `req` for expression `e`, if any. */ private int getValueInternal(Expr e, Expr req) { ( - interestingInternal(e, req, true) and + this.interestingInternal(e, req, true) and ( result = req.(CompileTimeConstantInt).getIntValue() or - result = getCompoundValue(e, req.(CompileTimeVariableExpr)) + result = this.getCompoundValue(e, req) ) and ( req.getUnderlyingType().(IntegralType).isSigned() or @@ -495,109 +495,126 @@ library class ExprEvaluator extends int { /** Gets the value of compound subexpressions `val` for expression `e`, if any. */ private int getCompoundValue(Expr e, CompileTimeVariableExpr val) { - interestingInternal(e, val, true) and + this.interestingInternal(e, val, true) and ( exists(NotExpr req | req = val | - result = 1 and getValueInternal(e, req.getOperand()) = 0 + result = 1 and this.getValueInternal(e, req.getOperand()) = 0 or - result = 0 and getValueInternal(e, req.getOperand()) != 0 + result = 0 and this.getValueInternal(e, req.getOperand()) != 0 ) or exists(LogicalAndExpr req | req = val | result = 1 and - getValueInternal(e, req.getLeftOperand()) != 0 and - getValueInternal(e, req.getRightOperand()) != 0 + this.getValueInternal(e, req.getLeftOperand()) != 0 and + this.getValueInternal(e, req.getRightOperand()) != 0 or - result = 0 and getValueInternal(e, req.getAnOperand()) = 0 + result = 0 and this.getValueInternal(e, req.getAnOperand()) = 0 ) or exists(LogicalOrExpr req | req = val | - result = 1 and getValueInternal(e, req.getAnOperand()) != 0 + result = 1 and this.getValueInternal(e, req.getAnOperand()) != 0 or result = 0 and - getValueInternal(e, req.getLeftOperand()) = 0 and - getValueInternal(e, req.getRightOperand()) = 0 + this.getValueInternal(e, req.getLeftOperand()) = 0 and + this.getValueInternal(e, req.getRightOperand()) = 0 ) or exists(LTExpr req | req = val | result = 1 and - getValueInternal(e, req.getLeftOperand()) < getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) < + this.getValueInternal(e, req.getRightOperand()) or result = 0 and - getValueInternal(e, req.getLeftOperand()) >= getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) >= + this.getValueInternal(e, req.getRightOperand()) ) or exists(GTExpr req | req = val | result = 1 and - getValueInternal(e, req.getLeftOperand()) > getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) > + this.getValueInternal(e, req.getRightOperand()) or result = 0 and - getValueInternal(e, req.getLeftOperand()) <= getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) <= + this.getValueInternal(e, req.getRightOperand()) ) or exists(LEExpr req | req = val | result = 1 and - getValueInternal(e, req.getLeftOperand()) <= getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) <= + this.getValueInternal(e, req.getRightOperand()) or result = 0 and - getValueInternal(e, req.getLeftOperand()) > getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) > + this.getValueInternal(e, req.getRightOperand()) ) or exists(GEExpr req | req = val | result = 1 and - getValueInternal(e, req.getLeftOperand()) >= getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) >= + this.getValueInternal(e, req.getRightOperand()) or result = 0 and - getValueInternal(e, req.getLeftOperand()) < getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) < + this.getValueInternal(e, req.getRightOperand()) ) or exists(EQExpr req | req = val | result = 1 and - getValueInternal(e, req.getLeftOperand()) = getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) = + this.getValueInternal(e, req.getRightOperand()) or result = 0 and - getValueInternal(e, req.getLeftOperand()) != getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) != + this.getValueInternal(e, req.getRightOperand()) ) or exists(NEExpr req | req = val | result = 0 and - getValueInternal(e, req.getLeftOperand()) = getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) = + this.getValueInternal(e, req.getRightOperand()) or result = 1 and - getValueInternal(e, req.getLeftOperand()) != getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) != + this.getValueInternal(e, req.getRightOperand()) ) or exists(AddExpr req | req = val | result = - getValueInternal(e, req.getLeftOperand()) + getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) + + this.getValueInternal(e, req.getRightOperand()) ) or exists(SubExpr req | req = val | result = - getValueInternal(e, req.getLeftOperand()) - getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) - + this.getValueInternal(e, req.getRightOperand()) ) or exists(MulExpr req | req = val | result = - getValueInternal(e, req.getLeftOperand()) * getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) * + this.getValueInternal(e, req.getRightOperand()) ) or exists(RemExpr req | req = val | result = - getValueInternal(e, req.getLeftOperand()) % getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) % + this.getValueInternal(e, req.getRightOperand()) ) or exists(DivExpr req | req = val | result = - getValueInternal(e, req.getLeftOperand()) / getValueInternal(e, req.getRightOperand()) + this.getValueInternal(e, req.getLeftOperand()) / + this.getValueInternal(e, req.getRightOperand()) ) or - exists(AssignExpr req | req = val | result = getValueInternal(e, req.getRValue())) + exists(AssignExpr req | req = val | result = this.getValueInternal(e, req.getRValue())) or - result = getVariableValue(e, val.(VariableAccess)) + result = this.getVariableValue(e, val) or exists(FunctionCall call | call = val and not callWithMultipleTargets(call) | - result = getFunctionValue(call.getTarget()) + result = this.getFunctionValue(call.getTarget()) ) ) } @@ -605,7 +622,7 @@ library class ExprEvaluator extends int { language[monotonicAggregates] private int getVariableValue(Expr e, VariableAccess va) { exists(Variable v | - interestingVariableAccess(e, va, v, true) and + this.interestingVariableAccess(e, va, v, true) and // All assignments must have the same int value result = unique(Expr value | @@ -619,14 +636,16 @@ library class ExprEvaluator extends int { /** Holds if the function `f` is considered by the analysis and may return `ret`. */ pragma[noinline] private predicate interestingReturnValue(Function f, Expr ret) { - interestingFunction(_, f) and + this.interestingFunction(_, f) and returnStmt(f, ret) } private int getFunctionValue(Function f) { // All returns must have the same int value // And it must have at least one return - forex(Expr ret | interestingReturnValue(f, ret) | result = getValueInternalNonSubExpr(ret)) + forex(Expr ret | this.interestingReturnValue(f, ret) | + result = this.getValueInternalNonSubExpr(ret) + ) } /** @@ -641,10 +660,10 @@ library class ExprEvaluator extends int { * omitted). */ private int getValueInternalNonSubExpr(Expr req) { - interestingInternal(_, req, false) and + this.interestingInternal(_, req, false) and ( result = req.(CompileTimeConstantInt).getIntValue() or - result = getCompoundValueNonSubExpr(req.(CompileTimeVariableExpr)) + result = this.getCompoundValueNonSubExpr(req) ) and ( req.getUnderlyingType().(IntegralType).isSigned() or @@ -655,131 +674,131 @@ library class ExprEvaluator extends int { private int getCompoundValueNonSubExpr(CompileTimeVariableExpr val) { ( exists(NotExpr req | req = val | - result = 1 and getValueInternalNonSubExpr(req.getOperand()) = 0 + result = 1 and this.getValueInternalNonSubExpr(req.getOperand()) = 0 or - result = 0 and getValueInternalNonSubExpr(req.getOperand()) != 0 + result = 0 and this.getValueInternalNonSubExpr(req.getOperand()) != 0 ) or exists(LogicalAndExpr req | req = val | result = 1 and - getValueInternalNonSubExpr(req.getLeftOperand()) != 0 and - getValueInternalNonSubExpr(req.getRightOperand()) != 0 + this.getValueInternalNonSubExpr(req.getLeftOperand()) != 0 and + this.getValueInternalNonSubExpr(req.getRightOperand()) != 0 or - result = 0 and getValueInternalNonSubExpr(req.getAnOperand()) = 0 + result = 0 and this.getValueInternalNonSubExpr(req.getAnOperand()) = 0 ) or exists(LogicalOrExpr req | req = val | - result = 1 and getValueInternalNonSubExpr(req.getAnOperand()) != 0 + result = 1 and this.getValueInternalNonSubExpr(req.getAnOperand()) != 0 or result = 0 and - getValueInternalNonSubExpr(req.getLeftOperand()) = 0 and - getValueInternalNonSubExpr(req.getRightOperand()) = 0 + this.getValueInternalNonSubExpr(req.getLeftOperand()) = 0 and + this.getValueInternalNonSubExpr(req.getRightOperand()) = 0 ) or exists(LTExpr req | req = val | result = 1 and - getValueInternalNonSubExpr(req.getLeftOperand()) < - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) < + this.getValueInternalNonSubExpr(req.getRightOperand()) or result = 0 and - getValueInternalNonSubExpr(req.getLeftOperand()) >= - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) >= + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(GTExpr req | req = val | result = 1 and - getValueInternalNonSubExpr(req.getLeftOperand()) > - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) > + this.getValueInternalNonSubExpr(req.getRightOperand()) or result = 0 and - getValueInternalNonSubExpr(req.getLeftOperand()) <= - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) <= + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(LEExpr req | req = val | result = 1 and - getValueInternalNonSubExpr(req.getLeftOperand()) <= - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) <= + this.getValueInternalNonSubExpr(req.getRightOperand()) or result = 0 and - getValueInternalNonSubExpr(req.getLeftOperand()) > - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) > + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(GEExpr req | req = val | result = 1 and - getValueInternalNonSubExpr(req.getLeftOperand()) >= - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) >= + this.getValueInternalNonSubExpr(req.getRightOperand()) or result = 0 and - getValueInternalNonSubExpr(req.getLeftOperand()) < - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) < + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(EQExpr req | req = val | result = 1 and - getValueInternalNonSubExpr(req.getLeftOperand()) = - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) = + this.getValueInternalNonSubExpr(req.getRightOperand()) or result = 0 and - getValueInternalNonSubExpr(req.getLeftOperand()) != - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) != + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(NEExpr req | req = val | result = 0 and - getValueInternalNonSubExpr(req.getLeftOperand()) = - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) = + this.getValueInternalNonSubExpr(req.getRightOperand()) or result = 1 and - getValueInternalNonSubExpr(req.getLeftOperand()) != - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) != + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(AddExpr req | req = val | result = - getValueInternalNonSubExpr(req.getLeftOperand()) + - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) + + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(SubExpr req | req = val | result = - getValueInternalNonSubExpr(req.getLeftOperand()) - - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) - + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(MulExpr req | req = val | result = - getValueInternalNonSubExpr(req.getLeftOperand()) * - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) * + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(RemExpr req | req = val | result = - getValueInternalNonSubExpr(req.getLeftOperand()) % - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) % + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or exists(DivExpr req | req = val | result = - getValueInternalNonSubExpr(req.getLeftOperand()) / - getValueInternalNonSubExpr(req.getRightOperand()) + this.getValueInternalNonSubExpr(req.getLeftOperand()) / + this.getValueInternalNonSubExpr(req.getRightOperand()) ) or - exists(AssignExpr req | req = val | result = getValueInternalNonSubExpr(req.getRValue())) + exists(AssignExpr req | req = val | result = this.getValueInternalNonSubExpr(req.getRValue())) or - result = getVariableValueNonSubExpr(val.(VariableAccess)) + result = this.getVariableValueNonSubExpr(val) or exists(FunctionCall call | call = val and not callWithMultipleTargets(call) | - result = getFunctionValue(call.getTarget()) + result = this.getFunctionValue(call.getTarget()) ) ) } private int getVariableValueNonSubExpr(VariableAccess va) { // All assignments must have the same int value - result = getMinVariableValueNonSubExpr(va) and - result = getMaxVariableValueNonSubExpr(va) + result = this.getMinVariableValueNonSubExpr(va) and + result = this.getMaxVariableValueNonSubExpr(va) } /** @@ -790,8 +809,9 @@ library class ExprEvaluator extends int { pragma[noopt] private int getMinVariableValueNonSubExpr(VariableAccess va) { exists(Variable v | - interestingVariableAccess(_, va, v, false) and - result = min(Expr value | value = v.getAnAssignedValue() | getValueInternalNonSubExpr(value)) + this.interestingVariableAccess(_, va, v, false) and + result = + min(Expr value | value = v.getAnAssignedValue() | this.getValueInternalNonSubExpr(value)) ) } @@ -803,8 +823,9 @@ library class ExprEvaluator extends int { pragma[noopt] private int getMaxVariableValueNonSubExpr(VariableAccess va) { exists(Variable v | - interestingVariableAccess(_, va, v, false) and - result = max(Expr value | value = v.getAnAssignedValue() | getValueInternalNonSubExpr(value)) + this.interestingVariableAccess(_, va, v, false) and + result = + max(Expr value | value = v.getAnAssignedValue() | this.getValueInternalNonSubExpr(value)) ) } } @@ -967,9 +988,9 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { abstract predicate isLoopBody(Expr e, StmtParent s); private predicate isLoopBodyDescendant(Expr e, StmtParent s) { - isLoopBody(e, s) + this.isLoopBody(e, s) or - exists(StmtParent mid | isLoopBodyDescendant(e, mid) | + exists(StmtParent mid | this.isLoopBodyDescendant(e, mid) | s = mid.(Stmt).getAChild() or s = mid.(Expr).getAChild() ) @@ -977,13 +998,13 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { // Same as `interestingInternal(e, sub, true)` but avoids negative recursion private predicate interestingSubExpr(Expr e, Expr sub) { - interesting(e) and e = sub + this.interesting(e) and e = sub or - exists(Expr mid | interestingSubExpr(e, mid) and sub = mid.getAChild()) + exists(Expr mid | this.interestingSubExpr(e, mid) and sub = mid.getAChild()) } private predicate maybeInterestingVariable(Expr e, Variable v) { - exists(VariableAccess va | interestingSubExpr(e, va) | va.getTarget() = v) + exists(VariableAccess va | this.interestingSubExpr(e, va) | va.getTarget() = v) } /** @@ -995,9 +1016,9 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { * definition of `v`. */ private predicate reachesLoopEntryFromLoopBody(Expr e, Variable v, StmtParent valueOrDef) { - maybeInterestingVariable(e, v) and + this.maybeInterestingVariable(e, v) and (valueOrDef = v.getAnAssignedValue() or nonAnalyzableVariableDefinition(v, valueOrDef)) and - isLoopBodyDescendant(e, valueOrDef) and + this.isLoopBodyDescendant(e, valueOrDef) and /* * Use primitive basic blocks in reachability analysis for better performance. * This is similar to the pattern used in e.g. `DefinitionsAndUses` and @@ -1007,16 +1028,16 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { exists(PrimitiveBasicBlock bb1, int pos1 | bb1.getNode(pos1) = valueOrDef | // Reaches in same basic block exists(int pos2 | - loopEntryAt(bb1, pos2, e) and + this.loopEntryAt(bb1, pos2, e) and pos2 > pos1 and - not exists(int k | assignmentAt(bb1, k, v) | k in [pos1 + 1 .. pos2 - 1]) + not exists(int k | this.assignmentAt(bb1, k, v) | k in [pos1 + 1 .. pos2 - 1]) ) or // Reaches in a successor block exists(PrimitiveBasicBlock bb2 | bb2 = bb1.getASuccessor() and - not exists(int pos3 | assignmentAt(bb1, pos3, v) and pos3 > pos1) and - bbReachesLoopEntry(bb2, e, v) + not exists(int pos3 | this.assignmentAt(bb1, pos3, v) and pos3 > pos1) and + this.bbReachesLoopEntry(bb2, e, v) ) ) } @@ -1024,12 +1045,12 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { private predicate loopEntryAt(PrimitiveBasicBlock bb, int pos, Expr e) { exists(Node cfn | bb.getNode(pos) = cfn and - isLoopEntry(e, cfn) + this.isLoopEntry(e, cfn) ) } private predicate assignmentAt(PrimitiveBasicBlock bb, int pos, Variable v) { - maybeInterestingVariable(_, v) and + this.maybeInterestingVariable(_, v) and bb.getNode(pos) = v.getAnAssignedValue() } @@ -1038,19 +1059,19 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { * the loop belonging to `e` without crossing an assignment to `v`. */ private predicate bbReachesLoopEntry(PrimitiveBasicBlock bb, Expr e, Variable v) { - bbReachesLoopEntryLocally(bb, e, v) + this.bbReachesLoopEntryLocally(bb, e, v) or exists(PrimitiveBasicBlock succ | succ = bb.getASuccessor() | - bbReachesLoopEntry(succ, e, v) and - not assignmentAt(bb, _, v) + this.bbReachesLoopEntry(succ, e, v) and + not this.assignmentAt(bb, _, v) ) } private predicate bbReachesLoopEntryLocally(PrimitiveBasicBlock bb, Expr e, Variable v) { exists(int pos | - loopEntryAt(bb, pos, e) and - maybeInterestingVariable(e, v) and - not exists(int pos1 | assignmentAt(bb, pos1, v) | pos1 < pos) + this.loopEntryAt(bb, pos, e) and + this.maybeInterestingVariable(e, v) and + not exists(int pos1 | this.assignmentAt(bb, pos1, v) | pos1 < pos) ) } @@ -1084,10 +1105,10 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { * ``` */ override predicate ignoreNonAnalyzableVariableDefinition(Expr e, Variable v, StmtParent def) { - maybeInterestingVariable(e, v) and + this.maybeInterestingVariable(e, v) and nonAnalyzableVariableDefinition(v, def) and - isLoopBodyDescendant(e, def) and - not reachesLoopEntryFromLoopBody(e, v, def) + this.isLoopBodyDescendant(e, def) and + not this.reachesLoopEntryFromLoopBody(e, v, def) } /** @@ -1120,10 +1141,10 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { * ``` */ override predicate ignoreVariableAssignment(Expr e, Variable v, Expr value) { - maybeInterestingVariable(e, v) and + this.maybeInterestingVariable(e, v) and value = v.getAnAssignedValue() and - isLoopBodyDescendant(e, value) and - not reachesLoopEntryFromLoopBody(e, v, value) + this.isLoopBodyDescendant(e, value) and + not this.reachesLoopEntryFromLoopBody(e, v, value) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index f43a550af57..c28ceabb438 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -2,6 +2,42 @@ private import DataFlowImplSpecific::Private private import DataFlowImplSpecific::Public import Cached +module DataFlowImplCommonPublic { + private newtype TFlowFeature = + TFeatureHasSourceCallContext() or + TFeatureHasSinkCallContext() or + TFeatureEqualSourceSinkCallContext() + + /** A flow configuration feature for use in `Configuration::getAFeature()`. */ + class FlowFeature extends TFlowFeature { + string toString() { none() } + } + + /** + * A flow configuration feature that implies that sources have some existing + * call context. + */ + class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext { + override string toString() { result = "FeatureHasSourceCallContext" } + } + + /** + * A flow configuration feature that implies that sinks have some existing + * call context. + */ + class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext { + override string toString() { result = "FeatureHasSinkCallContext" } + } + + /** + * A flow configuration feature that implies that source-sink pairs have some + * shared existing call context. + */ + class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext { + override string toString() { result = "FeatureEqualSourceSinkCallContext" } + } +} + /** * The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion. * @@ -251,7 +287,7 @@ private module Cached { predicate forceCachingInSameStage() { any() } cached - predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() } + predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) } cached predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) { @@ -316,9 +352,7 @@ private module Cached { } cached - predicate parameterNode(Node n, DataFlowCallable c, int i) { - n.(ParameterNode).isParameterOf(c, i) - } + predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) } cached predicate argumentNode(Node n, DataFlowCall call, int pos) { @@ -801,6 +835,9 @@ private module Cached { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } + cached + predicate allowParameterReturnInSelfCached(ParamNode p) { allowParameterReturnInSelf(p) } + cached newtype TCallContext = TAnyCallContext() or @@ -937,7 +974,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { } override predicate relevantFor(DataFlowCallable callable) { - recordDataFlowCallSite(getCall(), callable) + recordDataFlowCallSite(this.getCall(), callable) } override predicate matchesCall(DataFlowCall call) { call = this.getCall() } @@ -1257,7 +1294,7 @@ abstract class AccessPathFront extends TAccessPathFront { TypedContent getHead() { this = TFrontHead(result) } - predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) } + predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll index a55e65a81f6..acf31338f9a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll @@ -31,7 +31,7 @@ module Consistency { query predicate uniqueEnclosingCallable(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getEnclosingCallable()) and + c = count(nodeGetEnclosingCallable(n)) and c != 1 and msg = "Node should have one enclosing callable but has " + c + "." ) @@ -85,13 +85,13 @@ module Consistency { } query predicate parameterCallable(ParameterNode p, string msg) { - exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and + exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and msg = "Callable mismatch for parameter." } query predicate localFlowIsLocal(Node n1, Node n2, string msg) { simpleLocalFlowStep(n1, n2) and - n1.getEnclosingCallable() != n2.getEnclosingCallable() and + nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and msg = "Local flow step does not preserve enclosing callable." } @@ -106,7 +106,7 @@ module Consistency { query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) { isUnreachableInCall(n, call) and exists(DataFlowCallable c | - c = n.getEnclosingCallable() and + c = nodeGetEnclosingCallable(n) and not viableCallable(call) = c ) and msg = "Call context for isUnreachableInCall is inconsistent with call graph." @@ -120,7 +120,7 @@ module Consistency { n.(ArgumentNode).argumentOf(call, _) and msg = "ArgumentNode and call does not share enclosing callable." ) and - n.getEnclosingCallable() != call.getEnclosingCallable() + nodeGetEnclosingCallable(n) != call.getEnclosingCallable() } // This predicate helps the compiler forget that in some languages @@ -151,7 +151,7 @@ module Consistency { } query predicate postIsInSameCallable(PostUpdateNode n, string msg) { - n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and + nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and msg = "PostUpdateNode does not share callable with its pre-update node." } @@ -175,6 +175,7 @@ module Consistency { query predicate postWithInFlow(Node n, string msg) { isPostUpdateNode(n) and + not clearsContent(n, _) and simpleLocalFlowStep(_, n) and msg = "PostUpdateNode should not be the target of local flow." } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 7767b644cbd..462a6a98328 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -3,6 +3,12 @@ private import DataFlowUtil private import DataFlowDispatch private import FlowVar +/** Gets the callable in which this node occurs. */ +DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() } + +/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */ +predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) } + /** Gets the instance argument of a non-static call. */ private Node getInstanceArgument(Call call) { result.asExpr() = call.getQualifier() @@ -287,3 +293,12 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { no /** Extra data-flow steps needed for lambda flow analysis. */ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } + +/** + * Holds if flow is allowed to pass from parameter `p` and back to itself as a + * side-effect, resulting in a summary from `p` to itself. + * + * One example would be to allow flow like `p.foo = p.bar;`, which is disallowed + * by default as a heuristic. + */ +predicate allowParameterReturnInSelf(ParameterNode p) { none() } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index 2dfd02d14ef..c67374c3db9 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -106,13 +106,13 @@ class Node extends TNode { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } /** * Gets an upper bound on the type of this node. */ - Type getTypeBound() { result = getType() } + Type getTypeBound() { result = this.getType() } } /** @@ -293,11 +293,11 @@ abstract class PostUpdateNode extends Node { */ abstract Node getPreUpdateNode(); - override Function getFunction() { result = getPreUpdateNode().getFunction() } + override Function getFunction() { result = this.getPreUpdateNode().getFunction() } - override Type getType() { result = getPreUpdateNode().getType() } + override Type getType() { result = this.getPreUpdateNode().getType() } - override Location getLocation() { result = getPreUpdateNode().getLocation() } + override Location getLocation() { result = this.getPreUpdateNode().getLocation() } } abstract private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { @@ -309,7 +309,7 @@ abstract private class PartialDefinitionNode extends PostUpdateNode, TPartialDef PartialDefinition getPartialDefinition() { result = pd } - override string toString() { result = getPreUpdateNode().toString() + " [post update]" } + override string toString() { result = this.getPreUpdateNode().toString() + " [post update]" } } private class VariablePartialDefinitionNode extends PartialDefinitionNode { @@ -380,13 +380,13 @@ private class ObjectInitializerNode extends PostUpdateNode, TExprNode { class PreObjectInitializerNode extends Node, TPreObjectInitializerNode { Expr getExpr() { this = TPreObjectInitializerNode(result) } - override Function getFunction() { result = getExpr().getEnclosingFunction() } + override Function getFunction() { result = this.getExpr().getEnclosingFunction() } - override Type getType() { result = getExpr().getType() } + override Type getType() { result = this.getExpr().getType() } - override Location getLocation() { result = getExpr().getLocation() } + override Location getLocation() { result = this.getExpr().getLocation() } - override string toString() { result = getExpr().toString() + " [pre init]" } + override string toString() { result = this.getExpr().toString() + " [pre init]" } } /** @@ -401,7 +401,7 @@ private class PostConstructorInitThis extends PostUpdateNode, TPostConstructorIn } override string toString() { - result = getPreUpdateNode().getConstructorFieldInit().toString() + " [post-this]" + result = this.getPreUpdateNode().getConstructorFieldInit().toString() + " [post-this]" } } @@ -416,15 +416,17 @@ private class PostConstructorInitThis extends PostUpdateNode, TPostConstructorIn class PreConstructorInitThis extends Node, TPreConstructorInitThis { ConstructorFieldInit getConstructorFieldInit() { this = TPreConstructorInitThis(result) } - override Constructor getFunction() { result = getConstructorFieldInit().getEnclosingFunction() } - - override PointerType getType() { - result.getBaseType() = getConstructorFieldInit().getEnclosingFunction().getDeclaringType() + override Constructor getFunction() { + result = this.getConstructorFieldInit().getEnclosingFunction() } - override Location getLocation() { result = getConstructorFieldInit().getLocation() } + override PointerType getType() { + result.getBaseType() = this.getConstructorFieldInit().getEnclosingFunction().getDeclaringType() + } - override string toString() { result = getConstructorFieldInit().toString() + " [pre-this]" } + override Location getLocation() { result = this.getConstructorFieldInit().getLocation() } + + override string toString() { result = this.getConstructorFieldInit().toString() + " [pre-this]" } } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowVar.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowVar.qll index e3f8b6f68fb..c01edf0429a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -354,7 +354,7 @@ module FlowVar_internal { result = def.getAUse(v) or exists(SsaDefinition descendentDef | - getASuccessorSsaVar+() = TSsaVar(descendentDef, _) and + this.getASuccessorSsaVar+() = TSsaVar(descendentDef, _) and result = descendentDef.getAUse(v) ) ) @@ -515,7 +515,7 @@ module FlowVar_internal { this.bbInLoopCondition(bbInside) and not this.bbInLoop(bbOutside) and bbOutside = bbInside.getASuccessor() and - not reachesWithoutAssignment(bbInside, v) + not this.reachesWithoutAssignment(bbInside, v) } /** @@ -546,7 +546,7 @@ module FlowVar_internal { private predicate bbInLoop(BasicBlock bb) { bbDominates(this.(Loop).getStmt(), bb) or - bbInLoopCondition(bb) + this.bbInLoopCondition(bb) } /** Holds if `sbb` is inside this loop. */ @@ -563,7 +563,7 @@ module FlowVar_internal { bb = this.(Loop).getStmt() and v = this.getARelevantVariable() or - reachesWithoutAssignment(bb.getAPredecessor(), v) and + this.reachesWithoutAssignment(bb.getAPredecessor(), v) and this.bbInLoop(bb) ) and not assignsToVar(bb, v) diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll index fa9d2e94081..4fbea43b805 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll @@ -80,7 +80,7 @@ class SubBasicBlock extends ControlFlowNodeBase { * returns a 0-based position, while `getRankInBasicBlock` returns a 1-based * position. */ - deprecated int getPosInBasicBlock(BasicBlock bb) { result = getRankInBasicBlock(bb) - 1 } + deprecated int getPosInBasicBlock(BasicBlock bb) { result = this.getRankInBasicBlock(bb) - 1 } pragma[noinline] private int getIndexInBasicBlock(BasicBlock bb) { this = bb.getNode(result) } @@ -102,7 +102,7 @@ class SubBasicBlock extends ControlFlowNodeBase { exists(BasicBlock bb | exists(int outerIndex | result = bb.getNode(outerIndex) and - index = outerToInnerIndex(bb, outerIndex) + index = this.outerToInnerIndex(bb, outerIndex) ) ) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Access.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Access.qll index e18c0c78dc6..35cf1974127 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Access.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Access.qll @@ -203,7 +203,7 @@ class PointerFieldAccess extends FieldAccess { PointerFieldAccess() { exists(PointerType t | - t = getQualifier().getFullyConverted().getUnspecifiedType() and + t = this.getQualifier().getFullyConverted().getUnspecifiedType() and t.getBaseType() instanceof Class ) } @@ -218,7 +218,9 @@ class PointerFieldAccess extends FieldAccess { class DotFieldAccess extends FieldAccess { override string getAPrimaryQlClass() { result = "DotFieldAccess" } - DotFieldAccess() { exists(Class c | c = getQualifier().getFullyConverted().getUnspecifiedType()) } + DotFieldAccess() { + exists(Class c | c = this.getQualifier().getFullyConverted().getUnspecifiedType()) + } } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/ArithmeticOperation.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/ArithmeticOperation.qll index b94c9cee724..615192c86a7 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/ArithmeticOperation.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/ArithmeticOperation.qll @@ -148,7 +148,7 @@ class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @post override int getPrecedence() { result = 17 } - override string toString() { result = "... " + getOperator() } + override string toString() { result = "... " + this.getOperator() } } /** @@ -166,7 +166,7 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post override int getPrecedence() { result = 17 } - override string toString() { result = "... " + getOperator() } + override string toString() { result = "... " + this.getOperator() } } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll index b1f97f18802..dcbedde4475 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -35,12 +35,12 @@ class BuiltInVarArgsStart extends VarArgsExpr, @vastartexpr { /** * Gets the `va_list` argument. */ - final Expr getVAList() { result = getChild(0) } + final Expr getVAList() { result = this.getChild(0) } /** * Gets the argument that specifies the last named parameter before the ellipsis. */ - final VariableAccess getLastNamedParameter() { result = getChild(1) } + final VariableAccess getLastNamedParameter() { result = this.getChild(1) } } /** @@ -60,7 +60,7 @@ class BuiltInVarArgsEnd extends VarArgsExpr, @vaendexpr { /** * Gets the `va_list` argument. */ - final Expr getVAList() { result = getChild(0) } + final Expr getVAList() { result = this.getChild(0) } } /** @@ -78,7 +78,7 @@ class BuiltInVarArg extends VarArgsExpr, @vaargexpr { /** * Gets the `va_list` argument. */ - final Expr getVAList() { result = getChild(0) } + final Expr getVAList() { result = this.getChild(0) } } /** @@ -98,12 +98,12 @@ class BuiltInVarArgCopy extends VarArgsExpr, @vacopyexpr { /** * Gets the destination `va_list` argument. */ - final Expr getDestinationVAList() { result = getChild(0) } + final Expr getDestinationVAList() { result = this.getChild(0) } /** * Gets the the source `va_list` argument. */ - final Expr getSourceVAList() { result = getChild(1) } + final Expr getSourceVAList() { result = this.getChild(1) } } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Call.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Call.qll index 6f6f710ac4b..b4761dffe9a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Call.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Call.qll @@ -71,10 +71,10 @@ class Call extends Expr, NameQualifiableElement, TCall { * at index 2, respectively. */ Expr getAnArgumentSubExpr(int index) { - result = getArgument(index) + result = this.getArgument(index) or exists(Expr mid | - mid = getAnArgumentSubExpr(index) and + mid = this.getAnArgumentSubExpr(index) and not mid instanceof Call and not mid instanceof SizeofOperator and result = mid.getAChild() @@ -167,27 +167,27 @@ class FunctionCall extends Call, @funbindexpr { override string getAPrimaryQlClass() { result = "FunctionCall" } /** Gets an explicit template argument for this call. */ - Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) } + Locatable getAnExplicitTemplateArgument() { result = this.getExplicitTemplateArgument(_) } /** Gets an explicit template argument value for this call. */ - Locatable getAnExplicitTemplateArgumentKind() { result = getExplicitTemplateArgumentKind(_) } + Locatable getAnExplicitTemplateArgumentKind() { result = this.getExplicitTemplateArgumentKind(_) } /** Gets a template argument for this call. */ - Locatable getATemplateArgument() { result = getTarget().getATemplateArgument() } + Locatable getATemplateArgument() { result = this.getTarget().getATemplateArgument() } /** Gets a template argument value for this call. */ - Locatable getATemplateArgumentKind() { result = getTarget().getATemplateArgumentKind() } + Locatable getATemplateArgumentKind() { result = this.getTarget().getATemplateArgumentKind() } /** Gets the nth explicit template argument for this call. */ Locatable getExplicitTemplateArgument(int n) { - n < getNumberOfExplicitTemplateArguments() and - result = getTemplateArgument(n) + n < this.getNumberOfExplicitTemplateArguments() and + result = this.getTemplateArgument(n) } /** Gets the nth explicit template argument value for this call. */ Locatable getExplicitTemplateArgumentKind(int n) { - n < getNumberOfExplicitTemplateArguments() and - result = getTemplateArgumentKind(n) + n < this.getNumberOfExplicitTemplateArguments() and + result = this.getTemplateArgumentKind(n) } /** Gets the number of explicit template arguments for this call. */ @@ -198,19 +198,19 @@ class FunctionCall extends Call, @funbindexpr { } /** Gets the number of template arguments for this call. */ - int getNumberOfTemplateArguments() { result = count(int i | exists(getTemplateArgument(i))) } + int getNumberOfTemplateArguments() { result = count(int i | exists(this.getTemplateArgument(i))) } /** Gets the nth template argument for this call (indexed from 0). */ - Locatable getTemplateArgument(int n) { result = getTarget().getTemplateArgument(n) } + Locatable getTemplateArgument(int n) { result = this.getTarget().getTemplateArgument(n) } /** Gets the nth template argument value for this call (indexed from 0). */ - Locatable getTemplateArgumentKind(int n) { result = getTarget().getTemplateArgumentKind(n) } + Locatable getTemplateArgumentKind(int n) { result = this.getTarget().getTemplateArgumentKind(n) } /** Holds if any template arguments for this call are implicit / deduced. */ predicate hasImplicitTemplateArguments() { exists(int i | - exists(getTemplateArgument(i)) and - not exists(getExplicitTemplateArgument(i)) + exists(this.getTemplateArgument(i)) and + not exists(this.getExplicitTemplateArgument(i)) ) } @@ -233,9 +233,9 @@ class FunctionCall extends Call, @funbindexpr { * visible at the call site. */ Type getExpectedReturnType() { - if getTargetType() instanceof RoutineType - then result = getTargetType().(RoutineType).getReturnType() - else result = getTarget().getType() + if this.getTargetType() instanceof RoutineType + then result = this.getTargetType().(RoutineType).getReturnType() + else result = this.getTarget().getType() } /** @@ -247,9 +247,9 @@ class FunctionCall extends Call, @funbindexpr { * was visible at the call site. */ Type getExpectedParameterType(int n) { - if getTargetType() instanceof RoutineType - then result = getTargetType().(RoutineType).getParameterType(n) - else result = getTarget().getParameter(n).getType() + if this.getTargetType() instanceof RoutineType + then result = this.getTargetType().(RoutineType).getParameterType(n) + else result = this.getTarget().getParameter(n).getType() } /** @@ -263,7 +263,7 @@ class FunctionCall extends Call, @funbindexpr { /** * Gets the type of this expression, that is, the return type of the function being called. */ - override Type getType() { result = getExpectedReturnType() } + override Type getType() { result = this.getExpectedReturnType() } /** * Holds if this is a call to a virtual function. @@ -280,7 +280,7 @@ class FunctionCall extends Call, @funbindexpr { /** Gets a textual representation of this function call. */ override string toString() { - if exists(getTarget()) + if exists(this.getTarget()) then result = "call to " + this.getTarget().getName() else result = "call to unknown function" } @@ -288,15 +288,15 @@ class FunctionCall extends Call, @funbindexpr { override predicate mayBeImpure() { this.getChild(_).mayBeImpure() or this.getTarget().mayHaveSideEffects() or - isVirtual() or - getTarget().getAnAttribute().getName() = "weak" + this.isVirtual() or + this.getTarget().getAnAttribute().getName() = "weak" } override predicate mayBeGloballyImpure() { this.getChild(_).mayBeGloballyImpure() or this.getTarget().mayHaveSideEffects() or - isVirtual() or - getTarget().getAnAttribute().getName() = "weak" + this.isVirtual() or + this.getTarget().getAnAttribute().getName() = "weak" } } @@ -367,7 +367,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { * ``` */ class OverloadedArrayExpr extends FunctionCall { - OverloadedArrayExpr() { getTarget().hasName("operator[]") } + OverloadedArrayExpr() { this.getTarget().hasName("operator[]") } override string getAPrimaryQlClass() { result = "OverloadedArrayExpr" } @@ -585,7 +585,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit { */ Expr getExpr() { result = this.getChild(0) } - override string toString() { result = "constructor init of field " + getTarget().getName() } + override string toString() { result = "constructor init of field " + this.getTarget().getName() } override predicate mayBeImpure() { this.getExpr().mayBeImpure() } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll index ebe88ddf71c..273023a8229 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll @@ -188,8 +188,8 @@ private predicate isPointerToMemberOrNullPointer(Type type) { class ArithmeticConversion extends Cast { ArithmeticConversion() { conversionkinds(underlyingElement(this), 0) and - isArithmeticOrEnum(getUnspecifiedType()) and - isArithmeticOrEnum(getExpr().getUnspecifiedType()) + isArithmeticOrEnum(this.getUnspecifiedType()) and + isArithmeticOrEnum(this.getExpr().getUnspecifiedType()) } override string getSemanticConversionString() { result = "arithmetic conversion" } @@ -204,8 +204,8 @@ class ArithmeticConversion extends Cast { */ class IntegralConversion extends ArithmeticConversion { IntegralConversion() { - isIntegralOrEnum(getUnspecifiedType()) and - isIntegralOrEnum(getExpr().getUnspecifiedType()) + isIntegralOrEnum(this.getUnspecifiedType()) and + isIntegralOrEnum(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { @@ -224,8 +224,8 @@ class IntegralConversion extends ArithmeticConversion { */ class FloatingPointConversion extends ArithmeticConversion { FloatingPointConversion() { - getUnspecifiedType() instanceof FloatingPointType and - getExpr().getUnspecifiedType() instanceof FloatingPointType + this.getUnspecifiedType() instanceof FloatingPointType and + this.getExpr().getUnspecifiedType() instanceof FloatingPointType } override string getAPrimaryQlClass() { @@ -244,8 +244,8 @@ class FloatingPointConversion extends ArithmeticConversion { */ class FloatingPointToIntegralConversion extends ArithmeticConversion { FloatingPointToIntegralConversion() { - isIntegralOrEnum(getUnspecifiedType()) and - getExpr().getUnspecifiedType() instanceof FloatingPointType + isIntegralOrEnum(this.getUnspecifiedType()) and + this.getExpr().getUnspecifiedType() instanceof FloatingPointType } override string getAPrimaryQlClass() { @@ -264,8 +264,8 @@ class FloatingPointToIntegralConversion extends ArithmeticConversion { */ class IntegralToFloatingPointConversion extends ArithmeticConversion { IntegralToFloatingPointConversion() { - getUnspecifiedType() instanceof FloatingPointType and - isIntegralOrEnum(getExpr().getUnspecifiedType()) + this.getUnspecifiedType() instanceof FloatingPointType and + isIntegralOrEnum(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { @@ -290,8 +290,8 @@ class IntegralToFloatingPointConversion extends ArithmeticConversion { class PointerConversion extends Cast { PointerConversion() { conversionkinds(underlyingElement(this), 0) and - isPointerOrNullPointer(getUnspecifiedType()) and - isPointerOrNullPointer(getExpr().getUnspecifiedType()) + isPointerOrNullPointer(this.getUnspecifiedType()) and + isPointerOrNullPointer(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" } @@ -315,8 +315,8 @@ class PointerToMemberConversion extends Cast { PointerToMemberConversion() { conversionkinds(underlyingElement(this), 0) and exists(Type fromType, Type toType | - fromType = getExpr().getUnspecifiedType() and - toType = getUnspecifiedType() and + fromType = this.getExpr().getUnspecifiedType() and + toType = this.getUnspecifiedType() and isPointerToMemberOrNullPointer(fromType) and isPointerToMemberOrNullPointer(toType) and // A conversion from nullptr to nullptr is a `PointerConversion`, not a @@ -345,8 +345,8 @@ class PointerToMemberConversion extends Cast { class PointerToIntegralConversion extends Cast { PointerToIntegralConversion() { conversionkinds(underlyingElement(this), 0) and - isIntegralOrEnum(getUnspecifiedType()) and - isPointerOrNullPointer(getExpr().getUnspecifiedType()) + isIntegralOrEnum(this.getUnspecifiedType()) and + isPointerOrNullPointer(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { @@ -366,8 +366,8 @@ class PointerToIntegralConversion extends Cast { class IntegralToPointerConversion extends Cast { IntegralToPointerConversion() { conversionkinds(underlyingElement(this), 0) and - isPointerOrNullPointer(getUnspecifiedType()) and - isIntegralOrEnum(getExpr().getUnspecifiedType()) + isPointerOrNullPointer(this.getUnspecifiedType()) and + isIntegralOrEnum(this.getExpr().getUnspecifiedType()) } override string getAPrimaryQlClass() { @@ -403,7 +403,7 @@ class BoolConversion extends Cast { class VoidConversion extends Cast { VoidConversion() { conversionkinds(underlyingElement(this), 0) and - getUnspecifiedType() instanceof VoidType + this.getUnspecifiedType() instanceof VoidType } override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "VoidConversion" } @@ -434,8 +434,8 @@ class InheritanceConversion extends Cast { * conversion is to an indirect virtual base class. */ final ClassDerivation getDerivation() { - result.getBaseClass() = getBaseClass() and - result.getDerivedClass() = getDerivedClass() + result.getBaseClass() = this.getBaseClass() and + result.getDerivedClass() = this.getDerivedClass() } /** @@ -490,12 +490,12 @@ class BaseClassConversion extends InheritanceConversion { override Class getBaseClass() { result = getConversionClass(this) } - override Class getDerivedClass() { result = getConversionClass(getExpr()) } + override Class getDerivedClass() { result = getConversionClass(this.getExpr()) } /** * Holds if this conversion is to a virtual base class. */ - predicate isVirtual() { getDerivation().isVirtual() or not exists(getDerivation()) } + predicate isVirtual() { this.getDerivation().isVirtual() or not exists(this.getDerivation()) } } /** @@ -515,7 +515,7 @@ class DerivedClassConversion extends InheritanceConversion { override string getSemanticConversionString() { result = "derived class conversion" } - override Class getBaseClass() { result = getConversionClass(getExpr()) } + override Class getBaseClass() { result = getConversionClass(this.getExpr()) } override Class getDerivedClass() { result = getConversionClass(this) } } @@ -637,8 +637,8 @@ class DynamicCast extends Cast, @dynamic_cast { */ class UuidofOperator extends Expr, @uuidof { override string toString() { - if exists(getTypeOperand()) - then result = "__uuidof(" + getTypeOperand().getName() + ")" + if exists(this.getTypeOperand()) + then result = "__uuidof(" + this.getTypeOperand().getName() + ")" else result = "__uuidof(0)" } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll index f77518c2f56..a10a94f357d 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll @@ -26,12 +26,12 @@ class Expr extends StmtParent, @expr { Function getEnclosingFunction() { result = exprEnclosingElement(this) } /** Gets the nearest enclosing set of curly braces around this expression in the source, if any. */ - BlockStmt getEnclosingBlock() { result = getEnclosingStmt().getEnclosingBlock() } + BlockStmt getEnclosingBlock() { result = this.getEnclosingStmt().getEnclosingBlock() } override Stmt getEnclosingStmt() { result = this.getParent().(Expr).getEnclosingStmt() or - result = this.getParent().(Stmt) + result = this.getParent() or exists(Expr other | result = other.getEnclosingStmt() and other.getConversion() = this) or @@ -219,13 +219,13 @@ class Expr extends StmtParent, @expr { * Holds if this expression is a _glvalue_. A _glvalue_ is either an _lvalue_ or an * _xvalue_. */ - predicate isGLValueCategory() { isLValueCategory() or isXValueCategory() } + predicate isGLValueCategory() { this.isLValueCategory() or this.isXValueCategory() } /** * Holds if this expression is an _rvalue_. An _rvalue_ is either a _prvalue_ or an * _xvalue_. */ - predicate isRValueCategory() { isPRValueCategory() or isXValueCategory() } + predicate isRValueCategory() { this.isPRValueCategory() or this.isXValueCategory() } /** * Gets a string representation of the value category of the expression. @@ -240,15 +240,15 @@ class Expr extends StmtParent, @expr { * `hasLValueToRvalueConversion()` holds. */ string getValueCategoryString() { - isLValueCategory() and + this.isLValueCategory() and result = "lvalue" or - isXValueCategory() and + this.isXValueCategory() and result = "xvalue" or ( - isPRValueCategory() and - if hasLValueToRValueConversion() then result = "prvalue(load)" else result = "prvalue" + this.isPRValueCategory() and + if this.hasLValueToRValueConversion() then result = "prvalue(load)" else result = "prvalue" ) } @@ -263,7 +263,7 @@ class Expr extends StmtParent, @expr { * such as an expression inside a sizeof. */ predicate isUnevaluated() { - exists(Element e | e = getParentWithConversions+() | + exists(Element e | e = this.getParentWithConversions+() | e instanceof SizeofOperator or exists(Expr e2 | @@ -279,7 +279,7 @@ class Expr extends StmtParent, @expr { e instanceof AlignofOperator ) or - exists(Decltype d | d.getExpr() = getParentWithConversions*()) + exists(Decltype d | d.getExpr() = this.getParentWithConversions*()) } /** @@ -725,7 +725,7 @@ class PointerDereferenceExpr extends UnaryOperation, @indirect { * * Gets the expression that is being dereferenced. */ - deprecated Expr getExpr() { result = getOperand() } + deprecated Expr getExpr() { result = this.getOperand() } override string getOperator() { result = "*" } @@ -780,15 +780,15 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr { * Gets the alignment argument passed to the allocation function, if any. */ Expr getAlignmentArgument() { - hasAlignedAllocation() and + this.hasAlignedAllocation() and ( // If we have an allocator call, the alignment is the second argument to // that call. - result = getAllocatorCall().getArgument(1) + result = this.getAllocatorCall().getArgument(1) or // Otherwise, the alignment winds up as child number 3 of the `new` // itself. - result = getChild(3) + result = this.getChild(3) ) } @@ -916,7 +916,7 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr { * Gets the element type of the array being allocated. */ Type getAllocatedElementType() { - result = getType().getUnderlyingType().(PointerType).getBaseType() + result = this.getType().getUnderlyingType().(PointerType).getBaseType() } /** @@ -946,7 +946,12 @@ class DeleteExpr extends Expr, @delete_expr { */ Type getDeletedObjectType() { result = - getExpr().getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() + this.getExpr() + .getFullyConverted() + .getType() + .stripTopLevelSpecifiers() + .(PointerType) + .getBaseType() } /** @@ -957,7 +962,7 @@ class DeleteExpr extends Expr, @delete_expr { /** * Gets the destructor to be called to destroy the object, if any. */ - Destructor getDestructor() { result = getDestructorCall().getTarget() } + Destructor getDestructor() { result = this.getDestructorCall().getTarget() } /** * Gets the `operator delete` that deallocates storage. Does not hold @@ -1020,7 +1025,12 @@ class DeleteArrayExpr extends Expr, @delete_array_expr { */ Type getDeletedElementType() { result = - getExpr().getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() + this.getExpr() + .getFullyConverted() + .getType() + .stripTopLevelSpecifiers() + .(PointerType) + .getBaseType() } /** @@ -1034,7 +1044,7 @@ class DeleteArrayExpr extends Expr, @delete_array_expr { /** * Gets the destructor to be called to destroy each element in the array, if any. */ - Destructor getDestructor() { result = getDestructorCall().getTarget() } + Destructor getDestructor() { result = this.getDestructorCall().getTarget() } /** * Gets the `operator delete[]` that deallocates storage. @@ -1101,7 +1111,7 @@ class StmtExpr extends Expr, @expr_stmt { * x = ({ dosomething(); a+b; }); * ``` */ - Expr getResultExpr() { result = getStmtResultExpr(getStmt()) } + Expr getResultExpr() { result = getStmtResultExpr(this.getStmt()) } } /** Get the result expression of a statement. (Helper function for StmtExpr.) */ @@ -1230,20 +1240,20 @@ class FoldExpr extends Expr, @foldexpr { predicate isRightFold() { fold(underlyingElement(this), _, false) } /** Holds if this is a unary fold expression. */ - predicate isUnaryFold() { getNumChild() = 1 } + predicate isUnaryFold() { this.getNumChild() = 1 } /** Holds if this is a binary fold expression. */ - predicate isBinaryFold() { getNumChild() = 2 } + predicate isBinaryFold() { this.getNumChild() = 2 } /** * Gets the child expression containing the unexpanded parameter pack. */ Expr getPackExpr() { this.isUnaryFold() and - result = getChild(0) + result = this.getChild(0) or this.isBinaryFold() and - if this.isRightFold() then result = getChild(0) else result = getChild(1) + if this.isRightFold() then result = this.getChild(0) else result = this.getChild(1) } /** @@ -1251,7 +1261,7 @@ class FoldExpr extends Expr, @foldexpr { */ Expr getInitExpr() { this.isBinaryFold() and - if this.isRightFold() then result = getChild(1) else result = getChild(0) + if this.isRightFold() then result = this.getChild(1) else result = this.getChild(0) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Lambda.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Lambda.qll index 8a51001f4d5..c885831c444 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Lambda.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Lambda.qll @@ -24,7 +24,7 @@ class LambdaExpression extends Expr, @lambdaexpr { /** * Gets an implicitly or explicitly captured value of this lambda expression. */ - LambdaCapture getACapture() { result = getCapture(_) } + LambdaCapture getACapture() { result = this.getCapture(_) } /** * Gets the nth implicitly or explicitly captured value of this lambda expression. @@ -58,13 +58,13 @@ class LambdaExpression extends Expr, @lambdaexpr { * - The return type. * - The statements comprising the lambda body. */ - Operator getLambdaFunction() { result = getType().(Closure).getLambdaFunction() } + Operator getLambdaFunction() { result = this.getType().(Closure).getLambdaFunction() } /** * Gets the initializer that initializes the captured variables in the closure, if any. * A lambda that does not capture any variables will not have an initializer. */ - ClassAggregateLiteral getInitializer() { result = getChild(0) } + ClassAggregateLiteral getInitializer() { result = this.getChild(0) } } /** @@ -103,7 +103,7 @@ class Closure extends Class { * ``` */ class LambdaCapture extends Locatable, @lambdacapture { - override string toString() { result = getField().getName() } + override string toString() { result = this.getField().getName() } override string getAPrimaryQlClass() { result = "LambdaCapture" } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll index 31790f85bfb..18ca03740ac 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll @@ -60,12 +60,12 @@ class TextLiteral extends Literal { /** Gets a hex escape sequence that appears in the character or string literal (see [lex.ccon] in the C++ Standard). */ string getAHexEscapeSequence(int occurrence, int offset) { - result = getValueText().regexpFind("(?= 0 and - elementIndex < getArraySize() + elementIndex < this.getArraySize() } /** @@ -298,8 +298,8 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral { */ bindingset[elementIndex] predicate isValueInitialized(int elementIndex) { - isInitialized(elementIndex) and - not exists(getElementExpr(elementIndex)) + this.isInitialized(elementIndex) and + not exists(this.getElementExpr(elementIndex)) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/internal/AddressConstantExpression.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/internal/AddressConstantExpression.qll index 436be8384e8..b75703b11fc 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/internal/AddressConstantExpression.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/internal/AddressConstantExpression.qll @@ -31,7 +31,7 @@ private predicate addressConstantVariable(Variable v) { private predicate constantAddressLValue(Expr lvalue) { lvalue.(VariableAccess).getTarget() = any(Variable v | - v.(Variable).isStatic() + v.isStatic() or v instanceof GlobalOrNamespaceVariable ) diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll index 692ce1fee19..7cf0c647142 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll @@ -173,7 +173,7 @@ class LocalVariable extends LocalScopeVariable, @localvariable { } class VariableDeclarationEntry extends @var_decl { string toString() { result = "QualifiedName DeclarationEntry" } - Variable getDeclaration() { result = getVariable() } + Variable getDeclaration() { result = this.getVariable() } /** * Gets the variable which is being declared or defined. diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index ece55d181bf..626e81e095c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -474,6 +474,24 @@ module TaintedWithPath { } } + /** + * INTERNAL: Do not use. + */ + module Private { + /** Gets a predecessor `PathNode` of `pathNode`, if any. */ + PathNode getAPredecessor(PathNode pathNode) { edges(result, pathNode) } + + /** Gets the element that `pathNode` wraps, if any. */ + Element getElementFromPathNode(PathNode pathNode) { + exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() | + result = node.asExpr() or + result = node.asParameter() + ) + or + result = pathNode.(EndpointPathNode).inner() + } + } + private class WrapPathNode extends PathNode, TWrapPathNode { DataFlow3::PathNode inner() { this = TWrapPathNode(result) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index 4ebd8cbf758..9b421df2df3 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -63,8 +63,10 @@ private module VirtualDispatch { | // Call argument exists(DataFlowCall call, int i | - other.(DataFlow::ParameterNode).isParameterOf(call.getStaticCallTarget(), i) and - src.(ArgumentNode).argumentOf(call, i) + other + .(DataFlow::ParameterNode) + .isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and + src.(ArgumentNode).argumentOf(call, pragma[only_bind_into](pragma[only_bind_out](i))) ) and allowOtherFromArg = true and allowFromArg = true @@ -128,6 +130,7 @@ private module VirtualDispatch { * * Used to fix a join ordering issue in flowsFrom. */ + pragma[noinline] private predicate returnNodeWithKindAndEnclosingCallable( ReturnNode node, ReturnKind kind, DataFlowCallable callable ) { diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index f43a550af57..c28ceabb438 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -2,6 +2,42 @@ private import DataFlowImplSpecific::Private private import DataFlowImplSpecific::Public import Cached +module DataFlowImplCommonPublic { + private newtype TFlowFeature = + TFeatureHasSourceCallContext() or + TFeatureHasSinkCallContext() or + TFeatureEqualSourceSinkCallContext() + + /** A flow configuration feature for use in `Configuration::getAFeature()`. */ + class FlowFeature extends TFlowFeature { + string toString() { none() } + } + + /** + * A flow configuration feature that implies that sources have some existing + * call context. + */ + class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext { + override string toString() { result = "FeatureHasSourceCallContext" } + } + + /** + * A flow configuration feature that implies that sinks have some existing + * call context. + */ + class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext { + override string toString() { result = "FeatureHasSinkCallContext" } + } + + /** + * A flow configuration feature that implies that source-sink pairs have some + * shared existing call context. + */ + class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext { + override string toString() { result = "FeatureEqualSourceSinkCallContext" } + } +} + /** * The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion. * @@ -251,7 +287,7 @@ private module Cached { predicate forceCachingInSameStage() { any() } cached - predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() } + predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) } cached predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) { @@ -316,9 +352,7 @@ private module Cached { } cached - predicate parameterNode(Node n, DataFlowCallable c, int i) { - n.(ParameterNode).isParameterOf(c, i) - } + predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) } cached predicate argumentNode(Node n, DataFlowCall call, int pos) { @@ -801,6 +835,9 @@ private module Cached { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } + cached + predicate allowParameterReturnInSelfCached(ParamNode p) { allowParameterReturnInSelf(p) } + cached newtype TCallContext = TAnyCallContext() or @@ -937,7 +974,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { } override predicate relevantFor(DataFlowCallable callable) { - recordDataFlowCallSite(getCall(), callable) + recordDataFlowCallSite(this.getCall(), callable) } override predicate matchesCall(DataFlowCall call) { call = this.getCall() } @@ -1257,7 +1294,7 @@ abstract class AccessPathFront extends TAccessPathFront { TypedContent getHead() { this = TFrontHead(result) } - predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) } + predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index a55e65a81f6..acf31338f9a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -31,7 +31,7 @@ module Consistency { query predicate uniqueEnclosingCallable(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getEnclosingCallable()) and + c = count(nodeGetEnclosingCallable(n)) and c != 1 and msg = "Node should have one enclosing callable but has " + c + "." ) @@ -85,13 +85,13 @@ module Consistency { } query predicate parameterCallable(ParameterNode p, string msg) { - exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and + exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and msg = "Callable mismatch for parameter." } query predicate localFlowIsLocal(Node n1, Node n2, string msg) { simpleLocalFlowStep(n1, n2) and - n1.getEnclosingCallable() != n2.getEnclosingCallable() and + nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and msg = "Local flow step does not preserve enclosing callable." } @@ -106,7 +106,7 @@ module Consistency { query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) { isUnreachableInCall(n, call) and exists(DataFlowCallable c | - c = n.getEnclosingCallable() and + c = nodeGetEnclosingCallable(n) and not viableCallable(call) = c ) and msg = "Call context for isUnreachableInCall is inconsistent with call graph." @@ -120,7 +120,7 @@ module Consistency { n.(ArgumentNode).argumentOf(call, _) and msg = "ArgumentNode and call does not share enclosing callable." ) and - n.getEnclosingCallable() != call.getEnclosingCallable() + nodeGetEnclosingCallable(n) != call.getEnclosingCallable() } // This predicate helps the compiler forget that in some languages @@ -151,7 +151,7 @@ module Consistency { } query predicate postIsInSameCallable(PostUpdateNode n, string msg) { - n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and + nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and msg = "PostUpdateNode does not share callable with its pre-update node." } @@ -175,6 +175,7 @@ module Consistency { query predicate postWithInFlow(Node n, string msg) { isPostUpdateNode(n) and + not clearsContent(n, _) and simpleLocalFlowStep(_, n) and msg = "PostUpdateNode should not be the target of local flow." } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 00996a6ebfc..d454277a13c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -3,6 +3,12 @@ private import DataFlowUtil private import semmle.code.cpp.ir.IR private import DataFlowDispatch +/** Gets the callable in which this node occurs. */ +DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() } + +/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */ +predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) } + /** * A data flow node that occurs as the argument of a call and is passed as-is * to the callable. Instance arguments (`this` pointer) and read side effects @@ -106,11 +112,9 @@ class ReturnNode extends InstructionNode { Instruction primary; ReturnNode() { - exists(ReturnValueInstruction ret | instr = ret.getReturnValue() and primary = ret) + exists(ReturnValueInstruction ret | instr = ret and primary = ret) or - exists(ReturnIndirectionInstruction rii | - instr = rii.getSideEffectOperand().getAnyDef() and primary = rii - ) + exists(ReturnIndirectionInstruction rii | instr = rii and primary = rii) } /** Gets the kind of this returned value. */ @@ -184,108 +188,16 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { */ predicate jumpStep(Node n1, Node n2) { none() } -private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) { - exists(StoreInstruction store, Class c | - store = node2.asInstruction() and - store.getSourceValueOperand() = node1.asOperand() and - getWrittenField(store, f.(FieldContent).getAField(), c) and - f.hasOffset(c, _, _) - ) -} - -private FieldAddressInstruction getFieldInstruction(Instruction instr) { - result = instr or - result = instr.(CopyValueInstruction).getUnary() -} - -pragma[noinline] -private predicate getWrittenField(Instruction instr, Field f, Class c) { - exists(FieldAddressInstruction fa | - fa = - getFieldInstruction([ - instr.(StoreInstruction).getDestinationAddress(), - instr.(WriteSideEffectInstruction).getDestinationAddress() - ]) and - f = fa.getField() and - c = f.getDeclaringType() - ) -} - -private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) { - exists(ChiPartialOperand operand, ChiInstruction chi | - chi.getPartialOperand() = operand and - node1.asOperand() = operand and - node2.asInstruction() = chi and - exists(Class c | - c = chi.getResultType() and - exists(int startBit, int endBit | - chi.getUpdatedInterval(startBit, endBit) and - f.hasOffset(c, startBit, endBit) - ) - or - getWrittenField(operand.getDef(), f.getAField(), c) and - f.hasOffset(c, _, _) - ) - ) -} - -private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) { - exists(a) and - exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store | - chi.getPartialOperand() = operand and - store = operand.getDef() and - node1.asOperand() = operand and - // This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode` - // and `PointerStoreNode` require it in their characteristic predicates. - node2.asInstruction() = chi and - ( - // `x[i] = taint()` - // This matches the characteristic predicate in `ArrayStoreNode`. - store.getDestinationAddress() instanceof PointerAddInstruction - or - // `*p = taint()` - // This matches the characteristic predicate in `PointerStoreNode`. - store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction - ) - ) -} - /** * Holds if data can flow from `node1` to `node2` via an assignment to `f`. * Thus, `node2` references an object with a field `f` that contains the * value of `node1`. */ -predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - fieldStoreStepNoChi(node1, f, node2) or - fieldStoreStepChi(node1, f, node2) or - arrayStoreStepChi(node1, f, node2) or - fieldStoreStepAfterArraySuppression(node1, f, node2) -} - -// This predicate pushes the correct `FieldContent` onto the access path when the -// `suppressArrayRead` predicate has popped off an `ArrayContent`. -private predicate fieldStoreStepAfterArraySuppression( - Node node1, FieldContent f, PostUpdateNode node2 -) { - exists(WriteSideEffectInstruction write, ChiInstruction chi, Class c | - not chi.isResultConflated() and - node1.asInstruction() = chi and - node2.asInstruction() = chi and - chi.getPartial() = write and - getWrittenField(write, f.getAField(), c) and - f.hasOffset(c, _, _) - ) -} - -bindingset[result, i] -private int unbindInt(int i) { i <= result and i >= result } - -pragma[noinline] -private predicate getLoadedField(LoadInstruction load, Field f, Class c) { - exists(FieldAddressInstruction fa | - fa = load.getSourceAddress() and - f = fa.getField() and - c = f.getDeclaringType() +predicate storeStep(StoreNodeInstr node1, FieldContent f, StoreNodeInstr node2) { + exists(FieldAddressInstruction fai | + node1.getInstruction() = fai and + node2.getInstruction() = fai.getObjectAddress() and + f.getField() = fai.getField() ) } @@ -294,122 +206,14 @@ private predicate getLoadedField(LoadInstruction load, Field f, Class c) { * Thus, `node1` references an object with a field `f` whose value ends up in * `node2`. */ -private predicate fieldReadStep(Node node1, FieldContent f, Node node2) { - exists(LoadOperand operand | - node2.asOperand() = operand and - node1.asInstruction() = operand.getAnyDef() and - exists(Class c | - c = operand.getAnyDef().getResultType() and - exists(int startBit, int endBit | - operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and - f.hasOffset(c, startBit, endBit) - ) - or - getLoadedField(operand.getUse(), f.getAField(), c) and - f.hasOffset(c, _, _) - ) +predicate readStep(ReadNode node1, FieldContent f, ReadNode node2) { + exists(FieldAddressInstruction fai | + node1.getInstruction() = fai.getObjectAddress() and + node2.getInstruction() = fai and + f.getField() = fai.getField() ) } -/** - * When a store step happens in a function that looks like an array write such as: - * ```cpp - * void f(int* pa) { - * pa = source(); - * } - * ``` - * it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is - * the case, the `ArrayContent` that was written by the call to `f` should be popped off the access - * path, and a `FieldContent` containing `x` should be pushed instead. - * So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression` - * predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path. - */ -predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) { - exists(a) and - exists(WriteSideEffectInstruction write, ChiInstruction chi | - node1.asInstruction() = write and - node2.asInstruction() = chi and - chi.getPartial() = write and - getWrittenField(write, _, _) - ) -} - -private class ArrayToPointerConvertInstruction extends ConvertInstruction { - ArrayToPointerConvertInstruction() { - this.getUnary().getResultType() instanceof ArrayType and - this.getResultType() instanceof PointerType - } -} - -private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) { - copy.getUnary() = result and not result instanceof CopyValueInstruction - or - result = skipOneCopyValueInstructionRec(copy.getUnary()) -} - -private Instruction skipCopyValueInstructions(Operand op) { - not result instanceof CopyValueInstruction and result = op.getDef() - or - result = skipOneCopyValueInstructionRec(op.getDef()) -} - -private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { - exists(a) and - // Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array. - exists(LoadOperand operand, Instruction address | - operand.isDefinitionInexact() and - node1.asInstruction() = operand.getAnyDef() and - operand = node2.asOperand() and - address = skipCopyValueInstructions(operand.getAddressOperand()) and - ( - address instanceof LoadInstruction or - address instanceof ArrayToPointerConvertInstruction or - address instanceof PointerOffsetInstruction - ) - ) -} - -/** - * In cases such as: - * ```cpp - * void f(int* pa) { - * *pa = source(); - * } - * ... - * int x; - * f(&x); - * use(x); - * ``` - * the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition - * is a `WriteSideEffect`). This predicate pops the `ArrayContent` (pushed by the store in `f`) - * from the access path. - */ -private predicate exactReadStep(Node node1, ArrayContent a, Node node2) { - exists(a) and - exists(WriteSideEffectInstruction write, ChiInstruction chi | - not chi.isResultConflated() and - chi.getPartial() = write and - node1.asInstruction() = write and - node2.asInstruction() = chi and - // To distinquish this case from the `arrayReadStep` case we require that the entire variable was - // overwritten by the `WriteSideEffectInstruction` (i.e., there is a load that reads the - // entire variable). - exists(LoadInstruction load | load.getSourceValue() = chi) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` via a read of `f`. - * Thus, `node1` references an object with a field `f` whose value ends up in - * `node2`. - */ -predicate readStep(Node node1, Content f, Node node2) { - fieldReadStep(node1, f, node2) or - arrayReadStep(node1, f, node2) or - exactReadStep(node1, f, node2) or - suppressArrayRead(node1, f, node2) -} - /** * Holds if values stored inside content `c` are cleared at node `n`. */ @@ -441,7 +245,7 @@ private predicate suppressUnusedNode(Node n) { any() } // Java QL library compatibility wrappers ////////////////////////////////////////////////////////////////////////////// /** A node that performs a type cast. */ -class CastNode extends InstructionNode { +class CastNode extends Node { CastNode() { none() } // stub implementation } @@ -507,3 +311,12 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { no /** Extra data-flow steps needed for lambda flow analysis. */ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } + +/** + * Holds if flow is allowed to pass from parameter `p` and back to itself as a + * side-effect, resulting in a summary from `p` to itself. + * + * One example would be to allow flow like `p.foo = p.bar;`, which is disallowed + * by default as a heuristic. + */ +predicate allowParameterReturnInSelf(ParameterNode p) { none() } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9e7a95e010d..c3455d4790a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -10,19 +10,78 @@ private import semmle.code.cpp.ir.ValueNumbering private import semmle.code.cpp.ir.IR private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.models.interfaces.DataFlow +private import DataFlowPrivate +private import SsaInternals as Ssa cached private module Cached { + /** + * The IR dataflow graph consists of the following nodes: + * - `InstructionNode`, which represents an `Instruction` in the graph. + * - `OperandNode`, which represents an `Operand` in the graph. + * - `VariableNode`, which is used to model global variables. + * - Two kinds of `StoreNode`s: + * 1. `StoreNodeInstr`, which represents the value of an address computed by an `Instruction` that + * has been updated by a write operation. + * 2. `StoreNodeOperand`, which represents the value of an address in an `ArgumentOperand` after a + * function call that may have changed the value. + * - `ReadNode`, which represents the result of reading a field of an object. + * - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA library. + * + * The following section describes how flow is generally transferred between these nodes: + * - Flow between `InstructionNode`s and `OperandNode`s follow the def-use information as computed by + * the IR. Because the IR compute must-alias information for memory operands, we only follow def-use + * flow for register operands. + * - Flow can enter a `StoreNode` in two ways (both done in `StoreNode.flowInto`): + * 1. Flow is transferred from a `StoreValueOperand` to a `StoreNodeInstr`. Flow will then proceed + * along the chain of addresses computed by `StoreNodeInstr.getInner` to identify field writes + * and call `storeStep` accordingly (i.e., for an expression like `a.b.c = x`, we visit `c`, then + * `b`, then `a`). + * 2. Flow is transfered from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow + * returns to a caller. Flow will then proceed to the defining instruction of the operand (because + * the `StoreNodeInstr` computed by `StoreNodeOperand.getInner()` is the `StoreNode` containing + * the defining instruction), and then along the chain computed by `StoreNodeInstr.getInner` like + * above. + * In both cases, flow leaves a `StoreNode` once the entire chain has been traversed, and the shared + * SSA library is used to find the next use of the variable at the end of the chain. + * - Flow can enter a `ReadNode` through an `OperandNode` that represents an address of some variable. + * Flow will then proceed along the chain of addresses computed by `ReadNode.getOuter` (i.e., for an + * expression like `use(a.b.c)` we visit `a`, then `b`, then `c`) and call `readStep` accordingly. + * Once the entire chain has been traversed, flow is transferred to the load instruction that reads + * the final address of the chain. + * - Flow can enter a `SsaPhiNode` from an `InstructionNode`, a `StoreNode` or another `SsaPhiNode` + * (in `toPhiNode`), depending on which node provided the previous definition of the underlying + * variable. Flow leaves a `SsaPhiNode` (in `fromPhiNode`) by using the shared SSA library to + * determine the next use of the variable. + */ cached newtype TIRDataFlowNode = TInstructionNode(Instruction i) or TOperandNode(Operand op) or - TVariableNode(Variable var) + TVariableNode(Variable var) or + TStoreNodeInstr(Instruction i) { Ssa::explicitWrite(_, _, i) } or + TStoreNodeOperand(ArgumentOperand op) { Ssa::explicitWrite(_, _, op.getDef()) } or + TReadNode(Instruction i) { needsPostReadNode(i) } or + TSsaPhiNode(Ssa::PhiNode phi) cached predicate localFlowStepCached(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) } + + private predicate needsPostReadNode(Instruction iFrom) { + // If the instruction generates an address that flows to a load. + Ssa::addressFlowTC(iFrom, Ssa::getSourceAddress(_)) and + ( + // And it is either a field address + iFrom instanceof FieldAddressInstruction + or + // Or it is instruction that either uses or is used for an address that needs a post read node. + exists(Instruction mid | needsPostReadNode(mid) | + Ssa::addressFlow(mid, iFrom) or Ssa::addressFlow(iFrom, mid) + ) + ) + } } private import Cached @@ -110,7 +169,7 @@ class Node extends TIRDataFlowNode { /** * Gets an upper bound on the type of this node. */ - IRType getTypeBound() { result = getType() } + IRType getTypeBound() { result = this.getType() } /** Gets the location of this element. */ Location getLocation() { none() } // overridden by subclasses @@ -180,6 +239,234 @@ class OperandNode extends Node, TOperandNode { override string toString() { result = this.getOperand().toString() } } +/** + * INTERNAL: do not use. + * + * A `StoreNode` is a node that has been (or is about to be) the + * source or target of a `storeStep`. + */ +abstract private class StoreNode extends Node { + /** Holds if this node should receive flow from `addr`. */ + abstract predicate flowInto(Instruction addr); + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + /** Holds if this `StoreNode` is the root of the address computation used by a store operation. */ + predicate isTerminal() { + not exists(this.getInner()) and + not storeStep(this, _, _) + } + + /** Gets the store operation that uses the address computed by this `StoreNode`. */ + abstract Instruction getStoreInstruction(); + + /** Holds if the store operation associated with this `StoreNode` overwrites the entire variable. */ + final predicate isCertain() { Ssa::explicitWrite(true, this.getStoreInstruction(), _) } + + /** + * Gets the `StoreNode` that computes the address used by this `StoreNode`. + */ + abstract StoreNode getInner(); + + /** The inverse of `StoreNode.getInner`. */ + final StoreNode getOuter() { result.getInner() = this } +} + +class StoreNodeInstr extends StoreNode, TStoreNodeInstr { + Instruction instr; + + StoreNodeInstr() { this = TStoreNodeInstr(instr) } + + override predicate flowInto(Instruction addr) { this.getInstruction() = addr } + + /** Gets the underlying instruction. */ + Instruction getInstruction() { result = instr } + + override Function getFunction() { result = this.getInstruction().getEnclosingFunction() } + + override IRType getType() { result = this.getInstruction().getResultIRType() } + + override Location getLocation() { result = this.getInstruction().getLocation() } + + override string toString() { + result = instructionNode(this.getInstruction()).toString() + " [store]" + } + + override Instruction getStoreInstruction() { + Ssa::explicitWrite(_, result, this.getInstruction()) + } + + override StoreNodeInstr getInner() { + Ssa::addressFlow(result.getInstruction(), this.getInstruction()) + } +} + +/** + * To avoid having `PostUpdateNode`s with multiple pre-update nodes (which can cause performance + * problems) we attach the `PostUpdateNode` that represent output arguments to an operand instead of + * an instruction. + * + * To see why we need this, consider the expression `b->set(new C())`. The IR of this expression looks + * like (simplified): + * ``` + * r1(glval) = FunctionAddress[set] : + * r2(glval) = FunctionAddress[operator new] : + * r3(unsigned long) = Constant[8] : + * r4(void *) = Call[operator new] : func:r2, 0:r3 + * r5(C *) = Convert : r4 + * r6(glval) = FunctionAddress[C] : + * v1(void) = Call[C] : func:r6, this:r5 + * v2(void) = Call[set] : func:r1, this:r0, 0:r5 + * ``` + * + * Notice that both the call to `C` and the call to `set` will have an argument that is the + * result of calling `operator new` (i.e., `r4`). If we only have `PostUpdateNode`s that are + * instructions, both `PostUpdateNode`s would have `r4` as their pre-update node. + * + * We avoid this issue by having a `PostUpdateNode` for each argument, and let the pre-update node of + * each `PostUpdateNode` be the argument _operand_, instead of the defining instruction. + */ +class StoreNodeOperand extends StoreNode, TStoreNodeOperand { + ArgumentOperand operand; + + StoreNodeOperand() { this = TStoreNodeOperand(operand) } + + override predicate flowInto(Instruction addr) { this.getOperand().getDef() = addr } + + /** Gets the underlying operand. */ + Operand getOperand() { result = operand } + + override Function getFunction() { result = operand.getDef().getEnclosingFunction() } + + override IRType getType() { result = operand.getIRType() } + + override Location getLocation() { result = operand.getLocation() } + + override string toString() { result = operandNode(this.getOperand()).toString() + " [store]" } + + override WriteSideEffectInstruction getStoreInstruction() { + Ssa::explicitWrite(_, result, operand.getDef()) + } + + /** + * The result of `StoreNodeOperand.getInner` is the `StoreNodeInstr` representation the instruction + * that defines this operand. This means the graph of `getInner` looks like this: + * ``` + * I---I---I + * \ \ \ + * O O O + * ``` + * where each `StoreNodeOperand` "hooks" into the chain computed by `StoreNodeInstr.getInner`. + * This means that the chain of `getInner` calls on the argument `&o.f` on an expression + * like `func(&o.f)` is: + * ``` + * r4---r3---r2 + * \ + * 0:r4 + * ``` + * where the IR for `func(&o.f)` looks like (simplified): + * ``` + * r1(glval) = FunctionAddress[func] : + * r2(glval) = VariableAddress[o] : + * r3(glval) = FieldAddress[f] : r2 + * r4(int *) = CopyValue : r3 + * v1(void) = Call[func] : func:r1, 0:r4 + * ``` + */ + override StoreNodeInstr getInner() { operand.getDef() = result.getInstruction() } +} + +/** + * INTERNAL: do not use. + * + * A `ReadNode` is a node that has been (or is about to be) the + * source or target of a `readStep`. + */ +class ReadNode extends Node, TReadNode { + Instruction i; + + ReadNode() { this = TReadNode(i) } + + /** Gets the underlying instruction. */ + Instruction getInstruction() { result = i } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = this.getInstruction().getEnclosingFunction() } + + override IRType getType() { result = this.getInstruction().getResultIRType() } + + override Location getLocation() { result = this.getInstruction().getLocation() } + + override string toString() { + result = instructionNode(this.getInstruction()).toString() + " [read]" + } + + /** Gets a load instruction that uses the address computed by this read node. */ + final Instruction getALoadInstruction() { + Ssa::addressFlowTC(this.getInstruction(), Ssa::getSourceAddress(result)) + } + + /** + * Gets a read node with an underlying instruction that is used by this + * underlying instruction to compute an address of a load instruction. + */ + final ReadNode getInner() { Ssa::addressFlow(result.getInstruction(), this.getInstruction()) } + + /** The inverse of `ReadNode.getInner`. */ + final ReadNode getOuter() { result.getInner() = this } + + /** Holds if this read node computes a value that will not be used for any future read nodes. */ + final predicate isTerminal() { + not exists(this.getOuter()) and + not readStep(this, _, _) + } + + /** Holds if this read node computes a value that has not yet been used for any read operations. */ + final predicate isInitial() { + not exists(this.getInner()) and + not readStep(_, _, this) + } +} + +/** + * INTERNAL: do not use. + * + * A phi node produced by the shared SSA library, viewed as a node in a data flow graph. + */ +class SsaPhiNode extends Node, TSsaPhiNode { + Ssa::PhiNode phi; + + SsaPhiNode() { this = TSsaPhiNode(phi) } + + /* Get the phi node associated with this node. */ + Ssa::PhiNode getPhiNode() { result = phi } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = phi.getBasicBlock().getEnclosingFunction() } + + override IRType getType() { result instanceof IRVoidType } + + override Location getLocation() { result = phi.getBasicBlock().getLocation() } + + /** Holds if this phi node has input from the `rnk`'th write operation in block `block`. */ + final predicate hasInputAtRankInBlock(IRBlock block, int rnk) { + hasInputAtRankInBlock(block, rnk, _) + } + + /** + * Holds if this phi node has input from the definition `input` (which is the `rnk`'th write + * operation in block `block`). + */ + cached + final predicate hasInputAtRankInBlock(IRBlock block, int rnk, Ssa::Definition input) { + Ssa::phiHasInputFromBlock(phi, input, _) and input.definesAt(_, block, rnk) + } + + override string toString() { result = "Phi" } +} + /** * An expression, viewed as a node in a data flow graph. */ @@ -313,15 +600,14 @@ deprecated class UninitializedNode extends Node { * Nodes corresponding to AST elements, for example `ExprNode`, usually refer * to the value before the update with the exception of `ClassInstanceExpr`, * which represents the value after the constructor has run. - * - * This class exists to match the interface used by Java. There are currently no non-abstract - * classes that extend it. When we implement field flow, we can revisit this. */ -abstract class PostUpdateNode extends InstructionNode { +abstract class PostUpdateNode extends Node { /** * Gets the node before the state update. */ abstract Node getPreUpdateNode(); + + override string toString() { result = this.getPreUpdateNode() + " [post update]" } } /** @@ -332,7 +618,7 @@ abstract class PostUpdateNode extends InstructionNode { * value, but does not necessarily replace it entirely. For example: * ``` * x.y = 1; // a partial definition of the object `x`. - * x.y.z = 1; // a partial definition of the object `x.y`. + * x.y.z = 1; // a partial definition of the object `x.y` and `x`. * x.setY(1); // a partial definition of the object `x`. * setY(&x); // a partial definition of the object `x`. * ``` @@ -341,135 +627,34 @@ abstract private class PartialDefinitionNode extends PostUpdateNode { abstract Expr getDefinedExpr(); } -private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { - override ChiInstruction instr; - StoreInstruction store; - - ExplicitFieldStoreQualifierNode() { - not instr.isResultConflated() and - instr.getPartial() = store and - ( - instr.getUpdatedInterval(_, _) or - store.getDestinationAddress() instanceof FieldAddressInstruction - ) +private class FieldPartialDefinitionNode extends PartialDefinitionNode, StoreNodeInstr { + FieldPartialDefinitionNode() { + this.getInstruction() = any(FieldAddressInstruction fai).getObjectAddress() } - // By using an operand as the result of this predicate we avoid the dataflow inconsistency errors - // caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause - // a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node - // into a big step. - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + override Node getPreUpdateNode() { result.asInstruction() = this.getInstruction() } + + override Expr getDefinedExpr() { result = this.getInstruction().getUnconvertedResultExpression() } + + override string toString() { result = PartialDefinitionNode.super.toString() } +} + +private class NonPartialDefinitionPostUpdate extends PostUpdateNode, StoreNodeInstr { + NonPartialDefinitionPostUpdate() { not this instanceof PartialDefinitionNode } + + override Node getPreUpdateNode() { result.asInstruction() = this.getInstruction() } + + override string toString() { result = PostUpdateNode.super.toString() } +} + +private class ArgumentPostUpdateNode extends PartialDefinitionNode, StoreNodeOperand { + override ArgumentNode getPreUpdateNode() { result.asOperand() = operand } override Expr getDefinedExpr() { - result = - store - .getDestinationAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .getUnconvertedResultExpression() - } -} - -/** - * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. - * For instance, an update to a field of a struct containing only one field. Even if the store does - * have a chi instruction, a subsequent use of the result of the store may be linked directly to the - * result of the store as an inexact definition if the store totally overlaps the use. For these - * cases we attach the PostUpdateNode to the store instruction. There's no obvious pre update node - * for this case (as the entire memory is updated), so `getPreUpdateNode` is implemented as - * `none()`. - */ -private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { - override StoreInstruction instr; - - ExplicitSingleFieldStoreQualifierNode() { - ( - instr.getAUse().isDefinitionInexact() - or - not exists(ChiInstruction chi | chi.getPartial() = instr) - ) and - // Without this condition any store would create a `PostUpdateNode`. - instr.getDestinationAddress() instanceof FieldAddressInstruction + result = this.getOperand().getDef().getUnconvertedResultExpression() } - override Node getPreUpdateNode() { none() } - - override Expr getDefinedExpr() { - result = - instr - .getDestinationAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .getUnconvertedResultExpression() - } -} - -private FieldAddressInstruction getFieldInstruction(Instruction instr) { - result = instr or - result = instr.(CopyValueInstruction).getUnary() -} - -/** - * The target of a `fieldStoreStepAfterArraySuppression` store step, which is used to convert - * an `ArrayContent` to a `FieldContent` when the `WriteSideEffect` instruction stores - * into a field. See the QLDoc for `suppressArrayRead` for an example of where such a conversion - * is inserted. - */ -private class WriteSideEffectFieldStoreQualifierNode extends PartialDefinitionNode { - override ChiInstruction instr; - WriteSideEffectInstruction write; - FieldAddressInstruction field; - - WriteSideEffectFieldStoreQualifierNode() { - not instr.isResultConflated() and - instr.getPartial() = write and - field = getFieldInstruction(write.getDestinationAddress()) - } - - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } - - override Expr getDefinedExpr() { - result = field.getObjectAddress().getUnconvertedResultExpression() - } -} - -/** - * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden - * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. - */ -private class ArrayStoreNode extends PartialDefinitionNode { - override ChiInstruction instr; - PointerAddInstruction add; - - ArrayStoreNode() { - not instr.isResultConflated() and - exists(StoreInstruction store | - instr.getPartial() = store and - add = store.getDestinationAddress() - ) - } - - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } - - override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() } -} - -/** - * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden - * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. - */ -private class PointerStoreNode extends PostUpdateNode { - override ChiInstruction instr; - - PointerStoreNode() { - not instr.isResultConflated() and - exists(StoreInstruction store | - instr.getPartial() = store and - store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction - ) - } - - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + override string toString() { result = PartialDefinitionNode.super.toString() } } /** @@ -548,6 +733,11 @@ class VariableNode extends Node, TVariableNode { */ InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr } +/** + * Gets the node corresponding to `operand`. + */ +OperandNode operandNode(Operand operand) { result.getOperand() = operand } + /** * DEPRECATED: use `definitionByReferenceNodeFromArgument` instead. * @@ -614,61 +804,167 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { or // Instruction -> Operand flow simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) + or + // Flow into, through, and out of store nodes + StoreNodeFlow::flowInto(nodeFrom, nodeTo) + or + StoreNodeFlow::flowThrough(nodeFrom, nodeTo) + or + StoreNodeFlow::flowOutOf(nodeFrom, nodeTo) + or + // Flow into, through, and out of read nodes + ReadNodeFlow::flowInto(nodeFrom, nodeTo) + or + ReadNodeFlow::flowThrough(nodeFrom, nodeTo) + or + ReadNodeFlow::flowOutOf(nodeFrom, nodeTo) + or + // Adjacent-def-use and adjacent-use-use flow + adjacentDefUseFlow(nodeFrom, nodeTo) } -pragma[noinline] -private predicate getFieldSizeOfClass(Class c, Type type, int size) { - exists(Field f | - f.getDeclaringType() = c and - f.getUnderlyingType() = type and - type.getSize() = size +private predicate adjacentDefUseFlow(Node nodeFrom, Node nodeTo) { + // Flow that isn't already covered by field flow out of store/read nodes. + not nodeFrom.asInstruction() = any(StoreNode pun).getStoreInstruction() and + not nodeFrom.asInstruction() = any(ReadNode pun).getALoadInstruction() and + ( + //Def-use flow + Ssa::ssaFlow(nodeFrom, nodeTo) + or + exists(Instruction loadAddress | loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) | + // Use-use flow through reads + exists(Node address | + Ssa::addressFlowTC(address.asInstruction(), loadAddress) and + Ssa::ssaFlow(address, nodeTo) + ) + or + // Use-use flow through stores. + exists(Node store | + Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and + Ssa::ssaFlow(store, nodeTo) + ) + ) ) } -private predicate isSingleFieldClass(Type type, Operand op) { - exists(int size, Class c | - c = op.getType().getUnderlyingType() and - c.getSize() = size and - getFieldSizeOfClass(c, type, size) - ) +private module ReadNodeFlow { + /** Holds if the read node `nodeTo` should receive flow from `nodeFrom`. */ + predicate flowInto(Node nodeFrom, ReadNode nodeTo) { + nodeTo.isInitial() and + ( + // If we entered through an address operand. + nodeFrom.asOperand().getDef() = nodeTo.getInstruction() + or + // If we entered flow through a memory-producing instruction. + // This can happen if we have flow to an `InitializeParameterIndirection` through + // a `ReadSideEffectInstruction`. + exists(Instruction load, Instruction def | + def = nodeFrom.asInstruction() and + def = Ssa::getSourceValueOperand(load).getAnyDef() and + not def = any(StoreNode store).getStoreInstruction() and + pragma[only_bind_into](nodeTo).getALoadInstruction() = load + ) + ) + } + + /** Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`. */ + predicate flowThrough(ReadNode nodeFrom, ReadNode nodeTo) { + not readStep(nodeFrom, _, _) and + nodeFrom.getOuter() = nodeTo + } + + /** + * Holds if flow should leave the read node `nFrom` and enter the node `nodeTo`. + * This happens either because there is use-use flow from one of the variables used in + * the read operation, or because we have traversed all the field dereferences in the + * read operation. + */ + predicate flowOutOf(ReadNode nFrom, Node nodeTo) { + // Use-use flow to another use of the same variable instruction + Ssa::ssaFlow(nFrom, nodeTo) + or + not exists(nFrom.getInner()) and + exists(Node store | + Ssa::explicitWrite(_, store.asInstruction(), nFrom.getInstruction()) and + Ssa::ssaFlow(store, nodeTo) + ) + or + // Flow out of read nodes and into memory instructions if we cannot move any further through + // read nodes. + nFrom.isTerminal() and + ( + exists(Instruction load | + load = nodeTo.asInstruction() and + Ssa::getSourceAddress(load) = nFrom.getInstruction() + ) + or + exists(CallInstruction call, int i | + call.getArgument(i) = nodeTo.asInstruction() and + call.getArgument(i) = nFrom.getInstruction() + ) + ) + } +} + +private module StoreNodeFlow { + /** Holds if the store node `nodeTo` should receive flow from `nodeFrom`. */ + predicate flowInto(Node nodeFrom, StoreNode nodeTo) { + nodeTo.flowInto(Ssa::getDestinationAddress(nodeFrom.asInstruction())) + } + + /** Holds if the store node `nodeTo` should receive flow from `nodeFom`. */ + predicate flowThrough(StoreNode nFrom, StoreNode nodeTo) { + // Flow through a post update node that doesn't need a store step. + not storeStep(nFrom, _, _) and + nodeTo.getOuter() = nFrom + } + + /** + * Holds if flow should leave the store node `nodeFrom` and enter the node `nodeTo`. + * This happens because we have traversed an entire chain of field dereferences + * after a store operation. + */ + predicate flowOutOf(StoreNodeInstr nFrom, Node nodeTo) { + nFrom.isTerminal() and + Ssa::ssaFlow(nFrom, nodeTo) + } } private predicate simpleOperandLocalFlowStep(Instruction iFrom, Operand opTo) { // Propagate flow from an instruction to its exact uses. + // We do this for all instruction/operand pairs, except when the operand is the + // side effect operand of a ReturnIndirectionInstruction, or the load operand of a LoadInstruction. + // This is because we get these flows through the shared SSA library already, and including this + // flow here will create multiple dataflow paths which creates a blowup in stage 3 of dataflow. + ( + not any(ReturnIndirectionInstruction ret).getSideEffectOperand() = opTo and + not any(LoadInstruction load).getSourceValueOperand() = opTo and + not any(ReturnValueInstruction ret).getReturnValueOperand() = opTo + ) and opTo.getDef() = iFrom - or - opTo = any(ReadSideEffectInstruction read).getSideEffectOperand() and - not iFrom.isResultConflated() and - iFrom = opTo.getAnyDef() - or - // Loading a single `int` from an `int *` parameter is not an exact load since - // the parameter may point to an entire array rather than a single `int`. The - // following rule ensures that any flow going into the - // `InitializeIndirectionInstruction`, even if it's for a different array - // element, will propagate to a load of the first element. - // - // Since we're linking `InitializeIndirectionInstruction` and - // `LoadInstruction` together directly, this rule will break if there's any - // reassignment of the parameter indirection, including a conditional one that - // leads to a phi node. - exists(InitializeIndirectionInstruction init | - iFrom = init and - opTo.(LoadOperand).getAnyDef() = init and - // Check that the types match. Otherwise we can get flow from an object to - // its fields, which leads to field conflation when there's flow from other - // fields to the object elsewhere. - init.getParameter().getType().getUnspecifiedType().(DerivedType).getBaseType() = - opTo.getType().getUnspecifiedType() - ) - or - // Flow from stores to structs with a single field to a load of that field. - exists(LoadInstruction load | - load.getSourceValueOperand() = opTo and - opTo.getAnyDef() = iFrom and - isSingleFieldClass(pragma[only_bind_out](pragma[only_bind_out](iFrom).getResultType()), opTo) +} + +pragma[noinline] +private predicate getAddressType(LoadInstruction load, Type t) { + exists(Instruction address | + address = load.getSourceAddress() and + t = address.getResultType() ) } +/** + * Like the AST dataflow library, we want to conflate the address and value of a reference. This class + * represents the `LoadInstruction` that is generated from a reference dereference. + */ +private class ReferenceDereferenceInstruction extends LoadInstruction { + ReferenceDereferenceInstruction() { + exists(ReferenceType ref | + getAddressType(this, ref) and + this.getResultType() = ref.getBaseType() + ) + } +} + private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) { iTo.(CopyInstruction).getSourceValueOperand() = opFrom or @@ -681,40 +977,8 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo or iTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom or - // A chi instruction represents a point where a new value (the _partial_ - // operand) may overwrite an old value (the _total_ operand), but the alias - // analysis couldn't determine that it surely will overwrite every bit of it or - // that it surely will overwrite no bit of it. - // - // By allowing flow through the total operand, we ensure that flow is not lost - // due to shortcomings of the alias analysis. We may get false flow in cases - // where the data is indeed overwritten. - // - // Flow through the partial operand belongs in the taint-tracking libraries - // for now. - iTo.getAnOperand().(ChiTotalOperand) = opFrom - or - // Add flow from write side-effects to non-conflated chi instructions through their - // partial operands. From there, a `readStep` will find subsequent reads of that field. - // Consider the following example: - // ``` - // void setX(Point* p, int new_x) { - // p->x = new_x; - // } - // ... - // setX(&p, taint()); - // ``` - // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to - // `setX`, which will be melded into `p` through a chi instruction. - exists(ChiInstruction chi | chi = iTo | - opFrom.getAnyDef() instanceof WriteSideEffectInstruction and - chi.getPartialOperand() = opFrom and - not chi.isResultConflated() and - // In a call such as `set_value(&x->val);` we don't want the memory representing `x` to receive - // dataflow by a simple step. Instead, this is handled by field flow. If we add a simple step here - // we can get field-to-object flow. - not chi.isPartialUpdate() - ) + // Conflate references and values like in AST dataflow. + iTo.(ReferenceDereferenceInstruction).getSourceAddressOperand() = opFrom or // Flow through modeled functions modelFlow(opFrom, iTo) @@ -788,25 +1052,14 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) { */ predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) } -/** - * Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any. - */ -private Field getAField(Class c, int startBit, int endBit) { - result.getDeclaringType() = c and - startBit = 8 * result.getByteOffset() and - endBit = 8 * result.getType().getSize() + startBit - or - exists(Field f, Class cInner | - f = c.getAField() and - cInner = f.getUnderlyingType() and - result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset()) - ) -} - private newtype TContent = - TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or - TCollectionContent() or - TArrayContent() + TFieldContent(Field f) { + // As reads and writes to union fields can create flow even though the reads and writes + // target different fields, we don't want a read (write) to create a read (write) step. + not f.getDeclaringType() instanceof Union + } or + TCollectionContent() or // Not used in C/C++ + TArrayContent() // Not used in C/C++. /** * A description of the way data may be stored inside an object. Examples @@ -824,18 +1077,13 @@ class Content extends TContent { /** A reference through an instance field. */ class FieldContent extends Content, TFieldContent { - Class c; - int startBit; - int endBit; + Field f; - FieldContent() { this = TFieldContent(c, startBit, endBit) } + FieldContent() { this = TFieldContent(f) } - // Ensure that there's just 1 result for `toString`. - override string toString() { result = min(Field f | f = getAField() | f.toString()) } + override string toString() { result = f.toString() } - predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit } - - Field getAField() { result = getAField(c, startBit, endBit) } + Field getField() { result = f } } /** A reference through an array. */ diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll new file mode 100644 index 00000000000..eae5d23f544 --- /dev/null +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll @@ -0,0 +1,636 @@ +/** + * Provides a language-independent implementation of static single assignment + * (SSA) form. + */ + +private import SsaImplSpecific + +private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } + +/** + * Liveness analysis (based on source variables) to restrict the size of the + * SSA representation. + */ +private module Liveness { + /** + * A classification of variable references into reads (of a given kind) and + * (certain or uncertain) writes. + */ + private newtype TRefKind = + Read(boolean certain) { certain in [false, true] } or + Write(boolean certain) { certain in [false, true] } + + private class RefKind extends TRefKind { + string toString() { + exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") + or + exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") + } + + int getOrder() { + this = Read(_) and + result = 0 + or + this = Write(_) and + result = 1 + } + } + + /** + * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. + */ + private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { + exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) + or + exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) + } + + private newtype OrderedRefIndex = + MkOrderedRefIndex(int i, int tag) { + exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) + } + + private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { + ref(bb, i, v, k) and + result = MkOrderedRefIndex(i, ord) and + ord = k.getOrder() + } + + /** + * Gets the (1-based) rank of the reference to `v` at the `i`th node of + * basic block `bb`, which has the given reference kind `k`. + * + * Reads are considered before writes when they happen at the same index. + */ + private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { + refOrd(bb, i, v, k, _) = + rank[result](int j, int ord, OrderedRefIndex res | + res = refOrd(bb, j, v, _, ord) + | + res order by j, ord + ) + } + + private int maxRefRank(BasicBlock bb, SourceVariable v) { + result = refRank(bb, _, v, _) and + not result + 1 = refRank(bb, _, v, _) + } + + /** + * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` + * that is either a read or a certain write. + */ + private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { + result = + min(int r, RefKind k | + r = refRank(bb, _, v, k) and + k != Write(false) + | + r + ) + } + + /** + * Holds if source variable `v` is live at the beginning of basic block `bb`. + */ + predicate liveAtEntry(BasicBlock bb, SourceVariable v) { + // The first read or certain write to `v` inside `bb` is a read + refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) + or + // There is no certain write to `v` inside `bb`, but `v` is live at entry + // to a successor basic block of `bb` + not exists(firstReadOrCertainWrite(bb, v)) and + liveAtExit(bb, v) + } + + /** + * Holds if source variable `v` is live at the end of basic block `bb`. + */ + predicate liveAtExit(BasicBlock bb, SourceVariable v) { + liveAtEntry(getABasicBlockSuccessor(bb), v) + } + + /** + * Holds if variable `v` is live in basic block `bb` at index `i`. + * The rank of `i` is `rnk` as defined by `refRank()`. + */ + private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { + exists(RefKind kind | rnk = refRank(bb, i, v, kind) | + rnk = maxRefRank(bb, v) and + liveAtExit(bb, v) + or + ref(bb, i, v, kind) and + kind = Read(_) + or + exists(RefKind nextKind | + liveAtRank(bb, _, v, rnk + 1) and + rnk + 1 = refRank(bb, _, v, nextKind) and + nextKind != Write(true) + ) + ) + } + + /** + * Holds if variable `v` is live after the (certain or uncertain) write at + * index `i` inside basic block `bb`. + */ + predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { + exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) + } +} + +private import Liveness + +/** + * Holds if `df` is in the dominance frontier of `bb`. + * + * This is equivalent to: + * + * ```ql + * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and + * not bb = getImmediateBasicBlockDominator+(df) + * ``` + */ +private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { + bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) + or + exists(BasicBlock prev | inDominanceFrontier(prev, df) | + bb = getImmediateBasicBlockDominator(prev) and + not bb = getImmediateBasicBlockDominator(df) + ) +} + +/** + * Holds if `bb` is in the dominance frontier of a block containing a + * definition of `v`. + */ +pragma[noinline] +private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { + exists(BasicBlock defbb, Definition def | + def.definesAt(v, defbb, _) and + inDominanceFrontier(defbb, bb) + ) +} + +cached +newtype TDefinition = + TWriteDef(SourceVariable v, BasicBlock bb, int i) { + variableWrite(bb, i, v, _) and + liveAfterWrite(bb, i, v) + } or + TPhiNode(SourceVariable v, BasicBlock bb) { + inDefDominanceFrontier(bb, v) and + liveAtEntry(bb, v) + } + +private module SsaDefReaches { + newtype TSsaRefKind = + SsaRead() or + SsaDef() + + /** + * A classification of SSA variable references into reads and definitions. + */ + class SsaRefKind extends TSsaRefKind { + string toString() { + this = SsaRead() and + result = "SsaRead" + or + this = SsaDef() and + result = "SsaDef" + } + + int getOrder() { + this = SsaRead() and + result = 0 + or + this = SsaDef() and + result = 1 + } + } + + /** + * Holds if the `i`th node of basic block `bb` is a reference to `v`, + * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` + * is `SsaDef()`). + * + * Unlike `Liveness::ref`, this includes `phi` nodes. + */ + predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { + variableRead(bb, i, v, _) and + k = SsaRead() + or + exists(Definition def | def.definesAt(v, bb, i)) and + k = SsaDef() + } + + private newtype OrderedSsaRefIndex = + MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } + + private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { + ssaRef(bb, i, v, k) and + result = MkOrderedSsaRefIndex(i, k) and + ord = k.getOrder() + } + + /** + * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic + * block `bb`, which has the given reference kind `k`. + * + * For example, if `bb` is a basic block with a phi node for `v` (considered + * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: + * + * ```ql + * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node + * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 + * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 + * ``` + * + * Reads are considered before writes when they happen at the same index. + */ + int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { + ssaRefOrd(bb, i, v, k, _) = + rank[result](int j, int ord, OrderedSsaRefIndex res | + res = ssaRefOrd(bb, j, v, _, ord) + | + res order by j, ord + ) + } + + int maxSsaRefRank(BasicBlock bb, SourceVariable v) { + result = ssaRefRank(bb, _, v, _) and + not result + 1 = ssaRefRank(bb, _, v, _) + } + + /** + * Holds if the SSA definition `def` reaches rank index `rnk` in its own + * basic block `bb`. + */ + predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { + exists(int i | + rnk = ssaRefRank(bb, i, v, SsaDef()) and + def.definesAt(v, bb, i) + ) + or + ssaDefReachesRank(bb, def, rnk - 1, v) and + rnk = ssaRefRank(bb, _, v, SsaRead()) + } + + /** + * Holds if the SSA definition of `v` at `def` reaches index `i` in the same + * basic block `bb`, without crossing another SSA definition of `v`. + */ + predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { + exists(int rnk | + ssaDefReachesRank(bb, def, rnk, v) and + rnk = ssaRefRank(bb, i, v, SsaRead()) + ) + } + + /** + * Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition + * `redef` in the same basic block, without crossing another SSA definition of `v`. + */ + predicate ssaDefReachesUncertainDefWithinBlock( + SourceVariable v, Definition def, UncertainWriteDefinition redef + ) { + exists(BasicBlock bb, int rnk, int i | + ssaDefReachesRank(bb, def, rnk, v) and + rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and + redef.definesAt(v, bb, i) + ) + } + + /** + * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. + */ + int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { + v = def.getSourceVariable() and + result = ssaRefRank(bb, i, v, k) and + ( + ssaDefReachesRead(_, def, bb, i) + or + def.definesAt(_, bb, i) + ) + } + + /** + * Holds if the reference to `def` at index `i` in basic block `bb` is the + * last reference to `v` inside `bb`. + */ + pragma[noinline] + predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { + ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) + } + + predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) { + exists(ssaDefRank(def, v, bb, _, _)) + } + + pragma[noinline] + private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { + ssaDefReachesEndOfBlock(bb, def, _) and + not defOccursInBlock(_, bb, def.getSourceVariable()) + } + + /** + * Holds if `def` is accessed in basic block `bb1` (either a read or a write), + * `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`, + * and the underlying variable for `def` is neither read nor written in any block + * on the path between `bb1` and `bb2`. + */ + predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { + defOccursInBlock(def, bb1, _) and + bb2 = getABasicBlockSuccessor(bb1) + or + exists(BasicBlock mid | + varBlockReaches(def, bb1, mid) and + ssaDefReachesThroughBlock(def, mid) and + bb2 = getABasicBlockSuccessor(mid) + ) + } + + /** + * Holds if `def` is accessed in basic block `bb1` (either a read or a write), + * `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive + * successor block of `bb1`, and `def` is neither read nor written in any block + * on a path between `bb1` and `bb2`. + */ + predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { + varBlockReaches(def, bb1, bb2) and + ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 + } +} + +private import SsaDefReaches + +pragma[nomagic] +predicate liveThrough(BasicBlock bb, SourceVariable v) { + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches the end of basic + * block `bb`, at which point it is still live, without crossing another + * SSA definition of `v`. + */ +pragma[nomagic] +predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { + exists(int last | last = maxSsaRefRank(bb, v) | + ssaDefReachesRank(bb, def, last, v) and + liveAtExit(bb, v) + ) + or + // The construction of SSA form ensures that each read of a variable is + // dominated by its definition. An SSA definition therefore reaches a + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and + liveThrough(bb, pragma[only_bind_into](v)) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. + */ +pragma[nomagic] +predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { + exists(SourceVariable v, BasicBlock bbDef | + phi.definesAt(v, bbDef, _) and + getABasicBlockPredecessor(bbDef) = bb and + ssaDefReachesEndOfBlock(bb, inp, v) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in + * basic block `bb`, without crossing another SSA definition of `v`. The read + * is of kind `rk`. + */ +pragma[nomagic] +predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { + ssaDefReachesReadWithinBlock(v, def, bb, i) + or + variableRead(bb, i, v, _) and + ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and + not ssaDefReachesReadWithinBlock(v, _, bb, i) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read + * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a + * path between them without any read of `def`. + */ +pragma[nomagic] +predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + exists(int rnk | + rnk = ssaDefRank(def, _, bb1, i1, _) and + rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and + variableRead(bb1, i2, _, _) and + bb2 = bb1 + ) + or + lastSsaRef(def, _, bb1, i1) and + defAdjacentRead(def, bb1, bb2, i2) +} + +pragma[noinline] +private predicate adjacentDefRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v +) { + adjacentDefRead(def, bb1, i1, bb2, i2) and + v = def.getSourceVariable() +} + +private predicate adjacentDefReachesRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) | + ssaRef(bb1, i1, v, SsaDef()) + or + variableRead(bb1, i1, v, true) + ) + or + exists(BasicBlock bb3, int i3 | + adjacentDefReachesRead(def, bb1, i1, bb3, i3) and + variableRead(bb3, i3, _, false) and + adjacentDefRead(def, bb3, i3, bb2, i2) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `adjacentDefRead`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, true) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the node at index `i` in `bb` is a last reference to SSA definition + * `def`. The reference is last because it can reach another write `next`, + * without passing through another read or write. + */ +pragma[nomagic] +predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { + exists(SourceVariable v | + // Next reference to `v` inside `bb` is a write + exists(int rnk, int j | + rnk = ssaDefRank(def, v, bb, i, _) and + next.definesAt(v, bb, j) and + rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) + ) + or + // Can reach a write using one or more steps + lastSsaRef(def, v, bb, i) and + exists(BasicBlock bb2 | + varBlockReaches(def, bb, bb2) and + 1 = ssaDefRank(next, v, bb2, _, SsaDef()) + ) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an immediately preceding definition of uncertain definition + * `def`. Since `def` is uncertain, the value from the preceding definition might + * still be valid. + */ +pragma[nomagic] +predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { + lastRefRedef(inp, _, _, def) +} + +private predicate adjacentDefReachesUncertainRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, false) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { + lastRefRedef(def, bb, i, next) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRefRedef(def, bb0, i0, next) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the node at index `i` in `bb` is a last reference to SSA + * definition `def`. + * + * That is, the node can reach the end of the enclosing callable, or another + * SSA definition for the underlying source variable, without passing through + * another read. + */ +pragma[nomagic] +predicate lastRef(Definition def, BasicBlock bb, int i) { + lastRefRedef(def, bb, i, _) + or + lastSsaRef(def, _, bb, i) and + ( + // Can reach exit directly + bb instanceof ExitBasicBlock + or + // Can reach a block using one or more steps, where `def` is no longer live + exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) | + not defOccursInBlock(def, bb2, _) and + not ssaDefReachesEndOfBlock(bb2, def, _) + ) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { + lastRef(def, bb, i) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRef(def, bb0, i0) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + +/** A static single assignment (SSA) definition. */ +class Definition extends TDefinition { + /** Gets the source variable underlying this SSA definition. */ + SourceVariable getSourceVariable() { this.definesAt(result, _, _) } + + /** + * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. + * Phi nodes are considered to be at index `-1`, while normal variable writes + * are at the index of the control flow node they wrap. + */ + final predicate definesAt(SourceVariable v, BasicBlock bb, int i) { + this = TWriteDef(v, bb, i) + or + this = TPhiNode(v, bb) and i = -1 + } + + /** Gets the basic block to which this SSA definition belongs. */ + final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } + + /** Gets a textual representation of this SSA definition. */ + string toString() { none() } +} + +/** An SSA definition that corresponds to a write. */ +class WriteDefinition extends Definition, TWriteDef { + private SourceVariable v; + private BasicBlock bb; + private int i; + + WriteDefinition() { this = TWriteDef(v, bb, i) } + + override string toString() { result = "WriteDef" } +} + +/** A phi node. */ +class PhiNode extends Definition, TPhiNode { + override string toString() { result = "Phi" } +} + +/** + * An SSA definition that represents an uncertain update of the underlying + * source variable. + */ +class UncertainWriteDefinition extends WriteDefinition { + UncertainWriteDefinition() { + exists(SourceVariable v, BasicBlock bb, int i | + this.definesAt(v, bb, i) and + variableWrite(bb, i, v, false) + ) + } +} diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplSpecific.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplSpecific.qll new file mode 100644 index 00000000000..20f9d1894b1 --- /dev/null +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplSpecific.qll @@ -0,0 +1,18 @@ +private import semmle.code.cpp.ir.IR +private import SsaInternals as Ssa + +class BasicBlock = IRBlock; + +class SourceVariable = Ssa::SourceVariable; + +BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) } + +BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + +class ExitBasicBlock extends IRBlock { + ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction } +} + +predicate variableWrite = Ssa::variableWrite/4; + +predicate variableRead = Ssa::variableRead/4; diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll new file mode 100644 index 00000000000..1a353072be5 --- /dev/null +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll @@ -0,0 +1,600 @@ +import SsaImplCommon +private import cpp as Cpp +private import semmle.code.cpp.ir.IR +private import DataFlowUtil +private import DataFlowImplCommon as DataFlowImplCommon +private import semmle.code.cpp.models.interfaces.Allocation as Alloc +private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow + +private module SourceVariables { + private newtype TSourceVariable = + TSourceIRVariable(IRVariable var) or + TSourceIRVariableIndirection(InitializeIndirectionInstruction init) + + abstract class SourceVariable extends TSourceVariable { + IRVariable var; + + abstract string toString(); + } + + class SourceIRVariable extends SourceVariable, TSourceIRVariable { + SourceIRVariable() { this = TSourceIRVariable(var) } + + IRVariable getIRVariable() { result = var } + + override string toString() { result = this.getIRVariable().toString() } + } + + class SourceIRVariableIndirection extends SourceVariable, TSourceIRVariableIndirection { + InitializeIndirectionInstruction init; + + SourceIRVariableIndirection() { + this = TSourceIRVariableIndirection(init) and var = init.getIRVariable() + } + + IRVariable getUnderlyingIRVariable() { result = var } + + override string toString() { result = "*" + this.getUnderlyingIRVariable().toString() } + } +} + +import SourceVariables + +cached +private newtype TDefOrUse = + TExplicitDef(Instruction store) { explicitWrite(_, store, _) } or + TInitializeParam(Instruction instr) { + instr instanceof InitializeParameterInstruction + or + instr instanceof InitializeIndirectionInstruction + } or + TExplicitUse(Operand op) { isExplicitUse(op) } or + TReturnParamIndirection(Operand op) { returnParameterIndirection(op, _) } + +pragma[nomagic] +private int getRank(DefOrUse defOrUse, IRBlock block) { + defOrUse = + rank[result](int i, DefOrUse cand | + block.getInstruction(i) = toInstruction(cand) + | + cand order by i + ) +} + +private class DefOrUse extends TDefOrUse { + /** Gets the instruction associated with this definition, if any. */ + Instruction asDef() { none() } + + /** Gets the operand associated with this use, if any. */ + Operand asUse() { none() } + + /** Gets a textual representation of this element. */ + abstract string toString(); + + /** Gets the block of this definition or use. */ + abstract IRBlock getBlock(); + + /** Holds if this definition or use has rank `rank` in block `block`. */ + cached + final predicate hasRankInBlock(IRBlock block, int rnk) { rnk = getRank(this, block) } + + /** Gets the location of this element. */ + abstract Cpp::Location getLocation(); +} + +private Instruction toInstruction(DefOrUse defOrUse) { + result = defOrUse.asDef() + or + result = defOrUse.asUse().getUse() +} + +abstract class Def extends DefOrUse { + Instruction store; + + /** Gets the instruction of this definition. */ + Instruction getInstruction() { result = store } + + /** Gets the variable that is defined by this definition. */ + abstract SourceVariable getSourceVariable(); + + /** Holds if this definition is guaranteed to happen. */ + abstract predicate isCertain(); + + override Instruction asDef() { result = this.getInstruction() } + + override string toString() { result = "Def" } + + override IRBlock getBlock() { result = this.getInstruction().getBlock() } + + override Cpp::Location getLocation() { result = store.getLocation() } +} + +private class ExplicitDef extends Def, TExplicitDef { + ExplicitDef() { this = TExplicitDef(store) } + + override SourceVariable getSourceVariable() { + exists(VariableInstruction var | + explicitWrite(_, this.getInstruction(), var) and + result.(SourceIRVariable).getIRVariable() = var.getIRVariable() + ) + } + + override predicate isCertain() { explicitWrite(true, this.getInstruction(), _) } +} + +private class ParameterDef extends Def, TInitializeParam { + ParameterDef() { this = TInitializeParam(store) } + + override SourceVariable getSourceVariable() { + result.(SourceIRVariable).getIRVariable() = + store.(InitializeParameterInstruction).getIRVariable() + or + result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = + store.(InitializeIndirectionInstruction).getIRVariable() + } + + override predicate isCertain() { any() } +} + +abstract class Use extends DefOrUse { + Operand use; + + override Operand asUse() { result = use } + + /** Gets the underlying operand of this use. */ + Operand getOperand() { result = use } + + override string toString() { result = "Use" } + + /** Gets the variable that is used by this use. */ + abstract SourceVariable getSourceVariable(); + + override IRBlock getBlock() { result = use.getUse().getBlock() } + + override Cpp::Location getLocation() { result = use.getLocation() } +} + +private class ExplicitUse extends Use, TExplicitUse { + ExplicitUse() { this = TExplicitUse(use) } + + override SourceVariable getSourceVariable() { + exists(VariableInstruction var | + use.getDef() = var and + if use.getUse() instanceof ReadSideEffectInstruction + then result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = var.getIRVariable() + else result.(SourceIRVariable).getIRVariable() = var.getIRVariable() + ) + } +} + +private class ReturnParameterIndirection extends Use, TReturnParamIndirection { + ReturnParameterIndirection() { this = TReturnParamIndirection(use) } + + override SourceVariable getSourceVariable() { + exists(ReturnIndirectionInstruction ret | + returnParameterIndirection(use, ret) and + result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = ret.getIRVariable() + ) + } +} + +private predicate isExplicitUse(Operand op) { + op.getDef() instanceof VariableAddressInstruction and + not exists(LoadInstruction load | + load.getSourceAddressOperand() = op and + load.getAUse().getUse() instanceof InitializeIndirectionInstruction + ) +} + +private predicate returnParameterIndirection(Operand op, ReturnIndirectionInstruction ret) { + ret.getSourceAddressOperand() = op +} + +/** + * Holds if `iFrom` computes an address that is used by `iTo`. + */ +predicate addressFlow(Instruction iFrom, Instruction iTo) { + iTo.(CopyValueInstruction).getSourceValue() = iFrom + or + iTo.(ConvertInstruction).getUnary() = iFrom + or + iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom + or + iTo.(InheritanceConversionInstruction).getUnary() = iFrom + or + iTo.(PointerArithmeticInstruction).getLeft() = iFrom + or + iTo.(FieldAddressInstruction).getObjectAddress() = iFrom + or + // We traverse `LoadInstruction`s since we want to conclude that the + // destination of the store operation `*x = source()` is derived from `x`. + iTo.(LoadInstruction).getSourceAddress() = iFrom + or + // We want to include `ReadSideEffectInstruction`s for the same reason that we include + // `LoadInstruction`s, but only when a `WriteSideEffectInstruction` for the same index exists as well + // (as otherwise we know that the callee won't override the data). However, given an index `i`, the + // destination of the `WriteSideEffectInstruction` for `i` is identical to the source address of the + // `ReadSideEffectInstruction` for `i`. So we don't have to talk about the `ReadSideEffectInstruction` + // at all. + exists(WriteSideEffectInstruction write | + write.getPrimaryInstruction() = iTo and + write.getDestinationAddress() = iFrom + ) +} + +/** + * The reflexive, transitive closure of `addressFlow` that ends as the address of a + * store or read operation. + */ +cached +predicate addressFlowTC(Instruction iFrom, Instruction iTo) { + iTo = [getDestinationAddress(_), getSourceAddress(_)] and + addressFlow*(iFrom, iTo) +} + +/** + * Gets the destination address of `instr` if it is a `StoreInstruction` or + * a `WriteSideEffectInstruction`. + */ +Instruction getDestinationAddress(Instruction instr) { + result = + [ + instr.(StoreInstruction).getDestinationAddress(), + instr.(WriteSideEffectInstruction).getDestinationAddress() + ] +} + +class ReferenceToInstruction extends CopyValueInstruction { + ReferenceToInstruction() { + this.getResultType() instanceof Cpp::ReferenceType and + not this.getUnary().getResultType() instanceof Cpp::ReferenceType + } + + Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + + Operand getSourceAddressOperand() { result = this.getUnaryOperand() } +} + +/** Gets the source address of `instr` if it is an instruction that behaves like a `LoadInstruction`. */ +Instruction getSourceAddress(Instruction instr) { result = getSourceAddressOperand(instr).getDef() } + +/** + * Gets the operand that represents the source address of `instr` if it is an + * instruction that behaves like a `LoadInstruction`. + */ +Operand getSourceAddressOperand(Instruction instr) { + result = + [ + instr.(LoadInstruction).getSourceAddressOperand(), + instr.(ReadSideEffectInstruction).getArgumentOperand(), + // `ReferenceToInstruction` is really more of an address-of operation, + // but by including it in this list we break out of `flowOutOfAddressStep` at an + // instruction that, at the source level, looks like a use of a variable. + instr.(ReferenceToInstruction).getSourceAddressOperand() + ] +} + +/** + * Gets the source address of `node` if it's an instruction or operand that + * behaves like a `LoadInstruction`. + */ +Instruction getSourceAddressFromNode(Node node) { + result = getSourceAddress(node.asInstruction()) + or + result = getSourceAddress(node.asOperand().(SideEffectOperand).getUse()) +} + +/** Gets the source value of `instr` if it's an instruction that behaves like a `LoadInstruction`. */ +Instruction getSourceValue(Instruction instr) { result = getSourceValueOperand(instr).getDef() } + +/** + * Gets the operand that represents the source value of `instr` if it's an instruction + * that behaves like a `LoadInstruction`. + */ +Operand getSourceValueOperand(Instruction instr) { + result = instr.(LoadInstruction).getSourceValueOperand() + or + result = instr.(ReadSideEffectInstruction).getSideEffectOperand() + or + // See the comment on the `ReferenceToInstruction` disjunct in `getSourceAddressOperand` for why + // this case is included. + result = instr.(ReferenceToInstruction).getSourceValueOperand() +} + +/** + * Holds if `instr` is a `StoreInstruction` or a `WriteSideEffectInstruction` that writes to an address. + * The addresses is computed using `address`, and `certain` is `true` if the write is guaranteed to overwrite + * the entire variable. + */ +cached +predicate explicitWrite(boolean certain, Instruction instr, Instruction address) { + exists(StoreInstruction store | + store = instr and addressFlowTC(address, store.getDestinationAddress()) + | + // Set `certain = false` if the address is derived from any instructions that prevents us from + // concluding that the entire variable is overridden. + if + addressFlowTC(any(Instruction i | + i instanceof FieldAddressInstruction or + i instanceof PointerArithmeticInstruction or + i instanceof LoadInstruction or + i instanceof InheritanceConversionInstruction + ), store.getDestinationAddress()) + then certain = false + else certain = true + ) + or + addressFlowTC(address, instr.(WriteSideEffectInstruction).getDestinationAddress()) and + certain = false +} + +cached +private module Cached { + private predicate defUseFlow(Node nodeFrom, Node nodeTo) { + exists(IRBlock bb1, int i1, IRBlock bb2, int i2, DefOrUse defOrUse, Use use | + defOrUse.hasRankInBlock(bb1, i1) and + use.hasRankInBlock(bb2, i2) and + adjacentDefRead(_, bb1, i1, bb2, i2) and + nodeFrom.asInstruction() = toInstruction(defOrUse) and + flowOutOfAddressStep(use.getOperand(), nodeTo) + ) + } + + private predicate fromStoreNode(StoreNodeInstr nodeFrom, Node nodeTo) { + // Def-use flow from a `StoreNode`. + exists(IRBlock bb1, int i1, IRBlock bb2, int i2, Def def, Use use | + nodeFrom.isTerminal() and + def.getInstruction() = nodeFrom.getStoreInstruction() and + def.hasRankInBlock(bb1, i1) and + adjacentDefRead(_, bb1, i1, bb2, i2) and + use.hasRankInBlock(bb2, i2) and + flowOutOfAddressStep(use.getOperand(), nodeTo) + ) + or + // This final case is a bit annoying. The write side effect on an expression like `a = new A;` writes + // to a fresh address returned by `operator new`, and there's no easy way to use the shared SSA + // library to hook that up to the assignment to `a`. So instead we flow to the _first_ use of the + // value computed by `operator new` that occurs after `nodeFrom` (to avoid a loop in the + // dataflow graph). + exists(WriteSideEffectInstruction write, IRBlock bb, int i1, int i2, Operand op | + nodeFrom.getInstruction().(CallInstruction).getStaticCallTarget() instanceof + Alloc::OperatorNewAllocationFunction and + write = nodeFrom.getStoreInstruction() and + bb.getInstruction(i1) = write and + bb.getInstruction(i2) = op.getUse() and + // Flow to an instruction that occurs later in the block. + conversionFlow*(nodeFrom.getInstruction(), op.getDef()) and + nodeTo.asOperand() = op and + i2 > i1 and + // There is no previous instruction that also occurs after `nodeFrom`. + not exists(Instruction instr, int i | + bb.getInstruction(i) = instr and + conversionFlow(instr, op.getDef()) and + i1 < i and + i < i2 + ) + ) + } + + private predicate fromReadNode(ReadNode nodeFrom, Node nodeTo) { + exists(IRBlock bb1, int i1, IRBlock bb2, int i2, Use use1, Use use2 | + use1.hasRankInBlock(bb1, i1) and + use2.hasRankInBlock(bb2, i2) and + use1.getOperand().getDef() = nodeFrom.getInstruction() and + adjacentDefRead(_, bb1, i1, bb2, i2) and + flowOutOfAddressStep(use2.getOperand(), nodeTo) + ) + } + + private predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) { + exists(PhiNode phi, Use use, IRBlock block, int rnk | + phi = nodeFrom.getPhiNode() and + adjacentDefRead(phi, _, _, block, rnk) and + use.hasRankInBlock(block, rnk) and + flowOutOfAddressStep(use.getOperand(), nodeTo) + ) + } + + private predicate toPhiNode(Node nodeFrom, SsaPhiNode nodeTo) { + // Flow to phi nodes + exists(Def def, IRBlock block, int rnk | + def.hasRankInBlock(block, rnk) and + nodeTo.hasInputAtRankInBlock(block, rnk) + | + exists(StoreNodeInstr storeNode | + storeNode = nodeFrom and + storeNode.isTerminal() and + def.getInstruction() = storeNode.getStoreInstruction() + ) + or + def.getInstruction() = nodeFrom.asInstruction() + ) + or + // Phi -> phi flow + nodeTo.hasInputAtRankInBlock(_, _, nodeFrom.(SsaPhiNode).getPhiNode()) + } + + /** + * Holds if `nodeFrom` is a read or write, and `nTo` is the next subsequent read of the variable + * written (or read) by `storeOrRead`. + */ + cached + predicate ssaFlow(Node nodeFrom, Node nodeTo) { + // Def-use/use-use flow from an `InstructionNode`. + defUseFlow(nodeFrom, nodeTo) + or + // Def-use flow from a `StoreNode`. + fromStoreNode(nodeFrom, nodeTo) + or + // Use-use flow from a `ReadNode`. + fromReadNode(nodeFrom, nodeTo) + or + fromPhiNode(nodeFrom, nodeTo) + or + toPhiNode(nodeFrom, nodeTo) + or + // When we want to transfer flow out of a `StoreNode` we perform two steps: + // 1. Find the next use of the address being stored to + // 2. Find the `LoadInstruction` that loads the address + // When the address being stored into doesn't have a `LoadInstruction` associated with it because it's + // passed into a `CallInstruction` we transfer flow to the `ReadSideEffect`, which will then flow into + // the callee. We then pickup the flow from the `InitializeIndirectionInstruction` and use the shared + // SSA library to determine where the next use of the address that received the flow is. + exists(Node init, Node mid | + nodeFrom.asInstruction().(InitializeIndirectionInstruction).getIRVariable() = + init.asInstruction().(InitializeParameterInstruction).getIRVariable() and + // No need for the flow if the next use is the instruction that returns the flow out of the callee. + not mid.asInstruction() instanceof ReturnIndirectionInstruction and + // Find the next use of the address + ssaFlow(init, mid) and + // And flow to the next load of that address + flowOutOfAddressStep([mid.asInstruction().getAUse(), mid.asOperand()], nodeTo) + ) + } + + /** + * Holds if `iTo` is a conversion-like instruction that copies + * the value computed by `iFrom`. + * + * This predicate is used by `fromStoreNode` to find the next use of a pointer that + * points to freshly allocated memory. + */ + private predicate conversionFlow(Instruction iFrom, Instruction iTo) { + iTo.(CopyValueInstruction).getSourceValue() = iFrom + or + iTo.(ConvertInstruction).getUnary() = iFrom + or + iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom + or + iTo.(InheritanceConversionInstruction).getUnary() = iFrom + } + + pragma[noinline] + private predicate callTargetHasInputOutput( + CallInstruction call, DataFlow::FunctionInput input, DataFlow::FunctionOutput output + ) { + exists(DataFlow::DataFlowFunction func | + call.getStaticCallTarget() = func and + func.hasDataFlow(input, output) + ) + } + + /** + * The role of `flowOutOfAddressStep` is to select the node for which we want dataflow to end up in + * after the shared SSA library's `adjacentDefRead` predicate has determined that `operand` is the + * next use of some variable. + * + * More precisely, this predicate holds if `operand` is an operand that represents an address, and: + * - `nodeTo` is the next load of that address, or + * - `nodeTo` is a `ReadNode` that uses the definition of `operand` to start a sequence of reads, or + * - `nodeTo` is the outer-most `StoreNode` that uses the address represented by `operand`. We obtain + * use-use flow in this case since `StoreNodeFlow::flowOutOf` will then provide flow to the next of + * of `operand`. + * + * There is one final (slightly annoying) case: When `operand` is a an argument to a modeled function + * without any `ReadSideEffect` (such as `std::move`). Here, the address flows from the argument to + * the return value, which might then be read later. + */ + private predicate flowOutOfAddressStep(Operand operand, Node nodeTo) { + // Flow into a read node + exists(ReadNode readNode | readNode = nodeTo | + readNode.isInitial() and + operand.getDef() = readNode.getInstruction() + ) + or + exists(StoreNodeInstr storeNode, Instruction def | + storeNode = nodeTo and + def = operand.getDef() + | + storeNode.isTerminal() and + not addressFlow(def, _) and + // Only transfer flow to a store node if it doesn't immediately overwrite the address + // we've just written to. + explicitWrite(false, storeNode.getStoreInstruction(), def) + ) + or + operand = getSourceAddressOperand(nodeTo.asInstruction()) + or + exists(ReturnIndirectionInstruction ret | + ret.getSourceAddressOperand() = operand and + ret = nodeTo.asInstruction() + ) + or + exists(ReturnValueInstruction ret | + ret.getReturnAddressOperand() = operand and + nodeTo.asInstruction() = ret + ) + or + exists(CallInstruction call, int index, ReadSideEffectInstruction read | + call.getArgumentOperand(index) = operand and + read = getSideEffectFor(call, index) and + nodeTo.asOperand() = read.getSideEffectOperand() + ) + or + exists(CopyInstruction copy | + not exists(getSourceAddressOperand(copy)) and + copy.getSourceValueOperand() = operand and + flowOutOfAddressStep(copy.getAUse(), nodeTo) + ) + or + exists(ConvertInstruction convert | + convert.getUnaryOperand() = operand and + flowOutOfAddressStep(convert.getAUse(), nodeTo) + ) + or + exists(CheckedConvertOrNullInstruction convert | + convert.getUnaryOperand() = operand and + flowOutOfAddressStep(convert.getAUse(), nodeTo) + ) + or + exists(InheritanceConversionInstruction convert | + convert.getUnaryOperand() = operand and + flowOutOfAddressStep(convert.getAUse(), nodeTo) + ) + or + exists(PointerArithmeticInstruction arith | + arith.getLeftOperand() = operand and + flowOutOfAddressStep(arith.getAUse(), nodeTo) + ) + or + // Flow through a modeled function that has parameter -> return value flow. + exists( + CallInstruction call, int index, DataFlow::FunctionInput input, + DataFlow::FunctionOutput output + | + callTargetHasInputOutput(call, input, output) and + call.getArgumentOperand(index) = operand and + not getSideEffectFor(call, index) instanceof ReadSideEffectInstruction and + input.isParameter(index) and + output.isReturnValue() and + flowOutOfAddressStep(call.getAUse(), nodeTo) + ) + } +} + +import Cached + +/** + * Holds if the `i`'th write in block `bb` writes to the variable `v`. + * `certain` is `true` if the write is guaranteed to overwrite the entire variable. + */ +predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) { + DataFlowImplCommon::forceCachingInSameStage() and + exists(Def def | + def.hasRankInBlock(bb, i) and + v = def.getSourceVariable() and + (if def.isCertain() then certain = true else certain = false) + ) +} + +/** + * Holds if the `i`'th read in block `bb` reads to the variable `v`. + * `certain` is `true` if the read is guaranteed. For C++, this is always the case. + */ +predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) { + exists(Use use | + use.hasRankInBlock(bb, i) and + v = use.getSourceVariable() and + certain = true + ) +} diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index f563e47db9f..287958ebea4 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -44,8 +44,6 @@ private predicate instructionToOperandTaintStep(Instruction fromInstr, Operand t fromInstr = readInstr.getArgumentDef() and toOperand = readInstr.getSideEffectOperand() ) - or - toOperand.(LoadOperand).getAnyDef() = fromInstr } /** @@ -84,8 +82,6 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union ) or - instrTo.(LoadInstruction).getSourceAddressOperand() = opFrom - or // Flow from an element to an array or union that contains it. instrTo.(ChiInstruction).getPartialOperand() = opFrom and not instrTo.isResultConflated() and diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index 4b86f9a7cec..bb8630a5e0c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -24,7 +24,7 @@ class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ - final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() } /** * INTERNAL: Do not use. @@ -39,7 +39,7 @@ class IRBlockBase extends TIRBlock { ) and this = rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 | - funcBlock.getEnclosingFunction() = getEnclosingFunction() and + funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and // Ensure that the block containing `EnterFunction` always comes first. if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction @@ -59,15 +59,15 @@ class IRBlockBase extends TIRBlock { * Get the `Phi` instructions that appear at the start of this block. */ final PhiInstruction getAPhiInstruction() { - Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() + Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction() } /** * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { - result = getInstruction(_) or - result = getAPhiInstruction() + result = this.getInstruction(_) or + result = this.getAPhiInstruction() } /** @@ -78,7 +78,9 @@ class IRBlockBase extends TIRBlock { /** * Gets the last instruction in this block. */ - final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + final Instruction getLastInstruction() { + result = this.getInstruction(this.getInstructionCount() - 1) + } /** * Gets the number of non-`Phi` instructions in this block. @@ -149,7 +151,7 @@ class IRBlock extends IRBlockBase { * Block `A` dominates block `B` if any control flow path from the entry block of the function to * block `B` must pass through block `A`. A block always dominates itself. */ - final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block } /** * Gets a block on the dominance frontier of this block. @@ -159,8 +161,8 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock dominanceFrontier() { - dominates(result.getAPredecessor()) and - not strictlyDominates(result) + this.dominates(result.getAPredecessor()) and + not this.strictlyDominates(result) } /** @@ -189,7 +191,7 @@ class IRBlock extends IRBlockBase { * Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the * function must pass through block `A`. A block always post-dominates itself. */ - final predicate postDominates(IRBlock block) { strictlyPostDominates(block) or this = block } + final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block } /** * Gets a block on the post-dominance frontier of this block. @@ -199,16 +201,16 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock postPominanceFrontier() { - postDominates(result.getASuccessor()) and - not strictlyPostDominates(result) + this.postDominates(result.getASuccessor()) and + not this.strictlyPostDominates(result) } /** * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { - this = getEnclosingIRFunction().getEntryBlock() or - getAPredecessor().isReachableFromFunctionEntry() + this = this.getEnclosingIRFunction().getEntryBlock() or + this.getAPredecessor().isReachableFromFunctionEntry() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 6f471d8a7e8..1c2cc493338 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction { } /** Gets a textual representation of this element. */ - final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } + final string toString() { result = this.getOpcode().toString() + ": " + this.getAST().toString() } /** * Gets a string showing the result, opcode, and operands of the instruction, equivalent to what @@ -50,7 +50,8 @@ class Instruction extends Construction::TStageInstruction { * `mu0_28(int) = Store r0_26, r0_27` */ final string getDumpString() { - result = getResultString() + " = " + getOperationString() + " " + getOperandsString() + result = + this.getResultString() + " = " + this.getOperationString() + " " + this.getOperandsString() } private predicate shouldGenerateDumpStrings() { @@ -66,10 +67,13 @@ class Instruction extends Construction::TStageInstruction { * VariableAddress[x] */ final string getOperationString() { - shouldGenerateDumpStrings() and - if exists(getImmediateString()) - then result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]" - else result = getOperationPrefix() + getOpcode().toString() + this.shouldGenerateDumpStrings() and + if exists(this.getImmediateString()) + then + result = + this.getOperationPrefix() + this.getOpcode().toString() + "[" + this.getImmediateString() + + "]" + else result = this.getOperationPrefix() + this.getOpcode().toString() } /** @@ -78,17 +82,17 @@ class Instruction extends Construction::TStageInstruction { string getImmediateString() { none() } private string getOperationPrefix() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and if this instanceof SideEffectInstruction then result = "^" else result = "" } private string getResultPrefix() { - shouldGenerateDumpStrings() and - if getResultIRType() instanceof IRVoidType + this.shouldGenerateDumpStrings() and + if this.getResultIRType() instanceof IRVoidType then result = "v" else - if hasMemoryResult() - then if isResultModeled() then result = "m" else result = "mu" + if this.hasMemoryResult() + then if this.isResultModeled() then result = "m" else result = "mu" else result = "r" } @@ -97,7 +101,7 @@ class Instruction extends Construction::TStageInstruction { * used by debugging and printing code only. */ int getDisplayIndexInBlock() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and exists(IRBlock block | this = block.getInstruction(result) or @@ -111,12 +115,12 @@ class Instruction extends Construction::TStageInstruction { } private int getLineRank() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and this = rank[result](Instruction instr | instr = - getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(), - getLocation().getStartLine()) + getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(), + this.getLocation().getStartLine()) | instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() ) @@ -130,8 +134,9 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1` */ string getResultId() { - shouldGenerateDumpStrings() and - result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank() + this.shouldGenerateDumpStrings() and + result = + this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank() } /** @@ -142,8 +147,8 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1(int*)` */ final string getResultString() { - shouldGenerateDumpStrings() and - result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + this.shouldGenerateDumpStrings() and + result = this.getResultId() + "(" + this.getResultLanguageType().getDumpString() + ")" } /** @@ -153,10 +158,10 @@ class Instruction extends Construction::TStageInstruction { * Example: `func:r3_4, this:r3_5` */ string getOperandsString() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and result = concat(Operand operand | - operand = getAnOperand() + operand = this.getAnOperand() | operand.getDumpString(), ", " order by operand.getDumpSortOrder() ) @@ -190,7 +195,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the function that contains this instruction. */ final Language::Function getEnclosingFunction() { - result = getEnclosingIRFunction().getFunction() + result = this.getEnclosingIRFunction().getFunction() } /** @@ -208,7 +213,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets the location of the source code for this instruction. */ - final Language::Location getLocation() { result = getAST().getLocation() } + final Language::Location getLocation() { result = this.getAST().getLocation() } /** * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a @@ -243,7 +248,7 @@ class Instruction extends Construction::TStageInstruction { * a result, its result type will be `IRVoidType`. */ cached - final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() } /** * Gets the type of the result produced by this instruction. If the @@ -254,7 +259,7 @@ class Instruction extends Construction::TStageInstruction { */ final Language::Type getResultType() { exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and + resultType = this.getResultLanguageType() and ( resultType.hasUnspecifiedType(result, _) or @@ -283,7 +288,7 @@ class Instruction extends Construction::TStageInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { getResultLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -292,7 +297,7 @@ class Instruction extends Construction::TStageInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = getResultLanguageType().getByteSize() } + final int getResultSize() { result = this.getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -314,14 +319,16 @@ class Instruction extends Construction::TStageInstruction { /** * Holds if this instruction produces a memory result. */ - final predicate hasMemoryResult() { exists(getResultMemoryAccess()) } + final predicate hasMemoryResult() { exists(this.getResultMemoryAccess()) } /** * Gets the kind of memory access performed by this instruction's result. * Holds only for instructions with a memory result. */ pragma[inline] - final MemoryAccessKind getResultMemoryAccess() { result = getOpcode().getWriteMemoryAccess() } + final MemoryAccessKind getResultMemoryAccess() { + result = this.getOpcode().getWriteMemoryAccess() + } /** * Holds if the memory access performed by this instruction's result will not always write to @@ -332,7 +339,7 @@ class Instruction extends Construction::TStageInstruction { * (for example, the global side effects of a function call). */ pragma[inline] - final predicate hasResultMayMemoryAccess() { getOpcode().hasMayWriteMemoryAccess() } + final predicate hasResultMayMemoryAccess() { this.getOpcode().hasMayWriteMemoryAccess() } /** * Gets the operand that holds the memory address to which this instruction stores its @@ -340,7 +347,7 @@ class Instruction extends Construction::TStageInstruction { * is `r1`. */ final AddressOperand getResultAddressOperand() { - getResultMemoryAccess().usesAddressOperand() and + this.getResultMemoryAccess().usesAddressOperand() and result.getUse() = this } @@ -349,7 +356,7 @@ class Instruction extends Construction::TStageInstruction { * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` * is the instruction that defines `r1`. */ - final Instruction getResultAddress() { result = getResultAddressOperand().getDef() } + final Instruction getResultAddress() { result = this.getResultAddressOperand().getDef() } /** * Holds if the result of this instruction is precisely modeled in SSA. Always @@ -368,7 +375,7 @@ class Instruction extends Construction::TStageInstruction { */ final predicate isResultModeled() { // Register results are always in SSA form. - not hasMemoryResult() or + not this.hasMemoryResult() or Construction::hasModeledMemoryResult(this) } @@ -412,7 +419,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct successors of this instruction. */ - final Instruction getASuccessor() { result = getSuccessor(_) } + final Instruction getASuccessor() { result = this.getSuccessor(_) } /** * Gets a predecessor of this instruction such that the predecessor reaches @@ -423,7 +430,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct predecessors of this instruction. */ - final Instruction getAPredecessor() { result = getPredecessor(_) } + final Instruction getAPredecessor() { result = this.getPredecessor(_) } } /** @@ -543,7 +550,7 @@ class IndexedInstruction extends Instruction { * at this instruction. This instruction has no predecessors. */ class EnterFunctionInstruction extends Instruction { - EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } + EnterFunctionInstruction() { this.getOpcode() instanceof Opcode::EnterFunction } } /** @@ -554,7 +561,7 @@ class EnterFunctionInstruction extends Instruction { * struct, or union, see `FieldAddressInstruction`. */ class VariableAddressInstruction extends VariableInstruction { - VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } + VariableAddressInstruction() { this.getOpcode() instanceof Opcode::VariableAddress } } /** @@ -566,7 +573,7 @@ class VariableAddressInstruction extends VariableInstruction { * The result has an `IRFunctionAddress` type. */ class FunctionAddressInstruction extends FunctionInstruction { - FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } + FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress } } /** @@ -577,7 +584,7 @@ class FunctionAddressInstruction extends FunctionInstruction { * initializes that parameter. */ class InitializeParameterInstruction extends VariableInstruction { - InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + InitializeParameterInstruction() { this.getOpcode() instanceof Opcode::InitializeParameter } /** * Gets the parameter initialized by this instruction. @@ -603,7 +610,7 @@ class InitializeParameterInstruction extends VariableInstruction { * initialized elsewhere, would not otherwise have a definition in this function. */ class InitializeNonLocalInstruction extends Instruction { - InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } + InitializeNonLocalInstruction() { this.getOpcode() instanceof Opcode::InitializeNonLocal } } /** @@ -611,7 +618,7 @@ class InitializeNonLocalInstruction extends Instruction { * with the value of that memory on entry to the function. */ class InitializeIndirectionInstruction extends VariableInstruction { - InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + InitializeIndirectionInstruction() { this.getOpcode() instanceof Opcode::InitializeIndirection } /** * Gets the parameter initialized by this instruction. @@ -635,24 +642,24 @@ class InitializeIndirectionInstruction extends VariableInstruction { * An instruction that initializes the `this` pointer parameter of the enclosing function. */ class InitializeThisInstruction extends Instruction { - InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } + InitializeThisInstruction() { this.getOpcode() instanceof Opcode::InitializeThis } } /** * An instruction that computes the address of a non-static field of an object. */ class FieldAddressInstruction extends FieldInstruction { - FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + FieldAddressInstruction() { this.getOpcode() instanceof Opcode::FieldAddress } /** * Gets the operand that provides the address of the object containing the field. */ - final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the object containing the field. */ - final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } + final Instruction getObjectAddress() { result = this.getObjectAddressOperand().getDef() } } /** @@ -661,17 +668,19 @@ class FieldAddressInstruction extends FieldInstruction { * This instruction is used for element access to C# arrays. */ class ElementsAddressInstruction extends UnaryInstruction { - ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + ElementsAddressInstruction() { this.getOpcode() instanceof Opcode::ElementsAddress } /** * Gets the operand that provides the address of the array object. */ - final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getArrayObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the array object. */ - final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } + final Instruction getArrayObjectAddress() { + result = this.getArrayObjectAddressOperand().getDef() + } } /** @@ -685,7 +694,7 @@ class ElementsAddressInstruction extends UnaryInstruction { * taken may want to ignore any function that contains an `ErrorInstruction`. */ class ErrorInstruction extends Instruction { - ErrorInstruction() { getOpcode() instanceof Opcode::Error } + ErrorInstruction() { this.getOpcode() instanceof Opcode::Error } } /** @@ -695,7 +704,7 @@ class ErrorInstruction extends Instruction { * an initializer, or whose initializer only partially initializes the variable. */ class UninitializedInstruction extends VariableInstruction { - UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } + UninitializedInstruction() { this.getOpcode() instanceof Opcode::Uninitialized } /** * Gets the variable that is uninitialized. @@ -710,7 +719,7 @@ class UninitializedInstruction extends VariableInstruction { * least one instruction, even when the AST has no semantic effect. */ class NoOpInstruction extends Instruction { - NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } + NoOpInstruction() { this.getOpcode() instanceof Opcode::NoOp } } /** @@ -732,32 +741,42 @@ class NoOpInstruction extends Instruction { * `void`-returning function. */ class ReturnInstruction extends Instruction { - ReturnInstruction() { getOpcode() instanceof ReturnOpcode } + ReturnInstruction() { this.getOpcode() instanceof ReturnOpcode } } /** * An instruction that returns control to the caller of the function, without returning a value. */ class ReturnVoidInstruction extends ReturnInstruction { - ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } + ReturnVoidInstruction() { this.getOpcode() instanceof Opcode::ReturnVoid } } /** * An instruction that returns control to the caller of the function, including a return value. */ class ReturnValueInstruction extends ReturnInstruction { - ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + ReturnValueInstruction() { this.getOpcode() instanceof Opcode::ReturnValue } /** * Gets the operand that provides the value being returned by the function. */ - final LoadOperand getReturnValueOperand() { result = getAnOperand() } + final LoadOperand getReturnValueOperand() { result = this.getAnOperand() } + + /** + * Gets the operand that provides the address of the value being returned by the function. + */ + final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value being returned by the function, if an * exact definition is available. */ - final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } + final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() } + + /** + * Gets the instruction whose result provides the address of the value being returned by the function. + */ + final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() } } /** @@ -770,28 +789,28 @@ class ReturnValueInstruction extends ReturnInstruction { * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { - ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + ReturnIndirectionInstruction() { this.getOpcode() instanceof Opcode::ReturnIndirection } /** * Gets the operand that provides the value of the pointed-to memory. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the pointed-to memory, if an exact * definition is available. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** * Gets the operand that provides the address of the pointed-to memory. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the pointed-to memory. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } /** * Gets the parameter for which this instruction reads the final pointed-to value within the @@ -826,7 +845,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { * - `StoreInstruction` - Copies a register operand to a memory result. */ class CopyInstruction extends Instruction { - CopyInstruction() { getOpcode() instanceof CopyOpcode } + CopyInstruction() { this.getOpcode() instanceof CopyOpcode } /** * Gets the operand that provides the input value of the copy. @@ -837,16 +856,16 @@ class CopyInstruction extends Instruction { * Gets the instruction whose result provides the input value of the copy, if an exact definition * is available. */ - final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } + final Instruction getSourceValue() { result = this.getSourceValueOperand().getDef() } } /** * An instruction that returns a register result containing a copy of its register operand. */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { - CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } + CopyValueInstruction() { this.getOpcode() instanceof Opcode::CopyValue } - final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } + final override UnaryOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -863,47 +882,49 @@ private string getAddressOperandDescription(AddressOperand operand) { * An instruction that returns a register result containing a copy of its memory operand. */ class LoadInstruction extends CopyInstruction { - LoadInstruction() { getOpcode() instanceof Opcode::Load } + LoadInstruction() { this.getOpcode() instanceof Opcode::Load } final override string getImmediateString() { - result = getAddressOperandDescription(getSourceAddressOperand()) + result = getAddressOperandDescription(this.getSourceAddressOperand()) } /** * Gets the operand that provides the address of the value being loaded. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the value being loaded. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - final override LoadOperand getSourceValueOperand() { result = getAnOperand() } + final override LoadOperand getSourceValueOperand() { result = this.getAnOperand() } } /** * An instruction that returns a memory result containing a copy of its register operand. */ class StoreInstruction extends CopyInstruction { - StoreInstruction() { getOpcode() instanceof Opcode::Store } + StoreInstruction() { this.getOpcode() instanceof Opcode::Store } final override string getImmediateString() { - result = getAddressOperandDescription(getDestinationAddressOperand()) + result = getAddressOperandDescription(this.getDestinationAddressOperand()) } /** * Gets the operand that provides the address of the location to which the value will be stored. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the location to which the value will * be stored, if an exact definition is available. */ - final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + final Instruction getDestinationAddress() { + result = this.getDestinationAddressOperand().getDef() + } - final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } + final override StoreValueOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -911,27 +932,27 @@ class StoreInstruction extends CopyInstruction { * operand. */ class ConditionalBranchInstruction extends Instruction { - ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + ConditionalBranchInstruction() { this.getOpcode() instanceof Opcode::ConditionalBranch } /** * Gets the operand that provides the Boolean condition controlling the branch. */ - final ConditionOperand getConditionOperand() { result = getAnOperand() } + final ConditionOperand getConditionOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the Boolean condition controlling the branch. */ - final Instruction getCondition() { result = getConditionOperand().getDef() } + final Instruction getCondition() { result = this.getConditionOperand().getDef() } /** * Gets the instruction to which control will flow if the condition is true. */ - final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + final Instruction getTrueSuccessor() { result = this.getSuccessor(EdgeKind::trueEdge()) } /** * Gets the instruction to which control will flow if the condition is false. */ - final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } + final Instruction getFalseSuccessor() { result = this.getSuccessor(EdgeKind::falseEdge()) } } /** @@ -943,14 +964,14 @@ class ConditionalBranchInstruction extends Instruction { * successors. */ class ExitFunctionInstruction extends Instruction { - ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } + ExitFunctionInstruction() { this.getOpcode() instanceof Opcode::ExitFunction } } /** * An instruction whose result is a constant value. */ class ConstantInstruction extends ConstantValueInstruction { - ConstantInstruction() { getOpcode() instanceof Opcode::Constant } + ConstantInstruction() { this.getOpcode() instanceof Opcode::Constant } } /** @@ -959,7 +980,7 @@ class ConstantInstruction extends ConstantValueInstruction { class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | - resultType = getResultIRType() and + resultType = this.getResultIRType() and (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) ) } @@ -969,7 +990,7 @@ class IntegerConstantInstruction extends ConstantInstruction { * An instruction whose result is a constant value of floating-point type. */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } + FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType } } /** @@ -978,7 +999,9 @@ class FloatConstantInstruction extends ConstantInstruction { class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; - final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + final override string getImmediateString() { + result = Language::getStringLiteralText(this.getValue()) + } /** * Gets the string literal whose address is returned by this instruction. @@ -990,37 +1013,37 @@ class StringConstantInstruction extends VariableInstruction { * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { - BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + BinaryInstruction() { this.getOpcode() instanceof BinaryOpcode } /** * Gets the left operand of this binary instruction. */ - final LeftOperand getLeftOperand() { result = getAnOperand() } + final LeftOperand getLeftOperand() { result = this.getAnOperand() } /** * Gets the right operand of this binary instruction. */ - final RightOperand getRightOperand() { result = getAnOperand() } + final RightOperand getRightOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the left operand of this binary * instruction. */ - final Instruction getLeft() { result = getLeftOperand().getDef() } + final Instruction getLeft() { result = this.getLeftOperand().getDef() } /** * Gets the instruction whose result provides the value of the right operand of this binary * instruction. */ - final Instruction getRight() { result = getRightOperand().getDef() } + final Instruction getRight() { result = this.getRightOperand().getDef() } /** * Holds if this instruction's operands are `op1` and `op2`, in either order. */ final predicate hasOperands(Operand op1, Operand op2) { - op1 = getLeftOperand() and op2 = getRightOperand() + op1 = this.getLeftOperand() and op2 = this.getRightOperand() or - op1 = getRightOperand() and op2 = getLeftOperand() + op1 = this.getRightOperand() and op2 = this.getLeftOperand() } } @@ -1028,7 +1051,7 @@ class BinaryInstruction extends Instruction { * An instruction that computes the result of an arithmetic operation. */ class ArithmeticInstruction extends Instruction { - ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } + ArithmeticInstruction() { this.getOpcode() instanceof ArithmeticOpcode } } /** @@ -1050,7 +1073,7 @@ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction * performed according to IEEE-754. */ class AddInstruction extends BinaryArithmeticInstruction { - AddInstruction() { getOpcode() instanceof Opcode::Add } + AddInstruction() { this.getOpcode() instanceof Opcode::Add } } /** @@ -1061,7 +1084,7 @@ class AddInstruction extends BinaryArithmeticInstruction { * according to IEEE-754. */ class SubInstruction extends BinaryArithmeticInstruction { - SubInstruction() { getOpcode() instanceof Opcode::Sub } + SubInstruction() { this.getOpcode() instanceof Opcode::Sub } } /** @@ -1072,7 +1095,7 @@ class SubInstruction extends BinaryArithmeticInstruction { * performed according to IEEE-754. */ class MulInstruction extends BinaryArithmeticInstruction { - MulInstruction() { getOpcode() instanceof Opcode::Mul } + MulInstruction() { this.getOpcode() instanceof Opcode::Mul } } /** @@ -1083,7 +1106,7 @@ class MulInstruction extends BinaryArithmeticInstruction { * to IEEE-754. */ class DivInstruction extends BinaryArithmeticInstruction { - DivInstruction() { getOpcode() instanceof Opcode::Div } + DivInstruction() { this.getOpcode() instanceof Opcode::Div } } /** @@ -1093,7 +1116,7 @@ class DivInstruction extends BinaryArithmeticInstruction { * division by zero or integer overflow is undefined. */ class RemInstruction extends BinaryArithmeticInstruction { - RemInstruction() { getOpcode() instanceof Opcode::Rem } + RemInstruction() { this.getOpcode() instanceof Opcode::Rem } } /** @@ -1104,14 +1127,14 @@ class RemInstruction extends BinaryArithmeticInstruction { * is performed according to IEEE-754. */ class NegateInstruction extends UnaryArithmeticInstruction { - NegateInstruction() { getOpcode() instanceof Opcode::Negate } + NegateInstruction() { this.getOpcode() instanceof Opcode::Negate } } /** * An instruction that computes the result of a bitwise operation. */ class BitwiseInstruction extends Instruction { - BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } + BitwiseInstruction() { this.getOpcode() instanceof BitwiseOpcode } } /** @@ -1130,7 +1153,7 @@ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } * Both operands must have the same integer type, which will also be the result type. */ class BitAndInstruction extends BinaryBitwiseInstruction { - BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } + BitAndInstruction() { this.getOpcode() instanceof Opcode::BitAnd } } /** @@ -1139,7 +1162,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitOrInstruction extends BinaryBitwiseInstruction { - BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } + BitOrInstruction() { this.getOpcode() instanceof Opcode::BitOr } } /** @@ -1148,7 +1171,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitXorInstruction extends BinaryBitwiseInstruction { - BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } + BitXorInstruction() { this.getOpcode() instanceof Opcode::BitXor } } /** @@ -1159,7 +1182,7 @@ class BitXorInstruction extends BinaryBitwiseInstruction { * rightmost bits are zero-filled. */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { - ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } + ShiftLeftInstruction() { this.getOpcode() instanceof Opcode::ShiftLeft } } /** @@ -1172,7 +1195,7 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { * of the left operand. */ class ShiftRightInstruction extends BinaryBitwiseInstruction { - ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } + ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight } } /** @@ -1183,7 +1206,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { - getOpcode() instanceof PointerArithmeticOpcode and + this.getOpcode() instanceof PointerArithmeticOpcode and elementSize = Raw::getInstructionElementSize(this) } @@ -1206,7 +1229,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { * An instruction that adds or subtracts an integer offset from a pointer. */ class PointerOffsetInstruction extends PointerArithmeticInstruction { - PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } + PointerOffsetInstruction() { this.getOpcode() instanceof PointerOffsetOpcode } } /** @@ -1217,7 +1240,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { * overflow is undefined. */ class PointerAddInstruction extends PointerOffsetInstruction { - PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } + PointerAddInstruction() { this.getOpcode() instanceof Opcode::PointerAdd } } /** @@ -1228,7 +1251,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { * pointer underflow is undefined. */ class PointerSubInstruction extends PointerOffsetInstruction { - PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } + PointerSubInstruction() { this.getOpcode() instanceof Opcode::PointerSub } } /** @@ -1241,31 +1264,31 @@ class PointerSubInstruction extends PointerOffsetInstruction { * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { - PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } + PointerDiffInstruction() { this.getOpcode() instanceof Opcode::PointerDiff } } /** * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { - UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + UnaryInstruction() { this.getOpcode() instanceof UnaryOpcode } /** * Gets the sole operand of this instruction. */ - final UnaryOperand getUnaryOperand() { result = getAnOperand() } + final UnaryOperand getUnaryOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the sole operand of this instruction. */ - final Instruction getUnary() { result = getUnaryOperand().getDef() } + final Instruction getUnary() { result = this.getUnaryOperand().getDef() } } /** * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { - ConvertInstruction() { getOpcode() instanceof Opcode::Convert } + ConvertInstruction() { this.getOpcode() instanceof Opcode::Convert } } /** @@ -1279,7 +1302,7 @@ class ConvertInstruction extends UnaryInstruction { * `as` expression. */ class CheckedConvertOrNullInstruction extends UnaryInstruction { - CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } + CheckedConvertOrNullInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** @@ -1293,7 +1316,7 @@ class CheckedConvertOrNullInstruction extends UnaryInstruction { * expression. */ class CheckedConvertOrThrowInstruction extends UnaryInstruction { - CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } + CheckedConvertOrThrowInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrThrow } } /** @@ -1306,7 +1329,7 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { * the most-derived object. */ class CompleteObjectAddressInstruction extends UnaryInstruction { - CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } + CompleteObjectAddressInstruction() { this.getOpcode() instanceof Opcode::CompleteObjectAddress } } /** @@ -1351,7 +1374,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { - ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } + ConvertToBaseInstruction() { this.getOpcode() instanceof ConvertToBaseOpcode } } /** @@ -1361,7 +1384,9 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } + ConvertToNonVirtualBaseInstruction() { + this.getOpcode() instanceof Opcode::ConvertToNonVirtualBase + } } /** @@ -1371,7 +1396,7 @@ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } + ConvertToVirtualBaseInstruction() { this.getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** @@ -1381,7 +1406,7 @@ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { - ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } + ConvertToDerivedInstruction() { this.getOpcode() instanceof Opcode::ConvertToDerived } } /** @@ -1390,7 +1415,7 @@ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { * The operand must have an integer type, which will also be the result type. */ class BitComplementInstruction extends UnaryBitwiseInstruction { - BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } + BitComplementInstruction() { this.getOpcode() instanceof Opcode::BitComplement } } /** @@ -1399,14 +1424,14 @@ class BitComplementInstruction extends UnaryBitwiseInstruction { * The operand must have a Boolean type, which will also be the result type. */ class LogicalNotInstruction extends UnaryInstruction { - LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } + LogicalNotInstruction() { this.getOpcode() instanceof Opcode::LogicalNot } } /** * An instruction that compares two numeric operands. */ class CompareInstruction extends BinaryInstruction { - CompareInstruction() { getOpcode() instanceof CompareOpcode } + CompareInstruction() { this.getOpcode() instanceof CompareOpcode } } /** @@ -1417,7 +1442,7 @@ class CompareInstruction extends BinaryInstruction { * unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareEQInstruction extends CompareInstruction { - CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } + CompareEQInstruction() { this.getOpcode() instanceof Opcode::CompareEQ } } /** @@ -1428,14 +1453,14 @@ class CompareEQInstruction extends CompareInstruction { * `left == right`. Floating-point comparison is performed according to IEEE-754. */ class CompareNEInstruction extends CompareInstruction { - CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } + CompareNEInstruction() { this.getOpcode() instanceof Opcode::CompareNE } } /** * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { - RelationalInstruction() { getOpcode() instanceof RelationalOpcode } + RelationalInstruction() { this.getOpcode() instanceof RelationalOpcode } /** * Gets the operand on the "greater" (or "greater-or-equal") side @@ -1467,11 +1492,11 @@ class RelationalInstruction extends CompareInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLTInstruction extends RelationalInstruction { - CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } + CompareLTInstruction() { this.getOpcode() instanceof Opcode::CompareLT } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { any() } } @@ -1484,11 +1509,11 @@ class CompareLTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGTInstruction extends RelationalInstruction { - CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } + CompareGTInstruction() { this.getOpcode() instanceof Opcode::CompareGT } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { any() } } @@ -1502,11 +1527,11 @@ class CompareGTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLEInstruction extends RelationalInstruction { - CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } + CompareLEInstruction() { this.getOpcode() instanceof Opcode::CompareLE } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { none() } } @@ -1520,11 +1545,11 @@ class CompareLEInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGEInstruction extends RelationalInstruction { - CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } + CompareGEInstruction() { this.getOpcode() instanceof Opcode::CompareGE } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { none() } } @@ -1543,78 +1568,78 @@ class CompareGEInstruction extends RelationalInstruction { * of any case edge. */ class SwitchInstruction extends Instruction { - SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + SwitchInstruction() { this.getOpcode() instanceof Opcode::Switch } /** Gets the operand that provides the integer value controlling the switch. */ - final ConditionOperand getExpressionOperand() { result = getAnOperand() } + final ConditionOperand getExpressionOperand() { result = this.getAnOperand() } /** Gets the instruction whose result provides the integer value controlling the switch. */ - final Instruction getExpression() { result = getExpressionOperand().getDef() } + final Instruction getExpression() { result = this.getExpressionOperand().getDef() } /** Gets the successor instructions along the case edges of the switch. */ - final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = this.getSuccessor(edge)) } /** Gets the successor instruction along the default edge of the switch, if any. */ - final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } + final Instruction getDefaultSuccessor() { result = this.getSuccessor(EdgeKind::defaultEdge()) } } /** * An instruction that calls a function. */ class CallInstruction extends Instruction { - CallInstruction() { getOpcode() instanceof Opcode::Call } + CallInstruction() { this.getOpcode() instanceof Opcode::Call } final override string getImmediateString() { - result = getStaticCallTarget().toString() + result = this.getStaticCallTarget().toString() or - not exists(getStaticCallTarget()) and result = "?" + not exists(this.getStaticCallTarget()) and result = "?" } /** * Gets the operand the specifies the target function of the call. */ - final CallTargetOperand getCallTargetOperand() { result = getAnOperand() } + final CallTargetOperand getCallTargetOperand() { result = this.getAnOperand() } /** * Gets the `Instruction` that computes the target function of the call. This is usually a * `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a * function pointer. */ - final Instruction getCallTarget() { result = getCallTargetOperand().getDef() } + final Instruction getCallTarget() { result = this.getCallTargetOperand().getDef() } /** * Gets all of the argument operands of the call, including the `this` pointer, if any. */ - final ArgumentOperand getAnArgumentOperand() { result = getAnOperand() } + final ArgumentOperand getAnArgumentOperand() { result = this.getAnOperand() } /** * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() + result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** * Gets all of the arguments of the call, including the `this` pointer, if any. */ - final Instruction getAnArgument() { result = getAnArgumentOperand().getDef() } + final Instruction getAnArgument() { result = this.getAnArgumentOperand().getDef() } /** * Gets the `this` pointer argument operand of the call, if any. */ - final ThisArgumentOperand getThisArgumentOperand() { result = getAnOperand() } + final ThisArgumentOperand getThisArgumentOperand() { result = this.getAnOperand() } /** * Gets the `this` pointer argument of the call, if any. */ - final Instruction getThisArgument() { result = getThisArgumentOperand().getDef() } + final Instruction getThisArgument() { result = this.getThisArgumentOperand().getDef() } /** * Gets the argument operand at the specified index. */ pragma[noinline] final PositionalArgumentOperand getPositionalArgumentOperand(int index) { - result = getAnOperand() and + result = this.getAnOperand() and result.getIndex() = index } @@ -1623,7 +1648,7 @@ class CallInstruction extends Instruction { */ pragma[noinline] final Instruction getPositionalArgument(int index) { - result = getPositionalArgumentOperand(index).getDef() + result = this.getPositionalArgumentOperand(index).getDef() } /** @@ -1631,16 +1656,16 @@ class CallInstruction extends Instruction { */ pragma[noinline] final ArgumentOperand getArgumentOperand(int index) { - index >= 0 and result = getPositionalArgumentOperand(index) + index >= 0 and result = this.getPositionalArgumentOperand(index) or - index = -1 and result = getThisArgumentOperand() + index = -1 and result = this.getThisArgumentOperand() } /** * Gets the argument at the specified index, or `this` if `index` is `-1`. */ pragma[noinline] - final Instruction getArgument(int index) { result = getArgumentOperand(index).getDef() } + final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() } /** * Gets the number of arguments of the call, including the `this` pointer, if any. @@ -1665,7 +1690,7 @@ class CallInstruction extends Instruction { * An instruction representing a side effect of a function call. */ class SideEffectInstruction extends Instruction { - SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + SideEffectInstruction() { this.getOpcode() instanceof SideEffectOpcode } /** * Gets the instruction whose execution causes this side effect. @@ -1680,7 +1705,7 @@ class SideEffectInstruction extends Instruction { * accessed by that call. */ class CallSideEffectInstruction extends SideEffectInstruction { - CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect } + CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect } } /** @@ -1691,7 +1716,7 @@ class CallSideEffectInstruction extends SideEffectInstruction { * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { - CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } + CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect } } /** @@ -1699,33 +1724,33 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * specific parameter. */ class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode } + ReadSideEffectInstruction() { this.getOpcode() instanceof ReadSideEffectOpcode } /** Gets the operand for the value that will be read from this instruction, if known. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** Gets the value that will be read from this instruction, if known. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** Gets the operand for the address from which this instruction may read. */ - final AddressOperand getArgumentOperand() { result = getAnOperand() } + final AddressOperand getArgumentOperand() { result = this.getAnOperand() } /** Gets the address from which this instruction may read. */ - final Instruction getArgumentDef() { result = getArgumentOperand().getDef() } + final Instruction getArgumentDef() { result = this.getArgumentOperand().getDef() } } /** * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::IndirectReadSideEffect } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::BufferReadSideEffect } } /** @@ -1733,18 +1758,18 @@ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { */ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { SizedBufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferReadSideEffect + this.getOpcode() instanceof Opcode::SizedBufferReadSideEffect } /** * Gets the operand that holds the number of bytes read from the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes read from the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1752,17 +1777,17 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { * specific parameter. */ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } + WriteSideEffectInstruction() { this.getOpcode() instanceof WriteSideEffectOpcode } /** * Get the operand that holds the address of the memory to be written. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the memory to be written. */ - Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + Instruction getDestinationAddress() { result = this.getDestinationAddressOperand().getDef() } } /** @@ -1770,7 +1795,7 @@ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstructi */ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMustWriteSideEffect } } @@ -1780,7 +1805,7 @@ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction */ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { BufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::BufferMustWriteSideEffect } } @@ -1790,18 +1815,18 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1812,7 +1837,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi */ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMayWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } } @@ -1822,7 +1847,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } + BufferMayWriteSideEffectInstruction() { + this.getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } } /** @@ -1832,18 +1859,18 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1852,80 +1879,80 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { InitializeDynamicAllocationInstruction() { - getOpcode() instanceof Opcode::InitializeDynamicAllocation + this.getOpcode() instanceof Opcode::InitializeDynamicAllocation } /** * Gets the operand that represents the address of the allocation this instruction is initializing. */ - final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + final AddressOperand getAllocationAddressOperand() { result = this.getAnOperand() } /** * Gets the address for the allocation this instruction is initializing. */ - final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } + final Instruction getAllocationAddress() { result = this.getAllocationAddressOperand().getDef() } } /** * An instruction representing a GNU or MSVC inline assembly statement. */ class InlineAsmInstruction extends Instruction { - InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm } + InlineAsmInstruction() { this.getOpcode() instanceof Opcode::InlineAsm } } /** * An instruction that throws an exception. */ class ThrowInstruction extends Instruction { - ThrowInstruction() { getOpcode() instanceof ThrowOpcode } + ThrowInstruction() { this.getOpcode() instanceof ThrowOpcode } } /** * An instruction that throws a new exception. */ class ThrowValueInstruction extends ThrowInstruction { - ThrowValueInstruction() { getOpcode() instanceof Opcode::ThrowValue } + ThrowValueInstruction() { this.getOpcode() instanceof Opcode::ThrowValue } /** * Gets the address operand of the exception thrown by this instruction. */ - final AddressOperand getExceptionAddressOperand() { result = getAnOperand() } + final AddressOperand getExceptionAddressOperand() { result = this.getAnOperand() } /** * Gets the address of the exception thrown by this instruction. */ - final Instruction getExceptionAddress() { result = getExceptionAddressOperand().getDef() } + final Instruction getExceptionAddress() { result = this.getExceptionAddressOperand().getDef() } /** * Gets the operand for the exception thrown by this instruction. */ - final LoadOperand getExceptionOperand() { result = getAnOperand() } + final LoadOperand getExceptionOperand() { result = this.getAnOperand() } /** * Gets the exception thrown by this instruction. */ - final Instruction getException() { result = getExceptionOperand().getDef() } + final Instruction getException() { result = this.getExceptionOperand().getDef() } } /** * An instruction that re-throws the current exception. */ class ReThrowInstruction extends ThrowInstruction { - ReThrowInstruction() { getOpcode() instanceof Opcode::ReThrow } + ReThrowInstruction() { this.getOpcode() instanceof Opcode::ReThrow } } /** * An instruction that exits the current function by propagating an exception. */ class UnwindInstruction extends Instruction { - UnwindInstruction() { getOpcode() instanceof Opcode::Unwind } + UnwindInstruction() { this.getOpcode() instanceof Opcode::Unwind } } /** * An instruction that starts a `catch` handler. */ class CatchInstruction extends Instruction { - CatchInstruction() { getOpcode() instanceof CatchOpcode } + CatchInstruction() { this.getOpcode() instanceof CatchOpcode } } /** @@ -1935,7 +1962,7 @@ class CatchByTypeInstruction extends CatchInstruction { Language::LanguageType exceptionType; CatchByTypeInstruction() { - getOpcode() instanceof Opcode::CatchByType and + this.getOpcode() instanceof Opcode::CatchByType and exceptionType = Raw::getInstructionExceptionType(this) } @@ -1951,21 +1978,21 @@ class CatchByTypeInstruction extends CatchInstruction { * An instruction that catches any exception. */ class CatchAnyInstruction extends CatchInstruction { - CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } + CatchAnyInstruction() { this.getOpcode() instanceof Opcode::CatchAny } } /** * An instruction that initializes all escaped memory. */ class AliasedDefinitionInstruction extends Instruction { - AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition } + AliasedDefinitionInstruction() { this.getOpcode() instanceof Opcode::AliasedDefinition } } /** * An instruction that consumes all escaped memory on exit from the function. */ class AliasedUseInstruction extends Instruction { - AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } + AliasedUseInstruction() { this.getOpcode() instanceof Opcode::AliasedUse } } /** @@ -1979,7 +2006,7 @@ class AliasedUseInstruction extends Instruction { * runtime. */ class PhiInstruction extends Instruction { - PhiInstruction() { getOpcode() instanceof Opcode::Phi } + PhiInstruction() { this.getOpcode() instanceof Opcode::Phi } /** * Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block. @@ -2047,29 +2074,29 @@ class PhiInstruction extends Instruction { * https://link.springer.com/content/pdf/10.1007%2F3-540-61053-7_66.pdf. */ class ChiInstruction extends Instruction { - ChiInstruction() { getOpcode() instanceof Opcode::Chi } + ChiInstruction() { this.getOpcode() instanceof Opcode::Chi } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final ChiTotalOperand getTotalOperand() { result = getAnOperand() } + final ChiTotalOperand getTotalOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final Instruction getTotal() { result = getTotalOperand().getDef() } + final Instruction getTotal() { result = this.getTotalOperand().getDef() } /** * Gets the operand that represents the new value written by the memory write. */ - final ChiPartialOperand getPartialOperand() { result = getAnOperand() } + final ChiPartialOperand getPartialOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the new value written by the memory write. */ - final Instruction getPartial() { result = getPartialOperand().getDef() } + final Instruction getPartial() { result = this.getPartialOperand().getDef() } /** * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. @@ -2093,7 +2120,7 @@ class ChiInstruction extends Instruction { * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { - UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } + UnreachedInstruction() { this.getOpcode() instanceof Opcode::Unreached } } /** @@ -2106,7 +2133,7 @@ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { - getOpcode() instanceof BuiltInOperationOpcode and + this.getOpcode() instanceof BuiltInOperationOpcode and operation = Raw::getInstructionBuiltInOperation(this) } @@ -2122,9 +2149,9 @@ class BuiltInOperationInstruction extends Instruction { * actual operation is specified by the `getBuiltInOperation()` predicate. */ class BuiltInInstruction extends BuiltInOperationInstruction { - BuiltInInstruction() { getOpcode() instanceof Opcode::BuiltIn } + BuiltInInstruction() { this.getOpcode() instanceof Opcode::BuiltIn } - final override string getImmediateString() { result = getBuiltInOperation().toString() } + final override string getImmediateString() { result = this.getBuiltInOperation().toString() } } /** @@ -2135,7 +2162,7 @@ class BuiltInInstruction extends BuiltInOperationInstruction { * to the `...` parameter. */ class VarArgsStartInstruction extends UnaryInstruction { - VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } + VarArgsStartInstruction() { this.getOpcode() instanceof Opcode::VarArgsStart } } /** @@ -2145,7 +2172,7 @@ class VarArgsStartInstruction extends UnaryInstruction { * a result. */ class VarArgsEndInstruction extends UnaryInstruction { - VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } + VarArgsEndInstruction() { this.getOpcode() instanceof Opcode::VarArgsEnd } } /** @@ -2155,7 +2182,7 @@ class VarArgsEndInstruction extends UnaryInstruction { * argument. */ class VarArgInstruction extends UnaryInstruction { - VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } + VarArgInstruction() { this.getOpcode() instanceof Opcode::VarArg } } /** @@ -2166,7 +2193,7 @@ class VarArgInstruction extends UnaryInstruction { * argument of the `...` parameter. */ class NextVarArgInstruction extends UnaryInstruction { - NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } + NextVarArgInstruction() { this.getOpcode() instanceof Opcode::NextVarArg } } /** @@ -2180,5 +2207,5 @@ class NextVarArgInstruction extends UnaryInstruction { * The result is the address of the newly allocated object. */ class NewObjInstruction extends Instruction { - NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } + NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index d7cf89ca9aa..85d217bd361 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -46,12 +46,12 @@ class Operand extends TStageOperand { /** * Gets the location of the source code for this operand. */ - final Language::Location getLocation() { result = getUse().getLocation() } + final Language::Location getLocation() { result = this.getUse().getLocation() } /** * Gets the function that contains this operand. */ - final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } + final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() } /** * Gets the `Instruction` that consumes this operand. @@ -74,7 +74,7 @@ class Operand extends TStageOperand { */ final Instruction getDef() { result = this.getAnyDef() and - getDefinitionOverlap() instanceof MustExactlyOverlap + this.getDefinitionOverlap() instanceof MustExactlyOverlap } /** @@ -82,7 +82,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` that consumes this operand. */ - deprecated final Instruction getUseInstruction() { result = getUse() } + deprecated final Instruction getUseInstruction() { result = this.getUse() } /** * DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this @@ -91,7 +91,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` whose result is the value of the operand. */ - deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() } + deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() } /** * Gets the overlap relationship between the operand's definition and its use. @@ -101,7 +101,9 @@ class Operand extends TStageOperand { /** * Holds if the result of the definition instruction does not exactly overlap this use. */ - final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap } + final predicate isDefinitionInexact() { + not this.getDefinitionOverlap() instanceof MustExactlyOverlap + } /** * Gets a prefix to use when dumping the operand in an operand list. @@ -121,7 +123,7 @@ class Operand extends TStageOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId() } /** @@ -129,9 +131,9 @@ class Operand extends TStageOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - result = getAnyDef().getResultId() + result = this.getAnyDef().getResultId() or - not exists(getAnyDef()) and result = "m?" + not exists(this.getAnyDef()) and result = "m?" } /** @@ -140,7 +142,7 @@ class Operand extends TStageOperand { * the empty string. */ private string getInexactSpecifier() { - if isDefinitionInexact() then result = "~" else result = "" + if this.isDefinitionInexact() then result = "~" else result = "" } /** @@ -155,7 +157,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() } /** * Gets the language-neutral type of the value consumed by this operand. This is usually the same @@ -164,7 +166,7 @@ class Operand extends TStageOperand { * from the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final IRType getIRType() { result = getLanguageType().getIRType() } + final IRType getIRType() { result = this.getLanguageType().getIRType() } /** * Gets the type of the value consumed by this operand. This is usually the same as the @@ -173,7 +175,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final Language::Type getType() { getLanguageType().hasType(result, _) } + final Language::Type getType() { this.getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this @@ -182,13 +184,13 @@ class Operand extends TStageOperand { * not hold, the value of the operand represents a value whose type is * given by `getType()`. */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - final int getSize() { result = getLanguageType().getByteSize() } + final int getSize() { result = this.getLanguageType().getByteSize() } } /** @@ -205,7 +207,7 @@ class MemoryOperand extends Operand { /** * Gets the kind of memory access performed by the operand. */ - MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() } + MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() } /** * Holds if the memory access performed by this operand will not always read from every bit in the @@ -215,7 +217,7 @@ class MemoryOperand extends Operand { * conservative estimate of the memory that might actually be accessed at runtime (for example, * the global side effects of a function call). */ - predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() } + predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() } /** * Returns the operand that holds the memory address from which the current operand loads its @@ -223,8 +225,8 @@ class MemoryOperand extends Operand { * is `r1`. */ final AddressOperand getAddressOperand() { - getMemoryAccess().usesAddressOperand() and - result.getUse() = getUse() + this.getMemoryAccess().usesAddressOperand() and + result.getUse() = this.getUse() } } @@ -294,7 +296,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe result = unique(Instruction defInstr | hasDefinition(defInstr, _)) } - final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) } pragma[noinline] private predicate hasDefinition(Instruction defInstr, Overlap overlap) { @@ -449,13 +451,17 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { final override Overlap getDefinitionOverlap() { result = overlap } - final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() } - - final override string getDumpLabel() { - result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + final override int getDumpSortOrder() { + result = 11 + this.getPredecessorBlock().getDisplayIndex() } - final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + final override string getDumpLabel() { + result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + final override string getDumpId() { + result = this.getPredecessorBlock().getDisplayIndex().toString() + } /** * Gets the predecessor block from which this value comes. diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index 4b86f9a7cec..bb8630a5e0c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -24,7 +24,7 @@ class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ - final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() } /** * INTERNAL: Do not use. @@ -39,7 +39,7 @@ class IRBlockBase extends TIRBlock { ) and this = rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 | - funcBlock.getEnclosingFunction() = getEnclosingFunction() and + funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and // Ensure that the block containing `EnterFunction` always comes first. if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction @@ -59,15 +59,15 @@ class IRBlockBase extends TIRBlock { * Get the `Phi` instructions that appear at the start of this block. */ final PhiInstruction getAPhiInstruction() { - Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() + Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction() } /** * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { - result = getInstruction(_) or - result = getAPhiInstruction() + result = this.getInstruction(_) or + result = this.getAPhiInstruction() } /** @@ -78,7 +78,9 @@ class IRBlockBase extends TIRBlock { /** * Gets the last instruction in this block. */ - final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + final Instruction getLastInstruction() { + result = this.getInstruction(this.getInstructionCount() - 1) + } /** * Gets the number of non-`Phi` instructions in this block. @@ -149,7 +151,7 @@ class IRBlock extends IRBlockBase { * Block `A` dominates block `B` if any control flow path from the entry block of the function to * block `B` must pass through block `A`. A block always dominates itself. */ - final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block } /** * Gets a block on the dominance frontier of this block. @@ -159,8 +161,8 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock dominanceFrontier() { - dominates(result.getAPredecessor()) and - not strictlyDominates(result) + this.dominates(result.getAPredecessor()) and + not this.strictlyDominates(result) } /** @@ -189,7 +191,7 @@ class IRBlock extends IRBlockBase { * Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the * function must pass through block `A`. A block always post-dominates itself. */ - final predicate postDominates(IRBlock block) { strictlyPostDominates(block) or this = block } + final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block } /** * Gets a block on the post-dominance frontier of this block. @@ -199,16 +201,16 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock postPominanceFrontier() { - postDominates(result.getASuccessor()) and - not strictlyPostDominates(result) + this.postDominates(result.getASuccessor()) and + not this.strictlyPostDominates(result) } /** * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { - this = getEnclosingIRFunction().getEntryBlock() or - getAPredecessor().isReachableFromFunctionEntry() + this = this.getEnclosingIRFunction().getEntryBlock() or + this.getAPredecessor().isReachableFromFunctionEntry() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 6f471d8a7e8..1c2cc493338 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction { } /** Gets a textual representation of this element. */ - final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } + final string toString() { result = this.getOpcode().toString() + ": " + this.getAST().toString() } /** * Gets a string showing the result, opcode, and operands of the instruction, equivalent to what @@ -50,7 +50,8 @@ class Instruction extends Construction::TStageInstruction { * `mu0_28(int) = Store r0_26, r0_27` */ final string getDumpString() { - result = getResultString() + " = " + getOperationString() + " " + getOperandsString() + result = + this.getResultString() + " = " + this.getOperationString() + " " + this.getOperandsString() } private predicate shouldGenerateDumpStrings() { @@ -66,10 +67,13 @@ class Instruction extends Construction::TStageInstruction { * VariableAddress[x] */ final string getOperationString() { - shouldGenerateDumpStrings() and - if exists(getImmediateString()) - then result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]" - else result = getOperationPrefix() + getOpcode().toString() + this.shouldGenerateDumpStrings() and + if exists(this.getImmediateString()) + then + result = + this.getOperationPrefix() + this.getOpcode().toString() + "[" + this.getImmediateString() + + "]" + else result = this.getOperationPrefix() + this.getOpcode().toString() } /** @@ -78,17 +82,17 @@ class Instruction extends Construction::TStageInstruction { string getImmediateString() { none() } private string getOperationPrefix() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and if this instanceof SideEffectInstruction then result = "^" else result = "" } private string getResultPrefix() { - shouldGenerateDumpStrings() and - if getResultIRType() instanceof IRVoidType + this.shouldGenerateDumpStrings() and + if this.getResultIRType() instanceof IRVoidType then result = "v" else - if hasMemoryResult() - then if isResultModeled() then result = "m" else result = "mu" + if this.hasMemoryResult() + then if this.isResultModeled() then result = "m" else result = "mu" else result = "r" } @@ -97,7 +101,7 @@ class Instruction extends Construction::TStageInstruction { * used by debugging and printing code only. */ int getDisplayIndexInBlock() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and exists(IRBlock block | this = block.getInstruction(result) or @@ -111,12 +115,12 @@ class Instruction extends Construction::TStageInstruction { } private int getLineRank() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and this = rank[result](Instruction instr | instr = - getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(), - getLocation().getStartLine()) + getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(), + this.getLocation().getStartLine()) | instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() ) @@ -130,8 +134,9 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1` */ string getResultId() { - shouldGenerateDumpStrings() and - result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank() + this.shouldGenerateDumpStrings() and + result = + this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank() } /** @@ -142,8 +147,8 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1(int*)` */ final string getResultString() { - shouldGenerateDumpStrings() and - result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + this.shouldGenerateDumpStrings() and + result = this.getResultId() + "(" + this.getResultLanguageType().getDumpString() + ")" } /** @@ -153,10 +158,10 @@ class Instruction extends Construction::TStageInstruction { * Example: `func:r3_4, this:r3_5` */ string getOperandsString() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and result = concat(Operand operand | - operand = getAnOperand() + operand = this.getAnOperand() | operand.getDumpString(), ", " order by operand.getDumpSortOrder() ) @@ -190,7 +195,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the function that contains this instruction. */ final Language::Function getEnclosingFunction() { - result = getEnclosingIRFunction().getFunction() + result = this.getEnclosingIRFunction().getFunction() } /** @@ -208,7 +213,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets the location of the source code for this instruction. */ - final Language::Location getLocation() { result = getAST().getLocation() } + final Language::Location getLocation() { result = this.getAST().getLocation() } /** * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a @@ -243,7 +248,7 @@ class Instruction extends Construction::TStageInstruction { * a result, its result type will be `IRVoidType`. */ cached - final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() } /** * Gets the type of the result produced by this instruction. If the @@ -254,7 +259,7 @@ class Instruction extends Construction::TStageInstruction { */ final Language::Type getResultType() { exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and + resultType = this.getResultLanguageType() and ( resultType.hasUnspecifiedType(result, _) or @@ -283,7 +288,7 @@ class Instruction extends Construction::TStageInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { getResultLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -292,7 +297,7 @@ class Instruction extends Construction::TStageInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = getResultLanguageType().getByteSize() } + final int getResultSize() { result = this.getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -314,14 +319,16 @@ class Instruction extends Construction::TStageInstruction { /** * Holds if this instruction produces a memory result. */ - final predicate hasMemoryResult() { exists(getResultMemoryAccess()) } + final predicate hasMemoryResult() { exists(this.getResultMemoryAccess()) } /** * Gets the kind of memory access performed by this instruction's result. * Holds only for instructions with a memory result. */ pragma[inline] - final MemoryAccessKind getResultMemoryAccess() { result = getOpcode().getWriteMemoryAccess() } + final MemoryAccessKind getResultMemoryAccess() { + result = this.getOpcode().getWriteMemoryAccess() + } /** * Holds if the memory access performed by this instruction's result will not always write to @@ -332,7 +339,7 @@ class Instruction extends Construction::TStageInstruction { * (for example, the global side effects of a function call). */ pragma[inline] - final predicate hasResultMayMemoryAccess() { getOpcode().hasMayWriteMemoryAccess() } + final predicate hasResultMayMemoryAccess() { this.getOpcode().hasMayWriteMemoryAccess() } /** * Gets the operand that holds the memory address to which this instruction stores its @@ -340,7 +347,7 @@ class Instruction extends Construction::TStageInstruction { * is `r1`. */ final AddressOperand getResultAddressOperand() { - getResultMemoryAccess().usesAddressOperand() and + this.getResultMemoryAccess().usesAddressOperand() and result.getUse() = this } @@ -349,7 +356,7 @@ class Instruction extends Construction::TStageInstruction { * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` * is the instruction that defines `r1`. */ - final Instruction getResultAddress() { result = getResultAddressOperand().getDef() } + final Instruction getResultAddress() { result = this.getResultAddressOperand().getDef() } /** * Holds if the result of this instruction is precisely modeled in SSA. Always @@ -368,7 +375,7 @@ class Instruction extends Construction::TStageInstruction { */ final predicate isResultModeled() { // Register results are always in SSA form. - not hasMemoryResult() or + not this.hasMemoryResult() or Construction::hasModeledMemoryResult(this) } @@ -412,7 +419,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct successors of this instruction. */ - final Instruction getASuccessor() { result = getSuccessor(_) } + final Instruction getASuccessor() { result = this.getSuccessor(_) } /** * Gets a predecessor of this instruction such that the predecessor reaches @@ -423,7 +430,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct predecessors of this instruction. */ - final Instruction getAPredecessor() { result = getPredecessor(_) } + final Instruction getAPredecessor() { result = this.getPredecessor(_) } } /** @@ -543,7 +550,7 @@ class IndexedInstruction extends Instruction { * at this instruction. This instruction has no predecessors. */ class EnterFunctionInstruction extends Instruction { - EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } + EnterFunctionInstruction() { this.getOpcode() instanceof Opcode::EnterFunction } } /** @@ -554,7 +561,7 @@ class EnterFunctionInstruction extends Instruction { * struct, or union, see `FieldAddressInstruction`. */ class VariableAddressInstruction extends VariableInstruction { - VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } + VariableAddressInstruction() { this.getOpcode() instanceof Opcode::VariableAddress } } /** @@ -566,7 +573,7 @@ class VariableAddressInstruction extends VariableInstruction { * The result has an `IRFunctionAddress` type. */ class FunctionAddressInstruction extends FunctionInstruction { - FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } + FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress } } /** @@ -577,7 +584,7 @@ class FunctionAddressInstruction extends FunctionInstruction { * initializes that parameter. */ class InitializeParameterInstruction extends VariableInstruction { - InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + InitializeParameterInstruction() { this.getOpcode() instanceof Opcode::InitializeParameter } /** * Gets the parameter initialized by this instruction. @@ -603,7 +610,7 @@ class InitializeParameterInstruction extends VariableInstruction { * initialized elsewhere, would not otherwise have a definition in this function. */ class InitializeNonLocalInstruction extends Instruction { - InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } + InitializeNonLocalInstruction() { this.getOpcode() instanceof Opcode::InitializeNonLocal } } /** @@ -611,7 +618,7 @@ class InitializeNonLocalInstruction extends Instruction { * with the value of that memory on entry to the function. */ class InitializeIndirectionInstruction extends VariableInstruction { - InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + InitializeIndirectionInstruction() { this.getOpcode() instanceof Opcode::InitializeIndirection } /** * Gets the parameter initialized by this instruction. @@ -635,24 +642,24 @@ class InitializeIndirectionInstruction extends VariableInstruction { * An instruction that initializes the `this` pointer parameter of the enclosing function. */ class InitializeThisInstruction extends Instruction { - InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } + InitializeThisInstruction() { this.getOpcode() instanceof Opcode::InitializeThis } } /** * An instruction that computes the address of a non-static field of an object. */ class FieldAddressInstruction extends FieldInstruction { - FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + FieldAddressInstruction() { this.getOpcode() instanceof Opcode::FieldAddress } /** * Gets the operand that provides the address of the object containing the field. */ - final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the object containing the field. */ - final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } + final Instruction getObjectAddress() { result = this.getObjectAddressOperand().getDef() } } /** @@ -661,17 +668,19 @@ class FieldAddressInstruction extends FieldInstruction { * This instruction is used for element access to C# arrays. */ class ElementsAddressInstruction extends UnaryInstruction { - ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + ElementsAddressInstruction() { this.getOpcode() instanceof Opcode::ElementsAddress } /** * Gets the operand that provides the address of the array object. */ - final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getArrayObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the array object. */ - final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } + final Instruction getArrayObjectAddress() { + result = this.getArrayObjectAddressOperand().getDef() + } } /** @@ -685,7 +694,7 @@ class ElementsAddressInstruction extends UnaryInstruction { * taken may want to ignore any function that contains an `ErrorInstruction`. */ class ErrorInstruction extends Instruction { - ErrorInstruction() { getOpcode() instanceof Opcode::Error } + ErrorInstruction() { this.getOpcode() instanceof Opcode::Error } } /** @@ -695,7 +704,7 @@ class ErrorInstruction extends Instruction { * an initializer, or whose initializer only partially initializes the variable. */ class UninitializedInstruction extends VariableInstruction { - UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } + UninitializedInstruction() { this.getOpcode() instanceof Opcode::Uninitialized } /** * Gets the variable that is uninitialized. @@ -710,7 +719,7 @@ class UninitializedInstruction extends VariableInstruction { * least one instruction, even when the AST has no semantic effect. */ class NoOpInstruction extends Instruction { - NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } + NoOpInstruction() { this.getOpcode() instanceof Opcode::NoOp } } /** @@ -732,32 +741,42 @@ class NoOpInstruction extends Instruction { * `void`-returning function. */ class ReturnInstruction extends Instruction { - ReturnInstruction() { getOpcode() instanceof ReturnOpcode } + ReturnInstruction() { this.getOpcode() instanceof ReturnOpcode } } /** * An instruction that returns control to the caller of the function, without returning a value. */ class ReturnVoidInstruction extends ReturnInstruction { - ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } + ReturnVoidInstruction() { this.getOpcode() instanceof Opcode::ReturnVoid } } /** * An instruction that returns control to the caller of the function, including a return value. */ class ReturnValueInstruction extends ReturnInstruction { - ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + ReturnValueInstruction() { this.getOpcode() instanceof Opcode::ReturnValue } /** * Gets the operand that provides the value being returned by the function. */ - final LoadOperand getReturnValueOperand() { result = getAnOperand() } + final LoadOperand getReturnValueOperand() { result = this.getAnOperand() } + + /** + * Gets the operand that provides the address of the value being returned by the function. + */ + final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value being returned by the function, if an * exact definition is available. */ - final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } + final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() } + + /** + * Gets the instruction whose result provides the address of the value being returned by the function. + */ + final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() } } /** @@ -770,28 +789,28 @@ class ReturnValueInstruction extends ReturnInstruction { * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { - ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + ReturnIndirectionInstruction() { this.getOpcode() instanceof Opcode::ReturnIndirection } /** * Gets the operand that provides the value of the pointed-to memory. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the pointed-to memory, if an exact * definition is available. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** * Gets the operand that provides the address of the pointed-to memory. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the pointed-to memory. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } /** * Gets the parameter for which this instruction reads the final pointed-to value within the @@ -826,7 +845,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { * - `StoreInstruction` - Copies a register operand to a memory result. */ class CopyInstruction extends Instruction { - CopyInstruction() { getOpcode() instanceof CopyOpcode } + CopyInstruction() { this.getOpcode() instanceof CopyOpcode } /** * Gets the operand that provides the input value of the copy. @@ -837,16 +856,16 @@ class CopyInstruction extends Instruction { * Gets the instruction whose result provides the input value of the copy, if an exact definition * is available. */ - final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } + final Instruction getSourceValue() { result = this.getSourceValueOperand().getDef() } } /** * An instruction that returns a register result containing a copy of its register operand. */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { - CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } + CopyValueInstruction() { this.getOpcode() instanceof Opcode::CopyValue } - final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } + final override UnaryOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -863,47 +882,49 @@ private string getAddressOperandDescription(AddressOperand operand) { * An instruction that returns a register result containing a copy of its memory operand. */ class LoadInstruction extends CopyInstruction { - LoadInstruction() { getOpcode() instanceof Opcode::Load } + LoadInstruction() { this.getOpcode() instanceof Opcode::Load } final override string getImmediateString() { - result = getAddressOperandDescription(getSourceAddressOperand()) + result = getAddressOperandDescription(this.getSourceAddressOperand()) } /** * Gets the operand that provides the address of the value being loaded. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the value being loaded. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - final override LoadOperand getSourceValueOperand() { result = getAnOperand() } + final override LoadOperand getSourceValueOperand() { result = this.getAnOperand() } } /** * An instruction that returns a memory result containing a copy of its register operand. */ class StoreInstruction extends CopyInstruction { - StoreInstruction() { getOpcode() instanceof Opcode::Store } + StoreInstruction() { this.getOpcode() instanceof Opcode::Store } final override string getImmediateString() { - result = getAddressOperandDescription(getDestinationAddressOperand()) + result = getAddressOperandDescription(this.getDestinationAddressOperand()) } /** * Gets the operand that provides the address of the location to which the value will be stored. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the location to which the value will * be stored, if an exact definition is available. */ - final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + final Instruction getDestinationAddress() { + result = this.getDestinationAddressOperand().getDef() + } - final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } + final override StoreValueOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -911,27 +932,27 @@ class StoreInstruction extends CopyInstruction { * operand. */ class ConditionalBranchInstruction extends Instruction { - ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + ConditionalBranchInstruction() { this.getOpcode() instanceof Opcode::ConditionalBranch } /** * Gets the operand that provides the Boolean condition controlling the branch. */ - final ConditionOperand getConditionOperand() { result = getAnOperand() } + final ConditionOperand getConditionOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the Boolean condition controlling the branch. */ - final Instruction getCondition() { result = getConditionOperand().getDef() } + final Instruction getCondition() { result = this.getConditionOperand().getDef() } /** * Gets the instruction to which control will flow if the condition is true. */ - final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + final Instruction getTrueSuccessor() { result = this.getSuccessor(EdgeKind::trueEdge()) } /** * Gets the instruction to which control will flow if the condition is false. */ - final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } + final Instruction getFalseSuccessor() { result = this.getSuccessor(EdgeKind::falseEdge()) } } /** @@ -943,14 +964,14 @@ class ConditionalBranchInstruction extends Instruction { * successors. */ class ExitFunctionInstruction extends Instruction { - ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } + ExitFunctionInstruction() { this.getOpcode() instanceof Opcode::ExitFunction } } /** * An instruction whose result is a constant value. */ class ConstantInstruction extends ConstantValueInstruction { - ConstantInstruction() { getOpcode() instanceof Opcode::Constant } + ConstantInstruction() { this.getOpcode() instanceof Opcode::Constant } } /** @@ -959,7 +980,7 @@ class ConstantInstruction extends ConstantValueInstruction { class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | - resultType = getResultIRType() and + resultType = this.getResultIRType() and (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) ) } @@ -969,7 +990,7 @@ class IntegerConstantInstruction extends ConstantInstruction { * An instruction whose result is a constant value of floating-point type. */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } + FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType } } /** @@ -978,7 +999,9 @@ class FloatConstantInstruction extends ConstantInstruction { class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; - final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + final override string getImmediateString() { + result = Language::getStringLiteralText(this.getValue()) + } /** * Gets the string literal whose address is returned by this instruction. @@ -990,37 +1013,37 @@ class StringConstantInstruction extends VariableInstruction { * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { - BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + BinaryInstruction() { this.getOpcode() instanceof BinaryOpcode } /** * Gets the left operand of this binary instruction. */ - final LeftOperand getLeftOperand() { result = getAnOperand() } + final LeftOperand getLeftOperand() { result = this.getAnOperand() } /** * Gets the right operand of this binary instruction. */ - final RightOperand getRightOperand() { result = getAnOperand() } + final RightOperand getRightOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the left operand of this binary * instruction. */ - final Instruction getLeft() { result = getLeftOperand().getDef() } + final Instruction getLeft() { result = this.getLeftOperand().getDef() } /** * Gets the instruction whose result provides the value of the right operand of this binary * instruction. */ - final Instruction getRight() { result = getRightOperand().getDef() } + final Instruction getRight() { result = this.getRightOperand().getDef() } /** * Holds if this instruction's operands are `op1` and `op2`, in either order. */ final predicate hasOperands(Operand op1, Operand op2) { - op1 = getLeftOperand() and op2 = getRightOperand() + op1 = this.getLeftOperand() and op2 = this.getRightOperand() or - op1 = getRightOperand() and op2 = getLeftOperand() + op1 = this.getRightOperand() and op2 = this.getLeftOperand() } } @@ -1028,7 +1051,7 @@ class BinaryInstruction extends Instruction { * An instruction that computes the result of an arithmetic operation. */ class ArithmeticInstruction extends Instruction { - ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } + ArithmeticInstruction() { this.getOpcode() instanceof ArithmeticOpcode } } /** @@ -1050,7 +1073,7 @@ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction * performed according to IEEE-754. */ class AddInstruction extends BinaryArithmeticInstruction { - AddInstruction() { getOpcode() instanceof Opcode::Add } + AddInstruction() { this.getOpcode() instanceof Opcode::Add } } /** @@ -1061,7 +1084,7 @@ class AddInstruction extends BinaryArithmeticInstruction { * according to IEEE-754. */ class SubInstruction extends BinaryArithmeticInstruction { - SubInstruction() { getOpcode() instanceof Opcode::Sub } + SubInstruction() { this.getOpcode() instanceof Opcode::Sub } } /** @@ -1072,7 +1095,7 @@ class SubInstruction extends BinaryArithmeticInstruction { * performed according to IEEE-754. */ class MulInstruction extends BinaryArithmeticInstruction { - MulInstruction() { getOpcode() instanceof Opcode::Mul } + MulInstruction() { this.getOpcode() instanceof Opcode::Mul } } /** @@ -1083,7 +1106,7 @@ class MulInstruction extends BinaryArithmeticInstruction { * to IEEE-754. */ class DivInstruction extends BinaryArithmeticInstruction { - DivInstruction() { getOpcode() instanceof Opcode::Div } + DivInstruction() { this.getOpcode() instanceof Opcode::Div } } /** @@ -1093,7 +1116,7 @@ class DivInstruction extends BinaryArithmeticInstruction { * division by zero or integer overflow is undefined. */ class RemInstruction extends BinaryArithmeticInstruction { - RemInstruction() { getOpcode() instanceof Opcode::Rem } + RemInstruction() { this.getOpcode() instanceof Opcode::Rem } } /** @@ -1104,14 +1127,14 @@ class RemInstruction extends BinaryArithmeticInstruction { * is performed according to IEEE-754. */ class NegateInstruction extends UnaryArithmeticInstruction { - NegateInstruction() { getOpcode() instanceof Opcode::Negate } + NegateInstruction() { this.getOpcode() instanceof Opcode::Negate } } /** * An instruction that computes the result of a bitwise operation. */ class BitwiseInstruction extends Instruction { - BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } + BitwiseInstruction() { this.getOpcode() instanceof BitwiseOpcode } } /** @@ -1130,7 +1153,7 @@ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } * Both operands must have the same integer type, which will also be the result type. */ class BitAndInstruction extends BinaryBitwiseInstruction { - BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } + BitAndInstruction() { this.getOpcode() instanceof Opcode::BitAnd } } /** @@ -1139,7 +1162,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitOrInstruction extends BinaryBitwiseInstruction { - BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } + BitOrInstruction() { this.getOpcode() instanceof Opcode::BitOr } } /** @@ -1148,7 +1171,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitXorInstruction extends BinaryBitwiseInstruction { - BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } + BitXorInstruction() { this.getOpcode() instanceof Opcode::BitXor } } /** @@ -1159,7 +1182,7 @@ class BitXorInstruction extends BinaryBitwiseInstruction { * rightmost bits are zero-filled. */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { - ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } + ShiftLeftInstruction() { this.getOpcode() instanceof Opcode::ShiftLeft } } /** @@ -1172,7 +1195,7 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { * of the left operand. */ class ShiftRightInstruction extends BinaryBitwiseInstruction { - ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } + ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight } } /** @@ -1183,7 +1206,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { - getOpcode() instanceof PointerArithmeticOpcode and + this.getOpcode() instanceof PointerArithmeticOpcode and elementSize = Raw::getInstructionElementSize(this) } @@ -1206,7 +1229,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { * An instruction that adds or subtracts an integer offset from a pointer. */ class PointerOffsetInstruction extends PointerArithmeticInstruction { - PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } + PointerOffsetInstruction() { this.getOpcode() instanceof PointerOffsetOpcode } } /** @@ -1217,7 +1240,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { * overflow is undefined. */ class PointerAddInstruction extends PointerOffsetInstruction { - PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } + PointerAddInstruction() { this.getOpcode() instanceof Opcode::PointerAdd } } /** @@ -1228,7 +1251,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { * pointer underflow is undefined. */ class PointerSubInstruction extends PointerOffsetInstruction { - PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } + PointerSubInstruction() { this.getOpcode() instanceof Opcode::PointerSub } } /** @@ -1241,31 +1264,31 @@ class PointerSubInstruction extends PointerOffsetInstruction { * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { - PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } + PointerDiffInstruction() { this.getOpcode() instanceof Opcode::PointerDiff } } /** * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { - UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + UnaryInstruction() { this.getOpcode() instanceof UnaryOpcode } /** * Gets the sole operand of this instruction. */ - final UnaryOperand getUnaryOperand() { result = getAnOperand() } + final UnaryOperand getUnaryOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the sole operand of this instruction. */ - final Instruction getUnary() { result = getUnaryOperand().getDef() } + final Instruction getUnary() { result = this.getUnaryOperand().getDef() } } /** * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { - ConvertInstruction() { getOpcode() instanceof Opcode::Convert } + ConvertInstruction() { this.getOpcode() instanceof Opcode::Convert } } /** @@ -1279,7 +1302,7 @@ class ConvertInstruction extends UnaryInstruction { * `as` expression. */ class CheckedConvertOrNullInstruction extends UnaryInstruction { - CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } + CheckedConvertOrNullInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** @@ -1293,7 +1316,7 @@ class CheckedConvertOrNullInstruction extends UnaryInstruction { * expression. */ class CheckedConvertOrThrowInstruction extends UnaryInstruction { - CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } + CheckedConvertOrThrowInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrThrow } } /** @@ -1306,7 +1329,7 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { * the most-derived object. */ class CompleteObjectAddressInstruction extends UnaryInstruction { - CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } + CompleteObjectAddressInstruction() { this.getOpcode() instanceof Opcode::CompleteObjectAddress } } /** @@ -1351,7 +1374,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { - ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } + ConvertToBaseInstruction() { this.getOpcode() instanceof ConvertToBaseOpcode } } /** @@ -1361,7 +1384,9 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } + ConvertToNonVirtualBaseInstruction() { + this.getOpcode() instanceof Opcode::ConvertToNonVirtualBase + } } /** @@ -1371,7 +1396,7 @@ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } + ConvertToVirtualBaseInstruction() { this.getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** @@ -1381,7 +1406,7 @@ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { - ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } + ConvertToDerivedInstruction() { this.getOpcode() instanceof Opcode::ConvertToDerived } } /** @@ -1390,7 +1415,7 @@ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { * The operand must have an integer type, which will also be the result type. */ class BitComplementInstruction extends UnaryBitwiseInstruction { - BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } + BitComplementInstruction() { this.getOpcode() instanceof Opcode::BitComplement } } /** @@ -1399,14 +1424,14 @@ class BitComplementInstruction extends UnaryBitwiseInstruction { * The operand must have a Boolean type, which will also be the result type. */ class LogicalNotInstruction extends UnaryInstruction { - LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } + LogicalNotInstruction() { this.getOpcode() instanceof Opcode::LogicalNot } } /** * An instruction that compares two numeric operands. */ class CompareInstruction extends BinaryInstruction { - CompareInstruction() { getOpcode() instanceof CompareOpcode } + CompareInstruction() { this.getOpcode() instanceof CompareOpcode } } /** @@ -1417,7 +1442,7 @@ class CompareInstruction extends BinaryInstruction { * unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareEQInstruction extends CompareInstruction { - CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } + CompareEQInstruction() { this.getOpcode() instanceof Opcode::CompareEQ } } /** @@ -1428,14 +1453,14 @@ class CompareEQInstruction extends CompareInstruction { * `left == right`. Floating-point comparison is performed according to IEEE-754. */ class CompareNEInstruction extends CompareInstruction { - CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } + CompareNEInstruction() { this.getOpcode() instanceof Opcode::CompareNE } } /** * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { - RelationalInstruction() { getOpcode() instanceof RelationalOpcode } + RelationalInstruction() { this.getOpcode() instanceof RelationalOpcode } /** * Gets the operand on the "greater" (or "greater-or-equal") side @@ -1467,11 +1492,11 @@ class RelationalInstruction extends CompareInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLTInstruction extends RelationalInstruction { - CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } + CompareLTInstruction() { this.getOpcode() instanceof Opcode::CompareLT } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { any() } } @@ -1484,11 +1509,11 @@ class CompareLTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGTInstruction extends RelationalInstruction { - CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } + CompareGTInstruction() { this.getOpcode() instanceof Opcode::CompareGT } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { any() } } @@ -1502,11 +1527,11 @@ class CompareGTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLEInstruction extends RelationalInstruction { - CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } + CompareLEInstruction() { this.getOpcode() instanceof Opcode::CompareLE } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { none() } } @@ -1520,11 +1545,11 @@ class CompareLEInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGEInstruction extends RelationalInstruction { - CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } + CompareGEInstruction() { this.getOpcode() instanceof Opcode::CompareGE } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { none() } } @@ -1543,78 +1568,78 @@ class CompareGEInstruction extends RelationalInstruction { * of any case edge. */ class SwitchInstruction extends Instruction { - SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + SwitchInstruction() { this.getOpcode() instanceof Opcode::Switch } /** Gets the operand that provides the integer value controlling the switch. */ - final ConditionOperand getExpressionOperand() { result = getAnOperand() } + final ConditionOperand getExpressionOperand() { result = this.getAnOperand() } /** Gets the instruction whose result provides the integer value controlling the switch. */ - final Instruction getExpression() { result = getExpressionOperand().getDef() } + final Instruction getExpression() { result = this.getExpressionOperand().getDef() } /** Gets the successor instructions along the case edges of the switch. */ - final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = this.getSuccessor(edge)) } /** Gets the successor instruction along the default edge of the switch, if any. */ - final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } + final Instruction getDefaultSuccessor() { result = this.getSuccessor(EdgeKind::defaultEdge()) } } /** * An instruction that calls a function. */ class CallInstruction extends Instruction { - CallInstruction() { getOpcode() instanceof Opcode::Call } + CallInstruction() { this.getOpcode() instanceof Opcode::Call } final override string getImmediateString() { - result = getStaticCallTarget().toString() + result = this.getStaticCallTarget().toString() or - not exists(getStaticCallTarget()) and result = "?" + not exists(this.getStaticCallTarget()) and result = "?" } /** * Gets the operand the specifies the target function of the call. */ - final CallTargetOperand getCallTargetOperand() { result = getAnOperand() } + final CallTargetOperand getCallTargetOperand() { result = this.getAnOperand() } /** * Gets the `Instruction` that computes the target function of the call. This is usually a * `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a * function pointer. */ - final Instruction getCallTarget() { result = getCallTargetOperand().getDef() } + final Instruction getCallTarget() { result = this.getCallTargetOperand().getDef() } /** * Gets all of the argument operands of the call, including the `this` pointer, if any. */ - final ArgumentOperand getAnArgumentOperand() { result = getAnOperand() } + final ArgumentOperand getAnArgumentOperand() { result = this.getAnOperand() } /** * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() + result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** * Gets all of the arguments of the call, including the `this` pointer, if any. */ - final Instruction getAnArgument() { result = getAnArgumentOperand().getDef() } + final Instruction getAnArgument() { result = this.getAnArgumentOperand().getDef() } /** * Gets the `this` pointer argument operand of the call, if any. */ - final ThisArgumentOperand getThisArgumentOperand() { result = getAnOperand() } + final ThisArgumentOperand getThisArgumentOperand() { result = this.getAnOperand() } /** * Gets the `this` pointer argument of the call, if any. */ - final Instruction getThisArgument() { result = getThisArgumentOperand().getDef() } + final Instruction getThisArgument() { result = this.getThisArgumentOperand().getDef() } /** * Gets the argument operand at the specified index. */ pragma[noinline] final PositionalArgumentOperand getPositionalArgumentOperand(int index) { - result = getAnOperand() and + result = this.getAnOperand() and result.getIndex() = index } @@ -1623,7 +1648,7 @@ class CallInstruction extends Instruction { */ pragma[noinline] final Instruction getPositionalArgument(int index) { - result = getPositionalArgumentOperand(index).getDef() + result = this.getPositionalArgumentOperand(index).getDef() } /** @@ -1631,16 +1656,16 @@ class CallInstruction extends Instruction { */ pragma[noinline] final ArgumentOperand getArgumentOperand(int index) { - index >= 0 and result = getPositionalArgumentOperand(index) + index >= 0 and result = this.getPositionalArgumentOperand(index) or - index = -1 and result = getThisArgumentOperand() + index = -1 and result = this.getThisArgumentOperand() } /** * Gets the argument at the specified index, or `this` if `index` is `-1`. */ pragma[noinline] - final Instruction getArgument(int index) { result = getArgumentOperand(index).getDef() } + final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() } /** * Gets the number of arguments of the call, including the `this` pointer, if any. @@ -1665,7 +1690,7 @@ class CallInstruction extends Instruction { * An instruction representing a side effect of a function call. */ class SideEffectInstruction extends Instruction { - SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + SideEffectInstruction() { this.getOpcode() instanceof SideEffectOpcode } /** * Gets the instruction whose execution causes this side effect. @@ -1680,7 +1705,7 @@ class SideEffectInstruction extends Instruction { * accessed by that call. */ class CallSideEffectInstruction extends SideEffectInstruction { - CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect } + CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect } } /** @@ -1691,7 +1716,7 @@ class CallSideEffectInstruction extends SideEffectInstruction { * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { - CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } + CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect } } /** @@ -1699,33 +1724,33 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * specific parameter. */ class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode } + ReadSideEffectInstruction() { this.getOpcode() instanceof ReadSideEffectOpcode } /** Gets the operand for the value that will be read from this instruction, if known. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** Gets the value that will be read from this instruction, if known. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** Gets the operand for the address from which this instruction may read. */ - final AddressOperand getArgumentOperand() { result = getAnOperand() } + final AddressOperand getArgumentOperand() { result = this.getAnOperand() } /** Gets the address from which this instruction may read. */ - final Instruction getArgumentDef() { result = getArgumentOperand().getDef() } + final Instruction getArgumentDef() { result = this.getArgumentOperand().getDef() } } /** * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::IndirectReadSideEffect } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::BufferReadSideEffect } } /** @@ -1733,18 +1758,18 @@ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { */ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { SizedBufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferReadSideEffect + this.getOpcode() instanceof Opcode::SizedBufferReadSideEffect } /** * Gets the operand that holds the number of bytes read from the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes read from the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1752,17 +1777,17 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { * specific parameter. */ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } + WriteSideEffectInstruction() { this.getOpcode() instanceof WriteSideEffectOpcode } /** * Get the operand that holds the address of the memory to be written. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the memory to be written. */ - Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + Instruction getDestinationAddress() { result = this.getDestinationAddressOperand().getDef() } } /** @@ -1770,7 +1795,7 @@ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstructi */ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMustWriteSideEffect } } @@ -1780,7 +1805,7 @@ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction */ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { BufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::BufferMustWriteSideEffect } } @@ -1790,18 +1815,18 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1812,7 +1837,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi */ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMayWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } } @@ -1822,7 +1847,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } + BufferMayWriteSideEffectInstruction() { + this.getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } } /** @@ -1832,18 +1859,18 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1852,80 +1879,80 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { InitializeDynamicAllocationInstruction() { - getOpcode() instanceof Opcode::InitializeDynamicAllocation + this.getOpcode() instanceof Opcode::InitializeDynamicAllocation } /** * Gets the operand that represents the address of the allocation this instruction is initializing. */ - final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + final AddressOperand getAllocationAddressOperand() { result = this.getAnOperand() } /** * Gets the address for the allocation this instruction is initializing. */ - final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } + final Instruction getAllocationAddress() { result = this.getAllocationAddressOperand().getDef() } } /** * An instruction representing a GNU or MSVC inline assembly statement. */ class InlineAsmInstruction extends Instruction { - InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm } + InlineAsmInstruction() { this.getOpcode() instanceof Opcode::InlineAsm } } /** * An instruction that throws an exception. */ class ThrowInstruction extends Instruction { - ThrowInstruction() { getOpcode() instanceof ThrowOpcode } + ThrowInstruction() { this.getOpcode() instanceof ThrowOpcode } } /** * An instruction that throws a new exception. */ class ThrowValueInstruction extends ThrowInstruction { - ThrowValueInstruction() { getOpcode() instanceof Opcode::ThrowValue } + ThrowValueInstruction() { this.getOpcode() instanceof Opcode::ThrowValue } /** * Gets the address operand of the exception thrown by this instruction. */ - final AddressOperand getExceptionAddressOperand() { result = getAnOperand() } + final AddressOperand getExceptionAddressOperand() { result = this.getAnOperand() } /** * Gets the address of the exception thrown by this instruction. */ - final Instruction getExceptionAddress() { result = getExceptionAddressOperand().getDef() } + final Instruction getExceptionAddress() { result = this.getExceptionAddressOperand().getDef() } /** * Gets the operand for the exception thrown by this instruction. */ - final LoadOperand getExceptionOperand() { result = getAnOperand() } + final LoadOperand getExceptionOperand() { result = this.getAnOperand() } /** * Gets the exception thrown by this instruction. */ - final Instruction getException() { result = getExceptionOperand().getDef() } + final Instruction getException() { result = this.getExceptionOperand().getDef() } } /** * An instruction that re-throws the current exception. */ class ReThrowInstruction extends ThrowInstruction { - ReThrowInstruction() { getOpcode() instanceof Opcode::ReThrow } + ReThrowInstruction() { this.getOpcode() instanceof Opcode::ReThrow } } /** * An instruction that exits the current function by propagating an exception. */ class UnwindInstruction extends Instruction { - UnwindInstruction() { getOpcode() instanceof Opcode::Unwind } + UnwindInstruction() { this.getOpcode() instanceof Opcode::Unwind } } /** * An instruction that starts a `catch` handler. */ class CatchInstruction extends Instruction { - CatchInstruction() { getOpcode() instanceof CatchOpcode } + CatchInstruction() { this.getOpcode() instanceof CatchOpcode } } /** @@ -1935,7 +1962,7 @@ class CatchByTypeInstruction extends CatchInstruction { Language::LanguageType exceptionType; CatchByTypeInstruction() { - getOpcode() instanceof Opcode::CatchByType and + this.getOpcode() instanceof Opcode::CatchByType and exceptionType = Raw::getInstructionExceptionType(this) } @@ -1951,21 +1978,21 @@ class CatchByTypeInstruction extends CatchInstruction { * An instruction that catches any exception. */ class CatchAnyInstruction extends CatchInstruction { - CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } + CatchAnyInstruction() { this.getOpcode() instanceof Opcode::CatchAny } } /** * An instruction that initializes all escaped memory. */ class AliasedDefinitionInstruction extends Instruction { - AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition } + AliasedDefinitionInstruction() { this.getOpcode() instanceof Opcode::AliasedDefinition } } /** * An instruction that consumes all escaped memory on exit from the function. */ class AliasedUseInstruction extends Instruction { - AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } + AliasedUseInstruction() { this.getOpcode() instanceof Opcode::AliasedUse } } /** @@ -1979,7 +2006,7 @@ class AliasedUseInstruction extends Instruction { * runtime. */ class PhiInstruction extends Instruction { - PhiInstruction() { getOpcode() instanceof Opcode::Phi } + PhiInstruction() { this.getOpcode() instanceof Opcode::Phi } /** * Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block. @@ -2047,29 +2074,29 @@ class PhiInstruction extends Instruction { * https://link.springer.com/content/pdf/10.1007%2F3-540-61053-7_66.pdf. */ class ChiInstruction extends Instruction { - ChiInstruction() { getOpcode() instanceof Opcode::Chi } + ChiInstruction() { this.getOpcode() instanceof Opcode::Chi } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final ChiTotalOperand getTotalOperand() { result = getAnOperand() } + final ChiTotalOperand getTotalOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final Instruction getTotal() { result = getTotalOperand().getDef() } + final Instruction getTotal() { result = this.getTotalOperand().getDef() } /** * Gets the operand that represents the new value written by the memory write. */ - final ChiPartialOperand getPartialOperand() { result = getAnOperand() } + final ChiPartialOperand getPartialOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the new value written by the memory write. */ - final Instruction getPartial() { result = getPartialOperand().getDef() } + final Instruction getPartial() { result = this.getPartialOperand().getDef() } /** * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. @@ -2093,7 +2120,7 @@ class ChiInstruction extends Instruction { * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { - UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } + UnreachedInstruction() { this.getOpcode() instanceof Opcode::Unreached } } /** @@ -2106,7 +2133,7 @@ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { - getOpcode() instanceof BuiltInOperationOpcode and + this.getOpcode() instanceof BuiltInOperationOpcode and operation = Raw::getInstructionBuiltInOperation(this) } @@ -2122,9 +2149,9 @@ class BuiltInOperationInstruction extends Instruction { * actual operation is specified by the `getBuiltInOperation()` predicate. */ class BuiltInInstruction extends BuiltInOperationInstruction { - BuiltInInstruction() { getOpcode() instanceof Opcode::BuiltIn } + BuiltInInstruction() { this.getOpcode() instanceof Opcode::BuiltIn } - final override string getImmediateString() { result = getBuiltInOperation().toString() } + final override string getImmediateString() { result = this.getBuiltInOperation().toString() } } /** @@ -2135,7 +2162,7 @@ class BuiltInInstruction extends BuiltInOperationInstruction { * to the `...` parameter. */ class VarArgsStartInstruction extends UnaryInstruction { - VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } + VarArgsStartInstruction() { this.getOpcode() instanceof Opcode::VarArgsStart } } /** @@ -2145,7 +2172,7 @@ class VarArgsStartInstruction extends UnaryInstruction { * a result. */ class VarArgsEndInstruction extends UnaryInstruction { - VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } + VarArgsEndInstruction() { this.getOpcode() instanceof Opcode::VarArgsEnd } } /** @@ -2155,7 +2182,7 @@ class VarArgsEndInstruction extends UnaryInstruction { * argument. */ class VarArgInstruction extends UnaryInstruction { - VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } + VarArgInstruction() { this.getOpcode() instanceof Opcode::VarArg } } /** @@ -2166,7 +2193,7 @@ class VarArgInstruction extends UnaryInstruction { * argument of the `...` parameter. */ class NextVarArgInstruction extends UnaryInstruction { - NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } + NextVarArgInstruction() { this.getOpcode() instanceof Opcode::NextVarArg } } /** @@ -2180,5 +2207,5 @@ class NextVarArgInstruction extends UnaryInstruction { * The result is the address of the newly allocated object. */ class NewObjInstruction extends Instruction { - NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } + NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Operand.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Operand.qll index d7cf89ca9aa..85d217bd361 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -46,12 +46,12 @@ class Operand extends TStageOperand { /** * Gets the location of the source code for this operand. */ - final Language::Location getLocation() { result = getUse().getLocation() } + final Language::Location getLocation() { result = this.getUse().getLocation() } /** * Gets the function that contains this operand. */ - final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } + final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() } /** * Gets the `Instruction` that consumes this operand. @@ -74,7 +74,7 @@ class Operand extends TStageOperand { */ final Instruction getDef() { result = this.getAnyDef() and - getDefinitionOverlap() instanceof MustExactlyOverlap + this.getDefinitionOverlap() instanceof MustExactlyOverlap } /** @@ -82,7 +82,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` that consumes this operand. */ - deprecated final Instruction getUseInstruction() { result = getUse() } + deprecated final Instruction getUseInstruction() { result = this.getUse() } /** * DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this @@ -91,7 +91,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` whose result is the value of the operand. */ - deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() } + deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() } /** * Gets the overlap relationship between the operand's definition and its use. @@ -101,7 +101,9 @@ class Operand extends TStageOperand { /** * Holds if the result of the definition instruction does not exactly overlap this use. */ - final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap } + final predicate isDefinitionInexact() { + not this.getDefinitionOverlap() instanceof MustExactlyOverlap + } /** * Gets a prefix to use when dumping the operand in an operand list. @@ -121,7 +123,7 @@ class Operand extends TStageOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId() } /** @@ -129,9 +131,9 @@ class Operand extends TStageOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - result = getAnyDef().getResultId() + result = this.getAnyDef().getResultId() or - not exists(getAnyDef()) and result = "m?" + not exists(this.getAnyDef()) and result = "m?" } /** @@ -140,7 +142,7 @@ class Operand extends TStageOperand { * the empty string. */ private string getInexactSpecifier() { - if isDefinitionInexact() then result = "~" else result = "" + if this.isDefinitionInexact() then result = "~" else result = "" } /** @@ -155,7 +157,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() } /** * Gets the language-neutral type of the value consumed by this operand. This is usually the same @@ -164,7 +166,7 @@ class Operand extends TStageOperand { * from the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final IRType getIRType() { result = getLanguageType().getIRType() } + final IRType getIRType() { result = this.getLanguageType().getIRType() } /** * Gets the type of the value consumed by this operand. This is usually the same as the @@ -173,7 +175,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final Language::Type getType() { getLanguageType().hasType(result, _) } + final Language::Type getType() { this.getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this @@ -182,13 +184,13 @@ class Operand extends TStageOperand { * not hold, the value of the operand represents a value whose type is * given by `getType()`. */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - final int getSize() { result = getLanguageType().getByteSize() } + final int getSize() { result = this.getLanguageType().getByteSize() } } /** @@ -205,7 +207,7 @@ class MemoryOperand extends Operand { /** * Gets the kind of memory access performed by the operand. */ - MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() } + MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() } /** * Holds if the memory access performed by this operand will not always read from every bit in the @@ -215,7 +217,7 @@ class MemoryOperand extends Operand { * conservative estimate of the memory that might actually be accessed at runtime (for example, * the global side effects of a function call). */ - predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() } + predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() } /** * Returns the operand that holds the memory address from which the current operand loads its @@ -223,8 +225,8 @@ class MemoryOperand extends Operand { * is `r1`. */ final AddressOperand getAddressOperand() { - getMemoryAccess().usesAddressOperand() and - result.getUse() = getUse() + this.getMemoryAccess().usesAddressOperand() and + result.getUse() = this.getUse() } } @@ -294,7 +296,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe result = unique(Instruction defInstr | hasDefinition(defInstr, _)) } - final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) } pragma[noinline] private predicate hasDefinition(Instruction defInstr, Overlap overlap) { @@ -449,13 +451,17 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { final override Overlap getDefinitionOverlap() { result = overlap } - final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() } - - final override string getDumpLabel() { - result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + final override int getDumpSortOrder() { + result = 11 + this.getPredecessorBlock().getDisplayIndex() } - final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + final override string getDumpLabel() { + result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + final override string getDumpId() { + result = this.getPredecessorBlock().getDisplayIndex().toString() + } /** * Gets the predecessor block from which this value comes. diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index a9f408bf161..d3f70b94db7 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -55,7 +55,7 @@ abstract class TranslatedExpr extends TranslatedElement { abstract predicate producesExprResult(); final CppType getResultType() { - if isResultGLValue() + if this.isResultGLValue() then result = getTypeForGLValue(expr.getType()) else result = getTypeForPRValue(expr.getType()) } @@ -128,9 +128,9 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, TTranslatedConditionValue { TranslatedConditionValue() { this = TTranslatedConditionValue(expr) } - override TranslatedElement getChild(int id) { id = 0 and result = getCondition() } + override TranslatedElement getChild(int id) { id = 0 and result = this.getCondition() } - override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } + override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { ( @@ -146,46 +146,46 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, tag = ConditionValueFalseConstantTag() ) and opcode instanceof Opcode::Constant and - resultType = getResultType() + resultType = this.getResultType() or ( tag = ConditionValueTrueStoreTag() or tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = getResultType() + resultType = this.getResultType() or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() + resultType = this.getResultType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { kind instanceof GotoEdge and ( tag = ConditionValueTrueTempAddressTag() and - result = getInstruction(ConditionValueTrueConstantTag()) + result = this.getInstruction(ConditionValueTrueConstantTag()) or tag = ConditionValueTrueConstantTag() and - result = getInstruction(ConditionValueTrueStoreTag()) + result = this.getInstruction(ConditionValueTrueStoreTag()) or tag = ConditionValueTrueStoreTag() and - result = getInstruction(ConditionValueResultTempAddressTag()) + result = this.getInstruction(ConditionValueResultTempAddressTag()) or tag = ConditionValueFalseTempAddressTag() and - result = getInstruction(ConditionValueFalseConstantTag()) + result = this.getInstruction(ConditionValueFalseConstantTag()) or tag = ConditionValueFalseConstantTag() and - result = getInstruction(ConditionValueFalseStoreTag()) + result = this.getInstruction(ConditionValueFalseStoreTag()) or tag = ConditionValueFalseStoreTag() and - result = getInstruction(ConditionValueResultTempAddressTag()) + result = this.getInstruction(ConditionValueResultTempAddressTag()) or tag = ConditionValueResultTempAddressTag() and - result = getInstruction(ConditionValueResultLoadTag()) + result = this.getInstruction(ConditionValueResultLoadTag()) or tag = ConditionValueResultLoadTag() and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) ) } @@ -193,25 +193,25 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, tag = ConditionValueTrueStoreTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(ConditionValueTrueTempAddressTag()) + result = this.getInstruction(ConditionValueTrueTempAddressTag()) or operandTag instanceof StoreValueOperandTag and - result = getInstruction(ConditionValueTrueConstantTag()) + result = this.getInstruction(ConditionValueTrueConstantTag()) ) or tag = ConditionValueFalseStoreTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(ConditionValueFalseTempAddressTag()) + result = this.getInstruction(ConditionValueFalseTempAddressTag()) or operandTag instanceof StoreValueOperandTag and - result = getInstruction(ConditionValueFalseConstantTag()) + result = this.getInstruction(ConditionValueFalseConstantTag()) ) or tag = ConditionValueResultLoadTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(ConditionValueResultTempAddressTag()) + result = this.getInstruction(ConditionValueResultTempAddressTag()) ) } @@ -226,7 +226,7 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, tag = ConditionValueFalseTempAddressTag() or tag = ConditionValueResultTempAddressTag() ) and - result = getTempVariable(ConditionValueTempVar()) + result = this.getTempVariable(ConditionValueTempVar()) } override string getInstructionConstantValue(InstructionTag tag) { @@ -235,18 +235,18 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, tag = ConditionValueFalseConstantTag() and result = "0" } - override Instruction getResult() { result = getInstruction(ConditionValueResultLoadTag()) } + override Instruction getResult() { result = this.getInstruction(ConditionValueResultLoadTag()) } override Instruction getChildSuccessor(TranslatedElement child) { none() } override Instruction getChildTrueSuccessor(TranslatedCondition child) { - child = getCondition() and - result = getInstruction(ConditionValueTrueTempAddressTag()) + child = this.getCondition() and + result = this.getInstruction(ConditionValueTrueTempAddressTag()) } override Instruction getChildFalseSuccessor(TranslatedCondition child) { - child = getCondition() and - result = getInstruction(ConditionValueFalseTempAddressTag()) + child = this.getCondition() and + result = this.getInstruction(ConditionValueFalseTempAddressTag()) } private TranslatedCondition getCondition() { result = getTranslatedCondition(expr) } @@ -260,9 +260,11 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, * temporary variable. */ abstract class TranslatedValueCategoryAdjustment extends TranslatedExpr { - final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } + final override Instruction getFirstInstruction() { + result = this.getOperand().getFirstInstruction() + } - final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } final override predicate producesExprResult() { // A temp object always produces the result of the expression. @@ -284,28 +286,28 @@ class TranslatedLoad extends TranslatedValueCategoryAdjustment, TTranslatedLoad override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() + resultType = this.getResultType() } override predicate isResultGLValue() { none() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = LoadTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getInstruction(LoadTag()) + child = this.getOperand() and result = this.getInstruction(LoadTag()) } - override Instruction getResult() { result = getInstruction(LoadTag()) } + override Instruction getResult() { result = this.getInstruction(LoadTag()) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = LoadTag() and ( operandTag instanceof AddressOperandTag and - result = getOperand().getResult() + result = this.getOperand().getResult() ) } } @@ -337,28 +339,28 @@ class TranslatedSyntheticTemporaryObject extends TranslatedValueCategoryAdjustme override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = InitializerVariableAddressTag() and - result = getInstruction(InitializerStoreTag()) and + result = this.getInstruction(InitializerStoreTag()) and kind instanceof GotoEdge or tag = InitializerStoreTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getInstruction(InitializerVariableAddressTag()) + child = this.getOperand() and result = this.getInstruction(InitializerVariableAddressTag()) } - override Instruction getResult() { result = getInstruction(InitializerVariableAddressTag()) } + override Instruction getResult() { result = this.getInstruction(InitializerVariableAddressTag()) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerStoreTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(InitializerVariableAddressTag()) + result = this.getInstruction(InitializerVariableAddressTag()) or operandTag instanceof StoreValueOperandTag and - result = getOperand().getResult() + result = this.getOperand().getResult() ) } @@ -383,32 +385,32 @@ class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy { override string toString() { result = "Result of " + expr.toString() } - override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } + override Instruction getFirstInstruction() { result = this.getOperand().getFirstInstruction() } - override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } + override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = ResultCopyTag() and opcode instanceof Opcode::CopyValue and - resultType = getOperand().getResultType() + resultType = this.getOperand().getResultType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = ResultCopyTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getInstruction(ResultCopyTag()) + child = this.getOperand() and result = this.getInstruction(ResultCopyTag()) } - override Instruction getResult() { result = getInstruction(ResultCopyTag()) } + override Instruction getResult() { result = this.getInstruction(ResultCopyTag()) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ResultCopyTag() and operandTag instanceof UnaryOperandTag and - result = getOperand().getResult() + result = this.getOperand().getResult() } final override predicate producesExprResult() { any() } @@ -419,23 +421,25 @@ class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy { class TranslatedCommaExpr extends TranslatedNonConstantExpr { override CommaExpr expr; - override Instruction getFirstInstruction() { result = getLeftOperand().getFirstInstruction() } - - override TranslatedElement getChild(int id) { - id = 0 and result = getLeftOperand() - or - id = 1 and result = getRightOperand() + override Instruction getFirstInstruction() { + result = this.getLeftOperand().getFirstInstruction() } - override Instruction getResult() { result = getRightOperand().getResult() } + override TranslatedElement getChild(int id) { + id = 0 and result = this.getLeftOperand() + or + id = 1 and result = this.getRightOperand() + } + + override Instruction getResult() { result = this.getRightOperand().getResult() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } override Instruction getChildSuccessor(TranslatedElement child) { - child = getLeftOperand() and - result = getRightOperand().getFirstInstruction() + child = this.getLeftOperand() and + result = this.getRightOperand().getFirstInstruction() or - child = getRightOperand() and result = getParent().getChildSuccessor(this) + child = this.getRightOperand() and result = this.getParent().getChildSuccessor(this) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { @@ -462,7 +466,7 @@ private int getElementSize(Type type) { abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { override CrementOperation expr; - final override TranslatedElement getChild(int id) { id = 0 and result = getLoadedOperand() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getLoadedOperand() } final override string getInstructionConstantValue(InstructionTag tag) { tag = CrementConstantTag() and @@ -493,10 +497,10 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = CrementConstantTag() and opcode instanceof Opcode::Constant and - resultType = getConstantType() + resultType = this.getConstantType() or tag = CrementOpTag() and - opcode = getOpcode() and + opcode = this.getOpcode() and resultType = getTypeForPRValue(expr.getType()) or tag = CrementStoreTag() and @@ -508,49 +512,49 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { tag = CrementOpTag() and ( operandTag instanceof LeftOperandTag and - result = getLoadedOperand().getResult() + result = this.getLoadedOperand().getResult() or operandTag instanceof RightOperandTag and - result = getInstruction(CrementConstantTag()) + result = this.getInstruction(CrementConstantTag()) ) or tag = CrementStoreTag() and ( operandTag instanceof AddressOperandTag and - result = getUnloadedOperand().getResult() + result = this.getUnloadedOperand().getResult() or operandTag instanceof StoreValueOperandTag and - result = getInstruction(CrementOpTag()) + result = this.getInstruction(CrementOpTag()) ) } final override Instruction getFirstInstruction() { - result = getLoadedOperand().getFirstInstruction() + result = this.getLoadedOperand().getFirstInstruction() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { kind instanceof GotoEdge and ( tag = CrementConstantTag() and - result = getInstruction(CrementOpTag()) + result = this.getInstruction(CrementOpTag()) or tag = CrementOpTag() and - result = getInstruction(CrementStoreTag()) + result = this.getInstruction(CrementStoreTag()) or tag = CrementStoreTag() and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) ) } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getLoadedOperand() and result = getInstruction(CrementConstantTag()) + child = this.getLoadedOperand() and result = this.getInstruction(CrementConstantTag()) } final override int getInstructionElementSize(InstructionTag tag) { tag = CrementOpTag() and ( - getOpcode() instanceof Opcode::PointerAdd or - getOpcode() instanceof Opcode::PointerSub + this.getOpcode() instanceof Opcode::PointerAdd or + this.getOpcode() instanceof Opcode::PointerSub ) and result = getElementSize(expr.getType()) } @@ -567,7 +571,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { /** * Gets the address to which the result of this crement will be stored. */ - final TranslatedExpr getUnloadedOperand() { result = getLoadedOperand().getOperand() } + final TranslatedExpr getUnloadedOperand() { result = this.getLoadedOperand().getOperand() } final Opcode getOpcode() { exists(Type resultType | @@ -601,18 +605,18 @@ class TranslatedPrefixCrementOperation extends TranslatedCrementOperation { // new value assigned to the operand. If this is C++, then the result is // an lvalue, but that lvalue is being loaded as part of this expression. // EDG doesn't mark this as a load. - result = getInstruction(CrementOpTag()) + result = this.getInstruction(CrementOpTag()) else // This is C++, where the result is an lvalue for the operand, and that // lvalue is not being loaded as part of this expression. - result = getUnloadedOperand().getResult() + result = this.getUnloadedOperand().getResult() } } class TranslatedPostfixCrementOperation extends TranslatedCrementOperation { override PostfixCrementOperation expr; - override Instruction getResult() { result = getLoadedOperand().getResult() } + override Instruction getResult() { result = this.getLoadedOperand().getResult() } } /** @@ -624,30 +628,30 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr { override ArrayExpr expr; final override Instruction getFirstInstruction() { - result = getBaseOperand().getFirstInstruction() + result = this.getBaseOperand().getFirstInstruction() } final override TranslatedElement getChild(int id) { - id = 0 and result = getBaseOperand() + id = 0 and result = this.getBaseOperand() or - id = 1 and result = getOffsetOperand() + id = 1 and result = this.getOffsetOperand() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } override Instruction getChildSuccessor(TranslatedElement child) { - child = getBaseOperand() and - result = getOffsetOperand().getFirstInstruction() + child = this.getBaseOperand() and + result = this.getOffsetOperand().getFirstInstruction() or - child = getOffsetOperand() and - result = getInstruction(OnlyInstructionTag()) + child = this.getOffsetOperand() and + result = this.getInstruction(OnlyInstructionTag()) } - override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and @@ -659,10 +663,10 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr { tag = OnlyInstructionTag() and ( operandTag instanceof LeftOperandTag and - result = getBaseOperand().getResult() + result = this.getBaseOperand().getResult() or operandTag instanceof RightOperandTag and - result = getOffsetOperand().getResult() + result = this.getOffsetOperand().getResult() ) } @@ -681,21 +685,23 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr { } abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr { - final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } + final override Instruction getFirstInstruction() { + result = this.getOperand().getFirstInstruction() + } - final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getParent().getChildSuccessor(this) + child = this.getOperand() and result = this.getParent().getChildSuccessor(this) } final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } - final override Instruction getResult() { result = getOperand().getResult() } + final override Instruction getResult() { result = this.getOperand().getResult() } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() @@ -749,21 +755,23 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { or tag = ThisLoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() + resultType = this.getResultType() } - final override Instruction getResult() { result = getInstruction(ThisLoadTag()) } + final override Instruction getResult() { result = this.getInstruction(ThisLoadTag()) } - final override Instruction getFirstInstruction() { result = getInstruction(ThisAddressTag()) } + final override Instruction getFirstInstruction() { + result = this.getInstruction(ThisAddressTag()) + } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { kind instanceof GotoEdge and tag = ThisAddressTag() and - result = getInstruction(ThisLoadTag()) + result = this.getInstruction(ThisLoadTag()) or kind instanceof GotoEdge and tag = ThisLoadTag() and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { none() } @@ -771,7 +779,7 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ThisLoadTag() and operandTag instanceof AddressOperandTag and - result = getInstruction(ThisAddressTag()) + result = this.getInstruction(ThisAddressTag()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -784,23 +792,23 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { override VariableAccess expr; final override TranslatedElement getChild(int id) { - id = 0 and result = getQualifier() // Might not exist + id = 0 and result = this.getQualifier() // Might not exist } final TranslatedExpr getQualifier() { result = getTranslatedExpr(expr.getQualifier().getFullyConverted()) } - override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getQualifier() and result = getInstruction(OnlyInstructionTag()) + child = this.getQualifier() and result = this.getInstruction(OnlyInstructionTag()) } } @@ -808,9 +816,9 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { TranslatedNonFieldVariableAccess() { not expr instanceof FieldAccess } override Instruction getFirstInstruction() { - if exists(getQualifier()) - then result = getQualifier().getFirstInstruction() - else result = getInstruction(OnlyInstructionTag()) + if exists(this.getQualifier()) + then result = this.getQualifier().getFirstInstruction() + else result = this.getInstruction(OnlyInstructionTag()) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { @@ -832,12 +840,12 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { class TranslatedFieldAccess extends TranslatedVariableAccess { override FieldAccess expr; - override Instruction getFirstInstruction() { result = getQualifier().getFirstInstruction() } + override Instruction getFirstInstruction() { result = this.getQualifier().getFirstInstruction() } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and - result = getQualifier().getResult() + result = this.getQualifier().getResult() } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { @@ -857,20 +865,20 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr { override TranslatedElement getChild(int id) { none() } - override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } - override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::FunctionAddress and - resultType = getResultType() + resultType = this.getResultType() } override Function getInstructionFunction(InstructionTag tag) { @@ -902,11 +910,13 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal isIRConstant(expr) } - final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getFirstInstruction() { + result = this.getInstruction(OnlyInstructionTag()) + } final override TranslatedElement getChild(int id) { none() } - final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() @@ -914,13 +924,13 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and - opcode = getOpcode() and - resultType = getResultType() + opcode = this.getOpcode() and + resultType = this.getResultType() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } @@ -962,12 +972,12 @@ abstract class TranslatedSingleInstructionExpr extends TranslatedNonConstantExpr abstract Opcode getOpcode(); final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { - opcode = getOpcode() and + opcode = this.getOpcode() and tag = OnlyInstructionTag() and - resultType = getResultType() + resultType = this.getResultType() } - final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } } class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr { @@ -978,23 +988,25 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr { expr instanceof UnaryMinusExpr } - final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } + final override Instruction getFirstInstruction() { + result = this.getOperand().getFirstInstruction() + } - final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getInstruction(OnlyInstructionTag()) + child = this.getOperand() and result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and - result = getOperand().getResult() and + result = this.getOperand().getResult() and operandTag instanceof UnaryOperandTag } @@ -1016,11 +1028,11 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr { abstract class TranslatedConversion extends TranslatedNonConstantExpr { override Conversion expr; - override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } + override Instruction getFirstInstruction() { result = this.getOperand().getFirstInstruction() } - final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } - final TranslatedExpr getOperand() { result = getTranslatedExpr(expr.(Conversion).getExpr()) } + final TranslatedExpr getOperand() { result = getTranslatedExpr(expr.getExpr()) } } /** @@ -1030,26 +1042,26 @@ abstract class TranslatedConversion extends TranslatedNonConstantExpr { abstract class TranslatedSingleInstructionConversion extends TranslatedConversion { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getInstruction(OnlyInstructionTag()) + child = this.getOperand() and result = this.getInstruction(OnlyInstructionTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and - opcode = getOpcode() and - resultType = getResultType() + opcode = this.getOpcode() and + resultType = this.getResultType() } - override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and - result = getOperand().getResult() + result = this.getOperand().getResult() } /** @@ -1133,37 +1145,37 @@ class TranslatedBoolConversion extends TranslatedConversion { kind instanceof GotoEdge and ( tag = BoolConversionConstantTag() and - result = getInstruction(BoolConversionCompareTag()) + result = this.getInstruction(BoolConversionCompareTag()) or tag = BoolConversionCompareTag() and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) ) } override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getInstruction(BoolConversionConstantTag()) + child = this.getOperand() and result = this.getInstruction(BoolConversionConstantTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = BoolConversionConstantTag() and opcode instanceof Opcode::Constant and - resultType = getOperand().getResultType() + resultType = this.getOperand().getResultType() or tag = BoolConversionCompareTag() and opcode instanceof Opcode::CompareNE and resultType = getBoolType() } - override Instruction getResult() { result = getInstruction(BoolConversionCompareTag()) } + override Instruction getResult() { result = this.getInstruction(BoolConversionCompareTag()) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = BoolConversionCompareTag() and ( operandTag instanceof LeftOperandTag and - result = getOperand().getResult() + result = this.getOperand().getResult() or operandTag instanceof RightOperandTag and - result = getInstruction(BoolConversionConstantTag()) + result = this.getInstruction(BoolConversionConstantTag()) ) } @@ -1250,67 +1262,71 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { expr instanceof ComparisonOperation } - override Instruction getFirstInstruction() { result = getLeftOperand().getFirstInstruction() } + override Instruction getFirstInstruction() { + result = this.getLeftOperand().getFirstInstruction() + } final override TranslatedElement getChild(int id) { - id = 0 and result = getLeftOperand() + id = 0 and result = this.getLeftOperand() or - id = 1 and result = getRightOperand() + id = 1 and result = this.getRightOperand() } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and - if swapOperandsOnOp() + if this.swapOperandsOnOp() then ( operandTag instanceof RightOperandTag and - result = getLeftOperand().getResult() + result = this.getLeftOperand().getResult() or operandTag instanceof LeftOperandTag and - result = getRightOperand().getResult() + result = this.getRightOperand().getResult() ) else ( operandTag instanceof LeftOperandTag and - result = getLeftOperand().getResult() + result = this.getLeftOperand().getResult() or operandTag instanceof RightOperandTag and - result = getRightOperand().getResult() + result = this.getRightOperand().getResult() ) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } override Instruction getChildSuccessor(TranslatedElement child) { - child = getLeftOperand() and - result = getRightOperand().getFirstInstruction() + child = this.getLeftOperand() and + result = this.getRightOperand().getFirstInstruction() or - child = getRightOperand() and - result = getInstruction(OnlyInstructionTag()) + child = this.getRightOperand() and + result = this.getInstruction(OnlyInstructionTag()) } override Opcode getOpcode() { - result = binaryArithmeticOpcode(expr.(BinaryArithmeticOperation)) or - result = binaryBitwiseOpcode(expr.(BinaryBitwiseOperation)) or - result = comparisonOpcode(expr.(ComparisonOperation)) + result = binaryArithmeticOpcode(expr) or + result = binaryBitwiseOpcode(expr) or + result = comparisonOpcode(expr) } override int getInstructionElementSize(InstructionTag tag) { tag = OnlyInstructionTag() and exists(Opcode opcode | - opcode = getOpcode() and + opcode = this.getOpcode() and ( opcode instanceof Opcode::PointerAdd or opcode instanceof Opcode::PointerSub or opcode instanceof Opcode::PointerDiff ) and - result = getElementSize(getPointerOperand().getExpr().getType()) + result = getElementSize(this.getPointerOperand().getExpr().getType()) ) } private TranslatedExpr getPointerOperand() { - if swapOperandsOnOp() then result = getRightOperand() else result = getLeftOperand() + if this.swapOperandsOnOp() + then result = this.getRightOperand() + else result = this.getLeftOperand() } private predicate swapOperandsOnOp() { @@ -1337,14 +1353,14 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr { override AssignExpr expr; final override TranslatedElement getChild(int id) { - id = 0 and result = getLeftOperand() + id = 0 and result = this.getLeftOperand() or - id = 1 and result = getRightOperand() + id = 1 and result = this.getRightOperand() } final override Instruction getFirstInstruction() { // Evaluation is right-to-left - result = getRightOperand().getFirstInstruction() + result = this.getRightOperand().getFirstInstruction() } final override Instruction getResult() { @@ -1354,11 +1370,11 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr { // value assigned to the left operand. If this is C++, then the result is // an lvalue, but that lvalue is being loaded as part of this expression. // EDG doesn't mark this as a load. - result = getRightOperand().getResult() + result = this.getRightOperand().getResult() else // This is C++, where the result is an lvalue for the left operand, // and that lvalue is not being loaded as part of this expression. - result = getLeftOperand().getResult() + result = this.getLeftOperand().getResult() } abstract Instruction getStoredValue(); @@ -1373,17 +1389,17 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = AssignmentStoreTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } override Instruction getChildSuccessor(TranslatedElement child) { // Operands are evaluated right-to-left. - child = getRightOperand() and - result = getLeftOperand().getFirstInstruction() + child = this.getRightOperand() and + result = this.getLeftOperand().getFirstInstruction() or - child = getLeftOperand() and - result = getInstruction(AssignmentStoreTag()) + child = this.getLeftOperand() and + result = this.getInstruction(AssignmentStoreTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { @@ -1396,10 +1412,10 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr { tag = AssignmentStoreTag() and ( operandTag instanceof AddressOperandTag and - result = getLeftOperand().getResult() + result = this.getLeftOperand().getResult() or operandTag instanceof StoreValueOperandTag and - result = getRightOperand().getResult() + result = this.getRightOperand().getResult() ) } } @@ -1408,14 +1424,14 @@ class TranslatedAssignOperation extends TranslatedNonConstantExpr { override AssignOperation expr; final override TranslatedElement getChild(int id) { - id = 0 and result = getLoadedLeftOperand() + id = 0 and result = this.getLoadedLeftOperand() or - id = 1 and result = getRightOperand() + id = 1 and result = this.getRightOperand() } final override Instruction getFirstInstruction() { // Evaluation is right-to-left - result = getRightOperand().getFirstInstruction() + result = this.getRightOperand().getFirstInstruction() } final override Instruction getResult() { @@ -1425,14 +1441,16 @@ class TranslatedAssignOperation extends TranslatedNonConstantExpr { // value assigned to the left operand. If this is C++, then the result is // an lvalue, but that lvalue is being loaded as part of this expression. // EDG doesn't mark this as a load. - result = getStoredValue() + result = this.getStoredValue() else // This is C++, where the result is an lvalue for the left operand, // and that lvalue is not being loaded as part of this expression. - result = getUnloadedLeftOperand().getResult() + result = this.getUnloadedLeftOperand().getResult() } - final TranslatedExpr getUnloadedLeftOperand() { result = getLoadedLeftOperand().getOperand() } + final TranslatedExpr getUnloadedLeftOperand() { + result = this.getLoadedLeftOperand().getOperand() + } /** * Gets the `TranslatedLoad` on the `e` in this `e += ...` which is the @@ -1454,38 +1472,38 @@ class TranslatedAssignOperation extends TranslatedNonConstantExpr { kind instanceof GotoEdge and ( tag = AssignOperationConvertLeftTag() and - result = getInstruction(AssignOperationOpTag()) + result = this.getInstruction(AssignOperationOpTag()) or ( tag = AssignOperationOpTag() and - if leftOperandNeedsConversion() - then result = getInstruction(AssignOperationConvertResultTag()) - else result = getInstruction(AssignmentStoreTag()) + if this.leftOperandNeedsConversion() + then result = this.getInstruction(AssignOperationConvertResultTag()) + else result = this.getInstruction(AssignmentStoreTag()) ) or tag = AssignOperationConvertResultTag() and - result = getInstruction(AssignmentStoreTag()) + result = this.getInstruction(AssignmentStoreTag()) or tag = AssignmentStoreTag() and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) ) } override Instruction getChildSuccessor(TranslatedElement child) { // Operands are evaluated right-to-left. - child = getRightOperand() and - result = getLoadedLeftOperand().getFirstInstruction() + child = this.getRightOperand() and + result = this.getLoadedLeftOperand().getFirstInstruction() or - child = getLoadedLeftOperand() and - if leftOperandNeedsConversion() - then result = getInstruction(AssignOperationConvertLeftTag()) - else result = getInstruction(AssignOperationOpTag()) + child = this.getLoadedLeftOperand() and + if this.leftOperandNeedsConversion() + then result = this.getInstruction(AssignOperationConvertLeftTag()) + else result = this.getInstruction(AssignOperationOpTag()) } private Instruction getStoredValue() { - if leftOperandNeedsConversion() - then result = getInstruction(AssignOperationConvertResultTag()) - else result = getInstruction(AssignOperationOpTag()) + if this.leftOperandNeedsConversion() + then result = this.getInstruction(AssignOperationConvertResultTag()) + else result = this.getInstruction(AssignOperationOpTag()) } private Type getConvertedLeftOperandType() { @@ -1502,15 +1520,15 @@ class TranslatedAssignOperation extends TranslatedNonConstantExpr { // anyway. If we really want to model this case perfectly, we'll need the // extractor to tell us what the promoted type of the left operand would // be. - result = getLoadedLeftOperand().getExpr().getType() + result = this.getLoadedLeftOperand().getExpr().getType() else // The right operand has already been converted to the type of the op. - result = getRightOperand().getExpr().getType() + result = this.getRightOperand().getExpr().getType() } private predicate leftOperandNeedsConversion() { - getConvertedLeftOperandType().getUnspecifiedType() != - getLoadedLeftOperand().getExpr().getUnspecifiedType() + this.getConvertedLeftOperandType().getUnspecifiedType() != + this.getLoadedLeftOperand().getExpr().getUnspecifiedType() } private Opcode getOpcode() { @@ -1541,64 +1559,64 @@ class TranslatedAssignOperation extends TranslatedNonConstantExpr { override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = AssignOperationOpTag() and - opcode = getOpcode() and - resultType = getTypeForPRValue(getConvertedLeftOperandType()) + opcode = this.getOpcode() and + resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) or tag = AssignmentStoreTag() and opcode instanceof Opcode::Store and resultType = getTypeForPRValue(expr.getType()) // Always a prvalue or - leftOperandNeedsConversion() and + this.leftOperandNeedsConversion() and opcode instanceof Opcode::Convert and ( tag = AssignOperationConvertLeftTag() and - resultType = getTypeForPRValue(getConvertedLeftOperandType()) + resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) or tag = AssignOperationConvertResultTag() and - resultType = getTypeForPRValue(getLoadedLeftOperand().getExpr().getType()) + resultType = getTypeForPRValue(this.getLoadedLeftOperand().getExpr().getType()) ) } override int getInstructionElementSize(InstructionTag tag) { tag = AssignOperationOpTag() and exists(Opcode opcode | - opcode = getOpcode() and + opcode = this.getOpcode() and (opcode instanceof Opcode::PointerAdd or opcode instanceof Opcode::PointerSub) ) and result = getElementSize(expr.getType()) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { - leftOperandNeedsConversion() and + this.leftOperandNeedsConversion() and tag = AssignOperationConvertLeftTag() and operandTag instanceof UnaryOperandTag and - result = getLoadedLeftOperand().getResult() + result = this.getLoadedLeftOperand().getResult() or tag = AssignOperationOpTag() and ( ( operandTag instanceof LeftOperandTag and - if leftOperandNeedsConversion() - then result = getInstruction(AssignOperationConvertLeftTag()) - else result = getLoadedLeftOperand().getResult() + if this.leftOperandNeedsConversion() + then result = this.getInstruction(AssignOperationConvertLeftTag()) + else result = this.getLoadedLeftOperand().getResult() ) or operandTag instanceof RightOperandTag and - result = getRightOperand().getResult() + result = this.getRightOperand().getResult() ) or - leftOperandNeedsConversion() and + this.leftOperandNeedsConversion() and tag = AssignOperationConvertResultTag() and operandTag instanceof UnaryOperandTag and - result = getInstruction(AssignOperationOpTag()) + result = this.getInstruction(AssignOperationOpTag()) or tag = AssignmentStoreTag() and ( operandTag instanceof AddressOperandTag and - result = getUnloadedLeftOperand().getResult() + result = this.getUnloadedLeftOperand().getResult() or operandTag instanceof StoreValueOperandTag and - result = getStoredValue() + result = this.getStoredValue() ) } } @@ -1619,7 +1637,7 @@ abstract class TranslatedAllocationSize extends TranslatedExpr, TTranslatedAlloc final override predicate producesExprResult() { none() } - final override Instruction getResult() { result = getInstruction(AllocationSizeTag()) } + final override Instruction getResult() { result = this.getInstruction(AllocationSizeTag()) } } TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr) { @@ -1636,7 +1654,9 @@ TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr) class TranslatedConstantAllocationSize extends TranslatedAllocationSize { TranslatedConstantAllocationSize() { not exists(expr.(NewArrayExpr).getExtent()) } - final override Instruction getFirstInstruction() { result = getInstruction(AllocationSizeTag()) } + final override Instruction getFirstInstruction() { + result = this.getInstruction(AllocationSizeTag()) + } final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = AllocationSizeTag() and @@ -1647,7 +1667,7 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = AllocationSizeTag() and kind instanceof GotoEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } final override TranslatedElement getChild(int id) { none() } @@ -1672,7 +1692,9 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize { TranslatedNonConstantAllocationSize() { exists(expr.getExtent()) } - final override Instruction getFirstInstruction() { result = getExtent().getFirstInstruction() } + final override Instruction getFirstInstruction() { + result = this.getExtent().getFirstInstruction() + } final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { resultType = getTypeForPRValue(expr.getAllocator().getParameter(0).getType()) and @@ -1690,21 +1712,21 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize { kind instanceof GotoEdge and ( tag = AllocationExtentConvertTag() and - result = getInstruction(AllocationElementSizeTag()) + result = this.getInstruction(AllocationElementSizeTag()) or tag = AllocationElementSizeTag() and - result = getInstruction(AllocationSizeTag()) + result = this.getInstruction(AllocationSizeTag()) or tag = AllocationSizeTag() and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) ) } - final override TranslatedElement getChild(int id) { id = 0 and result = getExtent() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getExtent() } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getExtent() and - result = getInstruction(AllocationExtentConvertTag()) + child = this.getExtent() and + result = this.getInstruction(AllocationExtentConvertTag()) } final override string getInstructionConstantValue(InstructionTag tag) { @@ -1715,14 +1737,16 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize { final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = AllocationSizeTag() and ( - operandTag instanceof LeftOperandTag and result = getInstruction(AllocationExtentConvertTag()) + operandTag instanceof LeftOperandTag and + result = this.getInstruction(AllocationExtentConvertTag()) or - operandTag instanceof RightOperandTag and result = getInstruction(AllocationElementSizeTag()) + operandTag instanceof RightOperandTag and + result = this.getInstruction(AllocationElementSizeTag()) ) or tag = AllocationExtentConvertTag() and operandTag instanceof UnaryOperandTag and - result = getExtent().getResult() + result = this.getExtent().getResult() } private TranslatedExpr getExtent() { @@ -1806,7 +1830,7 @@ abstract class StructorCallContext extends TranslatedElement { class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, StructorCallContext { override DestructorFieldDestruction expr; - final override TranslatedElement getChild(int id) { id = 0 and result = getDestructorCall() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getDestructorCall() } final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and @@ -1817,17 +1841,19 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and kind instanceof GotoEdge and - result = getDestructorCall().getFirstInstruction() + result = this.getDestructorCall().getFirstInstruction() } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getDestructorCall() and - result = getParent().getChildSuccessor(this) + child = this.getDestructorCall() and + result = this.getParent().getChildSuccessor(this) } final override Instruction getResult() { none() } - final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getFirstInstruction() { + result = this.getInstruction(OnlyInstructionTag()) + } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and @@ -1840,7 +1866,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St result = expr.getTarget() } - final override Instruction getReceiver() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getReceiver() { result = this.getInstruction(OnlyInstructionTag()) } private TranslatedExpr getDestructorCall() { result = getTranslatedExpr(expr.getExpr()) } } @@ -1859,12 +1885,12 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { // the condition directly to the appropriate then/else block via // `getChild[True|False]Successor()`. // The binary flavor will override this predicate to add the `ConditionalBranch`. - not resultIsVoid() and + not this.resultIsVoid() and ( ( - not thenIsVoid() and tag = ConditionValueTrueTempAddressTag() + not this.thenIsVoid() and tag = ConditionValueTrueTempAddressTag() or - not elseIsVoid() and tag = ConditionValueFalseTempAddressTag() + not this.elseIsVoid() and tag = ConditionValueFalseTempAddressTag() or tag = ConditionValueResultTempAddressTag() ) and @@ -1876,106 +1902,106 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { ) or ( - not thenIsVoid() and tag = ConditionValueTrueStoreTag() + not this.thenIsVoid() and tag = ConditionValueTrueStoreTag() or - not elseIsVoid() and tag = ConditionValueFalseStoreTag() + not this.elseIsVoid() and tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = getResultType() + resultType = this.getResultType() or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() + resultType = this.getResultType() ) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - not resultIsVoid() and + not this.resultIsVoid() and kind instanceof GotoEdge and ( - not thenIsVoid() and + not this.thenIsVoid() and ( tag = ConditionValueTrueTempAddressTag() and - result = getInstruction(ConditionValueTrueStoreTag()) + result = this.getInstruction(ConditionValueTrueStoreTag()) or tag = ConditionValueTrueStoreTag() and - result = getInstruction(ConditionValueResultTempAddressTag()) + result = this.getInstruction(ConditionValueResultTempAddressTag()) ) or - not elseIsVoid() and + not this.elseIsVoid() and ( tag = ConditionValueFalseTempAddressTag() and - result = getInstruction(ConditionValueFalseStoreTag()) + result = this.getInstruction(ConditionValueFalseStoreTag()) or tag = ConditionValueFalseStoreTag() and - result = getInstruction(ConditionValueResultTempAddressTag()) + result = this.getInstruction(ConditionValueResultTempAddressTag()) ) or tag = ConditionValueResultTempAddressTag() and - result = getInstruction(ConditionValueResultLoadTag()) + result = this.getInstruction(ConditionValueResultLoadTag()) or tag = ConditionValueResultLoadTag() and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) ) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { - not resultIsVoid() and + not this.resultIsVoid() and ( - not thenIsVoid() and + not this.thenIsVoid() and tag = ConditionValueTrueStoreTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(ConditionValueTrueTempAddressTag()) + result = this.getInstruction(ConditionValueTrueTempAddressTag()) or operandTag instanceof StoreValueOperandTag and - result = getThen().getResult() + result = this.getThen().getResult() ) or - not elseIsVoid() and + not this.elseIsVoid() and tag = ConditionValueFalseStoreTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(ConditionValueFalseTempAddressTag()) + result = this.getInstruction(ConditionValueFalseTempAddressTag()) or operandTag instanceof StoreValueOperandTag and - result = getElse().getResult() + result = this.getElse().getResult() ) or tag = ConditionValueResultLoadTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(ConditionValueResultTempAddressTag()) + result = this.getInstruction(ConditionValueResultTempAddressTag()) ) ) } final override predicate hasTempVariable(TempVariableTag tag, CppType type) { - not resultIsVoid() and + not this.resultIsVoid() and tag = ConditionValueTempVar() and - type = getResultType() + type = this.getResultType() } final override IRVariable getInstructionVariable(InstructionTag tag) { - not resultIsVoid() and + not this.resultIsVoid() and ( tag = ConditionValueTrueTempAddressTag() or tag = ConditionValueFalseTempAddressTag() or tag = ConditionValueResultTempAddressTag() ) and - result = getTempVariable(ConditionValueTempVar()) + result = this.getTempVariable(ConditionValueTempVar()) } final override Instruction getResult() { - not resultIsVoid() and - result = getInstruction(ConditionValueResultLoadTag()) + not this.resultIsVoid() and + result = this.getInstruction(ConditionValueResultLoadTag()) } override Instruction getChildSuccessor(TranslatedElement child) { - child = getElse() and - if elseIsVoid() - then result = getParent().getChildSuccessor(this) - else result = getInstruction(ConditionValueFalseTempAddressTag()) + child = this.getElse() and + if this.elseIsVoid() + then result = this.getParent().getChildSuccessor(this) + else result = this.getInstruction(ConditionValueFalseTempAddressTag()) } /** @@ -1990,7 +2016,7 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { final TranslatedExpr getElse() { result = getTranslatedExpr(expr.getElse().getFullyConverted()) } final predicate thenIsVoid() { - getThen().getResultType().getIRType() instanceof IRVoidType + this.getThen().getResultType().getIRType() instanceof IRVoidType or // A `ThrowExpr.getType()` incorrectly returns the type of exception being // thrown, rather than `void`. Handle that case here. @@ -1998,14 +2024,14 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { } private predicate elseIsVoid() { - getElse().getResultType().getIRType() instanceof IRVoidType + this.getElse().getResultType().getIRType() instanceof IRVoidType or // A `ThrowExpr.getType()` incorrectly returns the type of exception being // thrown, rather than `void`. Handle that case here. expr.getElse() instanceof ThrowExpr } - private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType } + private predicate resultIsVoid() { this.getResultType().getIRType() instanceof IRVoidType } } /** @@ -2017,34 +2043,34 @@ class TranslatedTernaryConditionalExpr extends TranslatedConditionalExpr, Condit TranslatedTernaryConditionalExpr() { not expr.isTwoOperand() } final override TranslatedElement getChild(int id) { - id = 0 and result = getCondition() + id = 0 and result = this.getCondition() or - id = 1 and result = getThen() + id = 1 and result = this.getThen() or - id = 2 and result = getElse() + id = 2 and result = this.getElse() } - override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } + override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } override Instruction getChildSuccessor(TranslatedElement child) { result = TranslatedConditionalExpr.super.getChildSuccessor(child) or ( - child = getThen() and - if thenIsVoid() - then result = getParent().getChildSuccessor(this) - else result = getInstruction(ConditionValueTrueTempAddressTag()) + child = this.getThen() and + if this.thenIsVoid() + then result = this.getParent().getChildSuccessor(this) + else result = this.getInstruction(ConditionValueTrueTempAddressTag()) ) } override Instruction getChildTrueSuccessor(TranslatedCondition child) { - child = getCondition() and - result = getThen().getFirstInstruction() + child = this.getCondition() and + result = this.getThen().getFirstInstruction() } override Instruction getChildFalseSuccessor(TranslatedCondition child) { - child = getCondition() and - result = getElse().getFirstInstruction() + child = this.getCondition() and + result = this.getElse().getFirstInstruction() } private TranslatedCondition getCondition() { @@ -2069,12 +2095,12 @@ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr { final override TranslatedElement getChild(int id) { // We only truly have two children, because our "condition" and "then" are the same as far as // the extractor is concerned. - id = 0 and result = getCondition() + id = 0 and result = this.getCondition() or - id = 1 and result = getElse() + id = 1 and result = this.getElse() } - override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } + override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { super.hasInstruction(opcode, tag, resultType) @@ -2091,10 +2117,10 @@ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr { tag = ValueConditionConditionalBranchTag() and ( kind instanceof TrueEdge and - result = getInstruction(ConditionValueTrueTempAddressTag()) + result = this.getInstruction(ConditionValueTrueTempAddressTag()) or kind instanceof FalseEdge and - result = getElse().getFirstInstruction() + result = this.getElse().getFirstInstruction() ) } @@ -2103,13 +2129,14 @@ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr { or tag = ValueConditionConditionalBranchTag() and operandTag instanceof ConditionOperandTag and - result = getCondition().getResult() + result = this.getCondition().getResult() } override Instruction getChildSuccessor(TranslatedElement child) { result = super.getChildSuccessor(child) or - child = getCondition() and result = getInstruction(ValueConditionConditionalBranchTag()) + child = this.getCondition() and + result = this.getInstruction(ValueConditionConditionalBranchTag()) } private TranslatedExpr getCondition() { @@ -2154,10 +2181,10 @@ class TranslatedTemporaryObjectExpr extends TranslatedNonConstantExpr, } final override Instruction getInitializationSuccessor() { - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } - final override Instruction getResult() { result = getTargetAddress() } + final override Instruction getResult() { result = this.getTargetAddress() } } /** @@ -2168,14 +2195,14 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr { override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = ThrowTag() and - opcode = getThrowOpcode() and + opcode = this.getThrowOpcode() and resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = ThrowTag() and kind instanceof ExceptionEdge and - result = getParent().getExceptionSuccessorInstruction() + result = this.getParent().getExceptionSuccessorInstruction() } override Instruction getResult() { none() } @@ -2202,11 +2229,13 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn result = TranslatedVariableInitialization.super.getInstructionSuccessor(tag, kind) } - final override Instruction getInitializationSuccessor() { result = getInstruction(ThrowTag()) } + final override Instruction getInitializationSuccessor() { + result = this.getInstruction(ThrowTag()) + } final override predicate hasTempVariable(TempVariableTag tag, CppType type) { tag = ThrowTempVar() and - type = getTypeForPRValue(getExceptionType()) + type = getTypeForPRValue(this.getExceptionType()) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { @@ -2215,7 +2244,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn tag = ThrowTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(InitializerVariableAddressTag()) + result = this.getInstruction(InitializerVariableAddressTag()) ) } @@ -2224,10 +2253,10 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn ) { tag = ThrowTag() and operandTag instanceof LoadOperandTag and - result = getTypeForPRValue(getExceptionType()) + result = getTypeForPRValue(this.getExceptionType()) } - override Type getTargetType() { result = getExceptionType() } + override Type getTargetType() { result = this.getExceptionType() } final override TranslatedInitialization getInitialization() { result = getTranslatedInitialization(expr.getExpr().getFullyConverted()) @@ -2248,7 +2277,7 @@ class TranslatedReThrowExpr extends TranslatedThrowExpr { override TranslatedElement getChild(int id) { none() } - override Instruction getFirstInstruction() { result = getInstruction(ThrowTag()) } + override Instruction getFirstInstruction() { result = this.getInstruction(ThrowTag()) } override Instruction getChildSuccessor(TranslatedElement child) { none() } @@ -2271,12 +2300,12 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr { not expr instanceof BuiltInVarArgCopy } - final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getFirstInstruction() { - if exists(getChild(0)) - then result = getChild(0).getFirstInstruction() - else result = getInstruction(OnlyInstructionTag()) + if exists(this.getChild(0)) + then result = this.getChild(0).getFirstInstruction() + else result = this.getInstruction(OnlyInstructionTag()) } final override TranslatedElement getChild(int id) { @@ -2286,31 +2315,31 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and kind instanceof GotoEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { exists(int id | - child = getChild(id) and + child = this.getChild(id) and ( - result = getChild(id + 1).getFirstInstruction() + result = this.getChild(id + 1).getFirstInstruction() or - not exists(getChild(id + 1)) and result = getInstruction(OnlyInstructionTag()) + not exists(this.getChild(id + 1)) and result = this.getInstruction(OnlyInstructionTag()) ) ) } final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and - opcode = getOpcode() and - resultType = getResultType() + opcode = this.getOpcode() and + resultType = this.getResultType() } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and exists(int index | operandTag = positionalArgumentOperand(index) and - result = getChild(index).(TranslatedExpr).getResult() + result = this.getChild(index).(TranslatedExpr).getResult() ) } @@ -2391,12 +2420,12 @@ class TranslatedVarArgsStart extends TranslatedNonConstantExpr { } final override Instruction getFirstInstruction() { - result = getInstruction(VarArgsStartEllipsisAddressTag()) + result = this.getInstruction(VarArgsStartEllipsisAddressTag()) } final override Instruction getResult() { none() } - final override TranslatedElement getChild(int id) { id = 0 and result = getVAList() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getVAList() } private TranslatedExpr getVAList() { result = getTranslatedExpr(expr.getVAList().getFullyConverted()) @@ -2405,37 +2434,37 @@ class TranslatedVarArgsStart extends TranslatedNonConstantExpr { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = VarArgsStartEllipsisAddressTag() and kind instanceof GotoEdge and - result = getInstruction(VarArgsStartTag()) + result = this.getInstruction(VarArgsStartTag()) or tag = VarArgsStartTag() and kind instanceof GotoEdge and - result = getVAList().getFirstInstruction() + result = this.getVAList().getFirstInstruction() or tag = VarArgsVAListStoreTag() and kind instanceof GotoEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getVAList() and - result = getInstruction(VarArgsVAListStoreTag()) + child = this.getVAList() and + result = this.getInstruction(VarArgsVAListStoreTag()) } final override IRVariable getInstructionVariable(InstructionTag tag) { tag = VarArgsStartEllipsisAddressTag() and - result = getEnclosingFunction().getEllipsisVariable() + result = this.getEnclosingFunction().getEllipsisVariable() } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsStartTag() and operandTag instanceof UnaryOperandTag and - result = getInstruction(VarArgsStartEllipsisAddressTag()) + result = this.getInstruction(VarArgsStartEllipsisAddressTag()) or tag = VarArgsVAListStoreTag() and ( - operandTag instanceof AddressOperandTag and result = getVAList().getResult() + operandTag instanceof AddressOperandTag and result = this.getVAList().getResult() or - operandTag instanceof StoreValueOperandTag and result = getInstruction(VarArgsStartTag()) + operandTag instanceof StoreValueOperandTag and result = this.getInstruction(VarArgsStartTag()) ) } } @@ -2453,7 +2482,7 @@ class TranslatedVarArg extends TranslatedNonConstantExpr { or tag = VarArgsArgAddressTag() and opcode instanceof Opcode::VarArg and - resultType = getResultType() + resultType = this.getResultType() or tag = VarArgsMoveNextTag() and opcode instanceof Opcode::NextVarArg and @@ -2464,11 +2493,13 @@ class TranslatedVarArg extends TranslatedNonConstantExpr { resultType = getTypeForPRValue(getVAListType(expr.getVAList().getFullyConverted())) } - final override Instruction getFirstInstruction() { result = getVAList().getFirstInstruction() } + final override Instruction getFirstInstruction() { + result = this.getVAList().getFirstInstruction() + } - final override Instruction getResult() { result = getInstruction(VarArgsArgAddressTag()) } + final override Instruction getResult() { result = this.getInstruction(VarArgsArgAddressTag()) } - final override TranslatedElement getChild(int id) { id = 0 and result = getVAList() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getVAList() } private TranslatedExpr getVAList() { result = getTranslatedExpr(expr.getVAList().getFullyConverted()) @@ -2477,46 +2508,47 @@ class TranslatedVarArg extends TranslatedNonConstantExpr { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = VarArgsVAListLoadTag() and kind instanceof GotoEdge and - result = getInstruction(VarArgsArgAddressTag()) + result = this.getInstruction(VarArgsArgAddressTag()) or tag = VarArgsArgAddressTag() and kind instanceof GotoEdge and - result = getInstruction(VarArgsMoveNextTag()) + result = this.getInstruction(VarArgsMoveNextTag()) or tag = VarArgsMoveNextTag() and kind instanceof GotoEdge and - result = getInstruction(VarArgsVAListStoreTag()) + result = this.getInstruction(VarArgsVAListStoreTag()) or tag = VarArgsVAListStoreTag() and kind instanceof GotoEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getVAList() and - result = getInstruction(VarArgsVAListLoadTag()) + child = this.getVAList() and + result = this.getInstruction(VarArgsVAListLoadTag()) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsVAListLoadTag() and ( operandTag instanceof AddressOperandTag and - result = getVAList().getResult() + result = this.getVAList().getResult() ) or tag = VarArgsArgAddressTag() and operandTag instanceof UnaryOperandTag and - result = getInstruction(VarArgsVAListLoadTag()) + result = this.getInstruction(VarArgsVAListLoadTag()) or tag = VarArgsMoveNextTag() and operandTag instanceof UnaryOperandTag and - result = getInstruction(VarArgsVAListLoadTag()) + result = this.getInstruction(VarArgsVAListLoadTag()) or tag = VarArgsVAListStoreTag() and ( - operandTag instanceof AddressOperandTag and result = getVAList().getResult() + operandTag instanceof AddressOperandTag and result = this.getVAList().getResult() or - operandTag instanceof StoreValueOperandTag and result = getInstruction(VarArgsMoveNextTag()) + operandTag instanceof StoreValueOperandTag and + result = this.getInstruction(VarArgsMoveNextTag()) ) } } @@ -2533,11 +2565,13 @@ class TranslatedVarArgsEnd extends TranslatedNonConstantExpr { resultType = getVoidType() } - final override Instruction getFirstInstruction() { result = getVAList().getFirstInstruction() } + final override Instruction getFirstInstruction() { + result = this.getVAList().getFirstInstruction() + } final override Instruction getResult() { none() } - final override TranslatedElement getChild(int id) { id = 0 and result = getVAList() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getVAList() } private TranslatedExpr getVAList() { result = getTranslatedExpr(expr.getVAList().getFullyConverted()) @@ -2546,18 +2580,18 @@ class TranslatedVarArgsEnd extends TranslatedNonConstantExpr { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and kind instanceof GotoEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getVAList() and - result = getInstruction(OnlyInstructionTag()) + child = this.getVAList() and + result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and - result = getVAList().getResult() + result = this.getVAList().getResult() } } @@ -2578,15 +2612,15 @@ class TranslatedVarArgCopy extends TranslatedNonConstantExpr { } final override Instruction getFirstInstruction() { - result = getSourceVAList().getFirstInstruction() + result = this.getSourceVAList().getFirstInstruction() } - final override Instruction getResult() { result = getInstruction(VarArgsVAListStoreTag()) } + final override Instruction getResult() { result = this.getInstruction(VarArgsVAListStoreTag()) } final override TranslatedElement getChild(int id) { - id = 0 and result = getDestinationVAList() + id = 0 and result = this.getDestinationVAList() or - id = 1 and result = getSourceVAList() + id = 1 and result = this.getSourceVAList() } private TranslatedExpr getDestinationVAList() { @@ -2600,33 +2634,34 @@ class TranslatedVarArgCopy extends TranslatedNonConstantExpr { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = VarArgsVAListLoadTag() and kind instanceof GotoEdge and - result = getDestinationVAList().getFirstInstruction() + result = this.getDestinationVAList().getFirstInstruction() or tag = VarArgsVAListStoreTag() and kind instanceof GotoEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getSourceVAList() and - result = getInstruction(VarArgsVAListLoadTag()) + child = this.getSourceVAList() and + result = this.getInstruction(VarArgsVAListLoadTag()) or - child = getDestinationVAList() and - result = getInstruction(VarArgsVAListStoreTag()) + child = this.getDestinationVAList() and + result = this.getInstruction(VarArgsVAListStoreTag()) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsVAListLoadTag() and ( operandTag instanceof AddressOperandTag and - result = getSourceVAList().getResult() + result = this.getSourceVAList().getResult() ) or tag = VarArgsVAListStoreTag() and ( - operandTag instanceof AddressOperandTag and result = getDestinationVAList().getResult() + operandTag instanceof AddressOperandTag and result = this.getDestinationVAList().getResult() or - operandTag instanceof StoreValueOperandTag and result = getInstruction(VarArgsVAListLoadTag()) + operandTag instanceof StoreValueOperandTag and + result = this.getInstruction(VarArgsVAListLoadTag()) ) } } @@ -2638,44 +2673,46 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr, In override NewOrNewArrayExpr expr; final override TranslatedElement getChild(int id) { - id = 0 and result = getAllocatorCall() + id = 0 and result = this.getAllocatorCall() or - id = 1 and result = getInitialization() + id = 1 and result = this.getInitialization() } final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::Convert and - resultType = getResultType() + resultType = this.getResultType() } final override Instruction getFirstInstruction() { - result = getAllocatorCall().getFirstInstruction() + result = this.getAllocatorCall().getFirstInstruction() } - final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { kind instanceof GotoEdge and tag = OnlyInstructionTag() and - if exists(getInitialization()) - then result = getInitialization().getFirstInstruction() - else result = getParent().getChildSuccessor(this) + if exists(this.getInitialization()) + then result = this.getInitialization().getFirstInstruction() + else result = this.getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getAllocatorCall() and result = getInstruction(OnlyInstructionTag()) + child = this.getAllocatorCall() and result = this.getInstruction(OnlyInstructionTag()) or - child = getInitialization() and result = getParent().getChildSuccessor(this) + child = this.getInitialization() and result = this.getParent().getChildSuccessor(this) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and - result = getAllocatorCall().getResult() + result = this.getAllocatorCall().getResult() } - final override Instruction getTargetAddress() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getTargetAddress() { + result = this.getInstruction(OnlyInstructionTag()) + } private TranslatedAllocatorCall getAllocatorCall() { result = getTranslatedAllocatorCall(expr) } @@ -2718,18 +2755,20 @@ class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr { class TranslatedDeleteArrayExprPlaceHolder extends TranslatedSingleInstructionExpr { override DeleteArrayExpr expr; - final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } + final override Instruction getFirstInstruction() { + result = this.getOperand().getFirstInstruction() + } - final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getInstruction(OnlyInstructionTag()) + child = this.getOperand() and result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { @@ -2752,18 +2791,20 @@ class TranslatedDeleteArrayExprPlaceHolder extends TranslatedSingleInstructionEx class TranslatedDeleteExprPlaceHolder extends TranslatedSingleInstructionExpr { override DeleteExpr expr; - final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } + final override Instruction getFirstInstruction() { + result = this.getOperand().getFirstInstruction() + } - final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } final override Instruction getChildSuccessor(TranslatedElement child) { - child = getOperand() and result = getInstruction(OnlyInstructionTag()) + child = this.getOperand() and result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { @@ -2788,23 +2829,23 @@ class TranslatedDeleteExprPlaceHolder extends TranslatedSingleInstructionExpr { class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr { override ConditionDeclExpr expr; - final override Instruction getFirstInstruction() { result = getDecl().getFirstInstruction() } + final override Instruction getFirstInstruction() { result = this.getDecl().getFirstInstruction() } final override TranslatedElement getChild(int id) { - id = 0 and result = getDecl() + id = 0 and result = this.getDecl() or - id = 1 and result = getConditionExpr() + id = 1 and result = this.getConditionExpr() } - override Instruction getResult() { result = getConditionExpr().getResult() } + override Instruction getResult() { result = this.getConditionExpr().getResult() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } override Instruction getChildSuccessor(TranslatedElement child) { - child = getDecl() and - result = getConditionExpr().getFirstInstruction() + child = this.getDecl() and + result = this.getConditionExpr().getFirstInstruction() or - child = getConditionExpr() and result = getParent().getChildSuccessor(this) + child = this.getConditionExpr() and result = this.getParent().getChildSuccessor(this) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { @@ -2826,34 +2867,34 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont override LambdaExpression expr; final override Instruction getFirstInstruction() { - result = getInstruction(InitializerVariableAddressTag()) + result = this.getInstruction(InitializerVariableAddressTag()) } - final override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() } - override Instruction getResult() { result = getInstruction(LoadTag()) } + override Instruction getResult() { result = this.getInstruction(LoadTag()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = InitializerVariableAddressTag() and kind instanceof GotoEdge and - result = getInstruction(InitializerStoreTag()) + result = this.getInstruction(InitializerStoreTag()) or tag = InitializerStoreTag() and kind instanceof GotoEdge and ( - result = getInitialization().getFirstInstruction() + result = this.getInitialization().getFirstInstruction() or - not hasInitializer() and result = getInstruction(LoadTag()) + not this.hasInitializer() and result = this.getInstruction(LoadTag()) ) or tag = LoadTag() and kind instanceof GotoEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } override Instruction getChildSuccessor(TranslatedElement child) { - child = getInitialization() and - result = getInstruction(LoadTag()) + child = this.getInitialization() and + result = this.getInstruction(LoadTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { @@ -2873,12 +2914,12 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerStoreTag() and operandTag instanceof AddressOperandTag and - result = getInstruction(InitializerVariableAddressTag()) + result = this.getInstruction(InitializerVariableAddressTag()) or tag = LoadTag() and ( operandTag instanceof AddressOperandTag and - result = getInstruction(InitializerVariableAddressTag()) + result = this.getInstruction(InitializerVariableAddressTag()) ) } @@ -2887,7 +2928,7 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont tag = InitializerVariableAddressTag() or tag = InitializerStoreTag() ) and - result = getTempVariable(LambdaTempVar()) + result = this.getTempVariable(LambdaTempVar()) } override predicate hasTempVariable(TempVariableTag tag, CppType type) { @@ -2896,12 +2937,12 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont } final override Instruction getTargetAddress() { - result = getInstruction(InitializerVariableAddressTag()) + result = this.getInstruction(InitializerVariableAddressTag()) } final override Type getTargetType() { result = expr.getType() } - private predicate hasInitializer() { exists(getInitialization()) } + private predicate hasInitializer() { exists(this.getInitialization()) } private TranslatedInitialization getInitialization() { result = getTranslatedInitialization(expr.getChild(0).getFullyConverted()) @@ -2915,28 +2956,28 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont class TranslatedStmtExpr extends TranslatedNonConstantExpr { override StmtExpr expr; - final override Instruction getFirstInstruction() { result = getStmt().getFirstInstruction() } + final override Instruction getFirstInstruction() { result = this.getStmt().getFirstInstruction() } - final override TranslatedElement getChild(int id) { id = 0 and result = getStmt() } + final override TranslatedElement getChild(int id) { id = 0 and result = this.getStmt() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag instanceof OnlyInstructionTag and kind instanceof GotoEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } override Instruction getChildSuccessor(TranslatedElement child) { - child = getStmt() and - result = getInstruction(OnlyInstructionTag()) + child = this.getStmt() and + result = this.getInstruction(OnlyInstructionTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { opcode instanceof Opcode::CopyValue and tag instanceof OnlyInstructionTag and - resultType = getResultType() + resultType = this.getResultType() } - override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag instanceof OnlyInstructionTag and @@ -2950,13 +2991,15 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr { class TranslatedErrorExpr extends TranslatedSingleInstructionExpr { override ErrorExpr expr; - final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getFirstInstruction() { + result = this.getInstruction(OnlyInstructionTag()) + } final override TranslatedElement getChild(int id) { none() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } @@ -3034,13 +3077,15 @@ class TranslatedAssumeExpr extends TranslatedSingleInstructionExpr { final override Opcode getOpcode() { result instanceof Opcode::NoOp } - final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getFirstInstruction() { + result = this.getInstruction(OnlyInstructionTag()) + } final override TranslatedElement getChild(int id) { none() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - result = getParent().getChildSuccessor(this) and + result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index ce08fc9367f..2bc3b5bc3ef 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -103,9 +103,7 @@ class TranslatedDeclStmt extends TranslatedStmt { class TranslatedExprStmt extends TranslatedStmt { override ExprStmt stmt; - TranslatedExpr getExpr() { - result = getTranslatedExpr(stmt.(ExprStmt).getExpr().getFullyConverted()) - } + TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr().getFullyConverted()) } override TranslatedElement getChild(int id) { id = 0 and result = getExpr() } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index 4b86f9a7cec..bb8630a5e0c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -24,7 +24,7 @@ class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ - final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() } /** * INTERNAL: Do not use. @@ -39,7 +39,7 @@ class IRBlockBase extends TIRBlock { ) and this = rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 | - funcBlock.getEnclosingFunction() = getEnclosingFunction() and + funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and // Ensure that the block containing `EnterFunction` always comes first. if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction @@ -59,15 +59,15 @@ class IRBlockBase extends TIRBlock { * Get the `Phi` instructions that appear at the start of this block. */ final PhiInstruction getAPhiInstruction() { - Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() + Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction() } /** * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { - result = getInstruction(_) or - result = getAPhiInstruction() + result = this.getInstruction(_) or + result = this.getAPhiInstruction() } /** @@ -78,7 +78,9 @@ class IRBlockBase extends TIRBlock { /** * Gets the last instruction in this block. */ - final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + final Instruction getLastInstruction() { + result = this.getInstruction(this.getInstructionCount() - 1) + } /** * Gets the number of non-`Phi` instructions in this block. @@ -149,7 +151,7 @@ class IRBlock extends IRBlockBase { * Block `A` dominates block `B` if any control flow path from the entry block of the function to * block `B` must pass through block `A`. A block always dominates itself. */ - final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block } /** * Gets a block on the dominance frontier of this block. @@ -159,8 +161,8 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock dominanceFrontier() { - dominates(result.getAPredecessor()) and - not strictlyDominates(result) + this.dominates(result.getAPredecessor()) and + not this.strictlyDominates(result) } /** @@ -189,7 +191,7 @@ class IRBlock extends IRBlockBase { * Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the * function must pass through block `A`. A block always post-dominates itself. */ - final predicate postDominates(IRBlock block) { strictlyPostDominates(block) or this = block } + final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block } /** * Gets a block on the post-dominance frontier of this block. @@ -199,16 +201,16 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock postPominanceFrontier() { - postDominates(result.getASuccessor()) and - not strictlyPostDominates(result) + this.postDominates(result.getASuccessor()) and + not this.strictlyPostDominates(result) } /** * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { - this = getEnclosingIRFunction().getEntryBlock() or - getAPredecessor().isReachableFromFunctionEntry() + this = this.getEnclosingIRFunction().getEntryBlock() or + this.getAPredecessor().isReachableFromFunctionEntry() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 6f471d8a7e8..1c2cc493338 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction { } /** Gets a textual representation of this element. */ - final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } + final string toString() { result = this.getOpcode().toString() + ": " + this.getAST().toString() } /** * Gets a string showing the result, opcode, and operands of the instruction, equivalent to what @@ -50,7 +50,8 @@ class Instruction extends Construction::TStageInstruction { * `mu0_28(int) = Store r0_26, r0_27` */ final string getDumpString() { - result = getResultString() + " = " + getOperationString() + " " + getOperandsString() + result = + this.getResultString() + " = " + this.getOperationString() + " " + this.getOperandsString() } private predicate shouldGenerateDumpStrings() { @@ -66,10 +67,13 @@ class Instruction extends Construction::TStageInstruction { * VariableAddress[x] */ final string getOperationString() { - shouldGenerateDumpStrings() and - if exists(getImmediateString()) - then result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]" - else result = getOperationPrefix() + getOpcode().toString() + this.shouldGenerateDumpStrings() and + if exists(this.getImmediateString()) + then + result = + this.getOperationPrefix() + this.getOpcode().toString() + "[" + this.getImmediateString() + + "]" + else result = this.getOperationPrefix() + this.getOpcode().toString() } /** @@ -78,17 +82,17 @@ class Instruction extends Construction::TStageInstruction { string getImmediateString() { none() } private string getOperationPrefix() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and if this instanceof SideEffectInstruction then result = "^" else result = "" } private string getResultPrefix() { - shouldGenerateDumpStrings() and - if getResultIRType() instanceof IRVoidType + this.shouldGenerateDumpStrings() and + if this.getResultIRType() instanceof IRVoidType then result = "v" else - if hasMemoryResult() - then if isResultModeled() then result = "m" else result = "mu" + if this.hasMemoryResult() + then if this.isResultModeled() then result = "m" else result = "mu" else result = "r" } @@ -97,7 +101,7 @@ class Instruction extends Construction::TStageInstruction { * used by debugging and printing code only. */ int getDisplayIndexInBlock() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and exists(IRBlock block | this = block.getInstruction(result) or @@ -111,12 +115,12 @@ class Instruction extends Construction::TStageInstruction { } private int getLineRank() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and this = rank[result](Instruction instr | instr = - getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(), - getLocation().getStartLine()) + getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(), + this.getLocation().getStartLine()) | instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() ) @@ -130,8 +134,9 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1` */ string getResultId() { - shouldGenerateDumpStrings() and - result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank() + this.shouldGenerateDumpStrings() and + result = + this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank() } /** @@ -142,8 +147,8 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1(int*)` */ final string getResultString() { - shouldGenerateDumpStrings() and - result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + this.shouldGenerateDumpStrings() and + result = this.getResultId() + "(" + this.getResultLanguageType().getDumpString() + ")" } /** @@ -153,10 +158,10 @@ class Instruction extends Construction::TStageInstruction { * Example: `func:r3_4, this:r3_5` */ string getOperandsString() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and result = concat(Operand operand | - operand = getAnOperand() + operand = this.getAnOperand() | operand.getDumpString(), ", " order by operand.getDumpSortOrder() ) @@ -190,7 +195,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the function that contains this instruction. */ final Language::Function getEnclosingFunction() { - result = getEnclosingIRFunction().getFunction() + result = this.getEnclosingIRFunction().getFunction() } /** @@ -208,7 +213,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets the location of the source code for this instruction. */ - final Language::Location getLocation() { result = getAST().getLocation() } + final Language::Location getLocation() { result = this.getAST().getLocation() } /** * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a @@ -243,7 +248,7 @@ class Instruction extends Construction::TStageInstruction { * a result, its result type will be `IRVoidType`. */ cached - final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() } /** * Gets the type of the result produced by this instruction. If the @@ -254,7 +259,7 @@ class Instruction extends Construction::TStageInstruction { */ final Language::Type getResultType() { exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and + resultType = this.getResultLanguageType() and ( resultType.hasUnspecifiedType(result, _) or @@ -283,7 +288,7 @@ class Instruction extends Construction::TStageInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { getResultLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -292,7 +297,7 @@ class Instruction extends Construction::TStageInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = getResultLanguageType().getByteSize() } + final int getResultSize() { result = this.getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -314,14 +319,16 @@ class Instruction extends Construction::TStageInstruction { /** * Holds if this instruction produces a memory result. */ - final predicate hasMemoryResult() { exists(getResultMemoryAccess()) } + final predicate hasMemoryResult() { exists(this.getResultMemoryAccess()) } /** * Gets the kind of memory access performed by this instruction's result. * Holds only for instructions with a memory result. */ pragma[inline] - final MemoryAccessKind getResultMemoryAccess() { result = getOpcode().getWriteMemoryAccess() } + final MemoryAccessKind getResultMemoryAccess() { + result = this.getOpcode().getWriteMemoryAccess() + } /** * Holds if the memory access performed by this instruction's result will not always write to @@ -332,7 +339,7 @@ class Instruction extends Construction::TStageInstruction { * (for example, the global side effects of a function call). */ pragma[inline] - final predicate hasResultMayMemoryAccess() { getOpcode().hasMayWriteMemoryAccess() } + final predicate hasResultMayMemoryAccess() { this.getOpcode().hasMayWriteMemoryAccess() } /** * Gets the operand that holds the memory address to which this instruction stores its @@ -340,7 +347,7 @@ class Instruction extends Construction::TStageInstruction { * is `r1`. */ final AddressOperand getResultAddressOperand() { - getResultMemoryAccess().usesAddressOperand() and + this.getResultMemoryAccess().usesAddressOperand() and result.getUse() = this } @@ -349,7 +356,7 @@ class Instruction extends Construction::TStageInstruction { * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` * is the instruction that defines `r1`. */ - final Instruction getResultAddress() { result = getResultAddressOperand().getDef() } + final Instruction getResultAddress() { result = this.getResultAddressOperand().getDef() } /** * Holds if the result of this instruction is precisely modeled in SSA. Always @@ -368,7 +375,7 @@ class Instruction extends Construction::TStageInstruction { */ final predicate isResultModeled() { // Register results are always in SSA form. - not hasMemoryResult() or + not this.hasMemoryResult() or Construction::hasModeledMemoryResult(this) } @@ -412,7 +419,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct successors of this instruction. */ - final Instruction getASuccessor() { result = getSuccessor(_) } + final Instruction getASuccessor() { result = this.getSuccessor(_) } /** * Gets a predecessor of this instruction such that the predecessor reaches @@ -423,7 +430,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct predecessors of this instruction. */ - final Instruction getAPredecessor() { result = getPredecessor(_) } + final Instruction getAPredecessor() { result = this.getPredecessor(_) } } /** @@ -543,7 +550,7 @@ class IndexedInstruction extends Instruction { * at this instruction. This instruction has no predecessors. */ class EnterFunctionInstruction extends Instruction { - EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } + EnterFunctionInstruction() { this.getOpcode() instanceof Opcode::EnterFunction } } /** @@ -554,7 +561,7 @@ class EnterFunctionInstruction extends Instruction { * struct, or union, see `FieldAddressInstruction`. */ class VariableAddressInstruction extends VariableInstruction { - VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } + VariableAddressInstruction() { this.getOpcode() instanceof Opcode::VariableAddress } } /** @@ -566,7 +573,7 @@ class VariableAddressInstruction extends VariableInstruction { * The result has an `IRFunctionAddress` type. */ class FunctionAddressInstruction extends FunctionInstruction { - FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } + FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress } } /** @@ -577,7 +584,7 @@ class FunctionAddressInstruction extends FunctionInstruction { * initializes that parameter. */ class InitializeParameterInstruction extends VariableInstruction { - InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + InitializeParameterInstruction() { this.getOpcode() instanceof Opcode::InitializeParameter } /** * Gets the parameter initialized by this instruction. @@ -603,7 +610,7 @@ class InitializeParameterInstruction extends VariableInstruction { * initialized elsewhere, would not otherwise have a definition in this function. */ class InitializeNonLocalInstruction extends Instruction { - InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } + InitializeNonLocalInstruction() { this.getOpcode() instanceof Opcode::InitializeNonLocal } } /** @@ -611,7 +618,7 @@ class InitializeNonLocalInstruction extends Instruction { * with the value of that memory on entry to the function. */ class InitializeIndirectionInstruction extends VariableInstruction { - InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + InitializeIndirectionInstruction() { this.getOpcode() instanceof Opcode::InitializeIndirection } /** * Gets the parameter initialized by this instruction. @@ -635,24 +642,24 @@ class InitializeIndirectionInstruction extends VariableInstruction { * An instruction that initializes the `this` pointer parameter of the enclosing function. */ class InitializeThisInstruction extends Instruction { - InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } + InitializeThisInstruction() { this.getOpcode() instanceof Opcode::InitializeThis } } /** * An instruction that computes the address of a non-static field of an object. */ class FieldAddressInstruction extends FieldInstruction { - FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + FieldAddressInstruction() { this.getOpcode() instanceof Opcode::FieldAddress } /** * Gets the operand that provides the address of the object containing the field. */ - final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the object containing the field. */ - final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } + final Instruction getObjectAddress() { result = this.getObjectAddressOperand().getDef() } } /** @@ -661,17 +668,19 @@ class FieldAddressInstruction extends FieldInstruction { * This instruction is used for element access to C# arrays. */ class ElementsAddressInstruction extends UnaryInstruction { - ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + ElementsAddressInstruction() { this.getOpcode() instanceof Opcode::ElementsAddress } /** * Gets the operand that provides the address of the array object. */ - final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getArrayObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the array object. */ - final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } + final Instruction getArrayObjectAddress() { + result = this.getArrayObjectAddressOperand().getDef() + } } /** @@ -685,7 +694,7 @@ class ElementsAddressInstruction extends UnaryInstruction { * taken may want to ignore any function that contains an `ErrorInstruction`. */ class ErrorInstruction extends Instruction { - ErrorInstruction() { getOpcode() instanceof Opcode::Error } + ErrorInstruction() { this.getOpcode() instanceof Opcode::Error } } /** @@ -695,7 +704,7 @@ class ErrorInstruction extends Instruction { * an initializer, or whose initializer only partially initializes the variable. */ class UninitializedInstruction extends VariableInstruction { - UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } + UninitializedInstruction() { this.getOpcode() instanceof Opcode::Uninitialized } /** * Gets the variable that is uninitialized. @@ -710,7 +719,7 @@ class UninitializedInstruction extends VariableInstruction { * least one instruction, even when the AST has no semantic effect. */ class NoOpInstruction extends Instruction { - NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } + NoOpInstruction() { this.getOpcode() instanceof Opcode::NoOp } } /** @@ -732,32 +741,42 @@ class NoOpInstruction extends Instruction { * `void`-returning function. */ class ReturnInstruction extends Instruction { - ReturnInstruction() { getOpcode() instanceof ReturnOpcode } + ReturnInstruction() { this.getOpcode() instanceof ReturnOpcode } } /** * An instruction that returns control to the caller of the function, without returning a value. */ class ReturnVoidInstruction extends ReturnInstruction { - ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } + ReturnVoidInstruction() { this.getOpcode() instanceof Opcode::ReturnVoid } } /** * An instruction that returns control to the caller of the function, including a return value. */ class ReturnValueInstruction extends ReturnInstruction { - ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + ReturnValueInstruction() { this.getOpcode() instanceof Opcode::ReturnValue } /** * Gets the operand that provides the value being returned by the function. */ - final LoadOperand getReturnValueOperand() { result = getAnOperand() } + final LoadOperand getReturnValueOperand() { result = this.getAnOperand() } + + /** + * Gets the operand that provides the address of the value being returned by the function. + */ + final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value being returned by the function, if an * exact definition is available. */ - final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } + final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() } + + /** + * Gets the instruction whose result provides the address of the value being returned by the function. + */ + final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() } } /** @@ -770,28 +789,28 @@ class ReturnValueInstruction extends ReturnInstruction { * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { - ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + ReturnIndirectionInstruction() { this.getOpcode() instanceof Opcode::ReturnIndirection } /** * Gets the operand that provides the value of the pointed-to memory. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the pointed-to memory, if an exact * definition is available. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** * Gets the operand that provides the address of the pointed-to memory. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the pointed-to memory. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } /** * Gets the parameter for which this instruction reads the final pointed-to value within the @@ -826,7 +845,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { * - `StoreInstruction` - Copies a register operand to a memory result. */ class CopyInstruction extends Instruction { - CopyInstruction() { getOpcode() instanceof CopyOpcode } + CopyInstruction() { this.getOpcode() instanceof CopyOpcode } /** * Gets the operand that provides the input value of the copy. @@ -837,16 +856,16 @@ class CopyInstruction extends Instruction { * Gets the instruction whose result provides the input value of the copy, if an exact definition * is available. */ - final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } + final Instruction getSourceValue() { result = this.getSourceValueOperand().getDef() } } /** * An instruction that returns a register result containing a copy of its register operand. */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { - CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } + CopyValueInstruction() { this.getOpcode() instanceof Opcode::CopyValue } - final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } + final override UnaryOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -863,47 +882,49 @@ private string getAddressOperandDescription(AddressOperand operand) { * An instruction that returns a register result containing a copy of its memory operand. */ class LoadInstruction extends CopyInstruction { - LoadInstruction() { getOpcode() instanceof Opcode::Load } + LoadInstruction() { this.getOpcode() instanceof Opcode::Load } final override string getImmediateString() { - result = getAddressOperandDescription(getSourceAddressOperand()) + result = getAddressOperandDescription(this.getSourceAddressOperand()) } /** * Gets the operand that provides the address of the value being loaded. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the value being loaded. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - final override LoadOperand getSourceValueOperand() { result = getAnOperand() } + final override LoadOperand getSourceValueOperand() { result = this.getAnOperand() } } /** * An instruction that returns a memory result containing a copy of its register operand. */ class StoreInstruction extends CopyInstruction { - StoreInstruction() { getOpcode() instanceof Opcode::Store } + StoreInstruction() { this.getOpcode() instanceof Opcode::Store } final override string getImmediateString() { - result = getAddressOperandDescription(getDestinationAddressOperand()) + result = getAddressOperandDescription(this.getDestinationAddressOperand()) } /** * Gets the operand that provides the address of the location to which the value will be stored. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the location to which the value will * be stored, if an exact definition is available. */ - final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + final Instruction getDestinationAddress() { + result = this.getDestinationAddressOperand().getDef() + } - final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } + final override StoreValueOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -911,27 +932,27 @@ class StoreInstruction extends CopyInstruction { * operand. */ class ConditionalBranchInstruction extends Instruction { - ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + ConditionalBranchInstruction() { this.getOpcode() instanceof Opcode::ConditionalBranch } /** * Gets the operand that provides the Boolean condition controlling the branch. */ - final ConditionOperand getConditionOperand() { result = getAnOperand() } + final ConditionOperand getConditionOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the Boolean condition controlling the branch. */ - final Instruction getCondition() { result = getConditionOperand().getDef() } + final Instruction getCondition() { result = this.getConditionOperand().getDef() } /** * Gets the instruction to which control will flow if the condition is true. */ - final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + final Instruction getTrueSuccessor() { result = this.getSuccessor(EdgeKind::trueEdge()) } /** * Gets the instruction to which control will flow if the condition is false. */ - final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } + final Instruction getFalseSuccessor() { result = this.getSuccessor(EdgeKind::falseEdge()) } } /** @@ -943,14 +964,14 @@ class ConditionalBranchInstruction extends Instruction { * successors. */ class ExitFunctionInstruction extends Instruction { - ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } + ExitFunctionInstruction() { this.getOpcode() instanceof Opcode::ExitFunction } } /** * An instruction whose result is a constant value. */ class ConstantInstruction extends ConstantValueInstruction { - ConstantInstruction() { getOpcode() instanceof Opcode::Constant } + ConstantInstruction() { this.getOpcode() instanceof Opcode::Constant } } /** @@ -959,7 +980,7 @@ class ConstantInstruction extends ConstantValueInstruction { class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | - resultType = getResultIRType() and + resultType = this.getResultIRType() and (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) ) } @@ -969,7 +990,7 @@ class IntegerConstantInstruction extends ConstantInstruction { * An instruction whose result is a constant value of floating-point type. */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } + FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType } } /** @@ -978,7 +999,9 @@ class FloatConstantInstruction extends ConstantInstruction { class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; - final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + final override string getImmediateString() { + result = Language::getStringLiteralText(this.getValue()) + } /** * Gets the string literal whose address is returned by this instruction. @@ -990,37 +1013,37 @@ class StringConstantInstruction extends VariableInstruction { * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { - BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + BinaryInstruction() { this.getOpcode() instanceof BinaryOpcode } /** * Gets the left operand of this binary instruction. */ - final LeftOperand getLeftOperand() { result = getAnOperand() } + final LeftOperand getLeftOperand() { result = this.getAnOperand() } /** * Gets the right operand of this binary instruction. */ - final RightOperand getRightOperand() { result = getAnOperand() } + final RightOperand getRightOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the left operand of this binary * instruction. */ - final Instruction getLeft() { result = getLeftOperand().getDef() } + final Instruction getLeft() { result = this.getLeftOperand().getDef() } /** * Gets the instruction whose result provides the value of the right operand of this binary * instruction. */ - final Instruction getRight() { result = getRightOperand().getDef() } + final Instruction getRight() { result = this.getRightOperand().getDef() } /** * Holds if this instruction's operands are `op1` and `op2`, in either order. */ final predicate hasOperands(Operand op1, Operand op2) { - op1 = getLeftOperand() and op2 = getRightOperand() + op1 = this.getLeftOperand() and op2 = this.getRightOperand() or - op1 = getRightOperand() and op2 = getLeftOperand() + op1 = this.getRightOperand() and op2 = this.getLeftOperand() } } @@ -1028,7 +1051,7 @@ class BinaryInstruction extends Instruction { * An instruction that computes the result of an arithmetic operation. */ class ArithmeticInstruction extends Instruction { - ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } + ArithmeticInstruction() { this.getOpcode() instanceof ArithmeticOpcode } } /** @@ -1050,7 +1073,7 @@ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction * performed according to IEEE-754. */ class AddInstruction extends BinaryArithmeticInstruction { - AddInstruction() { getOpcode() instanceof Opcode::Add } + AddInstruction() { this.getOpcode() instanceof Opcode::Add } } /** @@ -1061,7 +1084,7 @@ class AddInstruction extends BinaryArithmeticInstruction { * according to IEEE-754. */ class SubInstruction extends BinaryArithmeticInstruction { - SubInstruction() { getOpcode() instanceof Opcode::Sub } + SubInstruction() { this.getOpcode() instanceof Opcode::Sub } } /** @@ -1072,7 +1095,7 @@ class SubInstruction extends BinaryArithmeticInstruction { * performed according to IEEE-754. */ class MulInstruction extends BinaryArithmeticInstruction { - MulInstruction() { getOpcode() instanceof Opcode::Mul } + MulInstruction() { this.getOpcode() instanceof Opcode::Mul } } /** @@ -1083,7 +1106,7 @@ class MulInstruction extends BinaryArithmeticInstruction { * to IEEE-754. */ class DivInstruction extends BinaryArithmeticInstruction { - DivInstruction() { getOpcode() instanceof Opcode::Div } + DivInstruction() { this.getOpcode() instanceof Opcode::Div } } /** @@ -1093,7 +1116,7 @@ class DivInstruction extends BinaryArithmeticInstruction { * division by zero or integer overflow is undefined. */ class RemInstruction extends BinaryArithmeticInstruction { - RemInstruction() { getOpcode() instanceof Opcode::Rem } + RemInstruction() { this.getOpcode() instanceof Opcode::Rem } } /** @@ -1104,14 +1127,14 @@ class RemInstruction extends BinaryArithmeticInstruction { * is performed according to IEEE-754. */ class NegateInstruction extends UnaryArithmeticInstruction { - NegateInstruction() { getOpcode() instanceof Opcode::Negate } + NegateInstruction() { this.getOpcode() instanceof Opcode::Negate } } /** * An instruction that computes the result of a bitwise operation. */ class BitwiseInstruction extends Instruction { - BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } + BitwiseInstruction() { this.getOpcode() instanceof BitwiseOpcode } } /** @@ -1130,7 +1153,7 @@ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } * Both operands must have the same integer type, which will also be the result type. */ class BitAndInstruction extends BinaryBitwiseInstruction { - BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } + BitAndInstruction() { this.getOpcode() instanceof Opcode::BitAnd } } /** @@ -1139,7 +1162,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitOrInstruction extends BinaryBitwiseInstruction { - BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } + BitOrInstruction() { this.getOpcode() instanceof Opcode::BitOr } } /** @@ -1148,7 +1171,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitXorInstruction extends BinaryBitwiseInstruction { - BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } + BitXorInstruction() { this.getOpcode() instanceof Opcode::BitXor } } /** @@ -1159,7 +1182,7 @@ class BitXorInstruction extends BinaryBitwiseInstruction { * rightmost bits are zero-filled. */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { - ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } + ShiftLeftInstruction() { this.getOpcode() instanceof Opcode::ShiftLeft } } /** @@ -1172,7 +1195,7 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { * of the left operand. */ class ShiftRightInstruction extends BinaryBitwiseInstruction { - ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } + ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight } } /** @@ -1183,7 +1206,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { - getOpcode() instanceof PointerArithmeticOpcode and + this.getOpcode() instanceof PointerArithmeticOpcode and elementSize = Raw::getInstructionElementSize(this) } @@ -1206,7 +1229,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { * An instruction that adds or subtracts an integer offset from a pointer. */ class PointerOffsetInstruction extends PointerArithmeticInstruction { - PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } + PointerOffsetInstruction() { this.getOpcode() instanceof PointerOffsetOpcode } } /** @@ -1217,7 +1240,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { * overflow is undefined. */ class PointerAddInstruction extends PointerOffsetInstruction { - PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } + PointerAddInstruction() { this.getOpcode() instanceof Opcode::PointerAdd } } /** @@ -1228,7 +1251,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { * pointer underflow is undefined. */ class PointerSubInstruction extends PointerOffsetInstruction { - PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } + PointerSubInstruction() { this.getOpcode() instanceof Opcode::PointerSub } } /** @@ -1241,31 +1264,31 @@ class PointerSubInstruction extends PointerOffsetInstruction { * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { - PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } + PointerDiffInstruction() { this.getOpcode() instanceof Opcode::PointerDiff } } /** * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { - UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + UnaryInstruction() { this.getOpcode() instanceof UnaryOpcode } /** * Gets the sole operand of this instruction. */ - final UnaryOperand getUnaryOperand() { result = getAnOperand() } + final UnaryOperand getUnaryOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the sole operand of this instruction. */ - final Instruction getUnary() { result = getUnaryOperand().getDef() } + final Instruction getUnary() { result = this.getUnaryOperand().getDef() } } /** * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { - ConvertInstruction() { getOpcode() instanceof Opcode::Convert } + ConvertInstruction() { this.getOpcode() instanceof Opcode::Convert } } /** @@ -1279,7 +1302,7 @@ class ConvertInstruction extends UnaryInstruction { * `as` expression. */ class CheckedConvertOrNullInstruction extends UnaryInstruction { - CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } + CheckedConvertOrNullInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** @@ -1293,7 +1316,7 @@ class CheckedConvertOrNullInstruction extends UnaryInstruction { * expression. */ class CheckedConvertOrThrowInstruction extends UnaryInstruction { - CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } + CheckedConvertOrThrowInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrThrow } } /** @@ -1306,7 +1329,7 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { * the most-derived object. */ class CompleteObjectAddressInstruction extends UnaryInstruction { - CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } + CompleteObjectAddressInstruction() { this.getOpcode() instanceof Opcode::CompleteObjectAddress } } /** @@ -1351,7 +1374,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { - ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } + ConvertToBaseInstruction() { this.getOpcode() instanceof ConvertToBaseOpcode } } /** @@ -1361,7 +1384,9 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } + ConvertToNonVirtualBaseInstruction() { + this.getOpcode() instanceof Opcode::ConvertToNonVirtualBase + } } /** @@ -1371,7 +1396,7 @@ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } + ConvertToVirtualBaseInstruction() { this.getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** @@ -1381,7 +1406,7 @@ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { - ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } + ConvertToDerivedInstruction() { this.getOpcode() instanceof Opcode::ConvertToDerived } } /** @@ -1390,7 +1415,7 @@ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { * The operand must have an integer type, which will also be the result type. */ class BitComplementInstruction extends UnaryBitwiseInstruction { - BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } + BitComplementInstruction() { this.getOpcode() instanceof Opcode::BitComplement } } /** @@ -1399,14 +1424,14 @@ class BitComplementInstruction extends UnaryBitwiseInstruction { * The operand must have a Boolean type, which will also be the result type. */ class LogicalNotInstruction extends UnaryInstruction { - LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } + LogicalNotInstruction() { this.getOpcode() instanceof Opcode::LogicalNot } } /** * An instruction that compares two numeric operands. */ class CompareInstruction extends BinaryInstruction { - CompareInstruction() { getOpcode() instanceof CompareOpcode } + CompareInstruction() { this.getOpcode() instanceof CompareOpcode } } /** @@ -1417,7 +1442,7 @@ class CompareInstruction extends BinaryInstruction { * unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareEQInstruction extends CompareInstruction { - CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } + CompareEQInstruction() { this.getOpcode() instanceof Opcode::CompareEQ } } /** @@ -1428,14 +1453,14 @@ class CompareEQInstruction extends CompareInstruction { * `left == right`. Floating-point comparison is performed according to IEEE-754. */ class CompareNEInstruction extends CompareInstruction { - CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } + CompareNEInstruction() { this.getOpcode() instanceof Opcode::CompareNE } } /** * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { - RelationalInstruction() { getOpcode() instanceof RelationalOpcode } + RelationalInstruction() { this.getOpcode() instanceof RelationalOpcode } /** * Gets the operand on the "greater" (or "greater-or-equal") side @@ -1467,11 +1492,11 @@ class RelationalInstruction extends CompareInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLTInstruction extends RelationalInstruction { - CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } + CompareLTInstruction() { this.getOpcode() instanceof Opcode::CompareLT } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { any() } } @@ -1484,11 +1509,11 @@ class CompareLTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGTInstruction extends RelationalInstruction { - CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } + CompareGTInstruction() { this.getOpcode() instanceof Opcode::CompareGT } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { any() } } @@ -1502,11 +1527,11 @@ class CompareGTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLEInstruction extends RelationalInstruction { - CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } + CompareLEInstruction() { this.getOpcode() instanceof Opcode::CompareLE } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { none() } } @@ -1520,11 +1545,11 @@ class CompareLEInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGEInstruction extends RelationalInstruction { - CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } + CompareGEInstruction() { this.getOpcode() instanceof Opcode::CompareGE } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { none() } } @@ -1543,78 +1568,78 @@ class CompareGEInstruction extends RelationalInstruction { * of any case edge. */ class SwitchInstruction extends Instruction { - SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + SwitchInstruction() { this.getOpcode() instanceof Opcode::Switch } /** Gets the operand that provides the integer value controlling the switch. */ - final ConditionOperand getExpressionOperand() { result = getAnOperand() } + final ConditionOperand getExpressionOperand() { result = this.getAnOperand() } /** Gets the instruction whose result provides the integer value controlling the switch. */ - final Instruction getExpression() { result = getExpressionOperand().getDef() } + final Instruction getExpression() { result = this.getExpressionOperand().getDef() } /** Gets the successor instructions along the case edges of the switch. */ - final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = this.getSuccessor(edge)) } /** Gets the successor instruction along the default edge of the switch, if any. */ - final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } + final Instruction getDefaultSuccessor() { result = this.getSuccessor(EdgeKind::defaultEdge()) } } /** * An instruction that calls a function. */ class CallInstruction extends Instruction { - CallInstruction() { getOpcode() instanceof Opcode::Call } + CallInstruction() { this.getOpcode() instanceof Opcode::Call } final override string getImmediateString() { - result = getStaticCallTarget().toString() + result = this.getStaticCallTarget().toString() or - not exists(getStaticCallTarget()) and result = "?" + not exists(this.getStaticCallTarget()) and result = "?" } /** * Gets the operand the specifies the target function of the call. */ - final CallTargetOperand getCallTargetOperand() { result = getAnOperand() } + final CallTargetOperand getCallTargetOperand() { result = this.getAnOperand() } /** * Gets the `Instruction` that computes the target function of the call. This is usually a * `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a * function pointer. */ - final Instruction getCallTarget() { result = getCallTargetOperand().getDef() } + final Instruction getCallTarget() { result = this.getCallTargetOperand().getDef() } /** * Gets all of the argument operands of the call, including the `this` pointer, if any. */ - final ArgumentOperand getAnArgumentOperand() { result = getAnOperand() } + final ArgumentOperand getAnArgumentOperand() { result = this.getAnOperand() } /** * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() + result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** * Gets all of the arguments of the call, including the `this` pointer, if any. */ - final Instruction getAnArgument() { result = getAnArgumentOperand().getDef() } + final Instruction getAnArgument() { result = this.getAnArgumentOperand().getDef() } /** * Gets the `this` pointer argument operand of the call, if any. */ - final ThisArgumentOperand getThisArgumentOperand() { result = getAnOperand() } + final ThisArgumentOperand getThisArgumentOperand() { result = this.getAnOperand() } /** * Gets the `this` pointer argument of the call, if any. */ - final Instruction getThisArgument() { result = getThisArgumentOperand().getDef() } + final Instruction getThisArgument() { result = this.getThisArgumentOperand().getDef() } /** * Gets the argument operand at the specified index. */ pragma[noinline] final PositionalArgumentOperand getPositionalArgumentOperand(int index) { - result = getAnOperand() and + result = this.getAnOperand() and result.getIndex() = index } @@ -1623,7 +1648,7 @@ class CallInstruction extends Instruction { */ pragma[noinline] final Instruction getPositionalArgument(int index) { - result = getPositionalArgumentOperand(index).getDef() + result = this.getPositionalArgumentOperand(index).getDef() } /** @@ -1631,16 +1656,16 @@ class CallInstruction extends Instruction { */ pragma[noinline] final ArgumentOperand getArgumentOperand(int index) { - index >= 0 and result = getPositionalArgumentOperand(index) + index >= 0 and result = this.getPositionalArgumentOperand(index) or - index = -1 and result = getThisArgumentOperand() + index = -1 and result = this.getThisArgumentOperand() } /** * Gets the argument at the specified index, or `this` if `index` is `-1`. */ pragma[noinline] - final Instruction getArgument(int index) { result = getArgumentOperand(index).getDef() } + final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() } /** * Gets the number of arguments of the call, including the `this` pointer, if any. @@ -1665,7 +1690,7 @@ class CallInstruction extends Instruction { * An instruction representing a side effect of a function call. */ class SideEffectInstruction extends Instruction { - SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + SideEffectInstruction() { this.getOpcode() instanceof SideEffectOpcode } /** * Gets the instruction whose execution causes this side effect. @@ -1680,7 +1705,7 @@ class SideEffectInstruction extends Instruction { * accessed by that call. */ class CallSideEffectInstruction extends SideEffectInstruction { - CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect } + CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect } } /** @@ -1691,7 +1716,7 @@ class CallSideEffectInstruction extends SideEffectInstruction { * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { - CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } + CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect } } /** @@ -1699,33 +1724,33 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * specific parameter. */ class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode } + ReadSideEffectInstruction() { this.getOpcode() instanceof ReadSideEffectOpcode } /** Gets the operand for the value that will be read from this instruction, if known. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** Gets the value that will be read from this instruction, if known. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** Gets the operand for the address from which this instruction may read. */ - final AddressOperand getArgumentOperand() { result = getAnOperand() } + final AddressOperand getArgumentOperand() { result = this.getAnOperand() } /** Gets the address from which this instruction may read. */ - final Instruction getArgumentDef() { result = getArgumentOperand().getDef() } + final Instruction getArgumentDef() { result = this.getArgumentOperand().getDef() } } /** * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::IndirectReadSideEffect } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::BufferReadSideEffect } } /** @@ -1733,18 +1758,18 @@ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { */ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { SizedBufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferReadSideEffect + this.getOpcode() instanceof Opcode::SizedBufferReadSideEffect } /** * Gets the operand that holds the number of bytes read from the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes read from the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1752,17 +1777,17 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { * specific parameter. */ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } + WriteSideEffectInstruction() { this.getOpcode() instanceof WriteSideEffectOpcode } /** * Get the operand that holds the address of the memory to be written. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the memory to be written. */ - Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + Instruction getDestinationAddress() { result = this.getDestinationAddressOperand().getDef() } } /** @@ -1770,7 +1795,7 @@ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstructi */ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMustWriteSideEffect } } @@ -1780,7 +1805,7 @@ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction */ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { BufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::BufferMustWriteSideEffect } } @@ -1790,18 +1815,18 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1812,7 +1837,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi */ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMayWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } } @@ -1822,7 +1847,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } + BufferMayWriteSideEffectInstruction() { + this.getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } } /** @@ -1832,18 +1859,18 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1852,80 +1879,80 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { InitializeDynamicAllocationInstruction() { - getOpcode() instanceof Opcode::InitializeDynamicAllocation + this.getOpcode() instanceof Opcode::InitializeDynamicAllocation } /** * Gets the operand that represents the address of the allocation this instruction is initializing. */ - final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + final AddressOperand getAllocationAddressOperand() { result = this.getAnOperand() } /** * Gets the address for the allocation this instruction is initializing. */ - final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } + final Instruction getAllocationAddress() { result = this.getAllocationAddressOperand().getDef() } } /** * An instruction representing a GNU or MSVC inline assembly statement. */ class InlineAsmInstruction extends Instruction { - InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm } + InlineAsmInstruction() { this.getOpcode() instanceof Opcode::InlineAsm } } /** * An instruction that throws an exception. */ class ThrowInstruction extends Instruction { - ThrowInstruction() { getOpcode() instanceof ThrowOpcode } + ThrowInstruction() { this.getOpcode() instanceof ThrowOpcode } } /** * An instruction that throws a new exception. */ class ThrowValueInstruction extends ThrowInstruction { - ThrowValueInstruction() { getOpcode() instanceof Opcode::ThrowValue } + ThrowValueInstruction() { this.getOpcode() instanceof Opcode::ThrowValue } /** * Gets the address operand of the exception thrown by this instruction. */ - final AddressOperand getExceptionAddressOperand() { result = getAnOperand() } + final AddressOperand getExceptionAddressOperand() { result = this.getAnOperand() } /** * Gets the address of the exception thrown by this instruction. */ - final Instruction getExceptionAddress() { result = getExceptionAddressOperand().getDef() } + final Instruction getExceptionAddress() { result = this.getExceptionAddressOperand().getDef() } /** * Gets the operand for the exception thrown by this instruction. */ - final LoadOperand getExceptionOperand() { result = getAnOperand() } + final LoadOperand getExceptionOperand() { result = this.getAnOperand() } /** * Gets the exception thrown by this instruction. */ - final Instruction getException() { result = getExceptionOperand().getDef() } + final Instruction getException() { result = this.getExceptionOperand().getDef() } } /** * An instruction that re-throws the current exception. */ class ReThrowInstruction extends ThrowInstruction { - ReThrowInstruction() { getOpcode() instanceof Opcode::ReThrow } + ReThrowInstruction() { this.getOpcode() instanceof Opcode::ReThrow } } /** * An instruction that exits the current function by propagating an exception. */ class UnwindInstruction extends Instruction { - UnwindInstruction() { getOpcode() instanceof Opcode::Unwind } + UnwindInstruction() { this.getOpcode() instanceof Opcode::Unwind } } /** * An instruction that starts a `catch` handler. */ class CatchInstruction extends Instruction { - CatchInstruction() { getOpcode() instanceof CatchOpcode } + CatchInstruction() { this.getOpcode() instanceof CatchOpcode } } /** @@ -1935,7 +1962,7 @@ class CatchByTypeInstruction extends CatchInstruction { Language::LanguageType exceptionType; CatchByTypeInstruction() { - getOpcode() instanceof Opcode::CatchByType and + this.getOpcode() instanceof Opcode::CatchByType and exceptionType = Raw::getInstructionExceptionType(this) } @@ -1951,21 +1978,21 @@ class CatchByTypeInstruction extends CatchInstruction { * An instruction that catches any exception. */ class CatchAnyInstruction extends CatchInstruction { - CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } + CatchAnyInstruction() { this.getOpcode() instanceof Opcode::CatchAny } } /** * An instruction that initializes all escaped memory. */ class AliasedDefinitionInstruction extends Instruction { - AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition } + AliasedDefinitionInstruction() { this.getOpcode() instanceof Opcode::AliasedDefinition } } /** * An instruction that consumes all escaped memory on exit from the function. */ class AliasedUseInstruction extends Instruction { - AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } + AliasedUseInstruction() { this.getOpcode() instanceof Opcode::AliasedUse } } /** @@ -1979,7 +2006,7 @@ class AliasedUseInstruction extends Instruction { * runtime. */ class PhiInstruction extends Instruction { - PhiInstruction() { getOpcode() instanceof Opcode::Phi } + PhiInstruction() { this.getOpcode() instanceof Opcode::Phi } /** * Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block. @@ -2047,29 +2074,29 @@ class PhiInstruction extends Instruction { * https://link.springer.com/content/pdf/10.1007%2F3-540-61053-7_66.pdf. */ class ChiInstruction extends Instruction { - ChiInstruction() { getOpcode() instanceof Opcode::Chi } + ChiInstruction() { this.getOpcode() instanceof Opcode::Chi } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final ChiTotalOperand getTotalOperand() { result = getAnOperand() } + final ChiTotalOperand getTotalOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final Instruction getTotal() { result = getTotalOperand().getDef() } + final Instruction getTotal() { result = this.getTotalOperand().getDef() } /** * Gets the operand that represents the new value written by the memory write. */ - final ChiPartialOperand getPartialOperand() { result = getAnOperand() } + final ChiPartialOperand getPartialOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the new value written by the memory write. */ - final Instruction getPartial() { result = getPartialOperand().getDef() } + final Instruction getPartial() { result = this.getPartialOperand().getDef() } /** * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. @@ -2093,7 +2120,7 @@ class ChiInstruction extends Instruction { * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { - UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } + UnreachedInstruction() { this.getOpcode() instanceof Opcode::Unreached } } /** @@ -2106,7 +2133,7 @@ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { - getOpcode() instanceof BuiltInOperationOpcode and + this.getOpcode() instanceof BuiltInOperationOpcode and operation = Raw::getInstructionBuiltInOperation(this) } @@ -2122,9 +2149,9 @@ class BuiltInOperationInstruction extends Instruction { * actual operation is specified by the `getBuiltInOperation()` predicate. */ class BuiltInInstruction extends BuiltInOperationInstruction { - BuiltInInstruction() { getOpcode() instanceof Opcode::BuiltIn } + BuiltInInstruction() { this.getOpcode() instanceof Opcode::BuiltIn } - final override string getImmediateString() { result = getBuiltInOperation().toString() } + final override string getImmediateString() { result = this.getBuiltInOperation().toString() } } /** @@ -2135,7 +2162,7 @@ class BuiltInInstruction extends BuiltInOperationInstruction { * to the `...` parameter. */ class VarArgsStartInstruction extends UnaryInstruction { - VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } + VarArgsStartInstruction() { this.getOpcode() instanceof Opcode::VarArgsStart } } /** @@ -2145,7 +2172,7 @@ class VarArgsStartInstruction extends UnaryInstruction { * a result. */ class VarArgsEndInstruction extends UnaryInstruction { - VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } + VarArgsEndInstruction() { this.getOpcode() instanceof Opcode::VarArgsEnd } } /** @@ -2155,7 +2182,7 @@ class VarArgsEndInstruction extends UnaryInstruction { * argument. */ class VarArgInstruction extends UnaryInstruction { - VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } + VarArgInstruction() { this.getOpcode() instanceof Opcode::VarArg } } /** @@ -2166,7 +2193,7 @@ class VarArgInstruction extends UnaryInstruction { * argument of the `...` parameter. */ class NextVarArgInstruction extends UnaryInstruction { - NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } + NextVarArgInstruction() { this.getOpcode() instanceof Opcode::NextVarArg } } /** @@ -2180,5 +2207,5 @@ class NextVarArgInstruction extends UnaryInstruction { * The result is the address of the newly allocated object. */ class NewObjInstruction extends Instruction { - NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } + NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index d7cf89ca9aa..85d217bd361 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -46,12 +46,12 @@ class Operand extends TStageOperand { /** * Gets the location of the source code for this operand. */ - final Language::Location getLocation() { result = getUse().getLocation() } + final Language::Location getLocation() { result = this.getUse().getLocation() } /** * Gets the function that contains this operand. */ - final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } + final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() } /** * Gets the `Instruction` that consumes this operand. @@ -74,7 +74,7 @@ class Operand extends TStageOperand { */ final Instruction getDef() { result = this.getAnyDef() and - getDefinitionOverlap() instanceof MustExactlyOverlap + this.getDefinitionOverlap() instanceof MustExactlyOverlap } /** @@ -82,7 +82,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` that consumes this operand. */ - deprecated final Instruction getUseInstruction() { result = getUse() } + deprecated final Instruction getUseInstruction() { result = this.getUse() } /** * DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this @@ -91,7 +91,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` whose result is the value of the operand. */ - deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() } + deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() } /** * Gets the overlap relationship between the operand's definition and its use. @@ -101,7 +101,9 @@ class Operand extends TStageOperand { /** * Holds if the result of the definition instruction does not exactly overlap this use. */ - final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap } + final predicate isDefinitionInexact() { + not this.getDefinitionOverlap() instanceof MustExactlyOverlap + } /** * Gets a prefix to use when dumping the operand in an operand list. @@ -121,7 +123,7 @@ class Operand extends TStageOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId() } /** @@ -129,9 +131,9 @@ class Operand extends TStageOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - result = getAnyDef().getResultId() + result = this.getAnyDef().getResultId() or - not exists(getAnyDef()) and result = "m?" + not exists(this.getAnyDef()) and result = "m?" } /** @@ -140,7 +142,7 @@ class Operand extends TStageOperand { * the empty string. */ private string getInexactSpecifier() { - if isDefinitionInexact() then result = "~" else result = "" + if this.isDefinitionInexact() then result = "~" else result = "" } /** @@ -155,7 +157,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() } /** * Gets the language-neutral type of the value consumed by this operand. This is usually the same @@ -164,7 +166,7 @@ class Operand extends TStageOperand { * from the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final IRType getIRType() { result = getLanguageType().getIRType() } + final IRType getIRType() { result = this.getLanguageType().getIRType() } /** * Gets the type of the value consumed by this operand. This is usually the same as the @@ -173,7 +175,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final Language::Type getType() { getLanguageType().hasType(result, _) } + final Language::Type getType() { this.getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this @@ -182,13 +184,13 @@ class Operand extends TStageOperand { * not hold, the value of the operand represents a value whose type is * given by `getType()`. */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - final int getSize() { result = getLanguageType().getByteSize() } + final int getSize() { result = this.getLanguageType().getByteSize() } } /** @@ -205,7 +207,7 @@ class MemoryOperand extends Operand { /** * Gets the kind of memory access performed by the operand. */ - MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() } + MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() } /** * Holds if the memory access performed by this operand will not always read from every bit in the @@ -215,7 +217,7 @@ class MemoryOperand extends Operand { * conservative estimate of the memory that might actually be accessed at runtime (for example, * the global side effects of a function call). */ - predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() } + predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() } /** * Returns the operand that holds the memory address from which the current operand loads its @@ -223,8 +225,8 @@ class MemoryOperand extends Operand { * is `r1`. */ final AddressOperand getAddressOperand() { - getMemoryAccess().usesAddressOperand() and - result.getUse() = getUse() + this.getMemoryAccess().usesAddressOperand() and + result.getUse() = this.getUse() } } @@ -294,7 +296,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe result = unique(Instruction defInstr | hasDefinition(defInstr, _)) } - final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) } pragma[noinline] private predicate hasDefinition(Instruction defInstr, Overlap overlap) { @@ -449,13 +451,17 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { final override Overlap getDefinitionOverlap() { result = overlap } - final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() } - - final override string getDumpLabel() { - result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + final override int getDumpSortOrder() { + result = 11 + this.getPredecessorBlock().getDisplayIndex() } - final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + final override string getDumpLabel() { + result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + final override string getDumpId() { + result = this.getPredecessorBlock().getDisplayIndex().toString() + } /** * Gets the predecessor block from which this value comes. diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricClass.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricClass.qll index 33a256ce3e5..496e3f4511d 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricClass.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricClass.qll @@ -366,7 +366,7 @@ class MetricClass extends Class { 1 + count(string s | exists(Operation op | op = this.getAnEnclosedExpression() and s = op.getOperator()) - ) + count(string s | s = getAUsedHalsteadN1Operator()) + ) + count(string s | s = this.getAUsedHalsteadN1Operator()) } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricFile.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricFile.qll index f12d1011865..b3838ce4a5a 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricFile.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricFile.qll @@ -134,7 +134,7 @@ class MetricFile extends File { result = // avoid 0 values 1 + count(string s | exists(Operation op | op.getFile() = this and s = op.getOperator())) + - count(string s | s = getAUsedHalsteadN1Operator()) + count(string s | s = this.getAUsedHalsteadN1Operator()) } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricFunction.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricFunction.qll index 45036cfddf3..960e06c8375 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricFunction.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/metrics/MetricFunction.qll @@ -41,7 +41,7 @@ class MetricFunction extends Function { * `&&`, and `||`) plus one. */ int getCyclomaticComplexity() { - result = 1 + cyclomaticComplexityBranches(getBlock()) and + result = 1 + cyclomaticComplexityBranches(this.getBlock()) and not this.isMultiplyDefined() } @@ -295,7 +295,7 @@ class MetricFunction extends Function { int getNestingDepth() { result = max(Stmt s, int aDepth | s.getEnclosingFunction() = this and nestingDepth(s, aDepth) | aDepth) and - not isMultiplyDefined() + not this.isMultiplyDefined() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Allocation.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Allocation.qll index 25dae1c2fd1..1da6e3b0b3b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Allocation.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Allocation.qll @@ -15,10 +15,10 @@ private class MallocAllocationFunction extends AllocationFunction { MallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdOrBslName("malloc") and // malloc(size) + this.hasGlobalOrStdOrBslName("malloc") and // malloc(size) sizeArg = 0 or - hasGlobalName([ + this.hasGlobalName([ // --- Windows Memory Management for Windows Drivers "MmAllocateContiguousMemory", // MmAllocateContiguousMemory(size, maxaddress) "MmAllocateContiguousNodeMemory", // MmAllocateContiguousNodeMemory(size, minaddress, maxaddress, bound, flag, prefer) @@ -39,7 +39,7 @@ private class MallocAllocationFunction extends AllocationFunction { ]) and sizeArg = 0 or - hasGlobalName([ + this.hasGlobalName([ // --- Windows Memory Management for Windows Drivers "ExAllocatePool", // ExAllocatePool(type, size) "ExAllocatePoolWithTag", // ExAllocatePool(type, size, tag) @@ -56,10 +56,10 @@ private class MallocAllocationFunction extends AllocationFunction { ]) and sizeArg = 1 or - hasGlobalName(["HeapAlloc"]) and // HeapAlloc(heap, flags, size) + this.hasGlobalName("HeapAlloc") and // HeapAlloc(heap, flags, size) sizeArg = 2 or - hasGlobalName([ + this.hasGlobalName([ // --- Windows Memory Management for Windows Drivers "MmAllocatePagesForMdl", // MmAllocatePagesForMdl(minaddress, maxaddress, skip, size) "MmAllocatePagesForMdlEx", // MmAllocatePagesForMdlEx(minaddress, maxaddress, skip, size, type, flags) @@ -79,7 +79,7 @@ private class AllocaAllocationFunction extends AllocationFunction { int sizeArg; AllocaAllocationFunction() { - hasGlobalName([ + this.hasGlobalName([ // --- stack allocation "alloca", // // alloca(size) "__builtin_alloca", // __builtin_alloca(size) @@ -104,7 +104,7 @@ private class CallocAllocationFunction extends AllocationFunction { CallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdOrBslName("calloc") and // calloc(num, size) + this.hasGlobalOrStdOrBslName("calloc") and // calloc(num, size) sizeArg = 1 and multArg = 0 } @@ -124,11 +124,11 @@ private class ReallocAllocationFunction extends AllocationFunction { ReallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdOrBslName("realloc") and // realloc(ptr, size) + this.hasGlobalOrStdOrBslName("realloc") and // realloc(ptr, size) sizeArg = 1 and reallocArg = 0 or - hasGlobalName([ + this.hasGlobalName([ // --- Windows Global / Local legacy allocation "LocalReAlloc", // LocalReAlloc(ptr, size, flags) "GlobalReAlloc", // GlobalReAlloc(ptr, size, flags) @@ -140,7 +140,7 @@ private class ReallocAllocationFunction extends AllocationFunction { sizeArg = 1 and reallocArg = 0 or - hasGlobalName("HeapReAlloc") and // HeapReAlloc(heap, flags, ptr, size) + this.hasGlobalName("HeapReAlloc") and // HeapReAlloc(heap, flags, ptr, size) sizeArg = 3 and reallocArg = 2 } @@ -156,7 +156,7 @@ private class ReallocAllocationFunction extends AllocationFunction { */ private class SizelessAllocationFunction extends AllocationFunction { SizelessAllocationFunction() { - hasGlobalName([ + this.hasGlobalName([ // --- Windows Memory Management for Windows Drivers "ExAllocateFromLookasideListEx", // ExAllocateFromLookasideListEx(list) "ExAllocateFromPagedLookasideList", // ExAllocateFromPagedLookasideList(list) @@ -209,18 +209,18 @@ private class CallAllocationExpr extends AllocationExpr, FunctionCall { AllocationFunction target; CallAllocationExpr() { - target = getTarget() and + target = this.getTarget() and // realloc(ptr, 0) only frees the pointer not ( exists(target.getReallocPtrArg()) and - getArgument(target.getSizeArg()).getValue().toInt() = 0 + this.getArgument(target.getSizeArg()).getValue().toInt() = 0 ) and // these are modelled directly (and more accurately), avoid duplication not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this) } override Expr getSizeExpr() { - exists(Expr sizeExpr | sizeExpr = getArgument(target.getSizeArg()) | + exists(Expr sizeExpr | sizeExpr = this.getArgument(target.getSizeArg()) | if exists(target.getSizeMult()) then result = sizeExpr else @@ -233,16 +233,18 @@ private class CallAllocationExpr extends AllocationExpr, FunctionCall { override int getSizeMult() { // malloc with multiplier argument that is a constant - result = getArgument(target.getSizeMult()).getValue().toInt() + result = this.getArgument(target.getSizeMult()).getValue().toInt() or // malloc with no multiplier argument not exists(target.getSizeMult()) and - deconstructSizeExpr(getArgument(target.getSizeArg()), _, result) + deconstructSizeExpr(this.getArgument(target.getSizeArg()), _, result) } - override int getSizeBytes() { result = getSizeExpr().getValue().toInt() * getSizeMult() } + override int getSizeBytes() { + result = this.getSizeExpr().getValue().toInt() * this.getSizeMult() + } - override Expr getReallocPtr() { result = getArgument(target.getReallocPtrArg()) } + override Expr getReallocPtr() { result = this.getArgument(target.getReallocPtrArg()) } override Type getAllocatedElementType() { result = @@ -259,11 +261,11 @@ private class CallAllocationExpr extends AllocationExpr, FunctionCall { private class NewAllocationExpr extends AllocationExpr, NewExpr { NewAllocationExpr() { this instanceof NewExpr } - override int getSizeBytes() { result = getAllocatedType().getSize() } + override int getSizeBytes() { result = this.getAllocatedType().getSize() } - override Type getAllocatedElementType() { result = getAllocatedType() } + override Type getAllocatedElementType() { result = this.getAllocatedType() } - override predicate requiresDealloc() { not exists(getPlacementPointer()) } + override predicate requiresDealloc() { not exists(this.getPlacementPointer()) } } /** @@ -274,18 +276,18 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr { override Expr getSizeExpr() { // new array expr with variable size - result = getExtent() + result = this.getExtent() } override int getSizeMult() { // new array expr with variable size - exists(getExtent()) and - result = getAllocatedElementType().getSize() + exists(this.getExtent()) and + result = this.getAllocatedElementType().getSize() } override Type getAllocatedElementType() { result = NewArrayExpr.super.getAllocatedElementType() } - override int getSizeBytes() { result = getAllocatedType().getSize() } + override int getSizeBytes() { result = this.getAllocatedType().getSize() } - override predicate requiresDealloc() { not exists(getPlacementPointer()) } + override predicate requiresDealloc() { not exists(this.getPlacementPointer()) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/GetDelim.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/GetDelim.qll index e2015406346..67950b6e135 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/GetDelim.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/GetDelim.qll @@ -8,7 +8,7 @@ import semmle.code.cpp.models.interfaces.FlowSource */ private class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectFunction, RemoteFlowSourceFunction { - GetDelimFunction() { hasGlobalName(["getdelim", "getwdelim", "__getdelim"]) } + GetDelimFunction() { this.hasGlobalName(["getdelim", "getwdelim", "__getdelim"]) } override predicate hasTaintFlow(FunctionInput i, FunctionOutput o) { i.isParameter(3) and o.isParameterDeref(0) diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Gets.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Gets.qll index 08222c2cd6a..407c11834e5 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Gets.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Gets.qll @@ -19,7 +19,7 @@ private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunctio // gets(str) // fgets(str, num, stream) // fgetws(wstr, num, stream) - hasGlobalOrStdOrBslName(["gets", "fgets", "fgetws"]) + this.hasGlobalOrStdOrBslName(["gets", "fgets", "fgetws"]) } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -54,13 +54,13 @@ private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunctio } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - not hasName("gets") and + not this.hasName("gets") and bufParam = 0 and countParam = 1 } override predicate hasArrayWithUnknownSize(int bufParam) { - hasName("gets") and + this.hasName("gets") and bufParam = 0 } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll index 24d5456293f..2fa9803d053 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll @@ -34,6 +34,16 @@ private class IteratorByTraits extends Iterator { IteratorByTraits() { exists(IteratorTraits it | it.getIteratorType() = this) } } +/** + * The C++ standard includes an `std::iterator_traits` specialization for pointer types. When + * this specialization is included in the database, a pointer type `T*` will be an instance + * of the `IteratorByTraits` class. However, if the `T*` specialization is not in the database, + * we need to explicitly include them with this class. + */ +private class IteratorByPointer extends Iterator instanceof PointerType { + IteratorByPointer() { not this instanceof IteratorByTraits } +} + /** * A type which has the typedefs expected for an iterator. */ diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll index b7d8aed60fa..a8d0e94f43c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll @@ -44,27 +44,27 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect */ int getParamSize() { if this.hasGlobalName("memccpy") then result = 3 else result = 2 } - override predicate hasArrayInput(int bufParam) { bufParam = getParamSrc() } + override predicate hasArrayInput(int bufParam) { bufParam = this.getParamSrc() } - override predicate hasArrayOutput(int bufParam) { bufParam = getParamDest() } + override predicate hasArrayOutput(int bufParam) { bufParam = this.getParamDest() } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { - input.isParameterDeref(getParamSrc()) and - output.isParameterDeref(getParamDest()) + input.isParameterDeref(this.getParamSrc()) and + output.isParameterDeref(this.getParamDest()) or - input.isParameterDeref(getParamSrc()) and + input.isParameterDeref(this.getParamSrc()) and output.isReturnValueDeref() or - input.isParameter(getParamDest()) and + input.isParameter(this.getParamDest()) and output.isReturnValue() } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { ( - bufParam = getParamDest() or - bufParam = getParamSrc() + bufParam = this.getParamDest() or + bufParam = this.getParamSrc() ) and - countParam = getParamSize() + countParam = this.getParamSize() } override predicate hasOnlySpecificReadSideEffects() { any() } @@ -72,37 +72,37 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { - i = getParamDest() and + i = this.getParamDest() and buffer = true and // memccpy only writes until a given character `c` is found (if this.hasGlobalName("memccpy") then mustWrite = false else mustWrite = true) } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - i = getParamSrc() and buffer = true + i = this.getParamSrc() and buffer = true } override ParameterIndex getParameterSizeIndex(ParameterIndex i) { - result = getParamSize() and + result = this.getParamSize() and ( - i = getParamDest() or - i = getParamSrc() + i = this.getParamDest() or + i = this.getParamSrc() ) } override predicate parameterNeverEscapes(int index) { - index = getParamSrc() + index = this.getParamSrc() or - this.hasGlobalName("bcopy") and index = getParamDest() + this.hasGlobalName("bcopy") and index = this.getParamDest() } override predicate parameterEscapesOnlyViaReturn(int index) { - not this.hasGlobalName("bcopy") and index = getParamDest() + not this.hasGlobalName("bcopy") and index = this.getParamDest() } override predicate parameterIsAlwaysReturned(int index) { not this.hasGlobalName(["bcopy", mempcpy(), "memccpy"]) and - index = getParamDest() + index = this.getParamDest() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll index d646be0363d..11ef853a0bc 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll @@ -31,17 +31,17 @@ private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct override predicate hasArrayWithVariableSize(int bufParam, int countParam) { bufParam = 0 and - (if hasGlobalName(bzero()) then countParam = 1 else countParam = 2) + (if this.hasGlobalName(bzero()) then countParam = 1 else countParam = 2) } - override predicate parameterNeverEscapes(int index) { hasGlobalName(bzero()) and index = 0 } + override predicate parameterNeverEscapes(int index) { this.hasGlobalName(bzero()) and index = 0 } override predicate parameterEscapesOnlyViaReturn(int index) { - not hasGlobalName(bzero()) and index = 0 + not this.hasGlobalName(bzero()) and index = 0 } override predicate parameterIsAlwaysReturned(int index) { - not hasGlobalName(bzero()) and index = 0 + not this.hasGlobalName(bzero()) and index = 0 } override predicate hasOnlySpecificReadSideEffects() { any() } @@ -54,7 +54,7 @@ private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 0 and - if hasGlobalName(bzero()) then result = 1 else result = 2 + if this.hasGlobalName(bzero()) then result = 1 else result = 2 } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Pure.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Pure.qll index d728a66463d..4efab29cabf 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Pure.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Pure.qll @@ -10,49 +10,49 @@ import semmle.code.cpp.models.interfaces.SideEffect private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureStrFunction() { - hasGlobalOrStdOrBslName([ + this.hasGlobalOrStdOrBslName([ atoi(), "strcasestr", "strchnul", "strchr", "strchrnul", "strstr", "strpbrk", "strrchr", "strspn", strtol(), strrev(), strcmp(), strlwr(), strupr() ]) } override predicate hasArrayInput(int bufParam) { - getParameter(bufParam).getUnspecifiedType() instanceof PointerType + this.getParameter(bufParam).getUnspecifiedType() instanceof PointerType } override predicate hasArrayWithNullTerminator(int bufParam) { - getParameter(bufParam).getUnspecifiedType() instanceof PointerType + this.getParameter(bufParam).getUnspecifiedType() instanceof PointerType } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { exists(ParameterIndex i | ( input.isParameter(i) and - exists(getParameter(i)) + exists(this.getParameter(i)) or input.isParameterDeref(i) and - getParameter(i).getUnspecifiedType() instanceof PointerType + this.getParameter(i).getUnspecifiedType() instanceof PointerType ) and // Functions that end with _l also take a locale argument (always as the last argument), // and we don't want taint from those arguments. - (not this.getName().matches("%\\_l") or exists(getParameter(i + 1))) + (not this.getName().matches("%\\_l") or exists(this.getParameter(i + 1))) ) and ( output.isReturnValueDeref() and - getUnspecifiedType() instanceof PointerType + this.getUnspecifiedType() instanceof PointerType or output.isReturnValue() ) } override predicate parameterNeverEscapes(int i) { - getParameter(i).getUnspecifiedType() instanceof PointerType and - not parameterEscapesOnlyViaReturn(i) + this.getParameter(i).getUnspecifiedType() instanceof PointerType and + not this.parameterEscapesOnlyViaReturn(i) } override predicate parameterEscapesOnlyViaReturn(int i) { i = 0 and - getUnspecifiedType() instanceof PointerType + this.getUnspecifiedType() instanceof PointerType } override predicate parameterIsAlwaysReturned(int i) { none() } @@ -62,7 +62,7 @@ private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunctio override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - getParameter(i).getUnspecifiedType() instanceof PointerType and + this.getParameter(i).getUnspecifiedType() instanceof PointerType and buffer = true } } @@ -97,21 +97,21 @@ private string strcmp() { */ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction { StrLenFunction() { - hasGlobalOrStdOrBslName(["strlen", "strnlen", "wcslen"]) + this.hasGlobalOrStdOrBslName(["strlen", "strnlen", "wcslen"]) or - hasGlobalName(["_mbslen", "_mbslen_l", "_mbstrlen", "_mbstrlen_l"]) + this.hasGlobalName(["_mbslen", "_mbslen_l", "_mbstrlen", "_mbstrlen_l"]) } override predicate hasArrayInput(int bufParam) { - getParameter(bufParam).getUnspecifiedType() instanceof PointerType + this.getParameter(bufParam).getUnspecifiedType() instanceof PointerType } override predicate hasArrayWithNullTerminator(int bufParam) { - getParameter(bufParam).getUnspecifiedType() instanceof PointerType + this.getParameter(bufParam).getUnspecifiedType() instanceof PointerType } override predicate parameterNeverEscapes(int i) { - getParameter(i).getUnspecifiedType() instanceof PointerType + this.getParameter(i).getUnspecifiedType() instanceof PointerType } override predicate parameterEscapesOnlyViaReturn(int i) { none() } @@ -123,7 +123,7 @@ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFun override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - getParameter(i).getUnspecifiedType() instanceof PointerType and + this.getParameter(i).getUnspecifiedType() instanceof PointerType and buffer = true } } @@ -133,12 +133,12 @@ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFun * side-effect free. Excludes functions modeled by `PureStrFunction` and `PureMemFunction`. */ private class PureFunction extends TaintFunction, SideEffectFunction { - PureFunction() { hasGlobalOrStdOrBslName(["abs", "labs"]) } + PureFunction() { this.hasGlobalOrStdOrBslName(["abs", "labs"]) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { exists(ParameterIndex i | input.isParameter(i) and - exists(getParameter(i)) + exists(this.getParameter(i)) ) and output.isReturnValue() } @@ -155,44 +155,44 @@ private class PureFunction extends TaintFunction, SideEffectFunction { private class PureMemFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureMemFunction() { - hasGlobalOrStdOrBslName([ + this.hasGlobalOrStdOrBslName([ "memchr", "__builtin_memchr", "memrchr", "rawmemchr", "memcmp", "__builtin_memcmp", "memmem" ]) or this.hasGlobalName("memfrob") } override predicate hasArrayInput(int bufParam) { - getParameter(bufParam).getUnspecifiedType() instanceof PointerType + this.getParameter(bufParam).getUnspecifiedType() instanceof PointerType } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { exists(ParameterIndex i | ( input.isParameter(i) and - exists(getParameter(i)) + exists(this.getParameter(i)) or input.isParameterDeref(i) and - getParameter(i).getUnspecifiedType() instanceof PointerType + this.getParameter(i).getUnspecifiedType() instanceof PointerType ) and // `memfrob` should not have taint from the size argument. (not this.hasGlobalName("memfrob") or i = 0) ) and ( output.isReturnValueDeref() and - getUnspecifiedType() instanceof PointerType + this.getUnspecifiedType() instanceof PointerType or output.isReturnValue() ) } override predicate parameterNeverEscapes(int i) { - getParameter(i).getUnspecifiedType() instanceof PointerType and - not parameterEscapesOnlyViaReturn(i) + this.getParameter(i).getUnspecifiedType() instanceof PointerType and + not this.parameterEscapesOnlyViaReturn(i) } override predicate parameterEscapesOnlyViaReturn(int i) { i = 0 and - getUnspecifiedType() instanceof PointerType + this.getUnspecifiedType() instanceof PointerType } override predicate parameterIsAlwaysReturned(int i) { none() } @@ -202,7 +202,7 @@ private class PureMemFunction extends AliasFunction, ArrayFunction, TaintFunctio override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - getParameter(i).getUnspecifiedType() instanceof PointerType and + this.getParameter(i).getUnspecifiedType() instanceof PointerType and buffer = true } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/SmartPointer.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/SmartPointer.qll index e249a164061..389ce6c5ab0 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/SmartPointer.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/SmartPointer.qll @@ -72,9 +72,9 @@ private class MakeUniqueOrShared extends TaintFunction { // since these just take a size argument, which we don't want to propagate taint through. not this.isArray() and ( - input.isParameter([0 .. getNumberOfParameters() - 1]) + input.isParameter([0 .. this.getNumberOfParameters() - 1]) or - input.isParameterDeref([0 .. getNumberOfParameters() - 1]) + input.isParameterDeref([0 .. this.getNumberOfParameters() - 1]) ) and output.isReturnValue() } @@ -116,14 +116,14 @@ private class SmartPtrSetterFunction extends MemberFunction, AliasFunction, Side or // When taking ownership of a smart pointer via an rvalue reference, always overwrite the input // smart pointer. - getPointerInput().isParameterDeref(i) and + this.getPointerInput().isParameterDeref(i) and this.getParameter(i).getUnspecifiedType() instanceof RValueReferenceType and buffer = false and mustWrite = true } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - getPointerInput().isParameterDeref(i) and + this.getPointerInput().isParameterDeref(i) and buffer = false or not this instanceof Constructor and @@ -136,7 +136,7 @@ private class SmartPtrSetterFunction extends MemberFunction, AliasFunction, Side override predicate parameterEscapesOnlyViaReturn(int index) { none() } override predicate hasAddressFlow(FunctionInput input, FunctionOutput output) { - input = getPointerInput() and + input = this.getPointerInput() and output.isQualifierObject() or // Assignment operator always returns a reference to `*this`. diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Sscanf.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Sscanf.qll index b6120abf05a..42166ae9baa 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Sscanf.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Sscanf.qll @@ -23,15 +23,15 @@ private class SscanfModel extends ArrayFunction, TaintFunction, AliasFunction, S bufParam = this.(ScanfFunction).getInputParameterIndex() } - override predicate hasArrayInput(int bufParam) { hasArrayWithNullTerminator(bufParam) } + override predicate hasArrayInput(int bufParam) { this.hasArrayWithNullTerminator(bufParam) } private int getLengthParameterIndex() { result = this.(Snscanf).getInputLengthParameterIndex() } private int getLocaleParameterIndex() { this.getName().matches("%\\_l") and ( - if exists(getLengthParameterIndex()) - then result = getLengthParameterIndex() + 2 + if exists(this.getLengthParameterIndex()) + then result = this.getLengthParameterIndex() + 2 else result = 2 ) } @@ -40,11 +40,11 @@ private class SscanfModel extends ArrayFunction, TaintFunction, AliasFunction, S override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isParameterDeref(this.(ScanfFunction).getInputParameterIndex()) and - output.isParameterDeref(any(int i | i >= getArgsStartPosition())) + output.isParameterDeref(any(int i | i >= this.getArgsStartPosition())) } override predicate parameterNeverEscapes(int index) { - index = [0 .. max(getACallToThisFunction().getNumberOfArguments())] + index = [0 .. max(this.getACallToThisFunction().getNumberOfArguments())] } override predicate parameterEscapesOnlyViaReturn(int index) { none() } @@ -56,7 +56,7 @@ private class SscanfModel extends ArrayFunction, TaintFunction, AliasFunction, S override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { - i >= getArgsStartPosition() and + i >= this.getArgsStartPosition() and buffer = true and mustWrite = true } @@ -66,7 +66,7 @@ private class SscanfModel extends ArrayFunction, TaintFunction, AliasFunction, S i = [ this.(ScanfFunction).getInputParameterIndex(), - this.(ScanfFunction).getFormatParameterIndex(), getLocaleParameterIndex() + this.(ScanfFunction).getFormatParameterIndex(), this.getLocaleParameterIndex() ] } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdContainer.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdContainer.qll index 367db1613fc..c93a5ad147b 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdContainer.qll @@ -61,20 +61,20 @@ private class StdSequenceContainerConstructor extends Constructor, TaintFunction * value type of the container. */ int getAValueTypeParameterIndex() { - getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = - getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` + this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` } /** * Gets the index of a parameter to this function that is an iterator. */ - int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // taint flow from any parameter of the value type to the returned object ( - input.isParameterDeref(getAValueTypeParameterIndex()) or - input.isParameter(getAnIteratorParameterIndex()) + input.isParameterDeref(this.getAValueTypeParameterIndex()) or + input.isParameter(this.getAnIteratorParameterIndex()) ) and ( output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object @@ -158,21 +158,21 @@ private class StdSequenceContainerInsert extends TaintFunction { * value type of the container. */ int getAValueTypeParameterIndex() { - getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = - getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` + this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` } /** * Gets the index of a parameter to this function that is an iterator. */ - int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from parameter to container itself (qualifier) and return value ( input.isQualifierObject() or - input.isParameterDeref(getAValueTypeParameterIndex()) or - input.isParameter(getAnIteratorParameterIndex()) + input.isParameterDeref(this.getAValueTypeParameterIndex()) or + input.isParameter(this.getAnIteratorParameterIndex()) ) and ( output.isQualifierObject() or @@ -197,20 +197,20 @@ private class StdSequenceContainerAssign extends TaintFunction { * value type of the container. */ int getAValueTypeParameterIndex() { - getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = - getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` + this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` } /** * Gets the index of a parameter to this function that is an iterator. */ - int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from parameter to container itself (qualifier) ( - input.isParameterDeref(getAValueTypeParameterIndex()) or - input.isParameter(getAnIteratorParameterIndex()) + input.isParameterDeref(this.getAValueTypeParameterIndex()) or + input.isParameter(this.getAnIteratorParameterIndex()) ) and output.isQualifierObject() } @@ -246,7 +246,7 @@ class StdVectorEmplace extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter except the position iterator to qualifier and return value // (here we assume taint flow from any constructor parameter to the constructed object) - input.isParameterDeref([1 .. getNumberOfParameters() - 1]) and + input.isParameterDeref([1 .. this.getNumberOfParameters() - 1]) and ( output.isQualifierObject() or output.isReturnValue() @@ -263,7 +263,7 @@ class StdVectorEmplaceBack extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter to qualifier // (here we assume taint flow from any constructor parameter to the constructed object) - input.isParameterDeref([0 .. getNumberOfParameters() - 1]) and + input.isParameterDeref([0 .. this.getNumberOfParameters() - 1]) and output.isQualifierObject() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdMap.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdMap.qll index aecd98981e8..9dc220e79af 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdMap.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdMap.qll @@ -22,12 +22,12 @@ private class StdMapConstructor extends Constructor, TaintFunction { * Gets the index of a parameter to this function that is an iterator. */ int getAnIteratorParameterIndex() { - getParameter(result).getUnspecifiedType() instanceof Iterator + this.getParameter(result).getUnspecifiedType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // taint flow from any parameter of an iterator type to the qualifier - input.isParameterDeref(getAnIteratorParameterIndex()) and + input.isParameterDeref(this.getAnIteratorParameterIndex()) and ( output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object or @@ -47,7 +47,7 @@ private class StdMapInsert extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from last parameter to qualifier and return value // (where the return value is a pair, this should really flow just to the first part of it) - input.isParameterDeref(getNumberOfParameters() - 1) and + input.isParameterDeref(this.getNumberOfParameters() - 1) and ( output.isQualifierObject() or output.isReturnValue() @@ -66,7 +66,7 @@ private class StdMapEmplace extends TaintFunction { // construct a pair, or a pair to be copied / moved) to the qualifier and // return value. // (where the return value is a pair, this should really flow just to the first part of it) - input.isParameterDeref(getNumberOfParameters() - 1) and + input.isParameterDeref(this.getNumberOfParameters() - 1) and ( output.isQualifierObject() or output.isReturnValue() @@ -87,9 +87,9 @@ private class StdMapTryEmplace extends TaintFunction { // flow from any parameter apart from the key to qualifier and return value // (here we assume taint flow from any constructor parameter to the constructed object) // (where the return value is a pair, this should really flow just to the first part of it) - exists(int arg | arg = [1 .. getNumberOfParameters() - 1] | + exists(int arg | arg = [1 .. this.getNumberOfParameters() - 1] | ( - not getUnspecifiedType() instanceof Iterator or + not this.getUnspecifiedType() instanceof Iterator or arg != 1 ) and input.isParameterDeref(arg) @@ -154,7 +154,7 @@ private class StdMapErase extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to iterator return value - getType().getUnderlyingType() instanceof Iterator and + this.getType().getUnderlyingType() instanceof Iterator and input.isQualifierObject() and output.isReturnValue() } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdPair.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdPair.qll index 755f6a48520..c6fabcac314 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdPair.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdPair.qll @@ -51,13 +51,13 @@ private class StdPairConstructor extends Constructor, TaintFunction { * either value type of the pair. */ int getAValueTypeParameterIndex() { - getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = - getDeclaringType().getTemplateArgument(_).(Type).getUnspecifiedType() // i.e. the `T1` or `T2` of this `std::pair` + this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + this.getDeclaringType().getTemplateArgument(_).(Type).getUnspecifiedType() // i.e. the `T1` or `T2` of this `std::pair` } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // taint flow from second parameter of a value type to the qualifier - getAValueTypeParameterIndex() = 1 and + this.getAValueTypeParameterIndex() = 1 and input.isParameterDeref(1) and ( output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdSet.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdSet.qll index d2e9892abcb..3e26d80c136 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdSet.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdSet.qll @@ -22,12 +22,12 @@ private class StdSetConstructor extends Constructor, TaintFunction { * Gets the index of a parameter to this function that is an iterator. */ int getAnIteratorParameterIndex() { - getParameter(result).getUnspecifiedType() instanceof Iterator + this.getParameter(result).getUnspecifiedType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // taint flow from any parameter of an iterator type to the qualifier - input.isParameterDeref(getAnIteratorParameterIndex()) and + input.isParameterDeref(this.getAnIteratorParameterIndex()) and ( output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object or @@ -45,7 +45,7 @@ private class StdSetInsert extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from last parameter to qualifier and return value // (where the return value is a pair, this should really flow just to the first part of it) - input.isParameterDeref(getNumberOfParameters() - 1) and + input.isParameterDeref(this.getNumberOfParameters() - 1) and ( output.isQualifierObject() or output.isReturnValue() @@ -63,7 +63,7 @@ private class StdSetEmplace extends TaintFunction { // flow from any parameter to qualifier and return value // (here we assume taint flow from any constructor parameter to the constructed object) // (where the return value is a pair, this should really flow just to the first part of it) - input.isParameterDeref([0 .. getNumberOfParameters() - 1]) and + input.isParameterDeref([0 .. this.getNumberOfParameters() - 1]) and ( output.isQualifierObject() or output.isReturnValue() @@ -107,7 +107,7 @@ private class StdSetErase extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to iterator return value - getType().getUnderlyingType() instanceof Iterator and + this.getType().getUnderlyingType() instanceof Iterator and input.isQualifierObject() and output.isReturnValue() } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll index 73a0f6edf26..ae190688b70 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll @@ -31,31 +31,31 @@ private class StdStringConstructor extends Constructor, TaintFunction { * character). */ int getAStringParameterIndex() { - exists(Type paramType | paramType = getParameter(result).getUnspecifiedType() | + exists(Type paramType | paramType = this.getParameter(result).getUnspecifiedType() | // e.g. `std::basic_string::CharT *` paramType instanceof PointerType or // e.g. `std::basic_string &`, avoiding `const Allocator&` paramType instanceof ReferenceType and not paramType.(ReferenceType).getBaseType() = - getDeclaringType().getTemplateArgument(2).(Type).getUnspecifiedType() + this.getDeclaringType().getTemplateArgument(2).(Type).getUnspecifiedType() or // i.e. `std::basic_string::CharT` - getParameter(result).getUnspecifiedType() = - getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() + this.getParameter(result).getUnspecifiedType() = + this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() ) } /** * Gets the index of a parameter to this function that is an iterator. */ - int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // taint flow from any parameter of the value type to the returned object ( - input.isParameterDeref(getAStringParameterIndex()) or - input.isParameter(getAnIteratorParameterIndex()) + input.isParameterDeref(this.getAStringParameterIndex()) or + input.isParameter(this.getAnIteratorParameterIndex()) ) and ( output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object @@ -156,23 +156,23 @@ private class StdStringAppend extends TaintFunction { * character). */ int getAStringParameterIndex() { - getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *` - getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &` - getParameter(result).getUnspecifiedType() = - getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` + this.getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *` + this.getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &` + this.getParameter(result).getUnspecifiedType() = + this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` } /** * Gets the index of a parameter to this function that is an iterator. */ - int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string and parameter to string (qualifier) and return value ( input.isQualifierObject() or - input.isParameterDeref(getAStringParameterIndex()) or - input.isParameter(getAnIteratorParameterIndex()) + input.isParameterDeref(this.getAStringParameterIndex()) or + input.isParameter(this.getAnIteratorParameterIndex()) ) and ( output.isQualifierObject() or @@ -197,22 +197,22 @@ private class StdStringAssign extends TaintFunction { * character). */ int getAStringParameterIndex() { - getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *` - getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &` - getParameter(result).getUnspecifiedType() = - getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` + this.getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *` + this.getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &` + this.getParameter(result).getUnspecifiedType() = + this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` } /** * Gets the index of a parameter to this function that is an iterator. */ - int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator } + int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from parameter to string itself (qualifier) and return value ( - input.isParameterDeref(getAStringParameterIndex()) or - input.isParameter(getAnIteratorParameterIndex()) + input.isParameterDeref(this.getAStringParameterIndex()) or + input.isParameter(this.getAnIteratorParameterIndex()) ) and ( output.isQualifierObject() or @@ -574,12 +574,12 @@ private class StdStringStreamConstructor extends Constructor, TaintFunction { * Gets the index of a parameter to this function that is a string. */ int getAStringParameterIndex() { - getParameter(result).getType() instanceof ReferenceType // `const std::basic_string &` + this.getParameter(result).getType() instanceof ReferenceType // `const std::basic_string &` } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // taint flow from any parameter of string type to the returned object - input.isParameterDeref(getAStringParameterIndex()) and + input.isParameterDeref(this.getAStringParameterIndex()) and ( output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object or diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll index ee9af547582..1a65e7b6ca4 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll @@ -32,7 +32,7 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid /** * Gets the index of the parameter that is the size of the copy (in characters). */ - int getParamSize() { exists(getParameter(2)) and result = 2 } + int getParamSize() { exists(this.getParameter(2)) and result = 2 } /** * Gets the index of the parameter that is the source of the copy. @@ -50,11 +50,11 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and + this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and input.isParameter(2) and output.isParameterDeref(0) or - getName() = ["_mbsncat_l", "_mbsnbcat_l"] and + this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and input.isParameter(3) and output.isParameterDeref(0) or diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll index 432fbf999ef..10b160dee47 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll @@ -45,22 +45,22 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid ) and // exclude the 2-parameter template versions // that find the size of a fixed size destination buffer. - getNumberOfParameters() = 3 + this.getNumberOfParameters() = 3 } /** * Holds if this is one of the `strcpy_s` variants. */ - private predicate isSVariant() { getName().matches("%\\_s") } + private predicate isSVariant() { this.getName().matches("%\\_s") } /** * Gets the index of the parameter that is the maximum size of the copy (in characters). */ int getParamSize() { - if isSVariant() + if this.isSVariant() then result = 1 else ( - getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and + this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and result = 2 ) } @@ -68,49 +68,49 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid /** * Gets the index of the parameter that is the source of the copy. */ - int getParamSrc() { if isSVariant() then result = 2 else result = 1 } + int getParamSrc() { if this.isSVariant() then result = 2 else result = 1 } /** * Gets the index of the parameter that is the destination of the copy. */ int getParamDest() { result = 0 } - override predicate hasArrayInput(int bufParam) { bufParam = getParamSrc() } + override predicate hasArrayInput(int bufParam) { bufParam = this.getParamSrc() } - override predicate hasArrayOutput(int bufParam) { bufParam = getParamDest() } + override predicate hasArrayOutput(int bufParam) { bufParam = this.getParamDest() } - override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = getParamSrc() } + override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = this.getParamSrc() } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - bufParam = getParamDest() and - countParam = getParamSize() + bufParam = this.getParamDest() and + countParam = this.getParamSize() } override predicate hasArrayWithUnknownSize(int bufParam) { - not exists(getParamSize()) and - bufParam = getParamDest() + not exists(this.getParamSize()) and + bufParam = this.getParamDest() } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { - not exists(getParamSize()) and - input.isParameterDeref(getParamSrc()) and - output.isParameterDeref(getParamDest()) + not exists(this.getParamSize()) and + input.isParameterDeref(this.getParamSrc()) and + output.isParameterDeref(this.getParamDest()) or - not exists(getParamSize()) and - input.isParameterDeref(getParamSrc()) and + not exists(this.getParamSize()) and + input.isParameterDeref(this.getParamSrc()) and output.isReturnValueDeref() or - input.isParameter(getParamDest()) and + input.isParameter(this.getParamDest()) and output.isReturnValue() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // these may do only a partial copy of the input buffer to the output // buffer - exists(getParamSize()) and - input.isParameter(getParamSrc()) and + exists(this.getParamSize()) and + input.isParameter(this.getParamSrc()) and ( - output.isParameterDeref(getParamDest()) or + output.isParameterDeref(this.getParamDest()) or output.isReturnValueDeref() ) } @@ -120,18 +120,18 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { - i = getParamDest() and + i = this.getParamDest() and buffer = true and mustWrite = false } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - i = getParamSrc() and + i = this.getParamSrc() and buffer = true } override ParameterIndex getParameterSizeIndex(ParameterIndex i) { - i = getParamDest() and - result = getParamSize() + i = this.getParamDest() and + result = this.getParamSize() } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcrement.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcrement.qll index 4c335c8581e..8f6c17aae54 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcrement.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcrement.qll @@ -29,10 +29,10 @@ private class Strcrement extends ArrayFunction, TaintFunction, SideEffectFunctio this.getParameter(bufParam).getUnspecifiedType() instanceof PointerType } - override predicate hasArrayInput(int bufParam) { hasArrayWithNullTerminator(bufParam) } + override predicate hasArrayInput(int bufParam) { this.hasArrayWithNullTerminator(bufParam) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - exists(int index | hasArrayInput(index) | + exists(int index | this.hasArrayInput(index) | input.isParameter(index) and output.isReturnValue() or input.isParameterDeref(index) and output.isReturnValueDeref() @@ -44,6 +44,6 @@ private class Strcrement extends ArrayFunction, TaintFunction, SideEffectFunctio override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - hasArrayInput(i) and buffer = true + this.hasArrayInput(i) and buffer = true } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Swap.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Swap.qll index b79f7afe5d9..446e659fac5 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Swap.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/implementations/Swap.qll @@ -31,7 +31,7 @@ private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction { this.hasName("swap") and this.getNumberOfParameters() = 1 and this.getParameter(0).getType().(ReferenceType).getBaseType().getUnspecifiedType() = - getDeclaringType() + this.getDeclaringType() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll index 4ab55ee5b3f..5e899be68d4 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -44,7 +44,7 @@ class FunctionInput extends TFunctionInput { * Holds if this is the input value of the parameter with index `index`. * DEPRECATED: Use `isParameter(index)` instead. */ - deprecated final predicate isInParameter(ParameterIndex index) { isParameter(index) } + deprecated final predicate isInParameter(ParameterIndex index) { this.isParameter(index) } /** * Holds if this is the input value pointed to by a pointer parameter to a function, or the input @@ -70,7 +70,9 @@ class FunctionInput extends TFunctionInput { * `index`. * DEPRECATED: Use `isParameterDeref(index)` instead. */ - deprecated final predicate isInParameterPointer(ParameterIndex index) { isParameterDeref(index) } + deprecated final predicate isInParameterPointer(ParameterIndex index) { + this.isParameterDeref(index) + } /** * Holds if this is the input value pointed to by the `this` pointer of an instance member @@ -92,7 +94,7 @@ class FunctionInput extends TFunctionInput { * function. * DEPRECATED: Use `isQualifierObject()` instead. */ - deprecated final predicate isInQualifier() { isQualifierObject() } + deprecated final predicate isInQualifier() { this.isQualifierObject() } /** * Holds if this is the input value of the `this` pointer of an instance member function. @@ -314,7 +316,9 @@ class FunctionOutput extends TFunctionOutput { * index `index`. * DEPRECATED: Use `isParameterDeref(index)` instead. */ - deprecated final predicate isOutParameterPointer(ParameterIndex index) { isParameterDeref(index) } + deprecated final predicate isOutParameterPointer(ParameterIndex index) { + this.isParameterDeref(index) + } /** * Holds if this is the output value pointed to by the `this` pointer of an instance member @@ -336,7 +340,7 @@ class FunctionOutput extends TFunctionOutput { * function. * DEPRECATED: Use `isQualifierObject()` instead. */ - deprecated final predicate isOutQualifier() { isQualifierObject() } + deprecated final predicate isOutQualifier() { this.isQualifierObject() } /** * Holds if this is the value returned by a function. @@ -361,7 +365,7 @@ class FunctionOutput extends TFunctionOutput { * Holds if this is the value returned by a function. * DEPRECATED: Use `isReturnValue()` instead. */ - deprecated final predicate isOutReturnValue() { isReturnValue() } + deprecated final predicate isOutReturnValue() { this.isReturnValue() } /** * Holds if this is the output value pointed to by the return value of a function, if the function @@ -389,7 +393,7 @@ class FunctionOutput extends TFunctionOutput { * function returns a reference. * DEPRECATED: Use `isReturnValueDeref()` instead. */ - deprecated final predicate isOutReturnPointer() { isReturnValueDeref() } + deprecated final predicate isOutReturnPointer() { this.isReturnValueDeref() } /** * Holds if `i >= 0` and `isParameterDeref(i)` holds for this is the value, or diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/padding/Padding.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/padding/Padding.qll index 7446569451d..c5c1903b4d1 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/padding/Padding.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/padding/Padding.qll @@ -72,7 +72,7 @@ abstract class Architecture extends string { or t instanceof CharType and result = 8 or - t instanceof WideCharType and result = wideCharSize() + t instanceof WideCharType and result = this.wideCharSize() or t instanceof Char8Type and result = 8 or @@ -84,22 +84,22 @@ abstract class Architecture extends string { or t instanceof IntType and result = 32 or - t instanceof LongType and result = longSize() + t instanceof LongType and result = this.longSize() or - t instanceof LongLongType and result = longLongSize() + t instanceof LongLongType and result = this.longLongSize() or - result = enumBitSize(t.(Enum)) + result = this.enumBitSize(t) or - result = integralBitSize(t.(SpecifiedType).getBaseType()) + result = this.integralBitSize(t.(SpecifiedType).getBaseType()) or - result = integralBitSize(t.(TypedefType).getBaseType()) + result = this.integralBitSize(t.(TypedefType).getBaseType()) } /** * Gets the bit size of enum type `e`. */ int enumBitSize(Enum e) { - result = integralBitSize(e.getExplicitUnderlyingType()) + result = this.integralBitSize(e.getExplicitUnderlyingType()) or not exists(e.getExplicitUnderlyingType()) and result = 32 } @@ -108,7 +108,7 @@ abstract class Architecture extends string { * Gets the alignment of enum type `e`. */ int enumAlignment(Enum e) { - result = alignment(e.getExplicitUnderlyingType()) + result = this.alignment(e.getExplicitUnderlyingType()) or not exists(e.getExplicitUnderlyingType()) and result = 32 } @@ -120,26 +120,26 @@ abstract class Architecture extends string { */ cached int bitSize(Type t) { - result = integralBitSize(t) + result = this.integralBitSize(t) or t instanceof FloatType and result = 32 or t instanceof DoubleType and result = 64 or - t instanceof LongDoubleType and result = longDoubleSize() + t instanceof LongDoubleType and result = this.longDoubleSize() or - t instanceof PointerType and result = pointerSize() + t instanceof PointerType and result = this.pointerSize() or - t instanceof ReferenceType and result = pointerSize() + t instanceof ReferenceType and result = this.pointerSize() or - t instanceof FunctionPointerType and result = pointerSize() + t instanceof FunctionPointerType and result = this.pointerSize() or - result = bitSize(t.(SpecifiedType).getBaseType()) + result = this.bitSize(t.(SpecifiedType).getBaseType()) or - result = bitSize(t.(TypedefType).getBaseType()) + result = this.bitSize(t.(TypedefType).getBaseType()) or exists(ArrayType array | array = t | - result = array.getArraySize() * paddedSize(array.getBaseType()) + result = array.getArraySize() * this.paddedSize(array.getBaseType()) ) or result = t.(PaddedType).typeBitSize(this) @@ -155,7 +155,7 @@ abstract class Architecture extends string { or t instanceof CharType and result = 8 or - t instanceof WideCharType and result = wideCharSize() + t instanceof WideCharType and result = this.wideCharSize() or t instanceof Char8Type and result = 8 or @@ -169,27 +169,27 @@ abstract class Architecture extends string { or t instanceof FloatType and result = 32 or - t instanceof DoubleType and result = doubleAlign() + t instanceof DoubleType and result = this.doubleAlign() or - t instanceof LongType and result = longSize() + t instanceof LongType and result = this.longSize() or - t instanceof LongDoubleType and result = longDoubleAlign() + t instanceof LongDoubleType and result = this.longDoubleAlign() or - t instanceof LongLongType and result = longLongAlign() + t instanceof LongLongType and result = this.longLongAlign() or - t instanceof PointerType and result = pointerSize() + t instanceof PointerType and result = this.pointerSize() or - t instanceof FunctionPointerType and result = pointerSize() + t instanceof FunctionPointerType and result = this.pointerSize() or - t instanceof ReferenceType and result = pointerSize() + t instanceof ReferenceType and result = this.pointerSize() or - result = enumAlignment(t.(Enum)) + result = this.enumAlignment(t) or - result = alignment(t.(SpecifiedType).getBaseType()) + result = this.alignment(t.(SpecifiedType).getBaseType()) or - result = alignment(t.(TypedefType).getBaseType()) + result = this.alignment(t.(TypedefType).getBaseType()) or - result = alignment(t.(ArrayType).getBaseType()) + result = this.alignment(t.(ArrayType).getBaseType()) or result = t.(PaddedType).typeAlignment(this) } @@ -203,7 +203,7 @@ abstract class Architecture extends string { exists(Type realType | realType = stripSpecifiers(t) | if realType instanceof PaddedType then result = realType.(PaddedType).paddedSize(this) - else result = bitSize(realType) + else result = this.bitSize(realType) ) } @@ -232,14 +232,14 @@ private Field getAnInitialField(PaddedType t) { result = t.getAField() or // Initial field of the type of a field of the union - result = getAnInitialField(t.getAField().getUnspecifiedType().(PaddedType)) + result = getAnInitialField(t.getAField().getUnspecifiedType()) else exists(Field firstField | t.fieldIndex(firstField) = 1 | // The first field of `t` result = firstField or // Initial field of the first field of `t` - result = getAnInitialField(firstField.getUnspecifiedType().(PaddedType)) + result = getAnInitialField(firstField.getUnspecifiedType()) ) } @@ -429,7 +429,7 @@ class PaddedType extends Class { * Gets the number of bits wasted by padding at the end of this * struct. */ - int trailingPadding(Architecture arch) { result = paddedSize(arch) - arch.bitSize(this) } + int trailingPadding(Architecture arch) { result = this.paddedSize(arch) - arch.bitSize(this) } /** * Gets the number of bits wasted in this struct definition; that is. @@ -440,7 +440,7 @@ class PaddedType extends Class { * laid out one after another, and hence there is no padding between * them. */ - int wastedSpace(Architecture arch) { result = arch.paddedSize(this) - dataSize(arch) } + int wastedSpace(Architecture arch) { result = arch.paddedSize(this) - this.dataSize(arch) } /** * Gets the total size of all fields declared in this class, not including any @@ -448,8 +448,8 @@ class PaddedType extends Class { */ private int fieldDataSize(Architecture arch) { if this instanceof Union - then result = max(Field f | f = this.getAMember() | fieldSize(f, arch)) - else result = sum(Field f | f = this.getAMember() | fieldSize(f, arch)) + then result = max(Field f | f = this.getAMember() | this.fieldSize(f, arch)) + else result = sum(Field f | f = this.getAMember() | this.fieldSize(f, arch)) } /** @@ -472,7 +472,7 @@ class PaddedType extends Class { * reorganizing member structs' field layouts. */ int optimalSize(Architecture arch) { - result = alignUp(dataSize(arch), arch.alignment(this)).maximum(8) + result = alignUp(this.dataSize(arch), arch.alignment(this)).maximum(8) } /** @@ -490,11 +490,11 @@ class PaddedType extends Class { // but that uses a recursive aggregate, which isn't supported in // QL. We therefore use this slightly more complex implementation // instead. - result = biggestFieldSizeUpTo(lastFieldIndex(), arch) + result = this.biggestFieldSizeUpTo(this.lastFieldIndex(), arch) else // If we're not a union type, the size is the padded // sum of field sizes, padded. - result = fieldEnd(lastFieldIndex(), arch) + result = this.fieldEnd(this.lastFieldIndex(), arch) } /** @@ -522,8 +522,8 @@ class PaddedType extends Class { if index = 0 then result = 0 else - exists(Field f, int fSize | index = fieldIndex(f) and fSize = fieldSize(f, arch) | - result = fSize.maximum(biggestFieldSizeUpTo(index - 1, arch)) + exists(Field f, int fSize | index = this.fieldIndex(f) and fSize = this.fieldSize(f, arch) | + result = fSize.maximum(this.biggestFieldSizeUpTo(index - 1, arch)) ) } @@ -536,8 +536,10 @@ class PaddedType extends Class { if index = 0 then result = 1 // Minimum possible alignment else - exists(Field f, int fAlign | index = fieldIndex(f) and fAlign = arch.alignment(f.getType()) | - result = fAlign.maximum(biggestAlignmentUpTo(index - 1, arch)) + exists(Field f, int fAlign | + index = this.fieldIndex(f) and fAlign = arch.alignment(f.getType()) + | + result = fAlign.maximum(this.biggestAlignmentUpTo(index - 1, arch)) ) } @@ -545,17 +547,18 @@ class PaddedType extends Class { * Gets the 1-based index for each field. */ int fieldIndex(Field f) { - memberIndex(f) = rank[result](Field field, int index | memberIndex(field) = index | index) + this.memberIndex(f) = + rank[result](Field field, int index | this.memberIndex(field) = index | index) } - private int memberIndex(Field f) { result = min(int i | getCanonicalMember(i) = f) } + private int memberIndex(Field f) { result = min(int i | this.getCanonicalMember(i) = f) } /** * Gets the 1-based index for the last field. */ int lastFieldIndex() { - if exists(lastField()) - then result = fieldIndex(lastField()) + if exists(this.lastField()) + then result = this.fieldIndex(this.lastField()) else // Field indices are 1-based, so return 0 to represent the lack of fields. result = 0 @@ -566,25 +569,27 @@ class PaddedType extends Class { * `arch`. */ int fieldSize(Field f, Architecture arch) { - exists(fieldIndex(f)) and + exists(this.fieldIndex(f)) and if f instanceof BitField then result = f.(BitField).getNumBits() else result = arch.paddedSize(f.getType()) } /** Gets the last field of this type. */ - Field lastField() { fieldIndex(result) = max(Field other | | fieldIndex(other)) } + Field lastField() { this.fieldIndex(result) = max(Field other | | this.fieldIndex(other)) } /** * Gets the offset, in bits, of the end of the class' last base class * subobject, or zero if the class has no base classes. */ int baseClassEnd(Architecture arch) { - if exists(getABaseClass()) then result = arch.baseClassSize(getADerivation()) else result = 0 + if exists(this.getABaseClass()) + then result = arch.baseClassSize(this.getADerivation()) + else result = 0 } /** Gets the bitfield at field index `index`, if that field is a bitfield. */ - private BitField bitFieldAt(int index) { fieldIndex(result) = index } + private BitField bitFieldAt(int index) { this.fieldIndex(result) = index } /** * Gets the 0-based offset, in bits, of the first free bit after @@ -596,13 +601,13 @@ class PaddedType extends Class { then // Base case: No fields seen yet, so return the offset of the end of the // base class subojects. - result = baseClassEnd(arch) + result = this.baseClassEnd(arch) else - exists(Field f | index = fieldIndex(f) | - exists(int fSize | fSize = fieldSize(f, arch) | + exists(Field f | index = this.fieldIndex(f) | + exists(int fSize | fSize = this.fieldSize(f, arch) | // Recursive case: Take previous field's end point, pad and add // this field's size - exists(int firstFree | firstFree = fieldEnd(index - 1, arch) | + exists(int firstFree | firstFree = this.fieldEnd(index - 1, arch) | if f instanceof BitField then // Bitfield packing: @@ -629,9 +634,11 @@ class PaddedType extends Class { // No additional restrictions, so just pack it in with no padding. result = firstFree + fSize ) else ( - if exists(bitFieldAt(index - 1)) + if exists(this.bitFieldAt(index - 1)) then - exists(BitField previousBitField | previousBitField = bitFieldAt(index - 1) | + exists(BitField previousBitField | + previousBitField = this.bitFieldAt(index - 1) + | // Previous field was a bitfield. if nextSizeofBoundary >= (firstFree + fSize) and diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll index bc66d9b2dd0..d2d2fbd5b3c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll @@ -88,10 +88,10 @@ class RangeSsaDefinition extends ControlFlowNodeBase { ControlFlowNode getDefinition() { result = this } /** Gets the basic block containing this definition. */ - BasicBlock getBasicBlock() { result.contains(getDefinition()) } + BasicBlock getBasicBlock() { result.contains(this.getDefinition()) } /** Whether this definition is a phi node for variable `v`. */ - predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) } + predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this)) } /** * DEPRECATED: Use isGuardPhi/4 instead diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 289187d4301..0be94ed4e62 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -127,17 +127,22 @@ private string getValue(Expr e) { private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { UnsignedBitwiseAndExpr() { ( - getLeftOperand().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned() or - getValue(getLeftOperand().getFullyConverted()).toInt() >= 0 - ) and - ( - getRightOperand() + this.getLeftOperand() .getFullyConverted() .getType() .getUnderlyingType() .(IntegralType) .isUnsigned() or - getValue(getRightOperand().getFullyConverted()).toInt() >= 0 + getValue(this.getLeftOperand().getFullyConverted()).toInt() >= 0 + ) and + ( + this.getRightOperand() + .getFullyConverted() + .getType() + .getUnderlyingType() + .(IntegralType) + .isUnsigned() or + getValue(this.getRightOperand().getFullyConverted()).toInt() >= 0 ) } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/BufferWrite.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/BufferWrite.qll index e5d892eb4cd..61845654721 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/BufferWrite.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/BufferWrite.qll @@ -77,21 +77,21 @@ abstract class BufferWrite extends Expr { * much smaller (8 bytes) than their true maximum length. This can be * helpful in determining the cause of a buffer overflow issue. */ - int getMaxDataLimited() { result = getMaxData() } + int getMaxDataLimited() { result = this.getMaxData() } /** * Gets the size of a single character of the type this * operation works with, in bytes. */ int getCharSize() { - result = getBufferType().(PointerType).getBaseType().getSize() or - result = getBufferType().(ArrayType).getBaseType().getSize() + result = this.getBufferType().(PointerType).getBaseType().getSize() or + result = this.getBufferType().(ArrayType).getBaseType().getSize() } /** * Gets a description of this buffer write. */ - string getBWDesc() { result = toString() } + string getBWDesc() { result = this.toString() } } /** @@ -109,7 +109,7 @@ abstract class BufferWriteCall extends BufferWrite, FunctionCall { } class StrCopyBW extends BufferWriteCall { StrcpyFunction f; - StrCopyBW() { getTarget() = f.(TopLevelFunction) } + StrCopyBW() { this.getTarget() = f.(TopLevelFunction) } /** * Gets the index of the parameter that is the maximum size of the copy (in characters). @@ -122,21 +122,22 @@ class StrCopyBW extends BufferWriteCall { int getParamSrc() { result = f.getParamSrc() } override Type getBufferType() { - result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType() + result = this.getTarget().getParameter(this.getParamSrc()).getUnspecifiedType() } - override Expr getASource() { result = getArgument(getParamSrc()) } + override Expr getASource() { result = this.getArgument(this.getParamSrc()) } - override Expr getDest() { result = getArgument(f.getParamDest()) } + override Expr getDest() { result = this.getArgument(f.getParamDest()) } - override predicate hasExplicitLimit() { exists(getParamSize()) } + override predicate hasExplicitLimit() { exists(this.getParamSize()) } override int getExplicitLimit() { - result = getArgument(getParamSize()).getValue().toInt() * getCharSize() + result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize() } override int getMaxData() { - result = getArgument(getParamSrc()).(AnalysedString).getMaxLength() * getCharSize() + result = + this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize() } } @@ -146,7 +147,7 @@ class StrCopyBW extends BufferWriteCall { class StrCatBW extends BufferWriteCall { StrcatFunction f; - StrCatBW() { getTarget() = f.(TopLevelFunction) } + StrCatBW() { this.getTarget() = f.(TopLevelFunction) } /** * Gets the index of the parameter that is the maximum size of the copy (in characters). @@ -159,21 +160,22 @@ class StrCatBW extends BufferWriteCall { int getParamSrc() { result = f.getParamSrc() } override Type getBufferType() { - result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType() + result = this.getTarget().getParameter(this.getParamSrc()).getUnspecifiedType() } - override Expr getASource() { result = getArgument(getParamSrc()) } + override Expr getASource() { result = this.getArgument(this.getParamSrc()) } - override Expr getDest() { result = getArgument(f.getParamDest()) } + override Expr getDest() { result = this.getArgument(f.getParamDest()) } - override predicate hasExplicitLimit() { exists(getParamSize()) } + override predicate hasExplicitLimit() { exists(this.getParamSize()) } override int getExplicitLimit() { - result = getArgument(getParamSize()).getValue().toInt() * getCharSize() + result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize() } override int getMaxData() { - result = getArgument(getParamSrc()).(AnalysedString).getMaxLength() * getCharSize() + result = + this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize() } } @@ -184,7 +186,7 @@ class SprintfBW extends BufferWriteCall { FormattingFunction f; SprintfBW() { - exists(string name | f = getTarget().(TopLevelFunction) and name = f.getName() | + exists(string name | f = this.getTarget().(TopLevelFunction) and name = f.getName() | /* * C sprintf variants: */ @@ -229,19 +231,19 @@ class SprintfBW extends BufferWriteCall { result = this.(FormattingFunctionCall).getFormatArgument(_) } - override Expr getDest() { result = getArgument(f.getOutputParameterIndex(false)) } + override Expr getDest() { result = this.getArgument(f.getOutputParameterIndex(false)) } override int getMaxData() { exists(FormatLiteral fl | fl = this.(FormattingFunctionCall).getFormat() and - result = fl.getMaxConvertedLength() * getCharSize() + result = fl.getMaxConvertedLength() * this.getCharSize() ) } override int getMaxDataLimited() { exists(FormatLiteral fl | fl = this.(FormattingFunctionCall).getFormat() and - result = fl.getMaxConvertedLengthLimited() * getCharSize() + result = fl.getMaxConvertedLengthLimited() * this.getCharSize() ) } } @@ -251,7 +253,7 @@ class SprintfBW extends BufferWriteCall { */ class SnprintfBW extends BufferWriteCall { SnprintfBW() { - exists(TopLevelFunction fn, string name | fn = getTarget() and name = fn.getName() | + exists(TopLevelFunction fn, string name | fn = this.getTarget() and name = fn.getName() | /* * C snprintf variants: */ @@ -326,25 +328,25 @@ class SnprintfBW extends BufferWriteCall { result = this.(FormattingFunctionCall).getFormatArgument(_) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = this.getArgument(0) } - override predicate hasExplicitLimit() { exists(getParamSize()) } + override predicate hasExplicitLimit() { exists(this.getParamSize()) } override int getExplicitLimit() { - result = getArgument(getParamSize()).getValue().toInt() * getCharSize() + result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize() } override int getMaxData() { exists(FormatLiteral fl | fl = this.(FormattingFunctionCall).getFormat() and - result = fl.getMaxConvertedLength() * getCharSize() + result = fl.getMaxConvertedLength() * this.getCharSize() ) } override int getMaxDataLimited() { exists(FormatLiteral fl | fl = this.(FormattingFunctionCall).getFormat() and - result = fl.getMaxConvertedLengthLimited() * getCharSize() + result = fl.getMaxConvertedLengthLimited() * this.getCharSize() ) } } @@ -354,7 +356,7 @@ class SnprintfBW extends BufferWriteCall { */ class GetsBW extends BufferWriteCall { GetsBW() { - getTarget().(TopLevelFunction).getName() = + this.getTarget().(TopLevelFunction).getName() = [ "gets", // gets(dst) "fgets", // fgets(dst, max_amount, src_stream) @@ -365,24 +367,24 @@ class GetsBW extends BufferWriteCall { /** * Gets the index of the parameter that is the maximum number of characters to be read. */ - int getParamSize() { exists(getArgument(1)) and result = 1 } + int getParamSize() { exists(this.getArgument(1)) and result = 1 } override Type getBufferType() { result = this.getTarget().getParameter(0).getUnspecifiedType() } override Expr getASource() { - if exists(getArgument(2)) - then result = getArgument(2) + if exists(this.getArgument(2)) + then result = this.getArgument(2) else // the source is input inside the 'gets' call itself result = this } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = this.getArgument(0) } - override predicate hasExplicitLimit() { exists(getParamSize()) } + override predicate hasExplicitLimit() { exists(this.getParamSize()) } override int getExplicitLimit() { - result = getArgument(getParamSize()).getValue().toInt() * getCharSize() + result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize() } } @@ -438,7 +440,7 @@ class ScanfBW extends BufferWrite { exists(ScanfFunctionCall fc, ScanfFormatLiteral fl, int arg | this = fc.getArgument(arg) and fl = fc.getFormat() and - result = (fl.getMaxConvertedLength(arg - getParamArgs()) + 1) * getCharSize() // +1 is for the terminating null + result = (fl.getMaxConvertedLength(arg - this.getParamArgs()) + 1) * this.getCharSize() // +1 is for the terminating null ) } @@ -463,14 +465,14 @@ private int path_max() { class RealpathBW extends BufferWriteCall { RealpathBW() { exists(path_max()) and // Ignore realpath() calls if PATH_MAX cannot be determined - getTarget().hasGlobalName("realpath") // realpath(path, resolved_path); + this.getTarget().hasGlobalName("realpath") // realpath(path, resolved_path); } override Type getBufferType() { result = this.getTarget().getParameter(0).getUnspecifiedType() } - override Expr getDest() { result = getArgument(1) } + override Expr getDest() { result = this.getArgument(1) } - override Expr getASource() { result = getArgument(0) } + override Expr getASource() { result = this.getArgument(0) } override int getMaxData() { result = path_max() and diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/CommandExecution.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/CommandExecution.qll index f8f7c6c476f..063c7300031 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/CommandExecution.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/CommandExecution.qll @@ -28,35 +28,19 @@ class SystemFunction extends FunctionWithWrappers instanceof CommandExecutionFun */ class VarargsExecFunctionCall extends FunctionCall { VarargsExecFunctionCall() { - getTarget().hasGlobalName("execl") or - getTarget().hasGlobalName("execle") or - getTarget().hasGlobalName("execlp") or - // Windows - getTarget().hasGlobalName("_execl") or - getTarget().hasGlobalName("_execle") or - getTarget().hasGlobalName("_execlp") or - getTarget().hasGlobalName("_execlpe") or - getTarget().hasGlobalName("_spawnl") or - getTarget().hasGlobalName("_spawnle") or - getTarget().hasGlobalName("_spawnlp") or - getTarget().hasGlobalName("_spawnlpe") or - getTarget().hasGlobalName("_wexecl") or - getTarget().hasGlobalName("_wexecle") or - getTarget().hasGlobalName("_wexeclp") or - getTarget().hasGlobalName("_wexeclpe") or - getTarget().hasGlobalName("_wspawnl") or - getTarget().hasGlobalName("_wspawnle") or - getTarget().hasGlobalName("_wspawnlp") or - getTarget().hasGlobalName("_wspawnlpe") + getTarget() + .hasGlobalName([ + "execl", "execle", "execlp", + // Windows + "_execl", "_execle", "_execlp", "_execlpe", "_spawnl", "_spawnle", "_spawnlp", + "_spawnlpe", "_wexecl", "_wexecle", "_wexeclp", "_wexeclpe", "_wspawnl", "_wspawnle", + "_wspawnlp", "_wspawnlpe" + ]) } /** Whether the last argument to the function is an environment pointer */ predicate hasEnvironmentArgument() { - getTarget().hasGlobalName("execle") or - getTarget().hasGlobalName("_execle") or - getTarget().hasGlobalName("_execlpe") or - getTarget().hasGlobalName("_wexecle") or - getTarget().hasGlobalName("_wexeclpe") + getTarget().hasGlobalName(["execle", "_execle", "_execlpe", "_wexecle", "_wexeclpe"]) } /** @@ -83,11 +67,7 @@ class VarargsExecFunctionCall extends FunctionCall { * all the other ones start with the command. */ private int getCommandIdx() { - if - getTarget().getName().matches("\\_spawn%") or - getTarget().getName().matches("\\_wspawn%") - then result = 1 - else result = 0 + if getTarget().getName().matches(["\\_spawn%", "\\_wspawn%"]) then result = 1 else result = 0 } } @@ -98,28 +78,14 @@ class VarargsExecFunctionCall extends FunctionCall { */ class ArrayExecFunctionCall extends FunctionCall { ArrayExecFunctionCall() { - getTarget().hasGlobalName("execv") or - getTarget().hasGlobalName("execvp") or - getTarget().hasGlobalName("execvpe") or - getTarget().hasGlobalName("execve") or - getTarget().hasGlobalName("fexecve") or - // Windows variants - getTarget().hasGlobalName("_execv") or - getTarget().hasGlobalName("_execve") or - getTarget().hasGlobalName("_execvp") or - getTarget().hasGlobalName("_execvpe") or - getTarget().hasGlobalName("_spawnv") or - getTarget().hasGlobalName("_spawnve") or - getTarget().hasGlobalName("_spawnvp") or - getTarget().hasGlobalName("_spawnvpe") or - getTarget().hasGlobalName("_wexecv") or - getTarget().hasGlobalName("_wexecve") or - getTarget().hasGlobalName("_wexecvp") or - getTarget().hasGlobalName("_wexecvpe") or - getTarget().hasGlobalName("_wspawnv") or - getTarget().hasGlobalName("_wspawnve") or - getTarget().hasGlobalName("_wspawnvp") or - getTarget().hasGlobalName("_wspawnvpe") + getTarget() + .hasGlobalName([ + "execv", "execvp", "execvpe", "execve", "fexecve", + // Windows variants + "_execv", "_execve", "_execvp", "_execvpe", "_spawnv", "_spawnve", "_spawnvp", + "_spawnvpe", "_wexecv", "_wexecve", "_wexecvp", "_wexecvpe", "_wspawnv", "_wspawnve", + "_wspawnvp", "_wspawnvpe" + ]) } /** The argument with the array of command arguments */ @@ -133,11 +99,7 @@ class ArrayExecFunctionCall extends FunctionCall { * all the other ones start with the command. */ private int getCommandIdx() { - if - getTarget().getName().matches("\\_spawn%") or - getTarget().getName().matches("\\_wspawn%") - then result = 1 - else result = 0 + if getTarget().getName().matches(["\\_spawn%", "\\_wspawn%"]) then result = 1 else result = 0 } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FileWrite.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FileWrite.qll index 7c3d893b471..dc421e8f3ae 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FileWrite.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FileWrite.qll @@ -52,9 +52,9 @@ class BasicOStreamClass extends Type { */ class BasicOStreamCall extends FunctionCall { BasicOStreamCall() { - if getTarget() instanceof MemberFunction - then getQualifier().getType() instanceof BasicOStreamClass - else getArgument(0).getType() instanceof BasicOStreamClass + if this.getTarget() instanceof MemberFunction + then this.getQualifier().getType() instanceof BasicOStreamClass + else this.getArgument(0).getType() instanceof BasicOStreamClass } } @@ -77,10 +77,10 @@ abstract class ChainedOutputCall extends BasicOStreamCall { */ Expr getEndDest() { // recurse into the destination - result = getDest().(ChainedOutputCall).getEndDest() + result = this.getDest().(ChainedOutputCall).getEndDest() or // or return something other than a ChainedOutputCall - result = getDest() and + result = this.getDest() and not result instanceof ChainedOutputCall } } @@ -89,18 +89,18 @@ abstract class ChainedOutputCall extends BasicOStreamCall { * A call to `operator<<` on an output stream. */ class OperatorLShiftCall extends ChainedOutputCall { - OperatorLShiftCall() { getTarget().(Operator).hasName("operator<<") } + OperatorLShiftCall() { this.getTarget().(Operator).hasName("operator<<") } override Expr getSource() { - if getTarget() instanceof MemberFunction - then result = getArgument(0) - else result = getArgument(1) + if this.getTarget() instanceof MemberFunction + then result = this.getArgument(0) + else result = this.getArgument(1) } override Expr getDest() { - if getTarget() instanceof MemberFunction - then result = getQualifier() - else result = getArgument(0) + if this.getTarget() instanceof MemberFunction + then result = this.getQualifier() + else result = this.getArgument(0) } } @@ -108,22 +108,22 @@ class OperatorLShiftCall extends ChainedOutputCall { * A call to 'put'. */ class PutFunctionCall extends ChainedOutputCall { - PutFunctionCall() { getTarget().(MemberFunction).hasName("put") } + PutFunctionCall() { this.getTarget().(MemberFunction).hasName("put") } - override Expr getSource() { result = getArgument(0) } + override Expr getSource() { result = this.getArgument(0) } - override Expr getDest() { result = getQualifier() } + override Expr getDest() { result = this.getQualifier() } } /** * A call to 'write'. */ class WriteFunctionCall extends ChainedOutputCall { - WriteFunctionCall() { getTarget().(MemberFunction).hasName("write") } + WriteFunctionCall() { this.getTarget().(MemberFunction).hasName("write") } - override Expr getSource() { result = getArgument(0) } + override Expr getSource() { result = this.getArgument(0) } - override Expr getDest() { result = getQualifier() } + override Expr getDest() { result = this.getQualifier() } } /** @@ -173,6 +173,6 @@ private predicate fileWriteWithConvChar(FormattingFunctionCall ffc, Expr source, source = ffc.getFormatArgument(n) | exists(f.getOutputParameterIndex(true)) and - conv = ffc.(FormattingFunctionCall).getFormat().(FormatLiteral).getConversionChar(n) + conv = ffc.getFormat().(FormatLiteral).getConversionChar(n) ) } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll index b080651951f..d2c90a38075 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll @@ -24,7 +24,7 @@ private class RemoteReturnSource extends RemoteFlowSource { RemoteReturnSource() { exists(RemoteFlowSourceFunction func, CallInstruction instr, FunctionOutput output | - asInstruction() = instr and + this.asInstruction() = instr and instr.getStaticCallTarget() = func and func.hasRemoteFlowSource(output, sourceType) and ( @@ -43,7 +43,7 @@ private class RemoteParameterSource extends RemoteFlowSource { RemoteParameterSource() { exists(RemoteFlowSourceFunction func, WriteSideEffectInstruction instr, FunctionOutput output | - asInstruction() = instr and + this.asInstruction() = instr and instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and func.hasRemoteFlowSource(output, sourceType) and output.isParameterDerefOrQualifierObject(instr.getIndex()) @@ -58,7 +58,7 @@ private class LocalReturnSource extends LocalFlowSource { LocalReturnSource() { exists(LocalFlowSourceFunction func, CallInstruction instr, FunctionOutput output | - asInstruction() = instr and + this.asInstruction() = instr and instr.getStaticCallTarget() = func and func.hasLocalFlowSource(output, sourceType) and ( @@ -77,7 +77,7 @@ private class LocalParameterSource extends LocalFlowSource { LocalParameterSource() { exists(LocalFlowSourceFunction func, WriteSideEffectInstruction instr, FunctionOutput output | - asInstruction() = instr and + this.asInstruction() = instr and instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and func.hasLocalFlowSource(output, sourceType) and output.isParameterDerefOrQualifierObject(instr.getIndex()) diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll index 654e9d92451..b7a7a95a427 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -77,7 +77,7 @@ abstract class FunctionWithWrappers extends Function { ) { // base case func = this and - interestingArg(paramIndex) and + this.interestingArg(paramIndex) and callChain = toCause(func, paramIndex) and depth = 0 or @@ -101,7 +101,7 @@ abstract class FunctionWithWrappers extends Function { private predicate wrapperFunctionAnyDepth(Function func, int paramIndex, string cause) { // base case func = this and - interestingArg(paramIndex) and + this.interestingArg(paramIndex) and cause = toCause(func, paramIndex) or // recursive step @@ -147,7 +147,7 @@ abstract class FunctionWithWrappers extends Function { ) or not this.wrapperFunctionLimitedDepth(func, paramIndex, _, _) and - cause = wrapperFunctionAnyDepthUnique(func, paramIndex) + cause = this.wrapperFunctionAnyDepthUnique(func, paramIndex) } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/OutputWrite.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/OutputWrite.qll index 9ed22aa970f..affb9954926 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/OutputWrite.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/OutputWrite.qll @@ -21,14 +21,12 @@ class OutputWrite extends Expr { * A standard output or standard error variable. */ private predicate outputVariable(Variable v) { - // standard output - v.hasName("cout") or - v.hasName("wcout") or - // standard error - v.hasName("cerr") or - v.hasName("clog") or - v.hasName("wcerr") or - v.hasName("wclog") + v.hasName([ + // standard output + "cout", "wcout", + // standard error + "cerr", "clog", "wcerr", "wclog" + ]) } /** @@ -64,10 +62,7 @@ private predicate outputWrite(Expr write, Expr source) { arg >= f.(FormattingFunction).getFormatParameterIndex() or // puts, putchar - ( - f.hasGlobalOrStdName("puts") or - f.hasGlobalOrStdName("putchar") - ) and + f.hasGlobalOrStdName(["puts", "putchar"]) and arg = 0 or exists(Call wrappedCall, Expr wrappedSource | diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/Security.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/Security.qll index da808592b3e..7a73144f5fa 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/Security.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/Security.qll @@ -78,7 +78,7 @@ class SecurityOptions extends string { functionCall.getTarget().getName() = fname and ( fname = ["fgets", "gets"] or - userInputReturn(fname) + this.userInputReturn(fname) ) ) or diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/SensitiveExprs.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/SensitiveExprs.qll index 22e0ee71b66..389129835cb 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/SensitiveExprs.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/SensitiveExprs.qll @@ -11,17 +11,8 @@ import cpp */ bindingset[s] private predicate suspicious(string s) { - ( - s.matches("%password%") or - s.matches("%passwd%") or - s.matches("%trusted%") - ) and - not ( - s.matches("%hash%") or - s.matches("%crypt%") or - s.matches("%file%") or - s.matches("%path%") - ) + s.matches(["%password%", "%passwd%", "%trusted%"]) and + not s.matches(["%hash%", "%crypt%", "%file%", "%path%"]) } /** @@ -29,7 +20,7 @@ private predicate suspicious(string s) { */ class SensitiveVariable extends Variable { SensitiveVariable() { - suspicious(getName().toLowerCase()) and + suspicious(this.getName().toLowerCase()) and not this.getUnspecifiedType() instanceof IntegralType } } @@ -39,7 +30,7 @@ class SensitiveVariable extends Variable { */ class SensitiveFunction extends Function { SensitiveFunction() { - suspicious(getName().toLowerCase()) and + suspicious(this.getName().toLowerCase()) and not this.getUnspecifiedType() instanceof IntegralType } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/boostorg/asio/protocols.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/boostorg/asio/protocols.qll index e113d5e5745..c9d6b6613d8 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/boostorg/asio/protocols.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/security/boostorg/asio/protocols.qll @@ -113,7 +113,7 @@ module BoostorgAsio { result.getName() = "tls_server" ) or - result = getASslv23ProtocolConstant() + result = this.getASslv23ProtocolConstant() } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/stmts/Block.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/stmts/Block.qll index 3bebc660456..5fe8798cebb 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/stmts/Block.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/stmts/Block.qll @@ -76,9 +76,9 @@ class BlockStmt extends Stmt, @stmt_block { * the result is the expression statement `a = b`. */ Stmt getLastStmtIn() { - if getLastStmt() instanceof BlockStmt - then result = getLastStmt().(BlockStmt).getLastStmtIn() - else result = getLastStmt() + if this.getLastStmt() instanceof BlockStmt + then result = this.getLastStmt().(BlockStmt).getLastStmtIn() + else result = this.getLastStmt() } /** diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll index ed1fb4fbb50..af68daf025c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll @@ -27,10 +27,10 @@ class Stmt extends StmtParent, @stmt { */ BlockStmt getEnclosingBlock() { if - getParentStmt() instanceof BlockStmt and - not getParentStmt().(BlockStmt).getLocation() instanceof UnknownLocation - then result = getParentStmt() - else result = getParentStmt().getEnclosingBlock() + this.getParentStmt() instanceof BlockStmt and + not this.getParentStmt().(BlockStmt).getLocation() instanceof UnknownLocation + then result = this.getParentStmt() + else result = this.getParentStmt().getEnclosingBlock() } /** Gets a child of this statement. */ @@ -438,7 +438,7 @@ class WhileStmt extends Loop, @stmt_while { * while(1) { ...; if(b) break; ...; } * ``` */ - predicate conditionAlwaysTrue() { conditionAlwaysTrue(getCondition()) } + predicate conditionAlwaysTrue() { conditionAlwaysTrue(this.getCondition()) } /** * Holds if the loop condition is provably `false`. @@ -448,7 +448,7 @@ class WhileStmt extends Loop, @stmt_while { * while(0) { ...; } * ``` */ - predicate conditionAlwaysFalse() { conditionAlwaysFalse(getCondition()) } + predicate conditionAlwaysFalse() { conditionAlwaysFalse(this.getCondition()) } /** * Holds if the loop condition is provably `true` upon entry, @@ -857,7 +857,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for { * ``` * the result is `int x`. */ - LocalVariable getVariable() { result = getChild(4).(DeclStmt).getADeclaration() } + LocalVariable getVariable() { result = this.getChild(4).(DeclStmt).getADeclaration() } /** * Gets the expression giving the range to iterate over. @@ -868,10 +868,10 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for { * ``` * the result is `xs`. */ - Expr getRange() { result = getRangeVariable().getInitializer().getExpr() } + Expr getRange() { result = this.getRangeVariable().getInitializer().getExpr() } /** Gets the compiler-generated `__range` variable after desugaring. */ - LocalVariable getRangeVariable() { result = getChild(0).(DeclStmt).getADeclaration() } + LocalVariable getRangeVariable() { result = this.getChild(0).(DeclStmt).getADeclaration() } /** * Gets the compiler-generated `__begin != __end` which is the @@ -891,10 +891,10 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for { DeclStmt getBeginEndDeclaration() { result = this.getChild(1) } /** Gets the compiler-generated `__begin` variable after desugaring. */ - LocalVariable getBeginVariable() { result = getBeginEndDeclaration().getDeclaration(0) } + LocalVariable getBeginVariable() { result = this.getBeginEndDeclaration().getDeclaration(0) } /** Gets the compiler-generated `__end` variable after desugaring. */ - LocalVariable getEndVariable() { result = getBeginEndDeclaration().getDeclaration(1) } + LocalVariable getEndVariable() { result = this.getBeginEndDeclaration().getDeclaration(1) } /** * Gets the compiler-generated `++__begin` which is the update @@ -905,7 +905,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for { Expr getUpdate() { result = this.getChild(3) } /** Gets the compiler-generated `__begin` variable after desugaring. */ - LocalVariable getAnIterationVariable() { result = getBeginVariable() } + LocalVariable getAnIterationVariable() { result = this.getBeginVariable() } } /** @@ -1067,7 +1067,7 @@ class ForStmt extends Loop, @stmt_for { * for(x = 0; 1; ++x) { sum += x; } * ``` */ - predicate conditionAlwaysTrue() { conditionAlwaysTrue(getCondition()) } + predicate conditionAlwaysTrue() { conditionAlwaysTrue(this.getCondition()) } /** * Holds if the loop condition is provably `false`. @@ -1077,7 +1077,7 @@ class ForStmt extends Loop, @stmt_for { * for(x = 0; 0; ++x) { sum += x; } * ``` */ - predicate conditionAlwaysFalse() { conditionAlwaysFalse(getCondition()) } + predicate conditionAlwaysFalse() { conditionAlwaysFalse(this.getCondition()) } /** * Holds if the loop condition is provably `true` upon entry, @@ -1723,10 +1723,10 @@ class Handler extends Stmt, @stmt_handler { /** * Gets the block containing the implementation of this handler. */ - CatchBlock getBlock() { result = getChild(0) } + CatchBlock getBlock() { result = this.getChild(0) } /** Gets the 'try' statement corresponding to this 'catch block'. */ - TryStmt getTryStmt() { result = getParent() } + TryStmt getTryStmt() { result = this.getParent() } /** * Gets the parameter introduced by this 'catch block', if any. @@ -1734,7 +1734,7 @@ class Handler extends Stmt, @stmt_handler { * For example, `catch(std::exception& e)` introduces a * parameter `e`, whereas `catch(...)` does not introduce a parameter. */ - Parameter getParameter() { result = getBlock().getParameter() } + Parameter getParameter() { result = this.getBlock().getParameter() } override predicate mayBeImpure() { none() } @@ -1921,15 +1921,15 @@ class MicrosoftTryStmt extends Stmt, @stmt_microsoft_try { * This is a Microsoft C/C++ extension. */ class MicrosoftTryExceptStmt extends MicrosoftTryStmt { - MicrosoftTryExceptStmt() { getChild(1) instanceof Expr } + MicrosoftTryExceptStmt() { this.getChild(1) instanceof Expr } override string toString() { result = "__try { ... } __except( ... ) { ... }" } /** Gets the expression guarding the `__except` statement. */ - Expr getCondition() { result = getChild(1) } + Expr getCondition() { result = this.getChild(1) } /** Gets the `__except` statement (usually a `BlockStmt`). */ - Stmt getExcept() { result = getChild(2) } + Stmt getExcept() { result = this.getChild(2) } override string getAPrimaryQlClass() { result = "MicrosoftTryExceptStmt" } } @@ -1948,12 +1948,12 @@ class MicrosoftTryExceptStmt extends MicrosoftTryStmt { * This is a Microsoft C/C++ extension. */ class MicrosoftTryFinallyStmt extends MicrosoftTryStmt { - MicrosoftTryFinallyStmt() { not getChild(1) instanceof Expr } + MicrosoftTryFinallyStmt() { not this.getChild(1) instanceof Expr } override string toString() { result = "__try { ... } __finally { ... }" } /** Gets the `__finally` statement (usually a `BlockStmt`). */ - Stmt getFinally() { result = getChild(1) } + Stmt getFinally() { result = this.getChild(1) } override string getAPrimaryQlClass() { result = "MicrosoftTryFinallyStmt" } } diff --git a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/valuenumbering/HashCons.qll b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/valuenumbering/HashCons.qll index c16389ce9bf..0073154dd3c 100644 --- a/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/valuenumbering/HashCons.qll +++ b/repo-tests/codeql/cpp/ql/lib/semmle/code/cpp/valuenumbering/HashCons.qll @@ -589,7 +589,7 @@ private predicate mk_HasAlloc(HashCons hc, NewOrNewArrayExpr new) { } private predicate mk_HasExtent(HashCons hc, NewArrayExpr new) { - hc = hashCons(new.(NewArrayExpr).getExtent().getFullyConverted()) + hc = hashCons(new.getExtent().getFullyConverted()) } private predicate analyzableNewExpr(NewExpr new) { @@ -619,7 +619,7 @@ private predicate analyzableNewArrayExpr(NewArrayExpr new) { strictcount(new.getAllocatedType().getUnspecifiedType()) = 1 and count(new.getAllocatorCall().getFullyConverted()) <= 1 and count(new.getInitializer().getFullyConverted()) <= 1 and - count(new.(NewArrayExpr).getExtent().getFullyConverted()) <= 1 + count(new.getExtent().getFullyConverted()) <= 1 } private predicate mk_NewArrayExpr( diff --git a/repo-tests/codeql/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql b/repo-tests/codeql/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql index 5f11a9e0830..d2c69ba5fff 100644 --- a/repo-tests/codeql/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql +++ b/repo-tests/codeql/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql @@ -68,12 +68,12 @@ class VariableDeclarationLine extends TVariableDeclarationInfo { /** * Gets the start column of the first `VariableDeclarationEntry` on this line. */ - int getStartColumn() { result = min(getAVDE().getLocation().getStartColumn()) } + int getStartColumn() { result = min(this.getAVDE().getLocation().getStartColumn()) } /** * Gets the end column of the last `VariableDeclarationEntry` on this line. */ - int getEndColumn() { result = max(getAVDE().getLocation().getEndColumn()) } + int getEndColumn() { result = max(this.getAVDE().getLocation().getEndColumn()) } /** * Gets the rank of this `VariableDeclarationLine` in its file and class @@ -89,14 +89,14 @@ class VariableDeclarationLine extends TVariableDeclarationInfo { */ VariableDeclarationLine getNext() { result = TVariableDeclarationLine(c, f, _) and - result.getRank() = getRank() + 1 + result.getRank() = this.getRank() + 1 } /** * Gets the `VariableDeclarationLine` following this one, if it is nearby. */ VariableDeclarationLine getProximateNext() { - result = getNext() and + result = this.getNext() and result.getLine() <= this.getLine() + 3 } @@ -114,14 +114,14 @@ class VariableDeclarationGroup extends VariableDeclarationLine { // there is no `VariableDeclarationLine` within three lines previously not any(VariableDeclarationLine prev).getProximateNext() = this and // `end` is the last transitively proximate line - end = getProximateNext*() and + end = this.getProximateNext*() and not exists(end.getProximateNext()) } predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) { path = f.getAbsolutePath() and - startline = getLine() and - startcol = getStartColumn() and + startline = this.getLine() and + startcol = this.getStartColumn() and endline = end.getLine() and endcol = end.getEndColumn() } @@ -132,18 +132,18 @@ class VariableDeclarationGroup extends VariableDeclarationLine { int getCount() { result = count(VariableDeclarationLine l | - l = getProximateNext*() + l = this.getProximateNext*() | l.getAVDE().getVariable().getName() ) } override string toString() { - getCount() = 1 and - result = "declaration of " + getAVDE().getVariable().getName() + this.getCount() = 1 and + result = "declaration of " + this.getAVDE().getVariable().getName() or - getCount() > 1 and - result = "group of " + getCount() + " fields here" + this.getCount() > 1 and + result = "group of " + this.getCount() + " fields here" } } diff --git a/repo-tests/codeql/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql b/repo-tests/codeql/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql index 9fa8c4e5e3f..6e434c85c95 100644 --- a/repo-tests/codeql/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql +++ b/repo-tests/codeql/cpp/ql/src/Best Practices/Likely Errors/EmptyBlock.ql @@ -81,9 +81,8 @@ class BlockOrNonChild extends Element { predicate emptyBlockContainsNonchild(BlockStmt b) { emptyBlock(_, b) and exists(BlockOrNonChild c, AffectedFile file | - c.(BlockOrNonChild).getStartRankIn(file) = 1 + b.(BlockOrNonChild).getStartRankIn(file) and - c.(BlockOrNonChild).getNonContiguousEndRankIn(file) < - b.(BlockOrNonChild).getNonContiguousEndRankIn(file) + c.getStartRankIn(file) = 1 + b.(BlockOrNonChild).getStartRankIn(file) and + c.getNonContiguousEndRankIn(file) < b.(BlockOrNonChild).getNonContiguousEndRankIn(file) ) } diff --git a/repo-tests/codeql/cpp/ql/src/Best Practices/Magic Constants/MagicConstants.qll b/repo-tests/codeql/cpp/ql/src/Best Practices/Magic Constants/MagicConstants.qll index 587b64b60b3..fce3d286a5f 100644 --- a/repo-tests/codeql/cpp/ql/src/Best Practices/Magic Constants/MagicConstants.qll +++ b/repo-tests/codeql/cpp/ql/src/Best Practices/Magic Constants/MagicConstants.qll @@ -58,15 +58,7 @@ predicate intTrivial(Literal lit) { exists(string v | trivialIntValue(v) and v = predicate longTrivial(Literal lit) { exists(string v | trivialLongValue(v) and v = lit.getValue()) } predicate powerOfTen(float f) { - f = 10 or - f = 100 or - f = 1000 or - f = 10000 or - f = 100000 or - f = 1000000 or - f = 10000000 or - f = 100000000 or - f = 1000000000 + f = [10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000] } predicate floatTrivial(Literal lit) { diff --git a/repo-tests/codeql/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticFunctions.ql b/repo-tests/codeql/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticFunctions.ql index 2d7649d534e..4a08ce4fb4b 100644 --- a/repo-tests/codeql/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticFunctions.ql +++ b/repo-tests/codeql/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticFunctions.ql @@ -62,7 +62,7 @@ class Thing extends Locatable { } Thing callsOrAccesses() { - this.(Function).calls(result.(Function)) + this.(Function).calls(result) or this.(Function).accesses(result.(Function)) or diff --git a/repo-tests/codeql/cpp/ql/src/JPL_C/LOC-2/Rule 09/Semaphores.qll b/repo-tests/codeql/cpp/ql/src/JPL_C/LOC-2/Rule 09/Semaphores.qll index 0b60a3b9877..543c516e4bf 100644 --- a/repo-tests/codeql/cpp/ql/src/JPL_C/LOC-2/Rule 09/Semaphores.qll +++ b/repo-tests/codeql/cpp/ql/src/JPL_C/LOC-2/Rule 09/Semaphores.qll @@ -50,7 +50,7 @@ class SemaphoreTake extends LockOperation { result.(SemaphoreGive).getLocked() = this.getLocked() } - override string say() { result = "semaphore take of " + getLocked().getName() } + override string say() { result = "semaphore take of " + this.getLocked().getName() } } class SemaphoreGive extends UnlockOperation { @@ -76,13 +76,13 @@ class LockingPrimitive extends FunctionCall, LockOperation { this.getTarget().getName().replaceAll("Lock", "Unlock") } - override string say() { result = "call to " + getLocked().getName() } + override string say() { result = "call to " + this.getLocked().getName() } } class UnlockingPrimitive extends FunctionCall, UnlockOperation { UnlockingPrimitive() { this.getTarget().getName() = ["taskUnlock", "intUnlock", "taskRtpUnlock"] } - Function getLocked() { result = getMatchingLock().getLocked() } + Function getLocked() { result = this.getMatchingLock().getLocked() } override LockOperation getMatchingLock() { this = result.getMatchingUnlock() } } diff --git a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Conversion/NonzeroValueCastToPointer.ql b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Conversion/NonzeroValueCastToPointer.ql index 87f52198b0d..47842118874 100644 --- a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Conversion/NonzeroValueCastToPointer.ql +++ b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Conversion/NonzeroValueCastToPointer.ql @@ -13,14 +13,15 @@ import cpp predicate commonErrorCode(string value) { - value = "0" or - value = "1" or - value = "-1" or - value = "18446744073709551615" or // 2^64-1, i.e. -1 as an unsigned int64 - value = "4294967295" or // 2^32-1, i.e. -1 as an unsigned int32 - value = "3735928559" or // 0xdeadbeef - value = "3735929054" or // 0xdeadc0de - value = "3405691582" // 0xcafebabe + value = + [ + "0", "1", "-1", // common error codes + "18446744073709551615", // 2^64-1, i.e. -1 as an unsigned int64 + "4294967295", // 2^32-1, i.e. -1 as an unsigned int32 + "3735928559", // 0xdeadbeef + "3735929054", // 0xdeadc0de + "3405691582" // 0xcafebabe + ] } from Expr e diff --git a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql index f00dfa2213b..2a04669e85b 100644 --- a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql +++ b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql @@ -63,14 +63,14 @@ predicate cannotContainString(Type t) { predicate isNonConst(DataFlow::Node node) { exists(Expr e | e = node.asExpr() | - exists(FunctionCall fc | fc = e.(FunctionCall) | + exists(FunctionCall fc | fc = e | not ( whitelistFunction(fc.getTarget(), _) or fc.getTarget().hasDefinition() ) ) or - exists(Parameter p | p = e.(VariableAccess).getTarget().(Parameter) | + exists(Parameter p | p = e.(VariableAccess).getTarget() | p.getFunction().getName() = "main" and p.getType() instanceof PointerType ) or diff --git a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll index 23b66bd94a6..e164523700b 100644 --- a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll +++ b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll @@ -10,7 +10,7 @@ import semmle.code.cpp.commons.DateTime * Get the top-level `BinaryOperation` enclosing the expression e. */ private BinaryOperation getATopLevelBinaryOperationExpression(Expr e) { - result = e.getEnclosingElement().(BinaryOperation) + result = e.getEnclosingElement() or result = getATopLevelBinaryOperationExpression(e.getEnclosingElement()) } diff --git a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Likely Typos/ExprHasNoEffect.ql b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Likely Typos/ExprHasNoEffect.ql index d3a7dcb8939..6f240fa2d2a 100644 --- a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Likely Typos/ExprHasNoEffect.ql +++ b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Likely Typos/ExprHasNoEffect.ql @@ -66,7 +66,7 @@ predicate functionDefinedInIfDefRecursive(Function f) { */ predicate baseCall(FunctionCall call) { call.getNameQualifier().getQualifyingElement() = - call.getEnclosingFunction().getDeclaringType().(Class).getABaseClass+() + call.getEnclosingFunction().getDeclaringType().getABaseClass+() } from PureExprInVoidContext peivc, Locatable parent, Locatable info, string info_text, string tail diff --git a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql index 5c92b0a3db7..ed378dce60a 100644 --- a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql +++ b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql @@ -5,7 +5,6 @@ * @kind problem * @id cpp/improper-null-termination * @problem.severity warning - * @precision medium * @security-severity 7.8 * @tags security * external/cwe/cwe-170 diff --git a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll index 9606fb968ec..37d5a5e5c1b 100644 --- a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll +++ b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll @@ -126,13 +126,7 @@ class MallocSizeExpr extends BufferAccess, FunctionCall { } class NetworkFunctionCall extends FunctionCall { - NetworkFunctionCall() { - getTarget().hasName("ntohd") or - getTarget().hasName("ntohf") or - getTarget().hasName("ntohl") or - getTarget().hasName("ntohll") or - getTarget().hasName("ntohs") - } + NetworkFunctionCall() { getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) } } class NetworkToBufferSizeConfiguration extends DataFlow::Configuration { diff --git a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql index 8e7bc5bfcf4..f7eca2304b3 100644 --- a/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql +++ b/repo-tests/codeql/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql @@ -43,23 +43,25 @@ predicate isSizePlus(Expr e, BufferSizeExpr baseSize, int plus) { predicate strncpyFunction(Function f, int argDest, int argSrc, int argLimit) { exists(string name | name = f.getName() | - ( - name = "strcpy_s" or // strcpy_s(dst, max_amount, src) - name = "wcscpy_s" or // wcscpy_s(dst, max_amount, src) - name = "_mbscpy_s" // _mbscpy_s(dst, max_amount, src) - ) and + name = + [ + "strcpy_s", // strcpy_s(dst, max_amount, src) + "wcscpy_s", // wcscpy_s(dst, max_amount, src) + "_mbscpy_s" // _mbscpy_s(dst, max_amount, src) + ] and argDest = 0 and argSrc = 2 and argLimit = 1 or - ( - name = "strncpy" or // strncpy(dst, src, max_amount) - name = "strncpy_l" or // strncpy_l(dst, src, max_amount, locale) - name = "wcsncpy" or // wcsncpy(dst, src, max_amount) - name = "_wcsncpy_l" or // _wcsncpy_l(dst, src, max_amount, locale) - name = "_mbsncpy" or // _mbsncpy(dst, src, max_amount) - name = "_mbsncpy_l" // _mbsncpy_l(dst, src, max_amount, locale) - ) and + name = + [ + "strncpy", // strncpy(dst, src, max_amount) + "strncpy_l", // strncpy_l(dst, src, max_amount, locale) + "wcsncpy", // wcsncpy(dst, src, max_amount) + "_wcsncpy_l", // _wcsncpy_l(dst, src, max_amount, locale) + "_mbsncpy", // _mbsncpy(dst, src, max_amount) + "_mbsncpy_l" // _mbsncpy_l(dst, src, max_amount, locale) + ] and argDest = 0 and argSrc = 1 and argLimit = 2 diff --git a/repo-tests/codeql/cpp/ql/src/Metrics/Files/FCyclomaticComplexity.ql b/repo-tests/codeql/cpp/ql/src/Metrics/Files/FCyclomaticComplexity.ql index 8aae5042ca4..3c6953caa5a 100644 --- a/repo-tests/codeql/cpp/ql/src/Metrics/Files/FCyclomaticComplexity.ql +++ b/repo-tests/codeql/cpp/ql/src/Metrics/Files/FCyclomaticComplexity.ql @@ -15,7 +15,7 @@ import cpp from File f, float complexity, float loc where f.fromSource() and - loc = sum(FunctionDeclarationEntry fde | fde.getFile() = f | fde.getNumberOfLines()).(float) and + loc = sum(FunctionDeclarationEntry fde | fde.getFile() = f | fde.getNumberOfLines()) and if loc > 0 then // Weighted average of complexity by function length diff --git a/repo-tests/codeql/cpp/ql/src/Power of 10/Rule 1/UseOfJmp.ql b/repo-tests/codeql/cpp/ql/src/Power of 10/Rule 1/UseOfJmp.ql index 9a6d143bfb6..0a98eafc70f 100644 --- a/repo-tests/codeql/cpp/ql/src/Power of 10/Rule 1/UseOfJmp.ql +++ b/repo-tests/codeql/cpp/ql/src/Power of 10/Rule 1/UseOfJmp.ql @@ -15,10 +15,7 @@ import cpp class ForbiddenFunction extends Function { ForbiddenFunction() { exists(string name | name = this.getName() | - name = "setjmp" or - name = "longjmp" or - name = "sigsetjmp" or - name = "siglongjmp" + name = ["setjmp", "longjmp", "sigsetjmp", "siglongjmp"] ) } } diff --git a/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql index 5e22506d03a..fc8023053b0 100644 --- a/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -26,12 +26,8 @@ import TaintedWithPath class FileFunction extends FunctionWithWrappers { FileFunction() { exists(string nme | this.hasGlobalName(nme) | - nme = "fopen" or - nme = "_fopen" or - nme = "_wfopen" or - nme = "open" or - nme = "_open" or - nme = "_wopen" or + nme = ["fopen", "_fopen", "_wfopen", "open", "_open", "_wopen"] + or // create file function on windows nme.matches("CreateFile%") ) @@ -40,10 +36,7 @@ class FileFunction extends FunctionWithWrappers { or // on any of the fstream classes, or filebuf exists(string nme | this.getDeclaringType().hasQualifiedName("std", nme) | - nme = "basic_fstream" or - nme = "basic_ifstream" or - nme = "basic_ofstream" or - nme = "basic_filebuf" + nme = ["basic_fstream", "basic_ifstream", "basic_ofstream", "basic_filebuf"] ) and // we look for either the open method or the constructor (this.getName() = "open" or this instanceof Constructor) diff --git a/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql b/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql index 31ce1037b27..3b0e3f5198d 100644 --- a/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql +++ b/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql @@ -5,7 +5,6 @@ * @kind problem * @id cpp/user-controlled-null-termination-tainted * @problem.severity warning - * @precision medium * @security-severity 10.0 * @tags security * external/cwe/cwe-170 @@ -22,11 +21,7 @@ class TaintSource extends VariableAccess { this.getTarget() instanceof SemanticStackVariable and x.isUserInput(this, cause) | - cause = "read" or - cause = "fread" or - cause = "recv" or - cause = "recvfrom" or - cause = "recvmsg" + cause = ["read", "fread", "recv", "recvfrom", "recvmsg"] ) } diff --git a/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-319/UseOfHttp.ql b/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-319/UseOfHttp.ql new file mode 100644 index 00000000000..0ae7e12f90e --- /dev/null +++ b/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-319/UseOfHttp.ql @@ -0,0 +1,90 @@ +/** + * @name Failure to use HTTPS URLs + * @description Non-HTTPS connections can be intercepted by third parties. + * @kind path-problem + * @problem.severity warning + * @precision medium + * @id cpp/non-https-url + * @tags security + * external/cwe/cwe-319 + * external/cwe/cwe-345 + */ + +import cpp +import semmle.code.cpp.dataflow.TaintTracking +import DataFlow::PathGraph + +/** + * A string matching private host names of IPv4 and IPv6, which only matches + * the host portion therefore checking for port is not necessary. + * Several examples are localhost, reserved IPv4 IP addresses including + * 127.0.0.1, 10.x.x.x, 172.16.x,x, 192.168.x,x, and reserved IPv6 addresses + * including [0:0:0:0:0:0:0:1] and [::1] + */ +class PrivateHostName extends string { + bindingset[this] + PrivateHostName() { + this.regexpMatch("(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?") + } +} + +/** + * A string containing an HTTP URL not in a private domain. + */ +class HttpStringLiteral extends StringLiteral { + HttpStringLiteral() { + exists(string s | this.getValue() = s | + s = "http" + or + exists(string tail | + tail = s.regexpCapture("http://(.*)", 1) and not tail instanceof PrivateHostName + ) and + not TaintTracking::localExprTaint(any(StringLiteral p | + p.getValue() instanceof PrivateHostName + ), this.getParent*()) + ) + } +} + +/** + * Taint tracking configuration for HTTP connections. + */ +class HttpStringToUrlOpenConfig extends TaintTracking::Configuration { + HttpStringToUrlOpenConfig() { this = "HttpStringToUrlOpenConfig" } + + override predicate isSource(DataFlow::Node src) { + // Sources are strings containing an HTTP URL not in a private domain. + src.asExpr() instanceof HttpStringLiteral + } + + override predicate isSink(DataFlow::Node sink) { + // Sinks can be anything that demonstrates the string is likely to be + // accessed as a URL, for example using it in a network access. Some + // URLs are only ever displayed or used for data processing. + exists(FunctionCall fc | + fc.getTarget() + .hasGlobalOrStdName([ + "system", "gethostbyname", "gethostbyname2", "gethostbyname_r", "getaddrinfo", + "X509_load_http", "X509_CRL_load_http" + ]) and + sink.asExpr() = fc.getArgument(0) + or + fc.getTarget().hasGlobalOrStdName(["send", "URLDownloadToFile", "URLDownloadToCacheFile"]) and + sink.asExpr() = fc.getArgument(1) + or + fc.getTarget().hasGlobalOrStdName(["curl_easy_setopt", "getnameinfo"]) and + sink.asExpr() = fc.getArgument(2) + or + fc.getTarget().hasGlobalOrStdName(["ShellExecute", "ShellExecuteA", "ShellExecuteW"]) and + sink.asExpr() = fc.getArgument(3) + ) + } +} + +from + HttpStringToUrlOpenConfig config, DataFlow::PathNode source, DataFlow::PathNode sink, + HttpStringLiteral str +where + config.hasFlowPath(source, sink) and + str = source.getNode().asExpr() +select str, source, sink, "A URL may be constructed with the HTTP protocol." diff --git a/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql b/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql index bbe3b0805e1..b9176af1c68 100644 --- a/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql +++ b/repo-tests/codeql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql @@ -103,12 +103,7 @@ private predicate posixSystemInfo(FunctionCall source, Element use) { // - various filesystem parameters // int uname(struct utsname *buf) // - OS name and version - ( - source.getTarget().hasName("confstr") or - source.getTarget().hasName("statvfs") or - source.getTarget().hasName("fstatvfs") or - source.getTarget().hasName("uname") - ) and + source.getTarget().hasName(["confstr", "statvfs", "fstatvfs", "uname"]) and use = source.getArgument(1) } @@ -128,14 +123,9 @@ private predicate posixPWInfo(FunctionCall source, Element use) { // struct group *getgrnam(const char *name); // struct group *getgrgid(gid_t); // struct group *getgrent(void); - ( - source.getTarget().hasName("getpwnam") or - source.getTarget().hasName("getpwuid") or - source.getTarget().hasName("getpwent") or - source.getTarget().hasName("getgrnam") or - source.getTarget().hasName("getgrgid") or - source.getTarget().hasName("getgrent") - ) and + source + .getTarget() + .hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and use = source or // int getpwnam_r(const char *name, struct passwd *pwd, @@ -146,31 +136,15 @@ private predicate posixPWInfo(FunctionCall source, Element use) { // char *buf, size_t buflen, struct group **result); // int getgrnam_r(const char *name, struct group *grp, // char *buf, size_t buflen, struct group **result); - ( - source.getTarget().hasName("getpwnam_r") or - source.getTarget().hasName("getpwuid_r") or - source.getTarget().hasName("getgrgid_r") or - source.getTarget().hasName("getgrnam_r") - ) and - ( - use = source.getArgument(1) or - use = source.getArgument(2) or - use = source.getArgument(4) - ) + source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and + use = source.getArgument([1, 2, 4]) or // int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize, // struct passwd **result); // int getgrent_r(struct group *gbuf, char *buf, // size_t buflen, struct group **gbufp); - ( - source.getTarget().hasName("getpwent_r") or - source.getTarget().hasName("getgrent_r") - ) and - ( - use = source.getArgument(0) or - use = source.getArgument(1) or - use = source.getArgument(3) - ) + source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and + use = source.getArgument([0, 1, 3]) } /** @@ -190,13 +164,11 @@ private predicate windowsSystemInfo(FunctionCall source, Element use) { // BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo); // void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo); // void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo); - ( - source.getTarget().hasGlobalName("GetVersionEx") or - source.getTarget().hasGlobalName("GetVersionExA") or - source.getTarget().hasGlobalName("GetVersionExW") or - source.getTarget().hasGlobalName("GetSystemInfo") or - source.getTarget().hasGlobalName("GetNativeSystemInfo") - ) and + source + .getTarget() + .hasGlobalName([ + "GetVersionEx", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetNativeSystemInfo" + ]) and use = source.getArgument(0) } @@ -216,11 +188,11 @@ private predicate windowsFolderPath(FunctionCall source, Element use) { // _In_ int csidl, // _In_ BOOL fCreate // ); - ( - source.getTarget().hasGlobalName("SHGetSpecialFolderPath") or - source.getTarget().hasGlobalName("SHGetSpecialFolderPathA") or - source.getTarget().hasGlobalName("SHGetSpecialFolderPathW") - ) and + source + .getTarget() + .hasGlobalName([ + "SHGetSpecialFolderPath", "SHGetSpecialFolderPathA", "SHGetSpecialFolderPathW" + ]) and use = source.getArgument(1) or // HRESULT SHGetKnownFolderPath( @@ -239,11 +211,7 @@ private predicate windowsFolderPath(FunctionCall source, Element use) { // _In_ DWORD dwFlags, // _Out_ LPTSTR pszPath // ); - ( - source.getTarget().hasGlobalName("SHGetFolderPath") or - source.getTarget().hasGlobalName("SHGetFolderPathA") or - source.getTarget().hasGlobalName("SHGetFolderPathW") - ) and + source.getTarget().hasGlobalName(["SHGetFolderPath", "SHGetFolderPathA", "SHGetFolderPathW"]) and use = source.getArgument(4) or // HRESULT SHGetFolderPathAndSubDir( @@ -254,11 +222,11 @@ private predicate windowsFolderPath(FunctionCall source, Element use) { // _In_ LPCTSTR pszSubDir, // _Out_ LPTSTR pszPath // ); - ( - source.getTarget().hasGlobalName("SHGetFolderPathAndSubDir") or - source.getTarget().hasGlobalName("SHGetFolderPathAndSubDirA") or - source.getTarget().hasGlobalName("SHGetFolderPathAndSubDirW") - ) and + source + .getTarget() + .hasGlobalName([ + "SHGetFolderPathAndSubDir", "SHGetFolderPathAndSubDirA", "SHGetFolderPathAndSubDirW" + ]) and use = source.getArgument(5) } @@ -273,11 +241,7 @@ class WindowsFolderPath extends SystemData { } private predicate logonUser(FunctionCall source, VariableAccess use) { - ( - source.getTarget().hasGlobalName("LogonUser") or - source.getTarget().hasGlobalName("LogonUserW") or - source.getTarget().hasGlobalName("LogonUserA") - ) and + source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and use = source.getAnArgument() } @@ -297,11 +261,7 @@ private predicate regQuery(FunctionCall source, VariableAccess use) { // _Out_opt_ LPTSTR lpValue, // _Inout_opt_ PLONG lpcbValue // ); - ( - source.getTarget().hasGlobalName("RegQueryValue") or - source.getTarget().hasGlobalName("RegQueryValueA") or - source.getTarget().hasGlobalName("RegQueryValueW") - ) and + source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and use = source.getArgument(2) or // LONG WINAPI RegQueryMultipleValues( @@ -311,11 +271,11 @@ private predicate regQuery(FunctionCall source, VariableAccess use) { // _Out_opt_ LPTSTR lpValueBuf, // _Inout_opt_ LPDWORD ldwTotsize // ); - ( - source.getTarget().hasGlobalName("RegQueryMultipleValues") or - source.getTarget().hasGlobalName("RegQueryMultipleValuesA") or - source.getTarget().hasGlobalName("RegQueryMultipleValuesW") - ) and + source + .getTarget() + .hasGlobalName([ + "RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW" + ]) and use = source.getArgument(3) or // LONG WINAPI RegQueryValueEx( @@ -326,11 +286,7 @@ private predicate regQuery(FunctionCall source, VariableAccess use) { // _Out_opt_ LPBYTE lpData, // _Inout_opt_ LPDWORD lpcbData // ); - ( - source.getTarget().hasGlobalName("RegQueryValueEx") or - source.getTarget().hasGlobalName("RegQueryValueExA") or - source.getTarget().hasGlobalName("RegQueryValueExW") - ) and + source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and use = source.getArgument(4) or // LONG WINAPI RegGetValue( @@ -342,11 +298,7 @@ private predicate regQuery(FunctionCall source, VariableAccess use) { // _Out_opt_ PVOID pvData, // _Inout_opt_ LPDWORD pcbData // ); - ( - source.getTarget().hasGlobalName("RegGetValue") or - source.getTarget().hasGlobalName("RegGetValueA") or - source.getTarget().hasGlobalName("RegGetValueW") - ) and + source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and use = source.getArgument(5) } @@ -372,10 +324,8 @@ abstract class DataOutput extends Element { /** * Data that is output via standard output or standard error. */ -class StandardOutput extends DataOutput { - StandardOutput() { this instanceof OutputWrite } - - override Expr getASource() { result = this.(OutputWrite).getASource() } +class StandardOutput extends DataOutput instanceof OutputWrite { + override Expr getASource() { result = OutputWrite.super.getASource() } } private predicate socketCallOrIndirect(FunctionCall call) { @@ -408,12 +358,7 @@ private predicate socketOutput(FunctionCall call, Expr data) { // const struct sockaddr *dest_addr, socklen_t addrlen); // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); // int write(int handle, void *buffer, int nbyte); - ( - call.getTarget().hasGlobalName("send") or - call.getTarget().hasGlobalName("sendto") or - call.getTarget().hasGlobalName("sendmsg") or - call.getTarget().hasGlobalName("write") - ) and + call.getTarget().hasGlobalName(["send", "sendto", "sendmsg", "write"]) and data = call.getArgument(1) and socketFileDescriptor(call.getArgument(0)) ) @@ -431,5 +376,5 @@ class SocketOutput extends DataOutput { from SystemData sd, DataOutput ow where sd.getAnExprIndirect() = ow.getASource() or - sd.getAnExprIndirect() = ow.getASource().(Expr).getAChild*() + sd.getAnExprIndirect() = ow.getASource().getAChild*() select ow, "This operation exposes system data from $@.", sd, sd.toString() diff --git a/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-243/IncorrectChangingWorkingDirectory.ql b/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-243/IncorrectChangingWorkingDirectory.ql new file mode 100644 index 00000000000..02d57ee3c3f --- /dev/null +++ b/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-243/IncorrectChangingWorkingDirectory.ql @@ -0,0 +1,69 @@ +/** + * @name Find work with changing working directories, with security errors. + * @description Not validating the return value or pinning the directory can be unsafe. + * @kind problem + * @id cpp/work-with-changing-working-directories + * @problem.severity warning + * @precision medium + * @tags correctness + * security + * external/cwe/cwe-243 + * external/cwe/cwe-252 + */ + +import cpp +import semmle.code.cpp.commons.Exclusions + +/** Holds if a `fc` function call is available before or after a `chdir` function call. */ +predicate inExistsChdir(FunctionCall fcp) { + exists(FunctionCall fctmp | + ( + fctmp.getTarget().hasGlobalOrStdName("chdir") or + fctmp.getTarget().hasGlobalOrStdName("fchdir") + ) and + ( + fcp.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or + fctmp.getBasicBlock().getASuccessor*() = fcp.getBasicBlock() + ) + ) +} + +/** Holds if a `fc` function call is available before or after a function call containing a `chdir` call. */ +predicate outExistsChdir(FunctionCall fcp) { + exists(FunctionCall fctmp | + exists(FunctionCall fctmp2 | + ( + fctmp2.getTarget().hasGlobalOrStdName("chdir") or + fctmp2.getTarget().hasGlobalOrStdName("fchdir") + ) and + // we are looking for a call containing calls chdir and fchdir + fctmp2.getEnclosingStmt().getParentStmt*() = fctmp.getTarget().getEntryPoint().getChildStmt*() + ) and + ( + fcp.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or + fctmp.getBasicBlock().getASuccessor*() = fcp.getBasicBlock() + ) + ) +} + +from FunctionCall fc, string msg +where + fc.getTarget().hasGlobalOrStdName("chroot") and + not inExistsChdir(fc) and + not outExistsChdir(fc) and + // in this section I want to exclude calls to functions containing chroot that have a direct path to chdir, or to a function containing chdir + exists(FunctionCall fctmp | + fc.getEnclosingStmt().getParentStmt*() = fctmp.getTarget().getEntryPoint().getChildStmt*() and + not inExistsChdir(fctmp) and + not outExistsChdir(fctmp) + ) and + msg = "Creation of 'chroot' jail without changing the working directory" + or + ( + fc.getTarget().hasGlobalOrStdName("chdir") or + fc.getTarget().hasGlobalOrStdName("fchdir") + ) and + fc instanceof ExprInVoidContext and + not isFromMacroDefinition(fc) and + msg = "Unchecked return value for call to '" + fc.getTarget().getName() + "'." +select fc, msg diff --git a/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-273/PrivilegeDroppingOutoforder.ql b/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-273/PrivilegeDroppingOutoforder.ql index 7798203205a..9d2faf793c5 100644 --- a/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-273/PrivilegeDroppingOutoforder.ql +++ b/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-273/PrivilegeDroppingOutoforder.ql @@ -44,14 +44,13 @@ class SetuidLikeWrapperCall extends FunctionCall { class CallBeforeSetuidFunctionCall extends FunctionCall { CallBeforeSetuidFunctionCall() { - ( - getTarget().hasGlobalName("setgid") or - getTarget().hasGlobalName("setresgid") or - // Compatibility may require skipping initgroups and setgroups return checks. - // A stricter best practice is to check the result and errnor for EPERM. - getTarget().hasGlobalName("initgroups") or - getTarget().hasGlobalName("setgroups") - ) and + getTarget() + .hasGlobalName([ + "setgid", "setresgid", + // Compatibility may require skipping initgroups and setgroups return checks. + // A stricter best practice is to check the result and errnor for EPERM. + "initgroups", "setgroups" + ]) and // setgid/setresgid/etc with the root group are false positives. not argumentMayBeRoot(getArgument(0)) } diff --git a/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-377/InsecureTemporaryFile.ql b/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-377/InsecureTemporaryFile.ql new file mode 100644 index 00000000000..f08f7ef61f5 --- /dev/null +++ b/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-377/InsecureTemporaryFile.ql @@ -0,0 +1,112 @@ +/** + * @name Insecure generation of filenames. + * @description Using a predictable filename when creating a temporary file can lead to an attacker-controlled input. + * @kind problem + * @id cpp/insecure-generation-of-filename + * @problem.severity warning + * @precision medium + * @tags correctness + * security + * external/cwe/cwe-377 + */ + +import cpp +import semmle.code.cpp.valuenumbering.GlobalValueNumbering + +/** Holds for a function `f` that has an argument at index `apos` used to read the file. */ +predicate numberArgumentRead(Function f, int apos) { + f.hasGlobalOrStdName("fgets") and apos = 2 + or + f.hasGlobalOrStdName("fread") and apos = 3 + or + f.hasGlobalOrStdName("read") and apos = 0 + or + f.hasGlobalOrStdName("fscanf") and apos = 0 +} + +/** Holds for a function `f` that has an argument at index `apos` used to write to file */ +predicate numberArgumentWrite(Function f, int apos) { + f.hasGlobalOrStdName("fprintf") and apos = 0 + or + f.hasGlobalOrStdName("fputs") and apos = 1 + or + f.hasGlobalOrStdName("write") and apos = 0 + or + f.hasGlobalOrStdName("fwrite") and apos = 3 + or + f.hasGlobalOrStdName("fflush") and apos = 0 +} + +from FunctionCall fc, string msg +where + // search for functions for generating a name, without a guarantee of the absence of a file during the period of work with it. + ( + fc.getTarget().hasGlobalOrStdName("tmpnam") or + fc.getTarget().hasGlobalOrStdName("tmpnam_s") or + fc.getTarget().hasGlobalOrStdName("tmpnam_r") + ) and + not exists(FunctionCall fctmp | + ( + fctmp.getTarget().hasGlobalOrStdName("mktemp") or + fctmp.getTarget().hasGlobalOrStdName("mkstemp") or + fctmp.getTarget().hasGlobalOrStdName("mkstemps") or + fctmp.getTarget().hasGlobalOrStdName("mkdtemp") + ) and + ( + fc.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or + fctmp.getBasicBlock().getASuccessor*() = fc.getBasicBlock() + ) + ) and + msg = + "Finding the name of a file that does not exist does not mean that it will not be exist at the next operation." + or + // finding places to work with a file without setting permissions, but with predictable names. + ( + fc.getTarget().hasGlobalOrStdName("fopen") or + fc.getTarget().hasGlobalOrStdName("open") + ) and + fc.getNumberOfArguments() = 2 and + exists(FunctionCall fctmp, int i | + numberArgumentWrite(fctmp.getTarget(), i) and + globalValueNumber(fc) = globalValueNumber(fctmp.getArgument(i)) + ) and + not exists(FunctionCall fctmp, int i | + numberArgumentRead(fctmp.getTarget(), i) and + globalValueNumber(fc) = globalValueNumber(fctmp.getArgument(i)) + ) and + exists(FunctionCall fctmp | + ( + fctmp.getTarget().hasGlobalOrStdName("strcat") or + fctmp.getTarget().hasGlobalOrStdName("strcpy") + ) and + globalValueNumber(fc.getArgument(0)) = globalValueNumber(fctmp.getAnArgument()) + or + fctmp.getTarget().hasGlobalOrStdName("getenv") and + globalValueNumber(fc.getArgument(0)) = globalValueNumber(fctmp) + or + ( + fctmp.getTarget().hasGlobalOrStdName("asprintf") or + fctmp.getTarget().hasGlobalOrStdName("vasprintf") or + fctmp.getTarget().hasGlobalOrStdName("xasprintf") or + fctmp.getTarget().hasGlobalOrStdName("xvasprintf ") + ) and + exists(Variable vrtmp | + vrtmp = fc.getArgument(0).(VariableAccess).getTarget() and + vrtmp = fctmp.getArgument(0).(AddressOfExpr).getAddressable().(Variable) and + not vrtmp instanceof Field + ) + ) and + not exists(FunctionCall fctmp | + ( + fctmp.getTarget().hasGlobalOrStdName("umask") or + fctmp.getTarget().hasGlobalOrStdName("fchmod") or + fctmp.getTarget().hasGlobalOrStdName("chmod") + ) and + ( + fc.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or + fctmp.getBasicBlock().getASuccessor*() = fc.getBasicBlock() + ) + ) and + msg = + "Creating a file for writing without evaluating its existence and setting permissions can be unsafe." +select fc, msg diff --git a/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBitwiseOrLogicalOperations.ql b/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBitwiseOrLogicalOperations.ql index eae74f76749..78f539aae8b 100644 --- a/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBitwiseOrLogicalOperations.ql +++ b/repo-tests/codeql/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBitwiseOrLogicalOperations.ql @@ -188,8 +188,7 @@ where isBitwiseandBitwise(exp) and isDifferentResults(exp.(BinaryBitwiseOperation).getLeftOperand(), exp.(BinaryBitwiseOperation).getRightOperand().(BinaryBitwiseOperation).getLeftOperand(), - exp.(BinaryBitwiseOperation).getRightOperand().(BinaryBitwiseOperation).getRightOperand(), - exp.(BinaryBitwiseOperation), - exp.(BinaryBitwiseOperation).getRightOperand().(BinaryBitwiseOperation)) and + exp.(BinaryBitwiseOperation).getRightOperand().(BinaryBitwiseOperation).getRightOperand(), exp, + exp.(BinaryBitwiseOperation).getRightOperand()) and msg = "specify the priority with parentheses." select exp, msg diff --git a/repo-tests/codeql/cpp/ql/src/external/CodeDuplication.qll b/repo-tests/codeql/cpp/ql/src/external/CodeDuplication.qll index 1550ca697a3..2656378bf62 100644 --- a/repo-tests/codeql/cpp/ql/src/external/CodeDuplication.qll +++ b/repo-tests/codeql/cpp/ql/src/external/CodeDuplication.qll @@ -38,10 +38,10 @@ class Copy extends @duplication_or_similarity { int sourceStartColumn() { tokens(this, 0, _, result, _, _) } /** Gets the line on which the last token in this block ends. */ - int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) } + int sourceEndLine() { tokens(this, this.lastToken(), _, _, result, _) } /** Gets the column on which the last token in this block ends. */ - int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) } + int sourceEndColumn() { tokens(this, this.lastToken(), _, _, _, result) } /** Gets the number of lines containing at least (part of) one token in this block. */ int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() } @@ -66,11 +66,11 @@ class Copy extends @duplication_or_similarity { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - sourceFile().getAbsolutePath() = filepath and - startline = sourceStartLine() and - startcolumn = sourceStartColumn() and - endline = sourceEndLine() and - endcolumn = sourceEndColumn() + this.sourceFile().getAbsolutePath() = filepath and + startline = this.sourceStartLine() and + startcolumn = this.sourceStartColumn() and + endline = this.sourceEndLine() and + endcolumn = this.sourceEndColumn() } /** Gets a textual representation of this element. */ @@ -79,13 +79,15 @@ class Copy extends @duplication_or_similarity { /** A block of duplicated code. */ class DuplicateBlock extends Copy, @duplication { - override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." } + override string toString() { + result = "Duplicate code: " + this.sourceLines() + " duplicated lines." + } } /** A block of similar code. */ class SimilarBlock extends Copy, @similarity { override string toString() { - result = "Similar code: " + sourceLines() + " almost duplicated lines." + result = "Similar code: " + this.sourceLines() + " almost duplicated lines." } } diff --git a/repo-tests/codeql/cpp/ql/src/external/MetricFilter.qll b/repo-tests/codeql/cpp/ql/src/external/MetricFilter.qll index 58e8bf154e9..0315cd23c8d 100644 --- a/repo-tests/codeql/cpp/ql/src/external/MetricFilter.qll +++ b/repo-tests/codeql/cpp/ql/src/external/MetricFilter.qll @@ -67,7 +67,7 @@ class MetricResult extends int { /** Gets the URL corresponding to the location of this query result. */ string getURL() { result = - "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + - getEndLine() + ":" + getEndColumn() + "file://" + this.getFile().getAbsolutePath() + ":" + this.getStartLine() + ":" + + this.getStartColumn() + ":" + this.getEndLine() + ":" + this.getEndColumn() } } diff --git a/repo-tests/codeql/cpp/ql/src/jsf/4.09 Style/AV Rule 53.1.ql b/repo-tests/codeql/cpp/ql/src/jsf/4.09 Style/AV Rule 53.1.ql index 608374b241c..91b5e4e8b98 100644 --- a/repo-tests/codeql/cpp/ql/src/jsf/4.09 Style/AV Rule 53.1.ql +++ b/repo-tests/codeql/cpp/ql/src/jsf/4.09 Style/AV Rule 53.1.ql @@ -14,12 +14,5 @@ import cpp from Include i, string name where name = i.getIncludeText() and - ( - name.matches("%'%") or - name.matches("%\\\\%") or - name.matches("%/*%") or - name.matches("%//%") or - name.matches("%\"%\"%\"%") or - name.matches("%<%\"%>%") - ) + name.matches(["%'%", "%\\\\%", "%/*%", "%//%", "%\"%\"%\"%", "%<%\"%>%"]) select i, "AV Rule 53.1: Invalid character sequence in header file name '" + name + "'" diff --git a/repo-tests/codeql/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql b/repo-tests/codeql/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql index adeb54746df..b1eab42af37 100644 --- a/repo-tests/codeql/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql +++ b/repo-tests/codeql/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql @@ -142,7 +142,7 @@ class Resource extends MemberVariable { predicate acquisitionWithRequiredKind(Assignment acquireAssign, string kind) { // acquireAssign is an assignment to this resource - acquireAssign.(Assignment).getLValue() = this.getAnAccess() and + acquireAssign.getLValue() = this.getAnAccess() and // Should be in this class, but *any* member method will do this.inSameClass(acquireAssign) and // Check that it is an acquisition function and return the corresponding kind diff --git a/repo-tests/codeql/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.ql b/repo-tests/codeql/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.ql index d3e23c9a7f6..aa4cc984170 100644 --- a/repo-tests/codeql/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.ql +++ b/repo-tests/codeql/cpp/ql/src/jsf/4.15 Declarations and Definitions/AV Rule 135.ql @@ -31,7 +31,7 @@ from Variable v, Variable shadowed where not v.getParentScope().(BlockStmt).isInMacroExpansion() and ( - v.(LocalVariableOrParameter).shadowsGlobal(shadowed.(GlobalVariable)) or + v.(LocalVariableOrParameter).shadowsGlobal(shadowed) or localShadowsParameter(v, shadowed) or shadowing(v, shadowed) ) diff --git a/repo-tests/codeql/cpp/ql/src/jsf/4.22 Pointers and References/AV Rule 173.ql b/repo-tests/codeql/cpp/ql/src/jsf/4.22 Pointers and References/AV Rule 173.ql index 49ed13f1b48..1b1e92bd4a7 100644 --- a/repo-tests/codeql/cpp/ql/src/jsf/4.22 Pointers and References/AV Rule 173.ql +++ b/repo-tests/codeql/cpp/ql/src/jsf/4.22 Pointers and References/AV Rule 173.ql @@ -26,7 +26,7 @@ import cpp from Assignment a, Variable global, Variable local where a.fromSource() and - global.getAnAccess() = a.getLValue().(VariableAccess) and + global.getAnAccess() = a.getLValue() and local.getAnAccess() = a.getRValue().(AddressOfExpr).getOperand() and local.hasSpecifier("auto") and ( diff --git a/repo-tests/codeql/cpp/ql/src/jsf/4.28 Portable Code/AV Rule 209.ql b/repo-tests/codeql/cpp/ql/src/jsf/4.28 Portable Code/AV Rule 209.ql index b881c5ed601..64a130f46e0 100644 --- a/repo-tests/codeql/cpp/ql/src/jsf/4.28 Portable Code/AV Rule 209.ql +++ b/repo-tests/codeql/cpp/ql/src/jsf/4.28 Portable Code/AV Rule 209.ql @@ -15,13 +15,7 @@ import cpp from Element u, ArithmeticType at where - ( - at.hasName("int") or - at.hasName("short") or - at.hasName("long") or - at.hasName("float") or - at.hasName("double") - ) and + at.hasName(["int", "short", "long", "float", "double"]) and u = at.getATypeNameUse() and not at instanceof WideCharType select u, "AV Rule 209: The basic types of int, short, long, float and double shall not be used." diff --git a/repo-tests/codeql/cpp/ql/src/jsf/4.28 Portable Code/AV Rule 210.ql b/repo-tests/codeql/cpp/ql/src/jsf/4.28 Portable Code/AV Rule 210.ql index c12edf0c02a..a30509d9beb 100644 --- a/repo-tests/codeql/cpp/ql/src/jsf/4.28 Portable Code/AV Rule 210.ql +++ b/repo-tests/codeql/cpp/ql/src/jsf/4.28 Portable Code/AV Rule 210.ql @@ -49,11 +49,11 @@ class ExposingIntegralUnion extends Union { exists(MemberVariable mv1, MemberVariable mv2, IntegralType mv1tp, IntegralType mv2tp | mv1 = this.getAMemberVariable() and mv2 = this.getAMemberVariable() and - mv1tp = mv1.getUnderlyingType().(IntegralType) and + mv1tp = mv1.getUnderlyingType() and ( - mv2tp = mv2.getUnderlyingType().(IntegralType) + mv2tp = mv2.getUnderlyingType() or - mv2tp = mv2.getUnderlyingType().(ArrayType).getBaseType().getUnderlyingType().(IntegralType) + mv2tp = mv2.getUnderlyingType().(ArrayType).getBaseType().getUnderlyingType() ) and mv1tp.getSize() > mv2tp.getSize() ) diff --git a/repo-tests/codeql/csharp/ql/consistency-queries/CfgConsistency.ql b/repo-tests/codeql/csharp/ql/consistency-queries/CfgConsistency.ql new file mode 100644 index 00000000000..fe45e5a96d8 --- /dev/null +++ b/repo-tests/codeql/csharp/ql/consistency-queries/CfgConsistency.ql @@ -0,0 +1,64 @@ +import csharp +import semmle.code.csharp.controlflow.internal.Completion +import semmle.code.csharp.controlflow.internal.PreBasicBlocks +import ControlFlow +import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl +import semmle.code.csharp.controlflow.internal.Splitting +import Consistency + +private predicate splitBB(ControlFlow::BasicBlock bb) { + exists(ControlFlow::Node first | + first = bb.getFirstNode() and + first.isJoin() and + strictcount(first.getAPredecessor().getElement()) = 1 + ) +} + +private class RelevantBasicBlock extends ControlFlow::BasicBlock { + RelevantBasicBlock() { not splitBB(this) } +} + +predicate bbStartInconsistency(ControlFlowElement cfe) { + exists(RelevantBasicBlock bb | bb.getFirstNode() = cfe.getAControlFlowNode()) and + not cfe = any(PreBasicBlock bb).getFirstElement() +} + +predicate bbSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ) { + exists(RelevantBasicBlock predBB, RelevantBasicBlock succBB | + predBB.getLastNode() = pred.getAControlFlowNode() and + succBB = predBB.getASuccessor() and + succBB.getFirstNode() = succ.getAControlFlowNode() + ) and + not exists(PreBasicBlock predBB, PreBasicBlock succBB | + predBB.getLastElement() = pred and + succBB = predBB.getASuccessor() and + succBB.getFirstElement() = succ + ) +} + +predicate bbIntraSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ) { + exists(ControlFlow::BasicBlock bb, int i | + pred.getAControlFlowNode() = bb.getNode(i) and + succ.getAControlFlowNode() = bb.getNode(i + 1) + ) and + not exists(PreBasicBlock bb | + bb.getLastElement() = pred and + bb.getASuccessor().getFirstElement() = succ + ) and + not exists(PreBasicBlock bb, int i | + bb.getElement(i) = pred and + bb.getElement(i + 1) = succ + ) +} + +query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowElement cfe2, string s) { + bbStartInconsistency(cfe1) and + cfe2 = cfe1 and + s = "start inconsistency" + or + bbSuccInconsistency(cfe1, cfe2) and + s = "succ inconsistency" + or + bbIntraSuccInconsistency(cfe1, cfe2) and + s = "intra succ inconsistency" +} diff --git a/repo-tests/codeql/csharp/ql/consistency-queries/qlpack.yml b/repo-tests/codeql/csharp/ql/consistency-queries/qlpack.yml new file mode 100644 index 00000000000..ca83245a97f --- /dev/null +++ b/repo-tests/codeql/csharp/ql/consistency-queries/qlpack.yml @@ -0,0 +1,6 @@ +name: codeql-csharp-consistency-queries +version: 0.0.0 +libraryPathDependencies: + - codeql/csharp-all + - codeql/csharp-queries +extractor: csharp diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/asp/WebConfig.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/asp/WebConfig.qll index ed0f9aef451..16d5393afc2 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/asp/WebConfig.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/asp/WebConfig.qll @@ -8,7 +8,7 @@ import csharp * A `Web.config` file. */ class WebConfigXML extends XMLFile { - WebConfigXML() { getName().matches("%Web.config") } + WebConfigXML() { this.getName().matches("%Web.config") } } /** A `` tag in an ASP.NET configuration file. */ @@ -73,12 +73,14 @@ class FormsElement extends XMLElement { /** * Gets attribute's `requireSSL` value. */ - string getRequireSSL() { result = getAttribute("requireSSL").getValue().trim().toLowerCase() } + string getRequireSSL() { + result = this.getAttribute("requireSSL").getValue().trim().toLowerCase() + } /** * Holds if `requireSSL` value is true. */ - predicate isRequireSSL() { getRequireSSL() = "true" } + predicate isRequireSSL() { this.getRequireSSL() = "true" } } /** A `` tag in an ASP.NET configuration file. */ @@ -89,26 +91,28 @@ class HttpCookiesElement extends XMLElement { * Gets attribute's `httpOnlyCookies` value. */ string getHttpOnlyCookies() { - result = getAttribute("httpOnlyCookies").getValue().trim().toLowerCase() + result = this.getAttribute("httpOnlyCookies").getValue().trim().toLowerCase() } /** * Holds if there is any chance that `httpOnlyCookies` is set to `true`. */ - predicate isHttpOnlyCookies() { getHttpOnlyCookies() = "true" } + predicate isHttpOnlyCookies() { this.getHttpOnlyCookies() = "true" } /** * Gets attribute's `requireSSL` value. */ - string getRequireSSL() { result = getAttribute("requireSSL").getValue().trim().toLowerCase() } + string getRequireSSL() { + result = this.getAttribute("requireSSL").getValue().trim().toLowerCase() + } /** * Holds if there is any chance that `requireSSL` is set to `true` either globally or for Forms. */ predicate isRequireSSL() { - getRequireSSL() = "true" + this.getRequireSSL() = "true" or - not getRequireSSL() = "false" and // not set all, i.e. default - exists(FormsElement forms | forms.getFile() = getFile() | forms.isRequireSSL()) + not this.getRequireSSL() = "false" and // not set all, i.e. default + exists(FormsElement forms | forms.getFile() = this.getFile() | forms.isRequireSSL()) } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Access.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Access.qll index 6d72a48ff1b..5fecd8acb10 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Access.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Access.qll @@ -20,7 +20,7 @@ class VariableAccess extends Access, @cil_access { } /** An instruction that reads a variable. */ class ReadAccess extends VariableAccess, Expr, @cil_read_access { - override Type getType() { result = getTarget().getType() } + override Type getType() { result = this.getTarget().getType() } } /** An instruction yielding an address. */ @@ -49,7 +49,7 @@ class ParameterReadAccess extends ParameterAccess, ReadAccess { class ParameterWriteAccess extends ParameterAccess, WriteAccess { override int getPopCount() { result = 1 } - override Expr getExpr() { result = getOperand(0) } + override Expr getExpr() { result = this.getOperand(0) } } /** An access to the `this` parameter. */ @@ -71,9 +71,9 @@ class LocalVariableAccess extends StackVariableAccess, @cil_local_access { class LocalVariableWriteAccess extends LocalVariableAccess, WriteAccess { override int getPopCount() { result = 1 } - override Expr getExpr() { result = getOperand(0) } + override Expr getExpr() { result = this.getOperand(0) } - override string getExtra() { result = "L" + getTarget().getIndex() } + override string getExtra() { result = "L" + this.getTarget().getIndex() } } /** An instruction that reads a local variable. */ @@ -85,7 +85,7 @@ class LocalVariableReadAccess extends LocalVariableAccess, ReadAccess { class FieldAccess extends VariableAccess, @cil_field_access { override Field getTarget() { result = VariableAccess.super.getTarget() } - override string getExtra() { result = getTarget().getName() } + override string getExtra() { result = this.getTarget().getName() } /** Gets the qualifier of the access, if any. */ abstract Expr getQualifier(); diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/BasicBlock.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/BasicBlock.qll index 0c9c0b8ad07..2680cb0a769 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/BasicBlock.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/BasicBlock.qll @@ -10,7 +10,7 @@ private import CIL */ class BasicBlock extends Cached::TBasicBlockStart { /** Gets an immediate successor of this basic block, if any. */ - BasicBlock getASuccessor() { result.getFirstNode() = getLastNode().getASuccessor() } + BasicBlock getASuccessor() { result.getFirstNode() = this.getLastNode().getASuccessor() } /** Gets an immediate predecessor of this basic block, if any. */ BasicBlock getAPredecessor() { result.getASuccessor() = this } @@ -31,7 +31,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * The basic block on line 2 is an immediate `true` successor of the * basic block on line 1. */ - BasicBlock getATrueSuccessor() { result.getFirstNode() = getLastNode().getTrueSuccessor() } + BasicBlock getATrueSuccessor() { result.getFirstNode() = this.getLastNode().getTrueSuccessor() } /** * Gets an immediate `false` successor, if any. @@ -49,22 +49,22 @@ class BasicBlock extends Cached::TBasicBlockStart { * The basic block on line 2 is an immediate `false` successor of the * basic block on line 1. */ - BasicBlock getAFalseSuccessor() { result.getFirstNode() = getLastNode().getFalseSuccessor() } + BasicBlock getAFalseSuccessor() { result.getFirstNode() = this.getLastNode().getFalseSuccessor() } /** Gets the control flow node at a specific (zero-indexed) position in this basic block. */ - ControlFlowNode getNode(int pos) { Cached::bbIndex(getFirstNode(), result, pos) } + ControlFlowNode getNode(int pos) { Cached::bbIndex(this.getFirstNode(), result, pos) } /** Gets a control flow node in this basic block. */ - ControlFlowNode getANode() { result = getNode(_) } + ControlFlowNode getANode() { result = this.getNode(_) } /** Gets the first control flow node in this basic block. */ ControlFlowNode getFirstNode() { this = Cached::TBasicBlockStart(result) } /** Gets the last control flow node in this basic block. */ - ControlFlowNode getLastNode() { result = getNode(length() - 1) } + ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) } /** Gets the length of this basic block. */ - int length() { result = strictcount(getANode()) } + int length() { result = strictcount(this.getANode()) } /** * Holds if this basic block strictly dominates basic block `bb`. @@ -114,7 +114,7 @@ class BasicBlock extends Cached::TBasicBlockStart { */ predicate dominates(BasicBlock bb) { bb = this or - strictlyDominates(bb) + this.strictlyDominates(bb) } /** @@ -140,14 +140,14 @@ class BasicBlock extends Cached::TBasicBlockStart { * does not dominate the basic block on line 6. */ predicate inDominanceFrontier(BasicBlock df) { - dominatesPredecessor(df) and - not strictlyDominates(df) + this.dominatesPredecessor(df) and + not this.strictlyDominates(df) } /** * Holds if this basic block dominates a predecessor of `df`. */ - private predicate dominatesPredecessor(BasicBlock df) { dominates(df.getAPredecessor()) } + private predicate dominatesPredecessor(BasicBlock df) { this.dominates(df.getAPredecessor()) } /** * Gets the basic block that immediately dominates this basic block, if any. @@ -226,7 +226,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * post-dominates itself. */ predicate postDominates(BasicBlock bb) { - strictlyPostDominates(bb) or + this.strictlyPostDominates(bb) or this = bb } @@ -239,7 +239,7 @@ class BasicBlock extends Cached::TBasicBlockStart { predicate inLoop() { this.getASuccessor+() = this } /** Gets a textual representation of this basic block. */ - string toString() { result = getFirstNode().toString() } + string toString() { result = this.getFirstNode().toString() } /** Gets the location of this basic block. */ Location getLocation() { result = this.getFirstNode().getLocation() } @@ -325,16 +325,16 @@ private predicate exitBB(BasicBlock bb) { not exists(bb.getLastNode().getASucces * A basic block with more than one predecessor. */ class JoinBlock extends BasicBlock { - JoinBlock() { getFirstNode().isJoin() } + JoinBlock() { this.getFirstNode().isJoin() } } /** A basic block that terminates in a condition, splitting the subsequent control flow. */ class ConditionBlock extends BasicBlock { ConditionBlock() { exists(BasicBlock succ | - succ = getATrueSuccessor() + succ = this.getATrueSuccessor() or - succ = getAFalseSuccessor() + succ = this.getAFalseSuccessor() ) } @@ -380,16 +380,16 @@ class ConditionBlock extends BasicBlock { */ exists(BasicBlock succ | - isCandidateSuccessor(succ, testIsTrue) and + this.isCandidateSuccessor(succ, testIsTrue) and succ.dominates(controlled) ) } private predicate isCandidateSuccessor(BasicBlock succ, boolean testIsTrue) { ( - testIsTrue = true and succ = getATrueSuccessor() + testIsTrue = true and succ = this.getATrueSuccessor() or - testIsTrue = false and succ = getAFalseSuccessor() + testIsTrue = false and succ = this.getAFalseSuccessor() ) and forall(BasicBlock pred | pred = succ.getAPredecessor() and pred != this | succ.dominates(pred)) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/ConsistencyChecks.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/ConsistencyChecks.qll index 02cfd149886..262bb58ab9c 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/ConsistencyChecks.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/ConsistencyChecks.qll @@ -62,7 +62,7 @@ abstract class InstructionViolation extends CfgViolation, CfgCheck { override string toString() { result = instruction.getImplementation().getMethod().toStringWithTypes() + ": " + - instruction.toString() + ", " + getInstructionsUpTo() + instruction.toString() + ", " + this.getInstructionsUpTo() } } @@ -126,7 +126,7 @@ class MissingOperand extends InstructionViolation { } override string getMessage() { - result = "This instruction is missing operand " + getMissingOperand() + result = "This instruction is missing operand " + this.getMissingOperand() } } @@ -364,7 +364,7 @@ class TypeViolation extends ConsistencyViolation, TypeCheck { /** Gets the type containing the violation. */ Type getType() { this = TypeCheck(result) } - override string toString() { result = getType().toString() } + override string toString() { result = this.getType().toString() } abstract override string getMessage(); } @@ -374,7 +374,7 @@ class TypeViolation extends ConsistencyViolation, TypeCheck { */ class TypeIsBothConstructedAndUnbound extends TypeViolation { TypeIsBothConstructedAndUnbound() { - getType() instanceof ConstructedGeneric and getType() instanceof UnboundGeneric + this.getType() instanceof ConstructedGeneric and this.getType() instanceof UnboundGeneric } override string getMessage() { result = "Type is both constructed and unbound" } @@ -397,16 +397,16 @@ class InconsistentTypeLocation extends TypeViolation { */ class TypeParameterMismatch extends TypeViolation { TypeParameterMismatch() { - getType().(ConstructedGeneric).getNumberOfTypeArguments() != - getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() + this.getType().(ConstructedGeneric).getNumberOfTypeArguments() != + this.getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() } override string getMessage() { result = - "Constructed type (" + getType().toStringWithTypes() + ") has " + - getType().(ConstructedGeneric).getNumberOfTypeArguments() + - " type arguments and unbound type (" + getType().getUnboundType().toStringWithTypes() + - ") has " + getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() + + "Constructed type (" + this.getType().toStringWithTypes() + ") has " + + this.getType().(ConstructedGeneric).getNumberOfTypeArguments() + + " type arguments and unbound type (" + this.getType().getUnboundType().toStringWithTypes() + + ") has " + this.getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() + " type parameters" } } @@ -418,7 +418,7 @@ class MethodViolation extends ConsistencyViolation, DeclarationCheck { /** Gets the method containing the violation. */ Method getMethod() { this = DeclarationCheck(result) } - override string toString() { result = getMethod().toString() } + override string toString() { result = this.getMethod().toString() } override string getMessage() { none() } } @@ -440,14 +440,15 @@ class InconsistentMethodLocation extends MethodViolation { */ class ConstructedMethodTypeParams extends MethodViolation { ConstructedMethodTypeParams() { - getMethod().(ConstructedGeneric).getNumberOfTypeArguments() != - getMethod().getUnboundDeclaration().(UnboundGeneric).getNumberOfTypeParameters() + this.getMethod().(ConstructedGeneric).getNumberOfTypeArguments() != + this.getMethod().getUnboundDeclaration().(UnboundGeneric).getNumberOfTypeParameters() } override string getMessage() { result = - "The constructed method " + getMethod().toStringWithTypes() + - " does not match unbound method " + getMethod().getUnboundDeclaration().toStringWithTypes() + "The constructed method " + this.getMethod().toStringWithTypes() + + " does not match unbound method " + + this.getMethod().getUnboundDeclaration().toStringWithTypes() } } @@ -477,8 +478,8 @@ class InvalidOverride extends MethodViolation { private Method base; InvalidOverride() { - base = getMethod().getOverriddenMethod() and - not getMethod().getDeclaringType().getABaseType+() = base.getDeclaringType() and + base = this.getMethod().getOverriddenMethod() and + not this.getMethod().getDeclaringType().getABaseType+() = base.getDeclaringType() and base.getDeclaringType().isUnboundDeclaration() // Bases classes of constructed types aren't extracted properly. } @@ -493,7 +494,9 @@ class InvalidOverride extends MethodViolation { * A pointer type that does not have a pointee type. */ class InvalidPointerType extends TypeViolation { - InvalidPointerType() { exists(PointerType p | p = getType() | count(p.getReferentType()) != 1) } + InvalidPointerType() { + exists(PointerType p | p = this.getType() | count(p.getReferentType()) != 1) + } override string getMessage() { result = "Invalid Pointertype.getPointeeType()" } } @@ -502,7 +505,9 @@ class InvalidPointerType extends TypeViolation { * An array with an invalid `getElementType`. */ class ArrayTypeMissingElement extends TypeViolation { - ArrayTypeMissingElement() { exists(ArrayType t | t = getType() | count(t.getElementType()) != 1) } + ArrayTypeMissingElement() { + exists(ArrayType t | t = this.getType() | count(t.getElementType()) != 1) + } override string getMessage() { result = "Invalid ArrayType.getElementType()" } } @@ -511,7 +516,7 @@ class ArrayTypeMissingElement extends TypeViolation { * An array with an invalid `getRank`. */ class ArrayTypeInvalidRank extends TypeViolation { - ArrayTypeInvalidRank() { exists(ArrayType t | t = getType() | not t.getRank() > 0) } + ArrayTypeInvalidRank() { exists(ArrayType t | t = this.getType() | not t.getRank() > 0) } override string getMessage() { result = "Invalid ArrayType.getRank()" } } @@ -564,7 +569,7 @@ abstract class DeclarationViolation extends ConsistencyViolation, DeclarationChe /** Gets the member containing the potential violation. */ Declaration getDeclaration() { this = DeclarationCheck(result) } - override string toString() { result = getDeclaration().toString() } + override string toString() { result = this.getDeclaration().toString() } } /** @@ -572,7 +577,7 @@ abstract class DeclarationViolation extends ConsistencyViolation, DeclarationChe */ class PropertyWithNoAccessors extends DeclarationViolation { PropertyWithNoAccessors() { - exists(Property p | p = getDeclaration() | not exists(p.getAnAccessor())) + exists(Property p | p = this.getDeclaration() | not exists(p.getAnAccessor())) } override string getMessage() { result = "Property has no accessors" } @@ -646,7 +651,7 @@ class TypeMultiplyDefined extends TypeViolation, DisabledCheck { override string getMessage() { result = - "This type (" + getType().toStringWithTypes() + ") has " + + "This type (" + this.getType().toStringWithTypes() + ") has " + count(Type t | not t instanceof ConstructedGeneric and t.toStringWithTypes() = this.getType().toStringWithTypes() @@ -669,11 +674,11 @@ class MissingCilDeclaration extends ConsistencyViolation, MissingCSharpCheck { override string getMessage() { result = - "Cannot locate CIL for " + getDeclaration().toStringWithTypes() + " of class " + - getDeclaration().getPrimaryQlClasses() + "Cannot locate CIL for " + this.getDeclaration().toStringWithTypes() + " of class " + + this.getDeclaration().getPrimaryQlClasses() } - override string toString() { result = getDeclaration().toStringWithTypes() } + override string toString() { result = this.getDeclaration().toStringWithTypes() } } /** @@ -717,21 +722,23 @@ private predicate expectedCilDeclaration(CS::Declaration decl) { /** A member with an invalid name. */ class MemberWithInvalidName extends DeclarationViolation { MemberWithInvalidName() { - exists(string name | name = getDeclaration().(Member).getName() | + exists(string name | name = this.getDeclaration().(Member).getName() | exists(name.indexOf(".")) and not name = ".ctor" and not name = ".cctor" ) } - override string getMessage() { result = "Invalid name " + getDeclaration().(Member).getName() } + override string getMessage() { + result = "Invalid name " + this.getDeclaration().(Member).getName() + } } class ConstructedSourceDeclarationMethod extends MethodViolation { Method method; ConstructedSourceDeclarationMethod() { - method = getMethod() and + method = this.getMethod() and method = method.getUnboundDeclaration() and ( method instanceof ConstructedGeneric or @@ -751,7 +758,7 @@ class DeclarationWithMultipleLabels extends DeclarationViolation { } override string getMessage() { - result = "Multiple labels " + concat(getDeclaration().getLabel(), ", ") + result = "Multiple labels " + concat(this.getDeclaration().getLabel(), ", ") } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/ControlFlow.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/ControlFlow.qll index 52a2ddc3376..8b6d6c70a05 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/ControlFlow.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/ControlFlow.qll @@ -23,13 +23,13 @@ class ControlFlowNode extends @cil_controlflow_node { int getPopCount() { result = 0 } /** Gets a successor of this node, if any. */ - final Instruction getASuccessor() { result = getASuccessorType(_) } + final Instruction getASuccessor() { result = this.getASuccessorType(_) } /** Gets a true successor of this node, if any. */ - final Instruction getTrueSuccessor() { result = getASuccessorType(any(TrueFlow f)) } + final Instruction getTrueSuccessor() { result = this.getASuccessorType(any(TrueFlow f)) } /** Gets a false successor of this node, if any. */ - final Instruction getFalseSuccessor() { result = getASuccessorType(any(FalseFlow f)) } + final Instruction getFalseSuccessor() { result = this.getASuccessorType(any(FalseFlow f)) } /** Gets a successor to this node, of type `type`, if any. */ cached @@ -57,7 +57,7 @@ class ControlFlowNode extends @cil_controlflow_node { } /** Gets an operand of this instruction, if any. */ - ControlFlowNode getAnOperand() { result = getOperand(_) } + ControlFlowNode getAnOperand() { result = this.getOperand(_) } /** Gets an expression that consumes the output of this instruction on the stack. */ Instruction getParentExpr() { this = result.getAnOperand() } @@ -86,17 +86,17 @@ class ControlFlowNode extends @cil_controlflow_node { ) } - private int getStackDelta() { result = getPushCount() - getPopCount() } + private int getStackDelta() { result = this.getPushCount() - this.getPopCount() } /** Gets the stack size before this instruction. */ - int getStackSizeBefore() { result = getAPredecessor().getStackSizeAfter() } + int getStackSizeBefore() { result = this.getAPredecessor().getStackSizeAfter() } /** Gets the stack size after this instruction. */ final int getStackSizeAfter() { // This is a guard to prevent ill formed programs // and other logic errors going into an infinite loop. - result in [0 .. getImplementation().getStackSize()] and - result = getStackSizeBefore() + getStackDelta() + result in [0 .. this.getImplementation().getStackSize()] and + result = this.getStackSizeBefore() + this.getStackDelta() } /** Gets the method containing this control flow node. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Declaration.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Declaration.qll index a747d4a6d80..178b5c9966e 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Declaration.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Declaration.qll @@ -68,7 +68,7 @@ class Member extends DotNet::Member, Declaration, @cil_member { /** Holds if this member has a security attribute. */ predicate hasSecurity() { cil_security(this) } - override Location getLocation() { result = getDeclaringType().getLocation() } + override Location getLocation() { result = this.getDeclaringType().getLocation() } } /** A property. */ @@ -87,24 +87,25 @@ class Property extends DotNet::Property, Member, CustomModifierReceiver, @cil_pr override Setter getSetter() { this = result.getProperty() } /** Gets an accessor of this property. */ - Accessor getAnAccessor() { result = getGetter() or result = getSetter() } + Accessor getAnAccessor() { result = this.getGetter() or result = this.getSetter() } - override string toString() { result = "property " + getName() } + override string toString() { result = "property " + this.getName() } override string toStringWithTypes() { result = - getType().toStringWithTypes() + " " + getDeclaringType().toStringWithTypes() + "." + getName() + this.getType().toStringWithTypes() + " " + this.getDeclaringType().toStringWithTypes() + "." + + this.getName() } } /** A property that is trivial (wraps a field). */ class TrivialProperty extends Property { TrivialProperty() { - getGetter().(TrivialGetter).getField() = getSetter().(TrivialSetter).getField() + this.getGetter().(TrivialGetter).getField() = this.getSetter().(TrivialSetter).getField() } /** Gets the underlying field of this property. */ - Field getField() { result = getGetter().(TrivialGetter).getField() } + Field getField() { result = this.getGetter().(TrivialGetter).getField() } } /** An event. */ @@ -125,9 +126,9 @@ class Event extends DotNet::Event, Member, @cil_event { /** Gets the raiser. */ Method getRaiser() { cil_raiser(this, result) } - override string toString() { result = "event " + getName() } + override string toString() { result = "event " + this.getName() } override string toStringWithTypes() { - result = getDeclaringType().toStringWithTypes() + "." + getName() + result = this.getDeclaringType().toStringWithTypes() + "." + this.getName() } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Generics.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Generics.qll index a742a142cc4..2e702e68ffe 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Generics.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Generics.qll @@ -45,5 +45,5 @@ class ConstructedType extends ConstructedGeneric, Type { /** A constructed generic method. */ class ConstructedMethod extends ConstructedGeneric, Method { - final override UnboundGenericMethod getUnboundGeneric() { result = getUnboundMethod() } + final override UnboundGenericMethod getUnboundGeneric() { result = this.getUnboundMethod() } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Instruction.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Instruction.qll index 3e620031264..fa9753e1f0c 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Instruction.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Instruction.qll @@ -4,15 +4,17 @@ private import CIL /** An instruction. */ class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instruction { - override string toString() { result = getOpcodeName() } + override string toString() { result = this.getOpcodeName() } /** Gets a more verbose textual representation of this instruction. */ - string toStringExtra() { result = getIndex() + ": " + getOpcodeName() + getExtraStr() } + string toStringExtra() { + result = this.getIndex() + ": " + this.getOpcodeName() + this.getExtraStr() + } /** Gets the method containing this instruction. */ override MethodImplementation getImplementation() { cil_instruction(this, _, _, result) } - override Method getMethod() { result = getImplementation().getMethod() } + override Method getMethod() { result = this.getImplementation().getMethod() } /** * Gets the index of this instruction. @@ -30,7 +32,7 @@ class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instructi string getExtra() { none() } private string getExtraStr() { - if exists(getExtra()) then result = " " + getExtra() else result = "" + if exists(this.getExtra()) then result = " " + this.getExtra() else result = "" } /** Gets the declaration accessed by this instruction, if any. */ @@ -39,8 +41,8 @@ class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instructi /** Gets a successor instruction to this instruction. */ override Instruction getASuccessorType(FlowType t) { t instanceof NormalFlow and - canFlowNext() and - result = this.getImplementation().getInstruction(getIndex() + 1) + this.canFlowNext() and + result = this.getImplementation().getInstruction(this.getIndex() + 1) } /** Holds if this instruction passes control flow into the next instruction. */ @@ -61,7 +63,7 @@ class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instructi override Location getALocation() { cil_instruction_location(this, result) // The source code, if available or - result = getImplementation().getLocation() // The containing assembly + result = this.getImplementation().getLocation() // The containing assembly } override Location getLocation() { result = Element.super.getLocation() } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/InstructionGroups.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/InstructionGroups.qll index e4aeb05a839..5dac4bf7291 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/InstructionGroups.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/InstructionGroups.qll @@ -14,7 +14,7 @@ class Expr extends DotNet::Expr, Instruction, @cil_expr { override Type getType() { result = Instruction.super.getType() } - override Method getEnclosingCallable() { result = getImplementation().getMethod() } + override Method getEnclosingCallable() { result = this.getImplementation().getMethod() } /** * The "parent" of a CIL expression is taken to be the instruction @@ -28,13 +28,13 @@ class Branch extends Instruction, @cil_jump { /** Gets the instruction that is jumped to. */ Instruction getTarget() { cil_jump(this, result) } - override string getExtra() { result = getTarget().getIndex() + ":" } + override string getExtra() { result = this.getTarget().getIndex() + ":" } } /** An instruction that unconditionally jumps to another instruction. */ class UnconditionalBranch extends Branch, @cil_unconditional_jump { override Instruction getASuccessorType(FlowType t) { - t instanceof NormalFlow and result = getTarget() + t instanceof NormalFlow and result = this.getTarget() } override predicate canFlowNext() { none() } @@ -43,9 +43,9 @@ class UnconditionalBranch extends Branch, @cil_unconditional_jump { /** An instruction that jumps to a target based on a condition. */ class ConditionalBranch extends Branch, @cil_conditional_jump { override Instruction getASuccessorType(FlowType t) { - t instanceof TrueFlow and result = getTarget() + t instanceof TrueFlow and result = this.getTarget() or - t instanceof FalseFlow and result = getImplementation().getInstruction(getIndex() + 1) + t instanceof FalseFlow and result = this.getImplementation().getInstruction(this.getIndex() + 1) } override int getPushCount() { result = 0 } @@ -61,7 +61,7 @@ class UnaryExpr extends Expr, @cil_unary_expr { override int getPopCount() { result = 1 } /** Gets the operand of this unary expression. */ - Expr getOperand() { result = getOperand(0) } + Expr getOperand() { result = this.getOperand(0) } } /** A binary expression that compares two values. */ @@ -73,8 +73,8 @@ class ComparisonOperation extends BinaryExpr, @cil_comparison_operation { class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation { override Type getType() { exists(Type t0, Type t1 | - t0 = getOperand(0).getType().getUnderlyingType() and - t1 = getOperand(1).getType().getUnderlyingType() + t0 = this.getOperand(0).getType().getUnderlyingType() and + t1 = this.getOperand(1).getType().getUnderlyingType() | t0 = t1 and result = t0 or @@ -100,7 +100,7 @@ class UnaryBitwiseOperation extends UnaryExpr, @cil_unary_bitwise_operation { /** A unary expression that converts a value from one primitive type to another. */ class Conversion extends UnaryExpr, @cil_conversion_operation { /** Gets the expression being converted. */ - Expr getExpr() { result = getOperand(0) } + Expr getExpr() { result = this.getOperand(0) } } /** A branch that leaves the scope of a `Handler`. */ @@ -111,7 +111,7 @@ class Literal extends DotNet::Literal, Expr, @cil_literal { /** Gets the pushed value. */ override string getValue() { cil_value(this, result) } - override string getExtra() { result = getValue() } + override string getExtra() { result = this.getValue() } } /** An integer literal. */ @@ -149,44 +149,44 @@ class Call extends Expr, DotNet::Call, @cil_call_any { /** Gets the method that is called. */ override Method getTarget() { cil_access(this, result) } - override Method getARuntimeTarget() { result = getTarget().getAnOverrider*() } + override Method getARuntimeTarget() { result = this.getTarget().getAnOverrider*() } - override string getExtra() { result = getTarget().getQualifiedName() } + override string getExtra() { result = this.getTarget().getQualifiedName() } /** * Gets the return type of the call. Methods that do not return a value * return the `void` type, `System.Void`, although the value of `getPushCount` is * 0 in this case. */ - override Type getType() { result = getTarget().getReturnType() } + override Type getType() { result = this.getTarget().getReturnType() } // The number of items popped/pushed from the stack // depends on the target of the call. - override int getPopCount() { result = getTarget().getCallPopCount() } + override int getPopCount() { result = this.getTarget().getCallPopCount() } - override int getPushCount() { result = getTarget().getCallPushCount() } + override int getPushCount() { result = this.getTarget().getCallPushCount() } /** * Holds if this is a "tail call", meaning that control does not return to the * calling method. */ predicate isTailCall() { - getImplementation().getInstruction(getIndex() - 1) instanceof Opcodes::Tail + this.getImplementation().getInstruction(this.getIndex() - 1) instanceof Opcodes::Tail } /** Holds if this call is virtual and could go to an overriding method. */ predicate isVirtual() { none() } - override Expr getRawArgument(int i) { result = getOperand(getPopCount() - i - 1) } + override Expr getRawArgument(int i) { result = this.getOperand(this.getPopCount() - i - 1) } /** Gets the qualifier of this call, if any. */ - Expr getQualifier() { result = getRawArgument(0) and not getTarget().isStatic() } + Expr getQualifier() { result = this.getRawArgument(0) and not this.getTarget().isStatic() } override Expr getArgument(int i) { - if getTarget().isStatic() - then result = getRawArgument(i) + if this.getTarget().isStatic() + then result = this.getRawArgument(i) else ( - result = getRawArgument(i + 1) and i >= 0 + result = this.getRawArgument(i + 1) and i >= 0 ) } @@ -217,10 +217,10 @@ class VirtualCall extends Call { /** A read of an array element. */ class ReadArrayElement extends BinaryExpr, @cil_read_array { /** Gets the array being read. */ - Expr getArray() { result = getOperand(1) } + Expr getArray() { result = this.getOperand(1) } /** Gets the index into the array. */ - Expr getArrayIndex() { result = getOperand(0) } + Expr getArrayIndex() { result = this.getOperand(0) } } /** A write of an array element. */ @@ -233,14 +233,14 @@ class WriteArrayElement extends Instruction, @cil_write_array { /** A `return` statement. */ class Return extends Instruction, @cil_ret { /** Gets the expression being returned, if any. */ - Expr getExpr() { result = getOperand(0) } + Expr getExpr() { result = this.getOperand(0) } override predicate canFlowNext() { none() } } /** A `throw` statement. */ class Throw extends Instruction, DotNet::Throw, @cil_throw_any { - override Expr getExpr() { result = getOperand(0) } + override Expr getExpr() { result = this.getOperand(0) } override predicate canFlowNext() { none() } } @@ -250,10 +250,10 @@ class StoreIndirect extends Instruction, @cil_stind { override int getPopCount() { result = 2 } /** Gets the location to store the value at. */ - Expr getAddress() { result = getOperand(1) } + Expr getAddress() { result = this.getOperand(1) } /** Gets the value to store. */ - Expr getExpr() { result = getOperand(0) } + Expr getExpr() { result = this.getOperand(0) } } /** Loads a value from an address/location. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Instructions.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Instructions.qll index e385ceced31..5752ae45b20 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Instructions.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Instructions.qll @@ -83,21 +83,21 @@ module Opcodes { class Ldc_i4 extends IntLiteral, @cil_ldc_i4 { override string getOpcodeName() { result = "ldc.i4" } - override string getExtra() { result = getValue() } + override string getExtra() { result = this.getValue() } } /** An `ldc.i8` instruction. */ class Ldc_i8 extends IntLiteral, @cil_ldc_i8 { override string getOpcodeName() { result = "ldc.i8" } - override string getExtra() { result = getValue() } + override string getExtra() { result = this.getValue() } } /** An `ldc.i4.s` instruction. */ class Ldc_i4_s extends IntLiteral, @cil_ldc_i4_s { override string getOpcodeName() { result = "ldc.i4.s" } - override string getExtra() { result = getValue() } + override string getExtra() { result = this.getValue() } } /** An `ldnull` instruction. */ @@ -115,7 +115,7 @@ module Opcodes { class Ldc_r4 extends FloatLiteral, @cil_ldc_r4 { override string getOpcodeName() { result = "ldc.r4" } - override string getExtra() { result = getValue() } + override string getExtra() { result = this.getValue() } override Type getType() { result instanceof FloatType } } @@ -124,7 +124,7 @@ module Opcodes { class Ldc_r8 extends FloatLiteral, @cil_ldc_r8 { override string getOpcodeName() { result = "ldc.r8" } - override string getExtra() { result = getValue() } + override string getExtra() { result = this.getValue() } override Type getType() { result instanceof DoubleType } } @@ -199,9 +199,9 @@ module Opcodes { override string getOpcodeName() { result = "neg" } override NumericType getType() { - result = getOperand().getType() + result = this.getOperand().getType() or - getOperand().getType() instanceof Enum and result instanceof IntType + this.getOperand().getType() instanceof Enum and result instanceof IntType } } @@ -260,7 +260,7 @@ module Opcodes { override int getPushCount() { result = 2 } // This is the only instruction that pushes 2 items - override Type getType() { result = getOperand(0).getType() } + override Type getType() { result = this.getOperand(0).getType() } } /** A `ret` instruction. */ @@ -270,7 +270,7 @@ module Opcodes { override predicate canFlowNext() { none() } override int getPopCount() { - if getImplementation().getMethod().returnsVoid() then result = 0 else result = 1 + if this.getImplementation().getMethod().returnsVoid() then result = 0 else result = 1 } } @@ -283,7 +283,7 @@ module Opcodes { class Ldstr extends StringLiteral, @cil_ldstr { override string getOpcodeName() { result = "ldstr" } - override string getExtra() { result = "\"" + getValue() + "\"" } + override string getExtra() { result = "\"" + this.getValue() + "\"" } override Type getType() { result instanceof StringType } } @@ -427,11 +427,14 @@ module Opcodes { override Instruction getASuccessorType(FlowType t) { t instanceof NormalFlow and - (result = getTarget(_) or result = getImplementation().getInstruction(getIndex() + 1)) + ( + result = this.getTarget(_) or + result = this.getImplementation().getInstruction(this.getIndex() + 1) + ) } override string getExtra() { - result = concat(int n | exists(getTarget(n)) | getTarget(n).getIndex() + ":", " ") + result = concat(int n | exists(this.getTarget(n)) | this.getTarget(n).getIndex() + ":", " ") } } @@ -493,9 +496,9 @@ module Opcodes { // The number of items popped/pushed from the stack depends on the target of // the call. Also, we need to pop the function pointer itself too. - override int getPopCount() { result = getTargetType().getCallPopCount() + 1 } + override int getPopCount() { result = this.getTargetType().getCallPopCount() + 1 } - override int getPushCount() { result = getTargetType().getCallPushCount() } + override int getPushCount() { result = this.getTargetType().getCallPushCount() } } /** A `callvirt` instruction. */ @@ -524,49 +527,49 @@ module Opcodes { override BoolType getType() { exists(result) } /** Gets the type that is being tested against. */ - Type getTestedType() { result = getAccess() } + Type getTestedType() { result = this.getAccess() } - override string getExtra() { result = getTestedType().getQualifiedName() } + override string getExtra() { result = this.getTestedType().getQualifiedName() } } /** A `castclass` instruction. */ class Castclass extends UnaryExpr, @cil_castclass { override string getOpcodeName() { result = "castclass" } - override Type getType() { result = getAccess() } + override Type getType() { result = this.getAccess() } /** Gets the type that is being cast to. */ - Type getTestedType() { result = getAccess() } + Type getTestedType() { result = this.getAccess() } - override string getExtra() { result = getTestedType().getQualifiedName() } + override string getExtra() { result = this.getTestedType().getQualifiedName() } } /** An `stloc.0` instruction. */ class Stloc_0 extends LocalVariableWriteAccess, @cil_stloc_0 { override string getOpcodeName() { result = "stloc.0" } - override LocalVariable getTarget() { result = getImplementation().getLocalVariable(0) } + override LocalVariable getTarget() { result = this.getImplementation().getLocalVariable(0) } } /** An `stloc.1` instruction. */ class Stloc_1 extends LocalVariableWriteAccess, @cil_stloc_1 { override string getOpcodeName() { result = "stloc.1" } - override LocalVariable getTarget() { result = getImplementation().getLocalVariable(1) } + override LocalVariable getTarget() { result = this.getImplementation().getLocalVariable(1) } } /** An `stloc.2` instruction. */ class Stloc_2 extends LocalVariableWriteAccess, @cil_stloc_2 { override string getOpcodeName() { result = "stloc.2" } - override LocalVariable getTarget() { result = getImplementation().getLocalVariable(2) } + override LocalVariable getTarget() { result = this.getImplementation().getLocalVariable(2) } } /** An `stloc.3` instruction. */ class Stloc_3 extends LocalVariableWriteAccess, @cil_stloc_3 { override string getOpcodeName() { result = "stloc.3" } - override LocalVariable getTarget() { result = getImplementation().getLocalVariable(3) } + override LocalVariable getTarget() { result = this.getImplementation().getLocalVariable(3) } } /** An `stloc.s` instruction. */ @@ -587,28 +590,28 @@ module Opcodes { class Ldloc_0 extends LocalVariableReadAccess, @cil_ldloc_0 { override string getOpcodeName() { result = "ldloc.0" } - override LocalVariable getTarget() { result = getImplementation().getLocalVariable(0) } + override LocalVariable getTarget() { result = this.getImplementation().getLocalVariable(0) } } /** An `ldloc.1` instruction. */ class Ldloc_1 extends LocalVariableReadAccess, @cil_ldloc_1 { override string getOpcodeName() { result = "ldloc.1" } - override LocalVariable getTarget() { result = getImplementation().getLocalVariable(1) } + override LocalVariable getTarget() { result = this.getImplementation().getLocalVariable(1) } } /** An `ldloc.2` instruction. */ class Ldloc_2 extends LocalVariableReadAccess, @cil_ldloc_2 { override string getOpcodeName() { result = "ldloc.2" } - override LocalVariable getTarget() { result = getImplementation().getLocalVariable(2) } + override LocalVariable getTarget() { result = this.getImplementation().getLocalVariable(2) } } /** An `ldloc.3` instruction. */ class Ldloc_3 extends LocalVariableReadAccess, @cil_ldloc_3 { override string getOpcodeName() { result = "ldloc.3" } - override LocalVariable getTarget() { result = getImplementation().getLocalVariable(3) } + override LocalVariable getTarget() { result = this.getImplementation().getLocalVariable(3) } } /** An `ldloc.s` instruction. */ @@ -617,7 +620,7 @@ module Opcodes { override LocalVariable getTarget() { cil_access(this, result) } - override string getExtra() { result = "L" + getTarget().getIndex() } + override string getExtra() { result = "L" + this.getTarget().getIndex() } } /** An `ldloca.s` instruction. */ @@ -626,7 +629,7 @@ module Opcodes { override LocalVariable getTarget() { cil_access(this, result) } - override string getExtra() { result = "L" + getTarget().getIndex() } + override string getExtra() { result = "L" + this.getTarget().getIndex() } } /** An `ldloc` instruction. */ @@ -635,7 +638,7 @@ module Opcodes { override LocalVariable getTarget() { cil_access(this, result) } - override string getExtra() { result = "L" + getTarget().getIndex() } + override string getExtra() { result = "L" + this.getTarget().getIndex() } } /** An `ldarg.0` instruction. */ @@ -643,7 +646,7 @@ module Opcodes { override string getOpcodeName() { result = "ldarg.0" } override MethodParameter getTarget() { - result = getImplementation().getMethod().getRawParameter(0) + result = this.getImplementation().getMethod().getRawParameter(0) } } @@ -652,7 +655,7 @@ module Opcodes { override string getOpcodeName() { result = "ldarg.1" } override MethodParameter getTarget() { - result = getImplementation().getMethod().getRawParameter(1) + result = this.getImplementation().getMethod().getRawParameter(1) } } @@ -661,7 +664,7 @@ module Opcodes { override string getOpcodeName() { result = "ldarg.2" } override MethodParameter getTarget() { - result = getImplementation().getMethod().getRawParameter(2) + result = this.getImplementation().getMethod().getRawParameter(2) } } @@ -670,7 +673,7 @@ module Opcodes { override string getOpcodeName() { result = "ldarg.3" } override MethodParameter getTarget() { - result = getImplementation().getMethod().getRawParameter(3) + result = this.getImplementation().getMethod().getRawParameter(3) } } @@ -710,7 +713,7 @@ module Opcodes { override int getPopCount() { result = 1 } - override Expr getQualifier() { result = getOperand(0) } + override Expr getQualifier() { result = this.getOperand(0) } } /** An `ldflda` instruction. */ @@ -719,7 +722,7 @@ module Opcodes { override int getPopCount() { result = 1 } - override Expr getQualifier() { result = getOperand(0) } + override Expr getQualifier() { result = this.getOperand(0) } } /** An `ldsfld` instruction. */ @@ -746,9 +749,9 @@ module Opcodes { override int getPopCount() { result = 2 } - override Expr getQualifier() { result = getOperand(1) } + override Expr getQualifier() { result = this.getOperand(1) } - override Expr getExpr() { result = getOperand(0) } + override Expr getExpr() { result = this.getOperand(0) } } /** An `stsfld` instruction. */ @@ -759,7 +762,7 @@ module Opcodes { override Expr getQualifier() { none() } - override Expr getExpr() { result = getOperand(0) } + override Expr getExpr() { result = this.getOperand(0) } } /** A `newobj` instruction. */ @@ -772,7 +775,7 @@ module Opcodes { override Type getType() { result = this.getTarget().getDeclaringType() } - override Expr getArgument(int i) { result = getRawArgument(i) } + override Expr getArgument(int i) { result = this.getRawArgument(i) } pragma[noinline] private Parameter getARawTargetParameter() { result = this.getTarget().getARawParameter() } @@ -796,21 +799,21 @@ module Opcodes { class Box extends UnaryExpr, @cil_box { override string getOpcodeName() { result = "box" } - override Type getType() { result = getAccess() } + override Type getType() { result = this.getAccess() } } /** An `unbox.any` instruction. */ class Unbox_any extends UnaryExpr, @cil_unbox_any { override string getOpcodeName() { result = "unbox.any" } - override Type getType() { result = getAccess() } + override Type getType() { result = this.getAccess() } } /** An `unbox` instruction. */ class Unbox extends UnaryExpr, @cil_unbox { override string getOpcodeName() { result = "unbox" } - override Type getType() { result = getAccess() } + override Type getType() { result = this.getAccess() } } /** An `ldobj` instruction. */ @@ -820,7 +823,7 @@ module Opcodes { /** Gets the type of the object. */ Type getTarget() { cil_access(this, result) } - override Type getType() { result = getAccess() } + override Type getType() { result = this.getAccess() } } /** An `ldtoken` instruction. */ @@ -867,31 +870,31 @@ module Opcodes { // Note that this is technically wrong - it should be // result.(ArrayType).getElementType() = getAccess() // However the (ArrayType) may not be in the database. - result = getAccess() + result = this.getAccess() } - override string getExtra() { result = getType().getQualifiedName() } + override string getExtra() { result = this.getType().getQualifiedName() } } /** An `ldelem` instruction. */ class Ldelem extends ReadArrayElement, @cil_ldelem { override string getOpcodeName() { result = "ldelem" } - override Type getType() { result = getAccess() } + override Type getType() { result = this.getAccess() } } /** An `ldelem.ref` instruction. */ class Ldelem_ref extends ReadArrayElement, @cil_ldelem_ref { override string getOpcodeName() { result = "ldelem.ref" } - override Type getType() { result = getArray().getType() } + override Type getType() { result = this.getArray().getType() } } /** An `ldelema` instruction. */ class Ldelema extends ReadArrayElement, ReadRef, @cil_ldelema { override string getOpcodeName() { result = "ldelema" } - override Type getType() { result = getAccess() } + override Type getType() { result = this.getAccess() } } /** An `stelem.ref` instruction. */ @@ -1410,7 +1413,7 @@ module Opcodes { override int getPopCount() { result = 1 } - override Type getType() { result = getAccess() } + override Type getType() { result = this.getAccess() } } /** A `refanytype` instruction. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Method.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Method.qll index 82bde17a477..461a020972b 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Method.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Method.qll @@ -28,13 +28,13 @@ class MethodImplementation extends EntryPoint, @cil_method_implementation { LocalVariable getLocalVariable(int n) { cil_local_variable(result, this, n, _) } /** Gets a local variable of this implementation, if any. */ - LocalVariable getALocalVariable() { result = getLocalVariable(_) } + LocalVariable getALocalVariable() { result = this.getLocalVariable(_) } /** Gets an instruction in this implementation, if any. */ - Instruction getAnInstruction() { result = getInstruction(_) } + Instruction getAnInstruction() { result = this.getInstruction(_) } /** Gets the total number of instructions in this implementation. */ - int getNumberOfInstructions() { result = count(getAnInstruction()) } + int getNumberOfInstructions() { result = count(this.getAnInstruction()) } /** Gets the `i`th handler in this implementation. */ Handler getHandler(int i) { result.getImplementation() = this and result.getIndex() = i } @@ -49,7 +49,7 @@ class MethodImplementation extends EntryPoint, @cil_method_implementation { /** Gets the maximum stack size of this implementation. */ int getStackSize() { cil_method_stack_size(this, result) } - override string toString() { result = getMethod().toString() } + override string toString() { result = this.getMethod().toString() } /** Gets a string representing the disassembly of this implementation. */ string getDisassembly() { @@ -75,13 +75,13 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN MethodImplementation getAnImplementation() { result.getMethod() = this } /** Gets the "best" implementation of this method, if any. */ - BestImplementation getImplementation() { result = getAnImplementation() } + BestImplementation getImplementation() { result = this.getAnImplementation() } override Method getMethod() { result = this } override string getName() { cil_method(this, result, _, _) } - override string getUndecoratedName() { result = getName() } + override string getUndecoratedName() { result = this.getName() } override string toString() { result = this.getName() } @@ -92,25 +92,29 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN override Location getALocation() { cil_method_location(this.getUnboundDeclaration(), result) } override MethodParameter getParameter(int n) { - if isStatic() then result = getRawParameter(n) else (result = getRawParameter(n + 1) and n >= 0) + if this.isStatic() + then result = this.getRawParameter(n) + else ( + result = this.getRawParameter(n + 1) and n >= 0 + ) } - override Type getType() { result = getReturnType() } + override Type getType() { result = this.getReturnType() } /** Gets the return type of this method. */ override Type getReturnType() { cil_method(this, _, _, result) } /** Holds if the return type is `void`. */ - predicate returnsVoid() { getReturnType() instanceof VoidType } + predicate returnsVoid() { this.getReturnType() instanceof VoidType } /** Gets the number of stack items pushed in a call to this method. */ - int getCallPushCount() { if returnsVoid() then result = 0 else result = 1 } + int getCallPushCount() { if this.returnsVoid() then result = 0 else result = 1 } /** Gets the number of stack items popped in a call to this method. */ - int getCallPopCount() { result = count(getRawParameter(_)) } + int getCallPopCount() { result = count(this.getRawParameter(_)) } /** Gets a method called by this method. */ - Method getACallee() { result = getImplementation().getAnInstruction().(Call).getTarget() } + Method getACallee() { result = this.getImplementation().getAnInstruction().(Call).getTarget() } /** Holds if this method is `virtual`. */ predicate isVirtual() { cil_virtual(this) } @@ -129,43 +133,45 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN /** Gets the unbound declaration of this method, or the method itself. */ Method getUnboundMethod() { cil_method_source_declaration(this, result) } - override Method getUnboundDeclaration() { result = getUnboundMethod() } + override Method getUnboundDeclaration() { result = this.getUnboundMethod() } /** Holds if this method is an instance constructor. */ - predicate isInstanceConstructor() { isSpecial() and getName() = ".ctor" } + predicate isInstanceConstructor() { this.isSpecial() and this.getName() = ".ctor" } /** Holds if this method is a static class constructor. */ - predicate isStaticConstructor() { isSpecial() and getName() = ".cctor" } + predicate isStaticConstructor() { this.isSpecial() and this.getName() = ".cctor" } /** Holds if this method is a constructor (static or instance). */ - predicate isConstructor() { isStaticConstructor() or isInstanceConstructor() } + predicate isConstructor() { this.isStaticConstructor() or this.isInstanceConstructor() } /** Holds if this method is a destructor/finalizer. */ - predicate isFinalizer() { getOverriddenMethod*().getQualifiedName() = "System.Object.Finalize" } + predicate isFinalizer() { + this.getOverriddenMethod*().getQualifiedName() = "System.Object.Finalize" + } /** Holds if this method is an operator. */ - predicate isOperator() { isSpecial() and getName().matches("op\\_%") } + predicate isOperator() { this.isSpecial() and this.getName().matches("op\\_%") } /** Holds if this method is a getter. */ - predicate isGetter() { isSpecial() and getName().matches("get\\_%") } + predicate isGetter() { this.isSpecial() and this.getName().matches("get\\_%") } /** Holds if this method is a setter. */ - predicate isSetter() { isSpecial() and getName().matches("set\\_%") } + predicate isSetter() { this.isSpecial() and this.getName().matches("set\\_%") } /** Holds if this method is an adder/add event accessor. */ - predicate isAdder() { isSpecial() and getName().matches("add\\_%") } + predicate isAdder() { this.isSpecial() and this.getName().matches("add\\_%") } /** Holds if this method is a remover/remove event accessor. */ - predicate isRemove() { isSpecial() and getName().matches("remove\\_%") } + predicate isRemove() { this.isSpecial() and this.getName().matches("remove\\_%") } /** Holds if this method is an implicit conversion operator. */ - predicate isImplicitConversion() { isSpecial() and getName() = "op_Implicit" } + predicate isImplicitConversion() { this.isSpecial() and this.getName() = "op_Implicit" } /** Holds if this method is an explicit conversion operator. */ - predicate isExplicitConversion() { isSpecial() and getName() = "op_Explicit" } + predicate isExplicitConversion() { this.isSpecial() and this.getName() = "op_Explicit" } /** Holds if this method is a conversion operator. */ - predicate isConversion() { isImplicitConversion() or isExplicitConversion() } + predicate isConversion() { this.isImplicitConversion() or this.isExplicitConversion() } /** * Gets a method that is overridden, either in a base class @@ -176,7 +182,7 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN /** Gets a method that overrides this method, if any. */ final Method getAnOverrider() { result.getOverriddenMethod() = this } - override predicate hasBody() { exists(getImplementation()) } + override predicate hasBody() { exists(this.getImplementation()) } override predicate canReturn(DotNet::Expr expr) { exists(Return ret | ret.getImplementation() = this.getImplementation() and expr = ret.getExpr()) @@ -206,7 +212,7 @@ class InstanceConstructor extends Constructor { /** A method that always returns the `this` parameter. */ class ChainingMethod extends Method { ChainingMethod() { - forex(Return ret | ret = getImplementation().getAnInstruction() | + forex(Return ret | ret = this.getImplementation().getAnInstruction() | ret.getExpr() instanceof ThisAccess ) } @@ -231,7 +237,7 @@ class Getter extends Accessor { */ class TrivialGetter extends Method { TrivialGetter() { - exists(MethodImplementation impl | impl = getAnImplementation() | + exists(MethodImplementation impl | impl = this.getAnImplementation() | impl.getInstruction(0) instanceof ThisAccess and impl.getInstruction(1) instanceof FieldReadAccess and impl.getInstruction(2) instanceof Return @@ -239,7 +245,9 @@ class TrivialGetter extends Method { } /** Gets the underlying field of this getter. */ - Field getField() { getImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result } + Field getField() { + this.getImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result + } } /** A setter. */ @@ -262,7 +270,7 @@ class Setter extends Accessor { */ class TrivialSetter extends Method { TrivialSetter() { - exists(MethodImplementation impl | impl = getImplementation() | + exists(MethodImplementation impl | impl = this.getImplementation() | impl.getInstruction(0) instanceof ThisAccess and impl.getInstruction(1).(ParameterReadAccess).getTarget().getIndex() = 1 and impl.getInstruction(2) instanceof FieldWriteAccess @@ -271,7 +279,7 @@ class TrivialSetter extends Method { /** Gets the underlying field of this setter. */ Field getField() { - result = getImplementation().getAnInstruction().(FieldWriteAccess).getTarget() + result = this.getImplementation().getAnInstruction().(FieldWriteAccess).getTarget() } } @@ -283,5 +291,5 @@ class Operator extends Method { Operator() { this.isOperator() } /** Gets the name of the implementing method (for compatibility with C# data model). */ - string getFunctionName() { result = getName() } + string getFunctionName() { result = this.getName() } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Type.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Type.qll index a081d62b7ee..7aeaf9a6495 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Type.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Type.qll @@ -19,7 +19,7 @@ class TypeContainer extends DotNet::NamedElement, @cil_type_container { /** A namespace. */ class Namespace extends DotNet::Namespace, TypeContainer, @namespace { - override string toString() { result = getQualifiedName() } + override string toString() { result = this.getQualifiedName() } override Namespace getParent() { result = this.getParentNamespace() } @@ -39,7 +39,7 @@ class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type { override string toString() { result = this.getName() } /** Gets the containing type of this type, if any. */ - override Type getDeclaringType() { result = getParent() } + override Type getDeclaringType() { result = this.getParent() } /** Gets a member of this type, if any. */ Member getAMember() { result.getDeclaringType() = this } @@ -96,13 +96,13 @@ class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type { Type getABaseInterface() { cil_base_interface(this, result) } /** Gets an immediate base type of this type, if any. */ - Type getABaseType() { result = getBaseClass() or result = getABaseInterface() } + Type getABaseType() { result = this.getBaseClass() or result = this.getABaseInterface() } /** Gets an immediate subtype of this type, if any. */ Type getASubtype() { result.getABaseType() = this } /** Gets the namespace directly containing this type, if any. */ - Namespace getNamespace() { result = getParent() } + Namespace getNamespace() { result = this.getParent() } /** * Gets an index for implicit conversions. A type can be converted to another numeric type diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Types.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Types.qll index d4d9342b73d..1dfaa0191a1 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Types.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Types.qll @@ -12,7 +12,7 @@ class TypeParameter extends DotNet::TypeParameter, Type, @cil_typeparameter { /** Gets the generic type/method declaring this type parameter. */ TypeContainer getGeneric() { cil_type_parameter(result, _, this) } - override Location getLocation() { result = getParent().getLocation() } + override Location getLocation() { result = this.getParent().getLocation() } /** Holds if this type parameter has the `new` constraint. */ predicate isDefaultConstructible() { cil_typeparam_new(this) } @@ -34,11 +34,11 @@ class TypeParameter extends DotNet::TypeParameter, Type, @cil_typeparameter { /** A value or reference type. */ class ValueOrRefType extends DotNet::ValueOrRefType, Type, @cil_valueorreftype { - override ValueOrRefType getDeclaringType() { result = getParent() } + override ValueOrRefType getDeclaringType() { result = this.getParent() } override string getUndecoratedName() { cil_type(this, result, _, _, _) } - override Namespace getDeclaringNamespace() { result = getNamespace() } + override Namespace getDeclaringNamespace() { result = this.getNamespace() } override ValueOrRefType getABaseType() { result = Type.super.getABaseType() } } @@ -79,7 +79,7 @@ class ArrayType extends DotNet::ArrayType, Type, @cil_array_type { override string toStringWithTypes() { result = DotNet::ArrayType.super.toStringWithTypes() } - override Location getLocation() { result = getElementType().getLocation() } + override Location getLocation() { result = this.getElementType().getLocation() } override ValueOrRefType getABaseType() { result = Type.super.getABaseType() } } @@ -92,7 +92,7 @@ class PointerType extends DotNet::PointerType, PrimitiveType, @cil_pointer_type override string getName() { result = DotNet::PointerType.super.getName() } - override Location getLocation() { result = getReferentType().getLocation() } + override Location getLocation() { result = this.getReferentType().getLocation() } override string toString() { result = DotNet::PointerType.super.toString() } @@ -312,13 +312,13 @@ class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable, override string toString() { result = Type.super.toString() } /** Holds if the return type is `void`. */ - predicate returnsVoid() { getReturnType() instanceof VoidType } + predicate returnsVoid() { this.getReturnType() instanceof VoidType } /** Gets the number of stack items pushed in a call to this method. */ - int getCallPushCount() { if returnsVoid() then result = 0 else result = 1 } + int getCallPushCount() { if this.returnsVoid() then result = 0 else result = 1 } /** Gets the number of stack items popped in a call to this method. */ - int getCallPopCount() { result = count(getRawParameter(_)) } + int getCallPopCount() { result = count(this.getRawParameter(_)) } - override string getLabel() { result = getName() } + override string getLabel() { result = this.getName() } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Variable.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Variable.qll index 3a247e1f0d1..604f2c2b646 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Variable.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/Variable.qll @@ -17,10 +17,10 @@ class Variable extends DotNet::Variable, Declaration, DataFlowNode, @cil_variabl VariableAccess getAnAccess() { result.getTarget() = this } /** Gets a read access to this variable, if any. */ - ReadAccess getARead() { result = getAnAccess() } + ReadAccess getARead() { result = this.getAnAccess() } /** Gets a write access to this variable, if any. */ - WriteAccess getAWrite() { result = getAnAccess() } + WriteAccess getAWrite() { result = this.getAnAccess() } override string toString() { result = Declaration.super.toString() } @@ -40,20 +40,21 @@ class StackVariable extends Variable, @cil_stack_variable { class LocalVariable extends StackVariable, @cil_local_variable { override string toString() { result = - "Local variable " + getIndex() + " of method " + getImplementation().getMethod().getName() + "Local variable " + this.getIndex() + " of method " + + this.getImplementation().getMethod().getName() } /** Gets the method implementation defining this local variable. */ MethodImplementation getImplementation() { this = result.getALocalVariable() } /** Gets the index number of this local variable. This is not usually significant. */ - int getIndex() { this = getImplementation().getLocalVariable(result) } + int getIndex() { this = this.getImplementation().getLocalVariable(result) } override Type getType() { cil_local_variable(this, _, _, result) } - override Location getLocation() { result = getImplementation().getLocation() } + override Location getLocation() { result = this.getImplementation().getLocation() } - override Method getMethod() { result = getImplementation().getMethod() } + override Method getMethod() { result = this.getImplementation().getMethod() } } /** A parameter of a `Method` or `FunctionPointerType`. */ @@ -64,7 +65,7 @@ class Parameter extends DotNet::Parameter, CustomModifierReceiver, @cil_paramete int getIndex() { cil_parameter(this, _, result, _) } override string toString() { - result = "Parameter " + getIndex() + " of " + getDeclaringElement().getName() + result = "Parameter " + this.getIndex() + " of " + this.getDeclaringElement().getName() } override Type getType() { cil_parameter(this, _, _, result) } @@ -82,23 +83,25 @@ class Parameter extends DotNet::Parameter, CustomModifierReceiver, @cil_paramete predicate hasInFlag() { cil_parameter_in(this) } /** Holds if this parameter has C# `out` semantics. */ - override predicate isOut() { hasOutFlag() and not hasInFlag() } + override predicate isOut() { this.hasOutFlag() and not this.hasInFlag() } /** Holds if this parameter has C# `ref` semantics. */ - override predicate isRef() { hasOutFlag() and hasInFlag() } + override predicate isRef() { this.hasOutFlag() and this.hasInFlag() } - override string toStringWithTypes() { result = getPrefix() + getType().toStringWithTypes() } + override string toStringWithTypes() { + result = this.getPrefix() + this.getType().toStringWithTypes() + } private string getPrefix() { - if isOut() + if this.isOut() then result = "out " else - if isRef() + if this.isRef() then result = "ref " else result = "" } - override Location getLocation() { result = getDeclaringElement().getLocation() } + override Location getLocation() { result = this.getDeclaringElement().getLocation() } } /** A method parameter. */ @@ -110,11 +113,11 @@ class MethodParameter extends Parameter, StackVariable { /** Gets a parameter in an overridden method. */ MethodParameter getOverriddenParameter() { - result = getMethod().getOverriddenMethod().getRawParameter(getRawPosition()) + result = this.getMethod().getOverriddenMethod().getRawParameter(this.getRawPosition()) } override MethodParameter getUnboundDeclaration() { - result = getMethod().getUnboundDeclaration().getRawParameter(getRawPosition()) + result = this.getMethod().getUnboundDeclaration().getRawParameter(this.getRawPosition()) } override string toString() { result = Parameter.super.toString() } @@ -136,10 +139,10 @@ class ThisParameter extends MethodParameter { /** A field. */ class Field extends DotNet::Field, Variable, Member, CustomModifierReceiver, @cil_field { - override string toString() { result = getName() } + override string toString() { result = this.getName() } override string toStringWithTypes() { - result = getDeclaringType().toStringWithTypes() + "." + getName() + result = this.getDeclaringType().toStringWithTypes() + "." + this.getName() } override string getName() { cil_field(this, _, result, _) } @@ -148,5 +151,5 @@ class Field extends DotNet::Field, Variable, Member, CustomModifierReceiver, @ci override ValueOrRefType getDeclaringType() { cil_field(this, result, _, _) } - override Location getLocation() { result = getDeclaringType().getLocation() } + override Location getLocation() { result = this.getDeclaringType().getLocation() } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll index 884f4406d01..eae5d23f544 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll @@ -141,24 +141,23 @@ private module Liveness { private import Liveness -/** Holds if `bb1` strictly dominates `bb2`. */ -private predicate strictlyDominates(BasicBlock bb1, BasicBlock bb2) { - bb1 = getImmediateBasicBlockDominator+(bb2) -} - -/** Holds if `bb1` dominates a predecessor of `bb2`. */ -private predicate dominatesPredecessor(BasicBlock bb1, BasicBlock bb2) { - exists(BasicBlock pred | pred = getABasicBlockPredecessor(bb2) | - bb1 = pred - or - strictlyDominates(bb1, pred) - ) -} - -/** Holds if `df` is in the dominance frontier of `bb`. */ +/** + * Holds if `df` is in the dominance frontier of `bb`. + * + * This is equivalent to: + * + * ```ql + * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and + * not bb = getImmediateBasicBlockDominator+(df) + * ``` + */ private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - dominatesPredecessor(bb, df) and - not strictlyDominates(bb, df) + bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) + or + exists(BasicBlock prev | inDominanceFrontier(prev, df) | + bb = getImmediateBasicBlockDominator(prev) and + not bb = getImmediateBasicBlockDominator(df) + ) } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/AnnotatedType.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/AnnotatedType.qll index 37aa2b23410..8afdbd0d4a3 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/AnnotatedType.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/AnnotatedType.qll @@ -67,7 +67,7 @@ private module Annotations { Nullability() { this = TNullability(nullability) } - override string toString() { result = getMemberString() + getSelfNullability() } + override string toString() { result = this.getMemberString() + this.getSelfNullability() } language[monotonicAggregates] private string getMemberString() { @@ -125,7 +125,9 @@ private module Annotations { } /** Gets a textual representation of this type annotation. */ - string toString() { result = getTypePrefix() + getNullability() + getTypeSuffix() } + string toString() { + result = this.getTypePrefix() + this.getNullability() + this.getTypeSuffix() + } private int getFlags() { this = TAnnotationFlags(result, _) } @@ -136,7 +138,7 @@ private module Annotations { /** Gets an annotation in this set of annotations. */ TypeAnnotation getAnAnnotation() { - isSet(result.getBit()) + this.isSet(result.getBit()) or result = this.getNullability() } @@ -298,7 +300,7 @@ class AnnotatedType extends TAnnotatedType { /** Gets a textual representation of this annotated type. */ string toString() { result = - annotations.getTypePrefix() + getUnderlyingType().toStringWithTypes() + + annotations.getTypePrefix() + this.getUnderlyingType().toStringWithTypes() + annotations.getTypeSuffix() } @@ -327,7 +329,7 @@ class AnnotatedType extends TAnnotatedType { /** Gets a type annotation of this annotated type. */ private Annotations::TypeAnnotation getAnAnnotation() { - result = getAnnotations().getAnAnnotation() + result = this.getAnnotations().getAnAnnotation() } /** Holds if the type is a non-nullable reference, for example, `string` in a nullable-enabled context. */ @@ -376,7 +378,7 @@ class AnnotatedArrayType extends AnnotatedType { private string getDimensionString(AnnotatedType elementType) { exists(AnnotatedType et, string res | - et = getElementType() and + et = this.getElementType() and res = type.getArraySuffix() and if et.getUnderlyingType() instanceof ArrayType and not et.isNullableRefType() then result = res + et.(AnnotatedArrayType).getDimensionString(elementType) diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Attribute.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Attribute.qll index 06fbda2a150..dae9f8a9fad 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Attribute.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Attribute.qll @@ -89,7 +89,7 @@ class Attribute extends TopLevelExprParent, @attribute { override Location getALocation() { attribute_location(this, result) } override string toString() { - exists(string type, string name | type = getType().getName() | + exists(string type, string name | type = this.getType().getName() | (if type.matches("%Attribute") then name = type.prefix(type.length() - 9) else name = type) and result = "[" + name + "(...)]" ) diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Callable.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Callable.qll index 133ae86d551..41641a9d032 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -117,7 +117,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal final BlockStmt getAStatementBody() { result = this.getStatementBody() } /** Holds if this callable has a statement body. */ - final predicate hasStatementBody() { exists(getStatementBody()) } + final predicate hasStatementBody() { exists(this.getStatementBody()) } /** * Gets the expression body of this callable (if any), specified by `=>`. @@ -157,7 +157,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal deprecated final Expr getAnExpressionBody() { result = this.getExpressionBody() } /** Holds if this callable has an expression body. */ - final predicate hasExpressionBody() { exists(getExpressionBody()) } + final predicate hasExpressionBody() { exists(this.getExpressionBody()) } /** Gets the entry point in the control graph for this callable. */ ControlFlow::Nodes::EntryNode getEntryPoint() { result.getCallable() = this } @@ -218,7 +218,9 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal exists(YieldReturnStmt yield | yield.getEnclosingCallable() = this | e = yield.getExpr()) } - override string toStringWithTypes() { result = getName() + "(" + parameterTypesToString() + ")" } + override string toStringWithTypes() { + result = this.getName() + "(" + this.parameterTypesToString() + ")" + } /** Gets a `Call` that has this callable as a target. */ Call getACall() { this = result.getTarget() } @@ -270,18 +272,18 @@ class Method extends Callable, Virtualizable, Attributable, @method { override Location getALocation() { method_location(this, result) } /** Holds if this method is an extension method. */ - predicate isExtensionMethod() { getParameter(0).hasExtensionMethodModifier() } + predicate isExtensionMethod() { this.getParameter(0).hasExtensionMethodModifier() } /** Gets the type of the `params` parameter of this method, if any. */ Type getParamsType() { - exists(Parameter last | last = getParameter(getNumberOfParameters() - 1) | + exists(Parameter last | last = this.getParameter(this.getNumberOfParameters() - 1) | last.isParams() and result = last.getType().(ArrayType).getElementType() ) } /** Holds if this method has a `params` parameter. */ - predicate hasParams() { exists(getParamsType()) } + predicate hasParams() { exists(this.getParamsType()) } // Remove when `Callable.isOverridden()` is removed override predicate isOverridden() { Virtualizable.super.isOverridden() } @@ -316,7 +318,7 @@ class ExtensionMethod extends Method { /** Gets the type being extended by this method. */ pragma[noinline] - Type getExtendedType() { result = getParameter(0).getType() } + Type getExtendedType() { result = this.getParameter(0).getType() } override string getAPrimaryQlClass() { result = "ExtensionMethod" } } @@ -355,7 +357,7 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @ ConstructorInitializer getInitializer() { result = this.getChildExpr(-1) } /** Holds if this constructor has an initializer. */ - predicate hasInitializer() { exists(getInitializer()) } + predicate hasInitializer() { exists(this.getInitializer()) } override ValueOrRefType getDeclaringType() { constructors(this, _, result, _) } @@ -467,7 +469,7 @@ class Operator extends Callable, Member, Attributable, @operator { override string toString() { result = Callable.super.toString() } - override Parameter getRawParameter(int i) { result = getParameter(i) } + override Parameter getRawParameter(int i) { result = this.getParameter(i) } } /** A clone method on a record. */ @@ -999,10 +1001,10 @@ class LocalFunction extends Callable, Modifiable, Attributable, @local_function override Type getReturnType() { local_functions(this, _, result, _) } - override Element getParent() { result = getStatement().getParent() } + override Element getParent() { result = this.getStatement().getParent() } /** Gets the local function statement defining this function. */ - LocalFunctionStmt getStatement() { result.getLocalFunction() = getUnboundDeclaration() } + LocalFunctionStmt getStatement() { result.getLocalFunction() = this.getUnboundDeclaration() } override Callable getEnclosingCallable() { result = this.getStatement().getEnclosingCallable() } @@ -1011,9 +1013,9 @@ class LocalFunction extends Callable, Modifiable, Attributable, @local_function name = this.getName() } - override Location getALocation() { result = getStatement().getALocation() } + override Location getALocation() { result = this.getStatement().getALocation() } - override Parameter getRawParameter(int i) { result = getParameter(i) } + override Parameter getRawParameter(int i) { result = this.getParameter(i) } override string getAPrimaryQlClass() { result = "LocalFunction" } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Comments.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Comments.qll index 41f4e5b0be8..9a611b851e8 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Comments.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Comments.qll @@ -11,7 +11,7 @@ import Location /** * A single line of comment. * - * Either a single line comment (`SingleLineComment`), an XML comment (`XmlComment`), + * Either a single line comment (`SinglelineComment`), an XML comment (`XmlComment`), * or a line in a multi-line comment (`MultilineComment`). */ class CommentLine extends @commentline { diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Conversion.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Conversion.qll index 0c560d1d86f..d62055b6a17 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Conversion.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Conversion.qll @@ -552,11 +552,16 @@ private predicate defaultDynamicConversion(Type fromType, Type toType) { fromType instanceof RefType and toType instanceof DynamicType } +pragma[noinline] +private predicate systemDelegateBaseType(RefType t) { + t = any(SystemDelegateClass c).getABaseType*() +} + // This is a deliberate, small cartesian product, so we have manually lifted it to force the // evaluator to evaluate it in its entirety, rather than trying to optimize it in context. pragma[noinline] private predicate defaultDelegateConversion(RefType fromType, RefType toType) { - fromType instanceof DelegateType and toType = any(SystemDelegateClass c).getABaseType*() + fromType instanceof DelegateType and systemDelegateBaseType(toType) } private predicate convRefTypeRefType(RefType fromType, RefType toType) { diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Element.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Element.qll index fbd96f6086d..390a7b16632 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Element.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Element.qll @@ -31,7 +31,7 @@ class Element extends DotNet::Element, @element { Element getParent() { result.getAChild() = this } /** Gets a child of this element, if any. */ - Element getAChild() { result = getChild(_) } + Element getAChild() { result = this.getChild(_) } /** Gets the `i`th child of this element (zero-based). */ Element getChild(int i) { none() } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Event.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Event.qll index 7cbfda76877..810cffa927a 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Event.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Event.qll @@ -29,10 +29,10 @@ class Event extends DeclarationWithAccessors, @event { EventAccessor getAnEventAccessor() { result.getDeclaration() = this } /** Gets the `add` accessor of this event, if any. */ - AddEventAccessor getAddEventAccessor() { result = getAnEventAccessor() } + AddEventAccessor getAddEventAccessor() { result = this.getAnEventAccessor() } /** Gets the `remove` accessor of this event, if any. */ - RemoveEventAccessor getRemoveEventAccessor() { result = getAnEventAccessor() } + RemoveEventAccessor getRemoveEventAccessor() { result = this.getAnEventAccessor() } /** * Holds if this event can be used like a field within its declaring type @@ -111,9 +111,9 @@ class EventAccessor extends Accessor, @event_accessor { * ``` */ class AddEventAccessor extends EventAccessor, @add_event_accessor { - override string getName() { result = "add" + "_" + getDeclaration().getName() } + override string getName() { result = "add" + "_" + this.getDeclaration().getName() } - override string getUndecoratedName() { result = "add" + "_" + getDeclaration().getName() } + override string getUndecoratedName() { result = "add" + "_" + this.getDeclaration().getName() } override string getAPrimaryQlClass() { result = "AddEventAccessor" } } @@ -132,9 +132,9 @@ class AddEventAccessor extends EventAccessor, @add_event_accessor { * ``` */ class RemoveEventAccessor extends EventAccessor, @remove_event_accessor { - override string getName() { result = "remove" + "_" + getDeclaration().getName() } + override string getName() { result = "remove" + "_" + this.getDeclaration().getName() } - override string getUndecoratedName() { result = "remove" + "_" + getDeclaration().getName() } + override string getUndecoratedName() { result = "remove" + "_" + this.getDeclaration().getName() } override string getAPrimaryQlClass() { result = "RemoveEventAccessor" } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/File.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/File.qll index df9ce6f3cf6..55fd2ccdc81 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/File.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/File.qll @@ -47,7 +47,7 @@ class Container extends @container { */ string getRelativePath() { exists(string absPath, string pref | - absPath = getAbsolutePath() and sourceLocationPrefix(pref) + absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) | absPath = pref and result = "" or @@ -74,7 +74,7 @@ class Container extends @container { * */ string getBaseName() { - result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) + result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) } /** @@ -100,7 +100,9 @@ class Container extends @container { * "/tmp/x.tar.gz""gz" * */ - string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) } + string getExtension() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) + } /** * Gets the stem of this container, that is, the prefix of its base name up to @@ -119,7 +121,9 @@ class Container extends @container { * "/tmp/x.tar.gz""x.tar" * */ - string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) } + string getStem() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) + } /** Gets the parent container of this file or folder, if any. */ Container getParentContainer() { containerparent(result, this) } @@ -128,52 +132,52 @@ class Container extends @container { Container getAChildContainer() { this = result.getParentContainer() } /** Gets a file in this container. */ - File getAFile() { result = getAChildContainer() } + File getAFile() { result = this.getAChildContainer() } /** Gets the file in this container that has the given `baseName`, if any. */ File getFile(string baseName) { - result = getAFile() and + result = this.getAFile() and result.getBaseName() = baseName } /** Gets a sub-folder in this container. */ - Folder getAFolder() { result = getAChildContainer() } + Folder getAFolder() { result = this.getAChildContainer() } /** Gets the sub-folder in this container that has the given `baseName`, if any. */ Folder getFolder(string baseName) { - result = getAFolder() and + result = this.getAFolder() and result.getBaseName() = baseName } /** Gets the file or sub-folder in this container that has the given `name`, if any. */ Container getChildContainer(string name) { - result = getAChildContainer() and + result = this.getAChildContainer() and result.getBaseName() = name } /** Gets the file in this container that has the given `stem` and `extension`, if any. */ File getFile(string stem, string extension) { - result = getAChildContainer() and + result = this.getAChildContainer() and result.getStem() = stem and result.getExtension() = extension } /** Gets a sub-folder contained in this container. */ - Folder getASubFolder() { result = getAChildContainer() } + Folder getASubFolder() { result = this.getAChildContainer() } /** * Gets a textual representation of the path of this container. * * This is the absolute path of the container. */ - string toString() { result = getAbsolutePath() } + string toString() { result = this.getAbsolutePath() } } /** A folder. */ class Folder extends Container, @folder { override string getAbsolutePath() { folders(this, result) } - override string getURL() { result = "folder://" + getAbsolutePath() } + override string getURL() { result = "folder://" + this.getAbsolutePath() } } /** A file. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Generics.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Generics.qll index 25a3679715b..9190523e3c0 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Generics.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Generics.qll @@ -71,14 +71,14 @@ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { override UnboundGeneric getUnboundGeneric() { constructed_generic(this, result) } override UnboundGeneric getUnboundDeclaration() { - result = getUnboundGeneric().getUnboundDeclaration() + result = this.getUnboundGeneric().getUnboundDeclaration() } override int getNumberOfTypeArguments() { result = count(int i | type_arguments(_, i, this)) } override Type getTypeArgument(int i) { none() } - override Type getATypeArgument() { result = getTypeArgument(_) } + override Type getATypeArgument() { result = this.getTypeArgument(_) } /** Gets the annotated type of type argument `i`. */ final AnnotatedType getAnnotatedTypeArgument(int i) { result.appliesToTypeArgument(this, i) } @@ -141,7 +141,7 @@ class UnboundGenericType extends ValueOrRefType, UnboundGeneric { result = ValueOrRefType.super.getUnboundDeclaration() } - final override Type getChild(int n) { result = getTypeParameter(n) } + final override Type getChild(int n) { result = this.getTypeParameter(n) } override string toStringWithTypes() { result = this.getUndecoratedName() + "<" + getTypeParametersToString(this) + ">" @@ -173,7 +173,7 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { TypeParameterConstraints getConstraints() { result.getTypeParameter() = this } override predicate isRefType() { - exists(TypeParameterConstraints tpc | tpc = getConstraints() | + exists(TypeParameterConstraints tpc | tpc = this.getConstraints() | tpc.hasRefTypeConstraint() or tpc.getATypeConstraint() instanceof Class or tpc.getATypeConstraint().(TypeParameter).isRefType() @@ -182,7 +182,7 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { } override predicate isValueType() { - exists(TypeParameterConstraints tpc | tpc = getConstraints() | + exists(TypeParameterConstraints tpc | tpc = this.getConstraints() | tpc.hasValueTypeConstraint() or tpc.getATypeConstraint().(TypeParameter).isValueType() ) @@ -219,9 +219,9 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { /** Gets a non-type-parameter type that was transitively supplied for this parameter. */ Type getAnUltimatelySuppliedType() { - result = getASuppliedType() and not result instanceof TypeParameter + result = this.getASuppliedType() and not result instanceof TypeParameter or - result = getASuppliedType().(TypeParameter).getAnUltimatelySuppliedType() + result = this.getASuppliedType().(TypeParameter).getAnUltimatelySuppliedType() } override int getIndex() { type_parameters(this, result, _, _) } @@ -376,8 +376,8 @@ class UnboundGenericDelegateType extends DelegateType, UnboundGenericType { override string toStringWithTypes() { result = - getUndecoratedName() + "<" + getTypeParametersToString(this) + ">(" + parameterTypesToString() - + ")" + this.getUndecoratedName() + "<" + getTypeParametersToString(this) + ">(" + + this.parameterTypesToString() + ")" } } @@ -404,7 +404,7 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric { override UnboundGenericType getUnboundGeneric() { constructed_generic(this, getTypeRef(result)) } - final override Type getChild(int n) { result = getTypeArgument(n) } + final override Type getChild(int n) { result = this.getTypeArgument(n) } final override string toStringWithTypes() { result = this.getUndecoratedName() + "<" + getTypeArgumentsToString(this) + ">" @@ -542,12 +542,12 @@ class UnboundGenericMethod extends Method, UnboundGeneric { override string toStringWithTypes() { result = - getUndecoratedName() + "<" + getTypeParametersToString(this) + ">" + "(" + - parameterTypesToString() + ")" + this.getUndecoratedName() + "<" + getTypeParametersToString(this) + ">" + "(" + + this.parameterTypesToString() + ")" } final override string getName() { - result = getUndecoratedName() + "<" + getTypeParameterCommas(this) + ">" + result = this.getUndecoratedName() + "<" + getTypeParameterCommas(this) + ">" } final override string getUndecoratedName() { methods(this, result, _, _, _) } @@ -580,8 +580,8 @@ class ConstructedMethod extends Method, ConstructedGeneric { override string toStringWithTypes() { result = - getUndecoratedName() + "<" + getTypeArgumentsToString(this) + ">" + "(" + - parameterTypesToString() + ")" + this.getUndecoratedName() + "<" + getTypeArgumentsToString(this) + ">" + "(" + + this.parameterTypesToString() + ")" } override UnboundGenericMethod getUnboundDeclaration() { @@ -589,12 +589,12 @@ class ConstructedMethod extends Method, ConstructedGeneric { } final override string getName() { - result = getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">" + result = this.getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">" } override predicate hasQualifiedName(string qualifier, string name) { - qualifier = getDeclaringType().getQualifiedName() and - name = getUndecoratedName() + "<" + getTypeArgumentsQualifiedNames(this) + ">" + qualifier = this.getDeclaringType().getQualifiedName() and + name = this.getUndecoratedName() + "<" + getTypeArgumentsQualifiedNames(this) + ">" } final override string getUndecoratedName() { methods(this, result, _, _, _) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Member.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Member.qll index 9f8408621fc..40b887f052a 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Member.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Member.qll @@ -155,7 +155,9 @@ class Modifiable extends Declaration, @modifiable { * Holds if this declaration is effectively `public`, meaning that it can be * referenced outside the declaring assembly. */ - predicate isEffectivelyPublic() { not isEffectivelyPrivate() and not isEffectivelyInternal() } + predicate isEffectivelyPublic() { + not this.isEffectivelyPrivate() and not this.isEffectivelyInternal() + } } /** A declaration that is a member of a type. */ @@ -193,12 +195,12 @@ class Virtualizable extends Member, @virtualizable { override predicate isPublic() { Member.super.isPublic() or - implementsExplicitInterface() + this.implementsExplicitInterface() } override predicate isPrivate() { super.isPrivate() and - not implementsExplicitInterface() + not this.implementsExplicitInterface() } /** @@ -211,17 +213,17 @@ class Virtualizable extends Member, @virtualizable { /** * Holds if this member implements an interface member explicitly. */ - predicate implementsExplicitInterface() { exists(getExplicitlyImplementedInterface()) } + predicate implementsExplicitInterface() { exists(this.getExplicitlyImplementedInterface()) } /** Holds if this member can be overridden or implemented. */ predicate isOverridableOrImplementable() { - not isSealed() and - not getDeclaringType().isSealed() and + not this.isSealed() and + not this.getDeclaringType().isSealed() and ( - isVirtual() or - isOverride() or - isAbstract() or - getDeclaringType() instanceof Interface + this.isVirtual() or + this.isOverride() or + this.isAbstract() or + this.getDeclaringType() instanceof Interface ) } @@ -243,10 +245,10 @@ class Virtualizable extends Member, @virtualizable { Virtualizable getAnOverrider() { this = result.getOverridee() } /** Holds if this member is overridden by some other member. */ - predicate isOverridden() { exists(getAnOverrider()) } + predicate isOverridden() { exists(this.getAnOverrider()) } /** Holds if this member overrides another member. */ - predicate overrides() { exists(getOverridee()) } + predicate overrides() { exists(this.getOverridee()) } /** * Gets the interface member that is immediately implemented by this member, if any. @@ -274,7 +276,7 @@ class Virtualizable extends Member, @virtualizable { Virtualizable getImplementee(ValueOrRefType t) { implements(this, result, t) } /** Gets the interface member that is immediately implemented by this member, if any. */ - Virtualizable getImplementee() { result = getImplementee(_) } + Virtualizable getImplementee() { result = this.getImplementee(_) } /** * Gets a member that immediately implements this interface member, if any. @@ -338,8 +340,8 @@ class Virtualizable extends Member, @virtualizable { | this = implementation or - getOverridee+() = implementation and - getDeclaringType().getABaseType+() = implementationType + this.getOverridee+() = implementation and + this.getDeclaringType().getABaseType+() = implementationType ) } @@ -355,10 +357,10 @@ class Virtualizable extends Member, @virtualizable { Virtualizable getAnUltimateImplementor() { this = result.getAnUltimateImplementee() } /** Holds if this interface member is implemented by some other member. */ - predicate isImplemented() { exists(getAnImplementor()) } + predicate isImplemented() { exists(this.getAnImplementor()) } /** Holds if this member implements (transitively) an interface member. */ - predicate implements() { exists(getAnUltimateImplementee()) } + predicate implements() { exists(this.getAnUltimateImplementee()) } /** * Holds if this member overrides or implements (reflexively, transitively) @@ -366,8 +368,8 @@ class Virtualizable extends Member, @virtualizable { */ predicate overridesOrImplementsOrEquals(Virtualizable that) { this = that or - getOverridee+() = that or - getAnUltimateImplementee() = that + this.getOverridee+() = that or + this.getAnUltimateImplementee() = that } } @@ -386,7 +388,7 @@ class Parameterizable extends DotNet::Parameterizable, Declaration, @parameteriz */ private string parameterTypeToString(int i) { exists(Parameter p, string prefix | - p = getParameter(i) and + p = this.getParameter(i) and result = prefix + p.getType().toStringWithTypes() | if p.isOut() @@ -407,6 +409,7 @@ class Parameterizable extends DotNet::Parameterizable, Declaration, @parameteriz */ language[monotonicAggregates] string parameterTypesToString() { - result = concat(int i | exists(getParameter(i)) | parameterTypeToString(i), ", " order by i) + result = + concat(int i | exists(this.getParameter(i)) | this.parameterTypeToString(i), ", " order by i) } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Modifier.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Modifier.qll index 542598d204e..39652070af3 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Modifier.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Modifier.qll @@ -19,10 +19,5 @@ class Modifier extends Element, @modifier { * An access modifier: `public`, `private`, `internal` or `protected`. */ class AccessModifier extends Modifier { - AccessModifier() { - hasName("public") or - hasName("private") or - hasName("internal") or - hasName("protected") - } + AccessModifier() { this.hasName(["public", "private", "internal", "protected"]) } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Preprocessor.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Preprocessor.qll index daf4978da53..3342dd5c59c 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Preprocessor.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Preprocessor.qll @@ -289,7 +289,7 @@ class IfDirective extends ConditionalDirective, @directive_if { } /** Gets a sibling `#elif` or `#else` preprocessor directive. */ - BranchDirective getASiblingDirective() { result = getSiblingDirective(_) } + BranchDirective getASiblingDirective() { result = this.getSiblingDirective(_) } override string toString() { result = "#if ..." } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/PrintAst.ql b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/PrintAst.ql deleted file mode 100644 index 3867fd2990f..00000000000 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/PrintAst.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Print AST - * @description Outputs a representation of the Abstract Syntax Tree. - * @id csharp/print-ast - * @kind graph - */ - -import csharp -import PrintAst - -/** - * Temporarily tweak this class or make a copy to control which functions are - * printed. - */ -class PrintAstConfigurationOverride extends PrintAstConfiguration { - /** - * TWEAK THIS PREDICATE AS NEEDED. - */ - override predicate shouldPrint(Element e, Location l) { super.shouldPrint(e, l) } -} diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/PrintAst.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/PrintAst.qll index a701c7bfbf3..a3d36fba69d 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/PrintAst.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/PrintAst.qll @@ -171,7 +171,7 @@ class PrintAstNode extends TPrintAstNode { /** * Gets a child of this node. */ - final PrintAstNode getAChild() { result = getChild(_) } + final PrintAstNode getAChild() { result = this.getChild(_) } /** * Gets the parent of this node, if any. @@ -189,7 +189,7 @@ class PrintAstNode extends TPrintAstNode { */ string getProperty(string key) { key = "semmle.label" and - result = toString() + result = this.toString() } /** @@ -198,7 +198,7 @@ class PrintAstNode extends TPrintAstNode { * this. */ string getChildEdgeLabel(int childIndex) { - exists(getChild(childIndex)) and + exists(this.getChild(childIndex)) and result = childIndex.toString() } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Property.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Property.qll index 5464142a085..a91ac6f13a4 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Property.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Property.qll @@ -53,10 +53,10 @@ class DeclarationWithAccessors extends AssignableMember, Virtualizable, Attribut class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelExprParent, @assignable_with_accessors { /** Gets the `get` accessor of this declaration, if any. */ - Getter getGetter() { result = getAnAccessor() } + Getter getGetter() { result = this.getAnAccessor() } /** Gets the `set` accessor of this declaration, if any. */ - Setter getSetter() { result = getAnAccessor() } + Setter getSetter() { result = this.getAnAccessor() } override DeclarationWithGetSetAccessors getOverridee() { result = DeclarationWithAccessors.super.getOverridee() @@ -182,10 +182,10 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper or // For library types, we don't know about assignments in constructors. We instead assume that // arguments passed to parameters of constructors with suitable names. - getDeclaringType().fromLibrary() and + this.getDeclaringType().fromLibrary() and exists(Parameter param, Constructor c, string propertyName | - propertyName = getName() and - c = getDeclaringType().getAConstructor() and + propertyName = this.getName() and + c = this.getDeclaringType().getAConstructor() and param = c.getAParameter() and // Find a constructor parameter with the same name, but with a lower case initial letter. param.hasName(propertyName.charAt(0).toLowerCase() + propertyName.suffix(1)) @@ -256,7 +256,7 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer override string getUndecoratedName() { indexers(this, result, _, _, _) } /** Gets the dimension of this indexer, that is, its number of parameters. */ - int getDimension() { result = getNumberOfParameters() } + int getDimension() { result = this.getNumberOfParameters() } override ValueOrRefType getDeclaringType() { indexers(this, _, result, _, _) } @@ -304,7 +304,9 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer override Location getALocation() { indexer_location(this, result) } - override string toStringWithTypes() { result = getName() + "[" + parameterTypesToString() + "]" } + override string toStringWithTypes() { + result = this.getName() + "[" + this.parameterTypesToString() + "]" + } override string getAPrimaryQlClass() { result = "Indexer" } } @@ -368,17 +370,17 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * ``` */ override Modifier getAModifier() { - result = getAnAccessModifier() + result = this.getAnAccessModifier() or - result = getDeclaration().getAModifier() and - not (result instanceof AccessModifier and exists(getAnAccessModifier())) + result = this.getDeclaration().getAModifier() and + not (result instanceof AccessModifier and exists(this.getAnAccessModifier())) } override Accessor getUnboundDeclaration() { accessors(this, _, _, _, result) } override Location getALocation() { accessor_location(this, result) } - override string toString() { result = getName() } + override string toString() { result = this.getName() } } /** @@ -395,11 +397,11 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * ``` */ class Getter extends Accessor, @getter { - override string getName() { result = "get" + "_" + getDeclaration().getName() } + override string getName() { result = "get" + "_" + this.getDeclaration().getName() } - override string getUndecoratedName() { result = "get" + "_" + getDeclaration().getName() } + override string getUndecoratedName() { result = "get" + "_" + this.getDeclaration().getName() } - override Type getReturnType() { result = getDeclaration().getType() } + override Type getReturnType() { result = this.getDeclaration().getType() } /** * Gets the field used in the trival implementation of this getter, if any. @@ -417,8 +419,8 @@ class Getter extends Accessor, @getter { */ Field trivialGetterField() { exists(ReturnStmt ret | - getStatementBody().getNumberOfStmts() = 1 and - getStatementBody().getAChild() = ret and + this.getStatementBody().getNumberOfStmts() = 1 and + this.getStatementBody().getAChild() = ret and ret.getExpr() = result.getAnAccess() ) } @@ -444,9 +446,9 @@ class Getter extends Accessor, @getter { * ``` */ class Setter extends Accessor, @setter { - override string getName() { result = "set" + "_" + getDeclaration().getName() } + override string getName() { result = "set" + "_" + this.getDeclaration().getName() } - override string getUndecoratedName() { result = "set" + "_" + getDeclaration().getName() } + override string getUndecoratedName() { result = "set" + "_" + this.getDeclaration().getName() } override Type getReturnType() { exists(this) and // needed to avoid compiler warning @@ -469,8 +471,8 @@ class Setter extends Accessor, @setter { */ Field trivialSetterField() { exists(AssignExpr assign | - getStatementBody().getNumberOfStmts() = 1 and - assign.getParent() = getStatementBody().getAChild() and + this.getStatementBody().getNumberOfStmts() = 1 and + assign.getParent() = this.getStatementBody().getAChild() and assign.getLValue() = result.getAnAccess() and assign.getRValue() = accessToValue() ) @@ -521,9 +523,9 @@ private ParameterAccess accessToValue() { */ class TrivialProperty extends Property { TrivialProperty() { - isAutoImplemented() + this.isAutoImplemented() or - getGetter().trivialGetterField() = getSetter().trivialSetterField() + this.getGetter().trivialGetterField() = this.getSetter().trivialSetterField() or exists(CIL::TrivialProperty prop | this.matchesHandle(prop)) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Stmt.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Stmt.qll index 2ccd57078db..be074c176ba 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Stmt.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Stmt.qll @@ -65,10 +65,10 @@ class BlockStmt extends Stmt, @block_stmt { int getNumberOfStmts() { result = count(this.getAStmt()) } /** Gets the first statement in this block, if any. */ - Stmt getFirstStmt() { result = getStmt(0) } + Stmt getFirstStmt() { result = this.getStmt(0) } /** Gets the last statement in this block, if any. */ - Stmt getLastStmt() { result = getStmt(getNumberOfStmts() - 1) } + Stmt getLastStmt() { result = this.getStmt(this.getNumberOfStmts() - 1) } /** Holds if this block is an empty block with no statements. */ predicate isEmpty() { not exists(this.getAStmt()) } @@ -79,8 +79,8 @@ class BlockStmt extends Stmt, @block_stmt { } override Stmt stripSingletonBlocks() { - if getNumberOfStmts() = 1 - then result = getAChildStmt().stripSingletonBlocks() + if this.getNumberOfStmts() = 1 + then result = this.getAChildStmt().stripSingletonBlocks() else result = this } @@ -420,7 +420,7 @@ class ForStmt extends LoopStmt, @for_stmt { * } * ``` */ - Expr getAnInitializer() { result = getInitializer(_) } + Expr getAnInitializer() { result = this.getInitializer(_) } /** * Gets the `n`th initializer expression of this `for` loop @@ -451,7 +451,7 @@ class ForStmt extends LoopStmt, @for_stmt { * } * ``` */ - Expr getAnUpdate() { result = getUpdate(_) } + Expr getAnUpdate() { result = this.getUpdate(_) } /** * Gets the `n`th update expression of this `for` loop (starting at index 0). @@ -519,7 +519,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * ``` */ LocalVariableDeclExpr getVariableDeclExpr(int i) { - result = getVariableDeclTuple().getArgument(i) + result = this.getVariableDeclTuple().getArgument(i) or i = 0 and result = this.getChild(0) } @@ -547,7 +547,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * } * ``` */ - LocalVariable getVariable(int i) { result = getVariableDeclExpr(i).getVariable() } + LocalVariable getVariable(int i) { result = this.getVariableDeclExpr(i).getVariable() } /** * Gets a local variable of this `foreach` loop. @@ -560,7 +560,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * } * ``` */ - LocalVariable getAVariable() { result = getVariable(_) } + LocalVariable getAVariable() { result = this.getVariable(_) } /** * Gets a local variable declaration of this `foreach` loop. @@ -573,7 +573,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * } * ``` */ - LocalVariableDeclExpr getAVariableDeclExpr() { result = getVariableDeclExpr(_) } + LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) } override Expr getCondition() { none() } @@ -690,8 +690,8 @@ class GotoLabelStmt extends GotoStmt, @goto_stmt { /** Gets the target statement that this `goto` statement jumps to. */ LabeledStmt getTarget() { - result.getEnclosingCallable() = getEnclosingCallable() and - result.getLabel() = getLabel() + result.getEnclosingCallable() = this.getEnclosingCallable() and + result.getLabel() = this.getLabel() } override string getAPrimaryQlClass() { result = "GotoLabelStmt" } @@ -717,7 +717,7 @@ class GotoCaseStmt extends GotoStmt, @goto_case_stmt { /** Gets the constant expression that this `goto case` statement jumps to. */ Expr getExpr() { result = this.getChild(0) } - override string getLabel() { result = getExpr().getValue() } + override string getLabel() { result = this.getExpr().getValue() } override string toString() { result = "goto case ...;" } @@ -764,14 +764,14 @@ class ThrowStmt extends JumpStmt, ThrowElement, @throw_stmt { override ExceptionClass getThrownExceptionType() { result = ThrowElement.super.getThrownExceptionType() or - result = getRethrowParent().(CatchClause).getCaughtExceptionType() + result = this.getRethrowParent().(CatchClause).getCaughtExceptionType() } private ControlFlowElement getRethrowParent() { - result = this and not exists(getExpr()) + result = this and not exists(this.getExpr()) or exists(ControlFlowElement mid | - mid = getRethrowParent() and + mid = this.getRethrowParent() and not mid instanceof CatchClause and result = mid.getParent() ) @@ -785,7 +785,7 @@ class ThrowStmt extends JumpStmt, ThrowElement, @throw_stmt { * and may be thrown as an exception. */ class ExceptionClass extends Class { - ExceptionClass() { getBaseClass*() instanceof SystemExceptionClass } + ExceptionClass() { this.getBaseClass*() instanceof SystemExceptionClass } } /** @@ -897,13 +897,15 @@ class TryStmt extends Stmt, @try_stmt { override string getAPrimaryQlClass() { result = "TryStmt" } /** Gets the `catch` clause that handles an exception of type `ex`, if any. */ - CatchClause getAnExceptionHandler(ExceptionClass ex) { result = clauseHandlesException(ex, 0) } + CatchClause getAnExceptionHandler(ExceptionClass ex) { + result = this.clauseHandlesException(ex, 0) + } /** * Holds if catch clause `cc` definitely handles exceptions of type `ex`. */ predicate definitelyHandles(ExceptionClass ex, CatchClause cc) { - cc = getACatchClause() and + cc = this.getACatchClause() and not exists(cc.getFilterClause()) and ( cc.getCaughtExceptionType() = ex.getBaseClass*() @@ -913,22 +915,22 @@ class TryStmt extends Stmt, @try_stmt { } private predicate maybeHandles(ExceptionClass ex, CatchClause cc) { - cc = getACatchClause() and + cc = this.getACatchClause() and cc.getCaughtExceptionType().getBaseClass*() = ex } private CatchClause clauseHandlesException(ExceptionClass ex, int n) { - exists(CatchClause clause | clause = getCatchClause(n) | - if definitelyHandles(ex, clause) + exists(CatchClause clause | clause = this.getCatchClause(n) | + if this.definitelyHandles(ex, clause) then result = clause else - if maybeHandles(ex, clause) + if this.maybeHandles(ex, clause) then result = clause or - result = clauseHandlesException(ex, n + 1) + result = this.clauseHandlesException(ex, n + 1) else // Does not handle - result = clauseHandlesException(ex, n + 1) + result = this.clauseHandlesException(ex, n + 1) ) } @@ -939,10 +941,10 @@ class TryStmt extends Stmt, @try_stmt { * `try` statement. */ ControlFlowElement getATriedElement() { - result = getBlock() + result = this.getBlock() or exists(ControlFlowElement mid | - mid = getATriedElement() and + mid = this.getATriedElement() and not mid instanceof TryStmt and result = getAChild(mid, mid.getEnclosingCallable()) ) @@ -996,10 +998,10 @@ class CatchClause extends Stmt, @catch { * } * ``` */ - Expr getFilterClause() { result = getChild(2) } + Expr getFilterClause() { result = this.getChild(2) } /** Holds if this `catch` clause has a filter. */ - predicate hasFilterClause() { exists(getFilterClause()) } + predicate hasFilterClause() { exists(this.getFilterClause()) } /** Holds if this is the last `catch` clause in the `try` statement that it belongs to. */ predicate isLast() { @@ -1120,7 +1122,7 @@ class LockStmt extends Stmt, @lock_stmt { override string toString() { result = "lock (...) {...}" } /** Gets the variable being locked, if any. */ - Variable getLockVariable() { result.getAnAccess() = getExpr() } + Variable getLockVariable() { result.getAnAccess() = this.getExpr() } /** Gets a statement in the scope of this `lock` statement. */ Stmt getALockedStmt() { @@ -1128,14 +1130,14 @@ class LockStmt extends Stmt, @lock_stmt { // delegates and lambdas result.getParent() = this or - exists(Stmt mid | mid = getALockedStmt() and result.getParent() = mid) + exists(Stmt mid | mid = this.getALockedStmt() and result.getParent() = mid) } /** Holds if this statement is of the form `lock(this) { ... }`. */ - predicate isLockThis() { getExpr() instanceof ThisAccess } + predicate isLockThis() { this.getExpr() instanceof ThisAccess } /** Gets the type `T` if this statement is of the form `lock(typeof(T)) { ... }`. */ - Type getLockTypeObject() { result = getExpr().(TypeofExpr).getTypeAccess().getTarget() } + Type getLockTypeObject() { result = this.getExpr().(TypeofExpr).getTypeAccess().getTarget() } override string getAPrimaryQlClass() { result = "LockStmt" } } @@ -1453,7 +1455,7 @@ class LocalFunctionStmt extends Stmt, @local_function_stmt { /** Gets the local function defined by this statement. */ LocalFunction getLocalFunction() { local_function_stmts(this, result) } - override string toString() { result = getLocalFunction().getName() + "(...)" } + override string toString() { result = this.getLocalFunction().getName() + "(...)" } override string getAPrimaryQlClass() { result = "LocalFunctionStmt" } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Type.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Type.qll index d7a15000bbf..109c1df00c7 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Type.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Type.qll @@ -37,7 +37,7 @@ class Type extends DotNet::Type, Member, TypeContainer, @type { predicate containsTypeParameters() { this instanceof TypeParameter or - not this instanceof UnboundGenericType and getAChild().containsTypeParameters() + not this instanceof UnboundGenericType and this.getAChild().containsTypeParameters() } /** Holds if this type is a reference type, or a type parameter that is a reference type. */ @@ -133,8 +133,8 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ /** Gets an immediate base type of this type, if any. */ override ValueOrRefType getABaseType() { - result = getBaseClass() or - result = getABaseInterface() + result = this.getBaseClass() or + result = this.getABaseInterface() } /** Gets an immediate subtype of this type, if any. */ @@ -200,9 +200,9 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ */ pragma[inline] predicate hasCallable(Callable c) { - hasMethod(c) + this.hasMethod(c) or - hasMember(c.(Accessor).getDeclaration()) + this.hasMember(c.(Accessor).getDeclaration()) } /** @@ -234,63 +234,63 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ or hasNonOverriddenMember(this.getBaseClass+(), m) or - hasOverriddenMember(m) + this.hasOverriddenMember(m) } cached private predicate hasOverriddenMember(Virtualizable v) { v.isOverridden() and - v = getAMember() + v = this.getAMember() or - getBaseClass().(ValueOrRefType).hasOverriddenMember(v) and + this.getBaseClass().(ValueOrRefType).hasOverriddenMember(v) and not v.isPrivate() and - not memberOverrides(v) + not this.memberOverrides(v) } // Predicate folding for proper join-order pragma[noinline] private predicate memberOverrides(Virtualizable v) { - getAMember().(Virtualizable).getOverridee() = v + this.getAMember().(Virtualizable).getOverridee() = v } /** Gets a field (or member constant) with the given name. */ - Field getField(string name) { result = getAMember() and result.hasName(name) } + Field getField(string name) { result = this.getAMember() and result.hasName(name) } /** Gets a field (or member constant) of this type, if any. */ Field getAField() { result = this.getField(_) } /** Gets a member constant of this type, if any. */ - MemberConstant getAConstant() { result = getAMember() } + MemberConstant getAConstant() { result = this.getAMember() } /** Gets a method of this type, if any. */ - Method getAMethod() { result = getAMember() } + Method getAMethod() { result = this.getAMember() } /** Gets a method of this type with the given name. */ - Method getAMethod(string name) { result = getAMember() and result.hasName(name) } + Method getAMethod(string name) { result = this.getAMember() and result.hasName(name) } /** Gets a property of this type, if any. */ - Property getAProperty() { result = getAMember() } + Property getAProperty() { result = this.getAMember() } /** Gets a named property of this type. */ - Property getProperty(string name) { result = getAMember() and result.hasName(name) } + Property getProperty(string name) { result = this.getAMember() and result.hasName(name) } /** Gets an indexer of this type, if any. */ - Indexer getAnIndexer() { result = getAMember() } + Indexer getAnIndexer() { result = this.getAMember() } /** Gets an event of this type, if any. */ - Event getAnEvent() { result = getAMember() } + Event getAnEvent() { result = this.getAMember() } /** Gets a user-defined operator of this type, if any. */ - Operator getAnOperator() { result = getAMember() } + Operator getAnOperator() { result = this.getAMember() } /** Gets a static or instance constructor of this type, if any. */ - Constructor getAConstructor() { result = getAMember() } + Constructor getAConstructor() { result = this.getAMember() } /** Gets the static constructor of this type, if any. */ - StaticConstructor getStaticConstructor() { result = getAMember() } + StaticConstructor getStaticConstructor() { result = this.getAMember() } /** Gets a nested type of this type, if any. */ - NestedType getANestedType() { result = getAMember() } + NestedType getANestedType() { result = this.getAMember() } /** Gets the number of types that directly depend on this type. */ int getAfferentCoupling() { afferentCoupling(this, result) } @@ -675,10 +675,10 @@ class Enum extends ValueType, @enum_type { */ class Struct extends ValueType, @struct_type { /** Holds if this `struct` has a `ref` modifier. */ - predicate isRef() { hasModifier("ref") } + predicate isRef() { this.hasModifier("ref") } /** Holds if this `struct` has a `readonly` modifier. */ - predicate isReadonly() { hasModifier("readonly") } + predicate isReadonly() { this.hasModifier("readonly") } override string getAPrimaryQlClass() { result = "Struct" } } @@ -695,7 +695,7 @@ class RefType extends ValueOrRefType, @ref_type { /** Gets a member that overrides a non-abstract member in a super type, if any. */ private Virtualizable getAnOverrider() { - getAMember() = result and + this.getAMember() = result and exists(Virtualizable v | result.getOverridee() = v and not v.isAbstract()) } @@ -897,14 +897,14 @@ class FunctionPointerType extends Type, Parameterizable, @function_pointer_type } /** Gets an unmanaged calling convention. */ - Type getAnUnmanagedCallingConvention() { result = getUnmanagedCallingConvention(_) } + Type getAnUnmanagedCallingConvention() { result = this.getUnmanagedCallingConvention(_) } /** Gets the annotated return type of this function pointer type. */ AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) } override string getAPrimaryQlClass() { result = "FunctionPointerType" } - override string getLabel() { result = getName() } + override string getLabel() { result = this.getName() } } /** @@ -922,13 +922,15 @@ class NullableType extends ValueType, DotNet::ConstructedGeneric, @nullable_type */ Type getUnderlyingType() { nullable_underlying_type(this, getTypeRef(result)) } - override string toStringWithTypes() { result = getUnderlyingType().toStringWithTypes() + "?" } + override string toStringWithTypes() { + result = this.getUnderlyingType().toStringWithTypes() + "?" + } - override Type getChild(int n) { result = getUnderlyingType() and n = 0 } + override Type getChild(int n) { result = this.getUnderlyingType() and n = 0 } - override Location getALocation() { result = getUnderlyingType().getALocation() } + override Location getALocation() { result = this.getUnderlyingType().getALocation() } - override Type getTypeArgument(int p) { p = 0 and result = getUnderlyingType() } + override Type getTypeArgument(int p) { p = 0 and result = this.getUnderlyingType() } override string getAPrimaryQlClass() { result = "NullableType" } @@ -966,8 +968,8 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type { /** Holds if this array type has the same shape (dimension and rank) as `that` array type. */ predicate hasSameShapeAs(ArrayType that) { - getDimension() = that.getDimension() and - getRank() = that.getRank() + this.getDimension() = that.getDimension() and + this.getRank() = that.getRank() } /** @@ -981,7 +983,7 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type { private string getDimensionString(Type elementType) { exists(Type et, string res | et = this.getElementType() and - res = getArraySuffix() and + res = this.getArraySuffix() and if et instanceof ArrayType then result = res + et.(ArrayType).getDimensionString(elementType) else ( @@ -996,7 +998,7 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type { ) } - override Type getChild(int n) { result = getElementType() and n = 0 } + override Type getChild(int n) { result = this.getElementType() and n = 0 } override Location getALocation() { type_location(this, result) @@ -1021,13 +1023,15 @@ class PointerType extends DotNet::PointerType, Type, @pointer_type { override string toStringWithTypes() { result = DotNet::PointerType.super.toStringWithTypes() } - override Type getChild(int n) { result = getReferentType() and n = 0 } + override Type getChild(int n) { result = this.getReferentType() and n = 0 } final override string getName() { types(this, _, result) } - final override string getUndecoratedName() { result = getReferentType().getUndecoratedName() } + final override string getUndecoratedName() { + result = this.getReferentType().getUndecoratedName() + } - override Location getALocation() { result = getReferentType().getALocation() } + override Location getALocation() { result = this.getReferentType().getALocation() } override string toString() { result = DotNet::PointerType.super.toString() } @@ -1082,10 +1086,10 @@ class TupleType extends ValueType, @tuple_type { * Gets the type of the `n`th element of this tuple, indexed from 0. * For example, the 0th (first) element type of `(int, string)` is `int`. */ - Type getElementType(int n) { result = getElement(n).getType() } + Type getElementType(int n) { result = this.getElement(n).getType() } /** Gets an element of this tuple. */ - Field getAnElement() { result = getElement(_) } + Field getAnElement() { result = this.getElement(_) } override Location getALocation() { type_location(this, result) } @@ -1093,23 +1097,27 @@ class TupleType extends ValueType, @tuple_type { * Gets the arity of this tuple. For example, the arity of * `(int, int, double)` is 3. */ - int getArity() { result = count(getAnElement()) } + int getArity() { result = count(this.getAnElement()) } language[monotonicAggregates] override string toStringWithTypes() { result = "(" + - concat(Type t, int i | t = getElement(i).getType() | t.toStringWithTypes(), ", " order by i) - + ")" + concat(Type t, int i | + t = this.getElement(i).getType() + | + t.toStringWithTypes(), ", " order by i + ) + ")" } language[monotonicAggregates] override string getName() { result = - "(" + concat(Type t, int i | t = getElement(i).getType() | t.getName(), "," order by i) + ")" + "(" + concat(Type t, int i | t = this.getElement(i).getType() | t.getName(), "," order by i) + + ")" } - override string getLabel() { result = getUnderlyingType().getLabel() } + override string getLabel() { result = this.getUnderlyingType().getLabel() } override Type getChild(int i) { result = this.getUnderlyingType().getChild(i) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Unification.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Unification.qll index 3a2c6745f45..d9f39cec603 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Unification.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Unification.qll @@ -297,7 +297,7 @@ module Gvn { or result = strictconcat(int i, int j | - toStringPart(i, j) + this.toStringPart(i, j) | this.toStringConstructedPart(i, j) order by i desc, j ) diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Variable.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Variable.qll index a13175dfeb0..6592320fdd7 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Variable.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/Variable.qll @@ -149,7 +149,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top predicate isIn() { params(this, _, _, _, 5, _, _) } /** Holds if this parameter is an output or reference parameter. */ - predicate isOutOrRef() { isOut() or isRef() } + predicate isOutOrRef() { this.isOut() or this.isRef() } /** * Holds if this parameter is a parameter array. For example, `args` @@ -210,7 +210,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top Expr getDefaultValue() { result = this.getUnboundDeclaration().getChildExpr(0) } /** Holds if this parameter has a default value. */ - predicate hasDefaultValue() { exists(getDefaultValue()) } + predicate hasDefaultValue() { exists(this.getDefaultValue()) } /** Gets the callable to which this parameter belongs, if any. */ override Callable getCallable() { result = this.getDeclaringElement() } @@ -238,7 +238,9 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * `y` is `5`, and the assigned arguments to `z` are `3` and `6`, respectively. */ pragma[nomagic] - Expr getAnAssignedArgument() { result = getCallable().getACall().getArgumentForParameter(this) } + Expr getAnAssignedArgument() { + result = this.getCallable().getACall().getArgumentForParameter(this) + } /** Holds if this parameter is potentially overwritten in the body of its callable. */ predicate isOverwritten() { @@ -323,7 +325,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { /** Gets the enclosing callable of this local variable. */ Callable getEnclosingCallable() { result = this.getVariableDeclExpr().getEnclosingCallable() } - override Callable getCallable() { result = getEnclosingCallable() } + override Callable getCallable() { result = this.getEnclosingCallable() } override predicate isRef() { localvars(this, 3, _, _, _, _) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/XML.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/XML.qll index 4c762f4bf65..76f3b3cb022 100755 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/XML.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/XML.qll @@ -108,7 +108,7 @@ class XMLParent extends @xmlparent { } /** Gets the text value contained in this XML parent. */ - string getTextValue() { result = allCharactersString() } + string getTextValue() { result = this.allCharactersString() } /** Gets a printable representation of this XML parent. */ string toString() { result = this.getName() } @@ -119,7 +119,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = getName() } + override string toString() { result = this.getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -129,14 +129,14 @@ class XMLFile extends XMLParent, File { * * Gets the path of this XML file. */ - deprecated string getPath() { result = getAbsolutePath() } + deprecated string getPath() { result = this.getAbsolutePath() } /** * DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead. * * Gets the path of the folder that contains this XML file. */ - deprecated string getFolder() { result = getParentContainer().getAbsolutePath() } + deprecated string getFolder() { result = this.getParentContainer().getAbsolutePath() } /** Gets the encoding of this XML file. */ string getEncoding() { xmlEncoding(this, result) } @@ -200,7 +200,7 @@ class XMLDTD extends XMLLocatable, @xmldtd { */ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { /** Holds if this XML element has the given `name`. */ - predicate hasName(string name) { name = getName() } + predicate hasName(string name) { name = this.getName() } /** Gets the name of this XML element. */ override string getName() { xmlElements(this, result, _, _, _) } @@ -239,7 +239,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = getName() } + override string toString() { result = this.getName() } } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/Assertions.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/Assertions.qll index d425ec118ed..4f364147395 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/Assertions.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/Assertions.qll @@ -42,7 +42,7 @@ abstract class AssertMethod extends Method { * * Gets the index of a parameter being asserted. */ - deprecated final int getAssertionIndex() { result = getAnAssertionIndex() } + deprecated final int getAssertionIndex() { result = this.getAnAssertionIndex() } /** Gets the parameter at position `i` being asserted. */ final Parameter getAssertedParameter(int i) { @@ -55,7 +55,7 @@ abstract class AssertMethod extends Method { * * Gets a parameter being asserted. */ - deprecated final Parameter getAssertedParameter() { result = getAssertedParameter(_) } + deprecated final Parameter getAssertedParameter() { result = this.getAssertedParameter(_) } /** Gets the failure type if the assertion fails for argument `i`, if any. */ abstract AssertionFailure getAssertionFailure(int i); diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll index cee7b647fe7..0121ef13f8c 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll @@ -3,23 +3,12 @@ import csharp private string modifyMethodName() { - result = "Add" or - result = "AddFirst" or - result = "AddLast" or - result = "Clear" or - result = "Enqueue" or - result = "ExceptWith" or - result = "Insert" or - result = "IntersectWith" or - result = "Push" or - result = "Remove" or - result = "RemoveAt" or - result = "RemoveFirst" or - result = "RemoveLast" or - result = "Set" or - result = "SetAll" or - result = "SymmetricExceptWith" or - result = "UnionWith" + result = + [ + "Add", "AddFirst", "AddLast", "Clear", "Enqueue", "ExceptWith", "Insert", "IntersectWith", + "Push", "Remove", "RemoveAt", "RemoveFirst", "RemoveLast", "Set", "SetAll", + "SymmetricExceptWith", "UnionWith" + ] } /** A method call that modifies a collection. */ @@ -39,45 +28,27 @@ class CollectionModificationAccess extends Access { } private string collectionTypeName() { - result = "ArrayList" or - result = "BitArray" or - result = "Hashtable" or - result = "ICollection" or - result = "IDictionary" or - result = "IList" or - result = "Queue" or - result = "ReadOnlyCollectionBase" or - result = "SortedList" or - result = "Stack" + result = + [ + "ArrayList", "BitArray", "Hashtable", "ICollection", "IDictionary", "IList", "Queue", + "ReadOnlyCollectionBase", "SortedList", "Stack" + ] } -private string collectionNamespaceName() { - result = "Mono.Collections" or - result = "System.Collections" -} +private string collectionNamespaceName() { result = ["Mono.Collections", "System.Collections"] } private string genericCollectionNamespaceName() { - result = "Mono.Collections.Generic" or - result = "System.Collections.Generic" + result = ["Mono.Collections.Generic", "System.Collections.Generic"] } private string genericCollectionTypeName() { - result = "Dictionary<,>" or - result = "HashSet<>" or - result = "ICollection<>" or - result = "IDictionary<,>" or - result = "IList<>" or - result = "ISet<>" or - result = "LinkedList<>" or - result = "List<>" or - result = "Queue<>" or - result = "SortedDictionary<,>" or - result = "SortedList<,>" or - result = "SortedSet<>" or - result = "Stack<>" or - result = "SynchronizedCollection<>" or - result = "SynchronizedKeyedCollection<>" or - result = "SynchronizedReadOnlyCollection<>" + result = + [ + "Dictionary<,>", "HashSet<>", "ICollection<>", "IDictionary<,>", "IList<>", "ISet<>", + "LinkedList<>", "List<>", "Queue<>", "SortedDictionary<,>", "SortedList<,>", "SortedSet<>", + "Stack<>", "SynchronizedCollection<>", "SynchronizedKeyedCollection<>", + "SynchronizedReadOnlyCollection<>" + ] } /** A collection type. */ @@ -105,36 +76,18 @@ class EmptyCollectionCreation extends ObjectCreation { } private string readonlyMethodName() { - result = "BinarySearch" or - result = "Clone" or - result = "Contains" or - result = "ContainsKey" or - result = "ContainsValue" or - result = "CopyTo" or - result = "Equals" or - result = "FixedArray" or - result = "FixedSize" or - result = "Get" or - result = "GetEnumerator" or - result = "GetHashCode" or - result = "GetRange" or - result = "IndexOf" or - result = "IsProperSubsetOf" or - result = "IsProperSupersetOf" or - result = "IsSubsetOf" or - result = "IsSupersetOf" or - result = "LastIndexOf" or - result = "MemberwiseClone" or - result = "Peek" or - result = "ToArray" or - result = "ToString" or - result = "TryGetValue" + result = + [ + "BinarySearch", "Clone", "Contains", "ContainsKey", "ContainsValue", "CopyTo", "Equals", + "FixedArray", "FixedSize", "Get", "GetEnumerator", "GetHashCode", "GetRange", "IndexOf", + "IsProperSubsetOf", "IsProperSupersetOf", "IsSubsetOf", "IsSupersetOf", "LastIndexOf", + "MemberwiseClone", "Peek", "ToArray", "ToString", "TryGetValue" + ] } private string noAddMethodName() { result = readonlyMethodName() or - result = "Dequeue" or - result = "Pop" + result = ["Dequeue", "Pop"] } /** Holds if `a` is an access that does not modify a collection. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/GeneratedCode.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/GeneratedCode.qll index 42e04ddcbb9..38d559d8ffd 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/GeneratedCode.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/commons/GeneratedCode.qll @@ -57,7 +57,7 @@ abstract class GeneratedCodeComment extends CommentLine { } */ class GenericGeneratedCodeComment extends GeneratedCodeComment { GenericGeneratedCodeComment() { - exists(string line, string entity, string was, string automatically | line = getText() | + exists(string line, string entity, string was, string automatically | line = this.getText() | entity = "file|class|interface|art[ei]fact|module|script" and was = "was|is|has been" and automatically = "automatically |mechanically |auto[- ]?" and @@ -70,7 +70,7 @@ class GenericGeneratedCodeComment extends GeneratedCodeComment { /** A comment warning against modifications. */ class DontModifyMarkerComment extends GeneratedCodeComment { DontModifyMarkerComment() { - exists(string line | line = getText() | + exists(string line | line = this.getText() | line.regexpMatch("(?i).*\\bGenerated by\\b.*\\bDo not edit\\b.*") or line.regexpMatch("(?i).*\\bAny modifications to this file will be lost\\b.*") ) diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll index b4448a71380..08e5925ad50 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll @@ -11,7 +11,7 @@ private import ControlFlow::SuccessorTypes */ class BasicBlock extends TBasicBlockStart { /** Gets an immediate successor of this basic block, if any. */ - BasicBlock getASuccessor() { result.getFirstNode() = getLastNode().getASuccessor() } + BasicBlock getASuccessor() { result.getFirstNode() = this.getLastNode().getASuccessor() } /** Gets an immediate successor of this basic block of a given type, if any. */ BasicBlock getASuccessorByType(ControlFlow::SuccessorType t) { @@ -42,7 +42,7 @@ class BasicBlock extends TBasicBlockStart { * The basic block on line 2 is an immediate `true` successor of the * basic block on line 1. */ - BasicBlock getATrueSuccessor() { result.getFirstNode() = getLastNode().getATrueSuccessor() } + BasicBlock getATrueSuccessor() { result.getFirstNode() = this.getLastNode().getATrueSuccessor() } /** * Gets an immediate `false` successor, if any. @@ -60,25 +60,27 @@ class BasicBlock extends TBasicBlockStart { * The basic block on line 2 is an immediate `false` successor of the * basic block on line 1. */ - BasicBlock getAFalseSuccessor() { result.getFirstNode() = getLastNode().getAFalseSuccessor() } + BasicBlock getAFalseSuccessor() { + result.getFirstNode() = this.getLastNode().getAFalseSuccessor() + } /** Gets the control flow node at a specific (zero-indexed) position in this basic block. */ - ControlFlow::Node getNode(int pos) { bbIndex(getFirstNode(), result, pos) } + ControlFlow::Node getNode(int pos) { bbIndex(this.getFirstNode(), result, pos) } /** Gets a control flow node in this basic block. */ - ControlFlow::Node getANode() { result = getNode(_) } + ControlFlow::Node getANode() { result = this.getNode(_) } /** Gets the first control flow node in this basic block. */ ControlFlow::Node getFirstNode() { this = TBasicBlockStart(result) } /** Gets the last control flow node in this basic block. */ - ControlFlow::Node getLastNode() { result = getNode(length() - 1) } + ControlFlow::Node getLastNode() { result = this.getNode(this.length() - 1) } /** Gets the callable that this basic block belongs to. */ final Callable getCallable() { result = this.getFirstNode().getEnclosingCallable() } /** Gets the length of this basic block. */ - int length() { result = strictcount(getANode()) } + int length() { result = strictcount(this.getANode()) } /** * Holds if this basic block immediately dominates basic block `bb`. @@ -151,7 +153,7 @@ class BasicBlock extends TBasicBlockStart { */ predicate dominates(BasicBlock bb) { bb = this or - strictlyDominates(bb) + this.strictlyDominates(bb) } /** @@ -177,14 +179,14 @@ class BasicBlock extends TBasicBlockStart { * does not dominate the basic block on line 6. */ predicate inDominanceFrontier(BasicBlock df) { - dominatesPredecessor(df) and - not strictlyDominates(df) + this.dominatesPredecessor(df) and + not this.strictlyDominates(df) } /** * Holds if this basic block dominates a predecessor of `df`. */ - private predicate dominatesPredecessor(BasicBlock df) { dominates(df.getAPredecessor()) } + private predicate dominatesPredecessor(BasicBlock df) { this.dominates(df.getAPredecessor()) } /** * Gets the basic block that immediately dominates this basic block, if any. @@ -263,7 +265,7 @@ class BasicBlock extends TBasicBlockStart { * post-dominates itself. */ predicate postDominates(BasicBlock bb) { - strictlyPostDominates(bb) or + this.strictlyPostDominates(bb) or this = bb } @@ -276,10 +278,10 @@ class BasicBlock extends TBasicBlockStart { predicate inLoop() { this.getASuccessor+() = this } /** Gets a textual representation of this basic block. */ - string toString() { result = getFirstNode().toString() } + string toString() { result = this.getFirstNode().toString() } /** Gets the location of this basic block. */ - Location getLocation() { result = getFirstNode().getLocation() } + Location getLocation() { result = this.getFirstNode().getLocation() } } /** @@ -420,7 +422,7 @@ private module JoinBlockPredecessors { /** A basic block with more than one predecessor. */ class JoinBlock extends BasicBlock { - JoinBlock() { getFirstNode().isJoin() } + JoinBlock() { this.getFirstNode().isJoin() } /** * Gets the `i`th predecessor of this join block, with respect to some diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowElement.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowElement.qll index 7601b83f6b8..9e7fd92d2a4 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowElement.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowElement.qll @@ -72,13 +72,14 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { ControlFlowElement getAReachableElement() { // Reachable in same basic block exists(BasicBlock bb, int i, int j | - bb.getNode(i) = getAControlFlowNode() and + bb.getNode(i) = this.getAControlFlowNode() and bb.getNode(j) = result.getAControlFlowNode() and i < j ) or // Reachable in different basic blocks - getAControlFlowNode().getBasicBlock().getASuccessor+().getANode() = result.getAControlFlowNode() + this.getAControlFlowNode().getBasicBlock().getASuccessor+().getANode() = + result.getAControlFlowNode() } pragma[noinline] diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 96b73d8978d..c94184b4f66 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -33,10 +33,10 @@ module ControlFlow { ControlFlowElement getElement() { none() } /** Gets the location of this control flow node. */ - Location getLocation() { result = getElement().getLocation() } + Location getLocation() { result = this.getElement().getLocation() } /** Holds if this control flow node has conditional successors. */ - predicate isCondition() { exists(getASuccessorByType(any(ConditionalSuccessor e))) } + predicate isCondition() { exists(this.getASuccessorByType(any(ConditionalSuccessor e))) } /** Gets the basic block that this control flow node belongs to. */ BasicBlock getBasicBlock() { result.getANode() = this } @@ -67,7 +67,7 @@ module ControlFlow { // potentially very large predicate, so must be inlined pragma[inline] predicate dominates(Node that) { - strictlyDominates(that) + this.strictlyDominates(that) or this = that } @@ -138,7 +138,7 @@ module ControlFlow { // potentially very large predicate, so must be inlined pragma[inline] predicate postDominates(Node that) { - strictlyPostDominates(that) + this.strictlyPostDominates(that) or this = that } @@ -186,13 +186,13 @@ module ControlFlow { Node getASuccessorByType(SuccessorType t) { result = getASuccessor(this, t) } /** Gets an immediate successor, if any. */ - Node getASuccessor() { result = getASuccessorByType(_) } + Node getASuccessor() { result = this.getASuccessorByType(_) } /** Gets an immediate predecessor node of a given flow type, if any. */ Node getAPredecessorByType(SuccessorType t) { result.getASuccessorByType(t) = this } /** Gets an immediate predecessor, if any. */ - Node getAPredecessor() { result = getAPredecessorByType(_) } + Node getAPredecessor() { result = this.getAPredecessorByType(_) } /** * Gets an immediate `true` successor, if any. @@ -211,7 +211,7 @@ module ControlFlow { * on line 1. */ Node getATrueSuccessor() { - result = getASuccessorByType(any(BooleanSuccessor t | t.getValue() = true)) + result = this.getASuccessorByType(any(BooleanSuccessor t | t.getValue() = true)) } /** @@ -231,7 +231,7 @@ module ControlFlow { * on line 1. */ Node getAFalseSuccessor() { - result = getASuccessorByType(any(BooleanSuccessor t | t.getValue() = false)) + result = this.getASuccessorByType(any(BooleanSuccessor t | t.getValue() = false)) } /** Holds if this node has more than one predecessor. */ @@ -285,7 +285,7 @@ module ControlFlow { override Callable getEnclosingCallable() { result = this.getCallable() } - override Location getLocation() { result = getCallable().getLocation() } + override Location getLocation() { result = this.getCallable().getLocation() } override string toString() { exists(string s | @@ -293,7 +293,7 @@ module ControlFlow { or normal = false and s = "abnormal" | - result = "exit " + getCallable() + " (" + s + ")" + result = "exit " + this.getCallable() + " (" + s + ")" ) } } @@ -307,9 +307,9 @@ module ControlFlow { override Callable getEnclosingCallable() { result = this.getCallable() } - override Location getLocation() { result = getCallable().getLocation() } + override Location getLocation() { result = this.getCallable().getLocation() } - override string toString() { result = "exit " + getCallable().toString() } + override string toString() { result = "exit " + this.getCallable().toString() } } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll index 5a402717401..5e3f00c3c5e 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll @@ -1740,7 +1740,7 @@ module Internal { e = this.getAChildExpr() or exists(Expr mid | - descendant(mid) and + this.descendant(mid) and not interestingDescendantCandidate(mid) and e = mid.getAChildExpr() ) @@ -1748,7 +1748,7 @@ module Internal { /** Holds if `e` is an interesting descendant of this descendant. */ predicate interestingDescendant(Expr e) { - descendant(e) and + this.descendant(e) and interestingDescendantCandidate(e) } } @@ -1797,7 +1797,7 @@ module Internal { override predicate candidate(ControlFlowElement x, ControlFlowElement y) { exists(BasicBlock bb, Declaration d | - candidateAux(x, d, bb) and + this.candidateAux(x, d, bb) and y = any(AccessOrCallExpr e | e.getAControlFlowNode().getBasicBlock() = bb and diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll index 8a02fb95dee..473fa8f83c4 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll @@ -495,7 +495,7 @@ module Expressions { // Flow from last element of left operand to first element of right operand last(this.getLeftOperand(), pred, c) and c.(NullnessCompletion).isNull() and - first(getRightOperand(), succ) + first(this.getRightOperand(), succ) or // Post-order: flow from last element of left operand to element itself last(this.getLeftOperand(), pred, c) and @@ -504,7 +504,7 @@ module Expressions { not c.(NullnessCompletion).isNull() or // Post-order: flow from last element of right operand to element itself - last(getRightOperand(), pred, c) and + last(this.getRightOperand(), pred, c) and c instanceof NormalCompletion and succ = this } @@ -575,7 +575,7 @@ module Expressions { PostOrderTree.super.last(last, c) or // Qualifier exits with a `null` completion - lastQualifier(last, c) and + this.lastQualifier(last, c) and c.(NullnessCompletion).isNull() } @@ -1483,7 +1483,7 @@ module Statements { ) or // Flow into `finally` block - pred = getAFinallyPredecessor(c, true) and + pred = this.getAFinallyPredecessor(c, true) and first(this.getFinally(), succ) } } @@ -1540,7 +1540,7 @@ module Statements { c = any(NestedCompletion nc | nc.getNestLevel() = 0 and - this.throwMayBeUncaught(nc.getOuterCompletion().(ThrowCompletion)) and + this.throwMayBeUncaught(nc.getOuterCompletion()) and ( // Incompatible exception type: clause itself last = this and diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll index 050a9384729..ee901b9192e 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll @@ -924,7 +924,8 @@ module Consistency { succSplits(pred, predSplits, succ, succSplits, c) and split.hasEntry(pred, succ, c) and not split.getKind() = predSplits.getASplit().getKind() and - not split = succSplits.getASplit() + not split = succSplits.getASplit() and + split.getKind().isEnabled(succ) } query predicate breakInvariant5( diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll index 31155dea0ae..de44808b18e 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll @@ -69,9 +69,9 @@ class PreBasicBlock extends ControlFlowElement { ControlFlowElement getFirstElement() { result = this } - ControlFlowElement getLastElement() { result = this.getElement(length() - 1) } + ControlFlowElement getLastElement() { result = this.getElement(this.length() - 1) } - int length() { result = strictcount(getAnElement()) } + int length() { result = strictcount(this.getAnElement()) } predicate immediatelyDominates(PreBasicBlock bb) { bbIDominates(this, bb) } @@ -117,7 +117,7 @@ class ConditionBlock extends PreBasicBlock { pragma[nomagic] predicate controls(PreBasicBlock controlled, SuccessorTypes::ConditionalSuccessor s) { - exists(PreBasicBlock succ, ConditionalCompletion c | immediatelyControls(succ, c) | + exists(PreBasicBlock succ, ConditionalCompletion c | this.immediatelyControls(succ, c) | succ.dominates(controlled) and s = c.getAMatchingSuccessorType() ) diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll index 4d1d39de988..83ea302e691 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll @@ -628,7 +628,7 @@ module FinallySplitting { */ private predicate exit(ControlFlowElement pred, Completion c, boolean inherited) { exists(TryStmt try, FinallySplitType type | - exit0(pred, try, this.getNestLevel(), c) and + this.exit0(pred, try, this.getNestLevel(), c) and type = this.getType() | if last(try.getFinally(), pred, c) @@ -690,18 +690,18 @@ module FinallySplitting { override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) { succ(pred, succ, c) and ( - exit(pred, c, _) + this.exit(pred, c, _) or - exit(pred, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion(), _) + this.exit(pred, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion(), _) ) } override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) { scopeLast(scope, last, c) and ( - exit(last, c, _) + this.exit(last, c, _) or - exit(last, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion(), _) + this.exit(last, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion(), _) ) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/SuccessorType.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/SuccessorType.qll index 648c2cd847c..76da2fb62ef 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/SuccessorType.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/SuccessorType.qll @@ -77,7 +77,7 @@ module SuccessorTypes { class BooleanSuccessor extends ConditionalSuccessor, TBooleanSuccessor { override boolean getValue() { this = TBooleanSuccessor(result) } - override string toString() { result = getValue().toString() } + override string toString() { result = this.getValue().toString() } } /** @@ -310,7 +310,7 @@ module SuccessorTypes { /** Gets the type of exception. */ ExceptionClass getExceptionClass() { this = TExceptionSuccessor(result) } - override string toString() { result = "exception(" + getExceptionClass().getName() + ")" } + override string toString() { result = "exception(" + this.getExceptionClass().getName() + ")" } } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll index 884f4406d01..eae5d23f544 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll @@ -141,24 +141,23 @@ private module Liveness { private import Liveness -/** Holds if `bb1` strictly dominates `bb2`. */ -private predicate strictlyDominates(BasicBlock bb1, BasicBlock bb2) { - bb1 = getImmediateBasicBlockDominator+(bb2) -} - -/** Holds if `bb1` dominates a predecessor of `bb2`. */ -private predicate dominatesPredecessor(BasicBlock bb1, BasicBlock bb2) { - exists(BasicBlock pred | pred = getABasicBlockPredecessor(bb2) | - bb1 = pred - or - strictlyDominates(bb1, pred) - ) -} - -/** Holds if `df` is in the dominance frontier of `bb`. */ +/** + * Holds if `df` is in the dominance frontier of `bb`. + * + * This is equivalent to: + * + * ```ql + * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and + * not bb = getImmediateBasicBlockDominator+(df) + * ``` + */ private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - dominatesPredecessor(bb, df) and - not strictlyDominates(bb, df) + bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) + or + exists(BasicBlock prev | inDominanceFrontier(prev, df) | + bb = getImmediateBasicBlockDominator(prev) and + not bb = getImmediateBasicBlockDominator(df) + ) } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index b689602d7bf..8b0bc25f261 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -427,7 +427,7 @@ private Element interpretElement0( result = t or subtypes = true and - result = t.(UnboundValueOrRefType).getASubTypeUnbound+() + result = t.getASubTypeUnbound+() ) and result = t and name = "" and diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/FlowSummary.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/FlowSummary.qll index a20c3876050..3e5c8e51ba5 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/FlowSummary.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/FlowSummary.qll @@ -78,4 +78,21 @@ module SummaryComponentStack { class SummarizedCallable = Impl::Public::SummarizedCallable; +private class SummarizedCallableDefaultClearsContent extends Impl::Public::SummarizedCallable { + SummarizedCallableDefaultClearsContent() { + this instanceof Impl::Public::SummarizedCallable or none() + } + + // By default, we assume that all stores into arguments are definite + override predicate clearsContent(int i, DataFlow::Content content) { + exists(SummaryComponentStack output | + this.propagatesFlow(_, output, _) and + output.drop(_) = + SummaryComponentStack::push(SummaryComponent::content(content), + SummaryComponentStack::argument(i)) and + not content instanceof DataFlow::ElementContent + ) + } +} + class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack; diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index f36783f56c6..f405484a55d 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -505,20 +505,20 @@ class SystemBooleanFlow extends LibraryTypeDataFlow, SystemBooleanStruct { CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - methodFlow(source, sink, c) and + this.methodFlow(source, sink, c) and preservesValue = false } private predicate methodFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m ) { - m = getParseMethod() and + m = this.getParseMethod() and ( source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() ) or - m = getTryParseMethod() and + m = this.getTryParseMethod() and ( source = TCallableFlowSourceArg(0) and ( @@ -537,12 +537,12 @@ class SystemUriFlow extends LibraryTypeDataFlow, SystemUriClass { boolean preservesValue ) { ( - constructorFlow(source, sink, c) + this.constructorFlow(source, sink, c) or - methodFlow(source, sink, c) + this.methodFlow(source, sink, c) or exists(Property p | - propertyFlow(p) and + this.propertyFlow(p) and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and c = p.getGetter() @@ -552,7 +552,7 @@ class SystemUriFlow extends LibraryTypeDataFlow, SystemUriClass { } private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { - c = getAMember() and + c = this.getAMember() and c.getParameter(0).getType() instanceof StringType and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() @@ -567,11 +567,11 @@ class SystemUriFlow extends LibraryTypeDataFlow, SystemUriClass { } private predicate propertyFlow(Property p) { - p = getPathAndQueryProperty() + p = this.getPathAndQueryProperty() or - p = getQueryProperty() + p = this.getQueryProperty() or - p = getOriginalStringProperty() + p = this.getOriginalStringProperty() } } @@ -582,15 +582,15 @@ class SystemIOStringReaderFlow extends LibraryTypeDataFlow, SystemIOStringReader boolean preservesValue ) { ( - constructorFlow(source, sink, c) + this.constructorFlow(source, sink, c) or - methodFlow(source, sink, c) + this.methodFlow(source, sink, c) ) and preservesValue = false } private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { - c = getAMember() and + c = this.getAMember() and c.getParameter(0).getType() instanceof StringType and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() @@ -599,7 +599,7 @@ class SystemIOStringReaderFlow extends LibraryTypeDataFlow, SystemIOStringReader private predicate methodFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m ) { - m.getDeclaringType() = getABaseType*() and + m.getDeclaringType() = this.getABaseType*() and m.getName().matches("Read%") and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() @@ -612,17 +612,17 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, SourceDeclarationCallable c, boolean preservesValue ) { - constructorFlow(source, sourceAp, sink, sinkAp, c) and + this.constructorFlow(source, sourceAp, sink, sinkAp, c) and preservesValue = false or - methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) + this.methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) } private predicate constructorFlow( CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, Constructor c ) { - c = getAMember() and + c = this.getAMember() and c.getParameter(0).getType().(ArrayType).getElementType() instanceof CharType and source = TCallableFlowSourceArg(0) and sourceAp = AccessPath::element() and @@ -641,14 +641,14 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { sinkAp = AccessPath::empty() and preservesValue = true or - m = getSplitMethod() and + m = this.getSplitMethod() and source = TCallableFlowSourceQualifier() and sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::element() and preservesValue = false or - m = getReplaceMethod() and + m = this.getReplaceMethod() and sourceAp = AccessPath::empty() and sinkAp = AccessPath::empty() and ( @@ -661,21 +661,21 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { preservesValue = false ) or - m = getSubstringMethod() and + m = this.getSubstringMethod() and source = TCallableFlowSourceQualifier() and sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() and preservesValue = false or - m = getCloneMethod() and + m = this.getCloneMethod() and source = TCallableFlowSourceQualifier() and sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() and preservesValue = true or - m = getInsertMethod() and + m = this.getInsertMethod() and sourceAp = AccessPath::empty() and sinkAp = AccessPath::empty() and ( @@ -688,21 +688,21 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { preservesValue = false ) or - m = getNormalizeMethod() and + m = this.getNormalizeMethod() and source = TCallableFlowSourceQualifier() and sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() and preservesValue = false or - m = getRemoveMethod() and + m = this.getRemoveMethod() and source = TCallableFlowSourceQualifier() and sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() and preservesValue = false or - m = getAMethod() and + m = this.getAMethod() and m.getName().regexpMatch("((ToLower|ToUpper)(Invariant)?)|(Trim(Start|End)?)|(Pad(Left|Right))") and source = TCallableFlowSourceQualifier() and sourceAp = AccessPath::empty() and @@ -710,7 +710,7 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { sinkAp = AccessPath::empty() and preservesValue = false or - m = getConcatMethod() and + m = this.getConcatMethod() and exists(int i | source = getFlowSourceArg(m, i, sourceAp) and sink = TCallableFlowSinkReturn() and @@ -718,20 +718,20 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { preservesValue = false ) or - m = getCopyMethod() and + m = this.getCopyMethod() and source = TCallableFlowSourceArg(0) and sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() and preservesValue = true or - m = getJoinMethod() and + m = this.getJoinMethod() and source = getFlowSourceArg(m, [0, 1], sourceAp) and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() and preservesValue = false or - m = getFormatMethod() and + m = this.getFormatMethod() and exists(int i | (m.getParameter(0).getType() instanceof SystemIFormatProviderInterface implies i != 0) and source = getFlowSourceArg(m, i, sourceAp) and @@ -749,10 +749,10 @@ class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringB SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sourceAp, sink, sinkAp, c) and + this.constructorFlow(source, sourceAp, sink, sinkAp, c) and preservesValue = true or - methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) + this.methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) ) } @@ -760,7 +760,7 @@ class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringB CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, Constructor c ) { - c = getAMember() and + c = this.getAMember() and c.getParameter(0).getType() instanceof StringType and source = TCallableFlowSourceArg(0) and sourceAp = AccessPath::empty() and @@ -894,7 +894,7 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType { ) { preservesValue = true and ( - methodFlowLINQExtensions(source, sourceAp, sink, sinkAp, c) + this.methodFlowLINQExtensions(source, sourceAp, sink, sinkAp, c) or c = this.getFind() and sourceAp = AccessPath::element() and @@ -1674,14 +1674,14 @@ class SystemConvertFlow extends LibraryTypeDataFlow, SystemConvertClass { CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - methodFlow(source, sink, c) and + this.methodFlow(source, sink, c) and preservesValue = false } private predicate methodFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m ) { - m = getAMethod() and + m = this.getAMethod() and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() } @@ -1694,7 +1694,7 @@ class SystemWebHttpCookieFlow extends LibraryTypeDataFlow, SystemWebHttpCookie { boolean preservesValue ) { exists(Property p | - propertyFlow(p) and + this.propertyFlow(p) and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and c = p.getGetter() @@ -1703,8 +1703,8 @@ class SystemWebHttpCookieFlow extends LibraryTypeDataFlow, SystemWebHttpCookie { } private predicate propertyFlow(Property p) { - p = getValueProperty() or - p = getValuesProperty() + p = this.getValueProperty() or + p = this.getValuesProperty() } } @@ -1715,7 +1715,7 @@ class SystemNetCookieFlow extends LibraryTypeDataFlow, SystemNetCookieClass { boolean preservesValue ) { exists(Property p | - propertyFlow(p) and + this.propertyFlow(p) and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and c = p.getGetter() @@ -1733,7 +1733,7 @@ class SystemNetIPHostEntryFlow extends LibraryTypeDataFlow, SystemNetIPHostEntry boolean preservesValue ) { exists(Property p | - propertyFlow(p) and + this.propertyFlow(p) and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and c = p.getGetter() @@ -1742,8 +1742,8 @@ class SystemNetIPHostEntryFlow extends LibraryTypeDataFlow, SystemNetIPHostEntry } private predicate propertyFlow(Property p) { - p = getHostNameProperty() or - p = getAliasesProperty() + p = this.getHostNameProperty() or + p = this.getAliasesProperty() } } @@ -1755,7 +1755,7 @@ class SystemWebUIWebControlsTextBoxFlow extends LibraryTypeDataFlow, boolean preservesValue ) { exists(Property p | - propertyFlow(p) and + this.propertyFlow(p) and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and c = p.getGetter() @@ -1763,7 +1763,7 @@ class SystemWebUIWebControlsTextBoxFlow extends LibraryTypeDataFlow, preservesValue = false } - private predicate propertyFlow(Property p) { p = getTextProperty() } + private predicate propertyFlow(Property p) { p = this.getTextProperty() } } /** Data flow for `System.Collections.Generic.KeyValuePair`. */ @@ -1864,11 +1864,11 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sink, c) and + this.constructorFlow(source, sink, c) and sourceAp = AccessPath::empty() and sinkAp = AccessPath::empty() or - methodFlow(source, sourceAp, sink, sinkAp, c) + this.methodFlow(source, sourceAp, sink, sinkAp, c) ) and preservesValue = true } @@ -1954,9 +1954,9 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreading SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sourceAp, sink, sinkAp, c) + this.constructorFlow(source, sourceAp, sink, sinkAp, c) or - methodFlow(source, sourceAp, sink, sinkAp, c) + this.methodFlow(source, sourceAp, sink, sinkAp, c) ) and preservesValue = true or @@ -2101,14 +2101,14 @@ private class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTFlow extends class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow { SystemThreadingTasksFactoryFlow() { this instanceof SystemThreadingTasksClass and - getName().regexpMatch("TaskFactory(<>)?") + this.getName().regexpMatch("TaskFactory(<>)?") } override predicate callableFlow( CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, SourceDeclarationCallable c, boolean preservesValue ) { - methodFlow(source, sourceAp, sink, sinkAp, c) and + this.methodFlow(source, sourceAp, sink, sinkAp, c) and preservesValue = true } @@ -2236,12 +2236,12 @@ library class SystemTextEncodingFlow extends LibraryTypeDataFlow, SystemTextEnco preservesValue = false and c = this.getAMethod() and exists(Method m | m.getAnOverrider*().getUnboundDeclaration() = c | - m = getGetBytesMethod() and + m = this.getGetBytesMethod() and source = getFlowSourceArg(m, 0, sourceAp) and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() or - m = [getGetStringMethod(), getGetCharsMethod()] and + m = [this.getGetStringMethod(), this.getGetCharsMethod()] and source = TCallableFlowSourceArg(0) and sourceAp = AccessPath::element() and sink = TCallableFlowSinkReturn() and @@ -2257,9 +2257,9 @@ library class SystemIOMemoryStreamFlow extends LibraryTypeDataFlow, SystemIOMemo boolean preservesValue ) { ( - constructorFlow(source, sink, c) + this.constructorFlow(source, sink, c) or - c = getToArrayMethod().getAnOverrider*() and + c = this.getToArrayMethod().getAnOverrider*() and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() ) and @@ -2267,7 +2267,7 @@ library class SystemIOMemoryStreamFlow extends LibraryTypeDataFlow, SystemIOMemo } private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { - c = getAMember() and + c = this.getAMember() and c.getParameter(0).getType().(ArrayType).getElementType() instanceof ByteType and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() @@ -2281,17 +2281,17 @@ class SystemIOStreamFlow extends LibraryTypeDataFlow, SystemIOStreamClass { boolean preservesValue ) { ( - c = getAReadMethod().getAnOverrider*() and + c = this.getAReadMethod().getAnOverrider*() and c.getParameter(0).getType().(ArrayType).getElementType() instanceof ByteType and sink = TCallableFlowSinkArg(0) and source = TCallableFlowSourceQualifier() or - c = getAWriteMethod().getAnOverrider*() and + c = this.getAWriteMethod().getAnOverrider*() and c.getParameter(0).getType().(ArrayType).getElementType() instanceof ByteType and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkQualifier() or - c = any(Method m | m = getAMethod() and m.getName().matches("CopyTo%")).getAnOverrider*() and + c = any(Method m | m = this.getAMethod() and m.getName().matches("CopyTo%")).getAnOverrider*() and c.getParameter(0).getType() instanceof SystemIOStreamClass and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkArg(0) @@ -2307,12 +2307,12 @@ class SystemIOCompressionDeflateStreamFlow extends LibraryTypeDataFlow, CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - constructorFlow(source, sink, c) and + this.constructorFlow(source, sink, c) and preservesValue = false } private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { - c = getAMember() and + c = this.getAMember() and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() } @@ -2324,7 +2324,7 @@ class SystemXmlXmlReaderFlow extends LibraryTypeDataFlow, SystemXmlXmlReaderClas CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - c = getCreateMethod() and + c = this.getCreateMethod() and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() and preservesValue = false @@ -2337,7 +2337,7 @@ class SystemXmlXmlDocumentFlow extends LibraryTypeDataFlow, SystemXmlXmlDocument CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - c = getLoadMethod() and + c = this.getLoadMethod() and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkQualifier() and preservesValue = false @@ -2352,13 +2352,13 @@ class SystemXmlXmlNodeFlow extends LibraryTypeDataFlow, SystemXmlXmlNodeClass { ) { ( exists(Property p | - p = getAProperty() and + p = this.getAProperty() and c = p.getGetter() and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() ) or - c = getASelectNodeMethod() and + c = this.getASelectNodeMethod() and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() ) and @@ -2372,7 +2372,7 @@ class SystemXmlXmlNamedNodeMapFlow extends LibraryTypeDataFlow, SystemXmlXmlName CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - c = getGetNamedItemMethod() and + c = this.getGetNamedItemMethod() and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and preservesValue = true @@ -2385,14 +2385,14 @@ class SystemIOPathFlow extends LibraryTypeDataFlow, SystemIOPathClass { CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, SourceDeclarationCallable c, boolean preservesValue ) { - c = getAMethod("Combine") and + c = this.getAMethod("Combine") and source = getFlowSourceArg(c, _, sourceAp) and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() and preservesValue = false or exists(Parameter p | - c = getAMethod() and + c = this.getAMethod() and c.getName().matches("Get%") and p = c.getAParameter() and p.hasName("path") and @@ -2411,10 +2411,10 @@ class SystemWebHttpUtilityFlow extends LibraryTypeDataFlow, SystemWebHttpUtility boolean preservesValue ) { ( - c = getAnHtmlAttributeEncodeMethod() or - c = getAnHtmlEncodeMethod() or - c = getAJavaScriptStringEncodeMethod() or - c = getAnUrlEncodeMethod() + c = this.getAnHtmlAttributeEncodeMethod() or + c = this.getAnHtmlEncodeMethod() or + c = this.getAJavaScriptStringEncodeMethod() or + c = this.getAnUrlEncodeMethod() ) and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() and @@ -2429,8 +2429,8 @@ class SystemWebHttpServerUtilityFlow extends LibraryTypeDataFlow, SystemWebHttpS boolean preservesValue ) { ( - c = getAnHtmlEncodeMethod() or - c = getAnUrlEncodeMethod() + c = this.getAnHtmlEncodeMethod() or + c = this.getAnUrlEncodeMethod() ) and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() and @@ -2445,8 +2445,8 @@ class SystemNetWebUtilityFlow extends LibraryTypeDataFlow, SystemNetWebUtility { boolean preservesValue ) { ( - c = getAnHtmlEncodeMethod() or - c = getAnUrlEncodeMethod() + c = this.getAnHtmlEncodeMethod() or + c = this.getAnUrlEncodeMethod() ) and source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() and diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll index 44307d68e1f..4f70b53275d 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll @@ -76,9 +76,9 @@ module Ssa { override Callable getEnclosingCallable() { this = SsaImpl::TLocalVar(result, _) } - override string toString() { result = getAssignable().getName() } + override string toString() { result = this.getAssignable().getName() } - override Location getLocation() { result = getAssignable().getLocation() } + override Location getLocation() { result = this.getAssignable().getLocation() } } /** A fully qualified field or property. */ @@ -105,7 +105,7 @@ module Ssa { ) } - override Location getLocation() { result = getFirstAccess().getLocation() } + override Location getLocation() { result = this.getFirstAccess().getLocation() } } /** A plain field or property. */ @@ -115,8 +115,8 @@ module Ssa { override string toString() { exists(Assignable f, string prefix | - f = getAssignable() and - result = prefix + "." + getAssignable() + f = this.getAssignable() and + result = prefix + "." + this.getAssignable() | if f.(Modifiable).isStatic() then prefix = f.getDeclaringType().getQualifiedName() @@ -134,7 +134,7 @@ module Ssa { override SourceVariable getQualifier() { this = SsaImpl::TQualifiedFieldOrProp(_, result, _) } - override string toString() { result = getQualifier() + "." + getAssignable() } + override string toString() { result = this.getQualifier() + "." + this.getAssignable() } } } @@ -611,20 +611,20 @@ module Ssa { * and which targets the same assignable as this SSA definition. */ final AssignableDefinition getAPossibleDefinition() { - exists(Callable setter | SsaImpl::updatesNamedFieldOrProp(_, _, getCall(), _, setter) | + exists(Callable setter | SsaImpl::updatesNamedFieldOrProp(_, _, this.getCall(), _, setter) | result.getEnclosingCallable() = setter and result.getTarget() = this.getSourceVariable().getAssignable() ) or - SsaImpl::updatesCapturedVariable(_, _, getCall(), _, result, _) and + SsaImpl::updatesCapturedVariable(_, _, this.getCall(), _, result, _) and result.getTarget() = this.getSourceVariable().getAssignable() } override string toString() { - result = getToStringPrefix(this) + "SSA call def(" + getSourceVariable() + ")" + result = getToStringPrefix(this) + "SSA call def(" + this.getSourceVariable() + ")" } - override Location getLocation() { result = getCall().getLocation() } + override Location getLocation() { result = this.getCall().getLocation() } } /** @@ -649,10 +649,10 @@ module Ssa { final Definition getQualifierDefinition() { result = q } override string toString() { - result = getToStringPrefix(this) + "SSA qualifier def(" + getSourceVariable() + ")" + result = getToStringPrefix(this) + "SSA qualifier def(" + this.getSourceVariable() + ")" } - override Location getLocation() { result = getQualifierDefinition().getLocation() } + override Location getLocation() { result = this.getQualifierDefinition().getLocation() } } /** @@ -699,7 +699,7 @@ module Ssa { } override string toString() { - result = getToStringPrefix(this) + "SSA phi(" + getSourceVariable() + ")" + result = getToStringPrefix(this) + "SSA phi(" + this.getSourceVariable() + ")" } /* diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index f43a550af57..c28ceabb438 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -2,6 +2,42 @@ private import DataFlowImplSpecific::Private private import DataFlowImplSpecific::Public import Cached +module DataFlowImplCommonPublic { + private newtype TFlowFeature = + TFeatureHasSourceCallContext() or + TFeatureHasSinkCallContext() or + TFeatureEqualSourceSinkCallContext() + + /** A flow configuration feature for use in `Configuration::getAFeature()`. */ + class FlowFeature extends TFlowFeature { + string toString() { none() } + } + + /** + * A flow configuration feature that implies that sources have some existing + * call context. + */ + class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext { + override string toString() { result = "FeatureHasSourceCallContext" } + } + + /** + * A flow configuration feature that implies that sinks have some existing + * call context. + */ + class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext { + override string toString() { result = "FeatureHasSinkCallContext" } + } + + /** + * A flow configuration feature that implies that source-sink pairs have some + * shared existing call context. + */ + class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext { + override string toString() { result = "FeatureEqualSourceSinkCallContext" } + } +} + /** * The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion. * @@ -251,7 +287,7 @@ private module Cached { predicate forceCachingInSameStage() { any() } cached - predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() } + predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) } cached predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) { @@ -316,9 +352,7 @@ private module Cached { } cached - predicate parameterNode(Node n, DataFlowCallable c, int i) { - n.(ParameterNode).isParameterOf(c, i) - } + predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) } cached predicate argumentNode(Node n, DataFlowCall call, int pos) { @@ -801,6 +835,9 @@ private module Cached { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } + cached + predicate allowParameterReturnInSelfCached(ParamNode p) { allowParameterReturnInSelf(p) } + cached newtype TCallContext = TAnyCallContext() or @@ -937,7 +974,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { } override predicate relevantFor(DataFlowCallable callable) { - recordDataFlowCallSite(getCall(), callable) + recordDataFlowCallSite(this.getCall(), callable) } override predicate matchesCall(DataFlowCall call) { call = this.getCall() } @@ -1257,7 +1294,7 @@ abstract class AccessPathFront extends TAccessPathFront { TypedContent getHead() { this = TFrontHead(result) } - predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) } + predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll index a55e65a81f6..acf31338f9a 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll @@ -31,7 +31,7 @@ module Consistency { query predicate uniqueEnclosingCallable(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getEnclosingCallable()) and + c = count(nodeGetEnclosingCallable(n)) and c != 1 and msg = "Node should have one enclosing callable but has " + c + "." ) @@ -85,13 +85,13 @@ module Consistency { } query predicate parameterCallable(ParameterNode p, string msg) { - exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and + exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and msg = "Callable mismatch for parameter." } query predicate localFlowIsLocal(Node n1, Node n2, string msg) { simpleLocalFlowStep(n1, n2) and - n1.getEnclosingCallable() != n2.getEnclosingCallable() and + nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and msg = "Local flow step does not preserve enclosing callable." } @@ -106,7 +106,7 @@ module Consistency { query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) { isUnreachableInCall(n, call) and exists(DataFlowCallable c | - c = n.getEnclosingCallable() and + c = nodeGetEnclosingCallable(n) and not viableCallable(call) = c ) and msg = "Call context for isUnreachableInCall is inconsistent with call graph." @@ -120,7 +120,7 @@ module Consistency { n.(ArgumentNode).argumentOf(call, _) and msg = "ArgumentNode and call does not share enclosing callable." ) and - n.getEnclosingCallable() != call.getEnclosingCallable() + nodeGetEnclosingCallable(n) != call.getEnclosingCallable() } // This predicate helps the compiler forget that in some languages @@ -151,7 +151,7 @@ module Consistency { } query predicate postIsInSameCallable(PostUpdateNode n, string msg) { - n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and + nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and msg = "PostUpdateNode does not share callable with its pre-update node." } @@ -175,6 +175,7 @@ module Consistency { query predicate postWithInFlow(Node n, string msg) { isPostUpdateNode(n) and + not clearsContent(n, _) and simpleLocalFlowStep(_, n) and msg = "PostUpdateNode should not be the target of local flow." } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 6776025d172..729d351d391 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -18,6 +18,12 @@ private import semmle.code.csharp.frameworks.NHibernate private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.threading.Tasks +/** Gets the callable in which this node occurs. */ +DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() } + +/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */ +predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) } + abstract class NodeImpl extends Node { /** Do not call: use `getEnclosingCallable()` instead. */ abstract DataFlowCallable getEnclosingCallableImpl(); @@ -310,6 +316,18 @@ module LocalFlow { result = n.(ExplicitParameterNode).getSsaDefinition() } + /** + * Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo` + * involving SSA definition `def`. + */ + predicate localSsaFlowStepUseUse(Ssa::Definition def, Node nodeFrom, Node nodeTo) { + exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo | + SsaImpl::adjacentReadPairSameVar(def, cfnFrom, cfnTo) and + nodeTo = TExprNode(cfnTo) and + nodeFrom = TExprNode(cfnFrom) + ) + } + /** * Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving * SSA definition `def. @@ -322,14 +340,7 @@ module LocalFlow { ) or // Flow from read to next read - exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo | - SsaImpl::adjacentReadPairSameVar(def, cfnFrom, cfnTo) and - nodeTo = TExprNode(cfnTo) - | - nodeFrom = TExprNode(cfnFrom) - or - cfnFrom = nodeFrom.(PostUpdateNode).getPreUpdateNode().getControlFlowNode() - ) + localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) or // Flow into phi node exists(Ssa::PhiNode phi | @@ -399,6 +410,12 @@ module LocalFlow { predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) or + exists(Ssa::Definition def | + LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and + not FlowSummaryImpl::Private::Steps::summaryClearsContentArg(nodeFrom, _) and + not LocalFlow::usesInstanceField(def) + ) + or LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) or FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true) @@ -716,6 +733,8 @@ private module Cached { predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) { LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) or + LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) + or exists(Ssa::Definition def | LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and LocalFlow::usesInstanceField(def) @@ -772,12 +791,14 @@ predicate nodeIsHidden(Node n) { def instanceof Ssa::ImplicitCallDefinition ) or - exists(Parameter p | - p = n.(ParameterNode).getParameter() and + exists(Parameter p | p = n.(ParameterNode).getParameter() | not p.fromSource() + or + p.getCallable() instanceof SummarizedCallable ) or - n = TInstanceParameterNode(any(Callable c | not c.fromSource())) + n = + TInstanceParameterNode(any(Callable c | not c.fromSource() or c instanceof SummarizedCallable)) or n instanceof YieldReturnNode or @@ -1691,9 +1712,6 @@ predicate clearsContent(Node n, Content c) { or fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false) or - FlowSummaryImpl::Private::Steps::summaryStoresIntoArg(c, n) and - not c instanceof ElementContent - or FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c) or exists(WithExpr we, ObjectInitializer oi, FieldOrProperty f | @@ -2003,3 +2021,14 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves preservesValue = false ) } + +/** + * Holds if flow is allowed to pass from parameter `p` and back to itself as a + * side-effect, resulting in a summary from `p` to itself. + * + * One example would be to allow flow like `p.foo = p.bar;`, which is disallowed + * by default as a heuristic. + */ +predicate allowParameterReturnInSelf(ParameterNode p) { + FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p) +} diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll index 83076558ec4..5955285bd6f 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll @@ -261,7 +261,10 @@ module Private { private newtype TSummaryNodeState = TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or - TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } + TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } or + TSummaryNodeClearsContentState(int i, boolean post) { + any(SummarizedCallable sc).clearsContent(i, _) and post in [false, true] + } /** * A state used to break up (complex) flow summaries into atomic flow steps. @@ -308,6 +311,12 @@ module Private { this = TSummaryNodeOutputState(s) and result = "to write: " + s ) + or + exists(int i, boolean post, string postStr | + this = TSummaryNodeClearsContentState(i, post) and + (if post = true then postStr = " (post)" else postStr = "") and + result = "clear: " + i + postStr + ) } } @@ -329,6 +338,11 @@ module Private { not parameterReadState(c, state, _) or state.isOutputState(c, _) + or + exists(int i | + c.clearsContent(i, _) and + state = TSummaryNodeClearsContentState(i, _) + ) } pragma[noinline] @@ -364,6 +378,8 @@ module Private { parameterReadState(c, _, i) or isParameterPostUpdate(_, c, i) + or + c.clearsContent(i, _) } private predicate callbackOutput( @@ -436,6 +452,12 @@ module Private { ) ) ) + or + exists(SummarizedCallable c, int i, ParamNode p | + n = summaryNode(c, TSummaryNodeClearsContentState(i, false)) and + p.isParameterOf(c, i) and + result = getNodeType(p) + ) } /** Holds if summary node `out` contains output of kind `rk` from call `c`. */ @@ -461,6 +483,9 @@ module Private { exists(SummarizedCallable c, int i | isParameterPostUpdate(post, c, i) and pre.(ParamNode).isParameterOf(c, i) + or + pre = summaryNode(c, TSummaryNodeClearsContentState(i, false)) and + post = summaryNode(c, TSummaryNodeClearsContentState(i, true)) ) or exists(SummarizedCallable callable, SummaryComponentStack s | @@ -478,6 +503,17 @@ module Private { ) } + /** + * Holds if flow is allowed to pass from parameter `p`, to a return + * node, and back out to `p`. + */ + predicate summaryAllowParameterReturnInSelf(ParamNode p) { + exists(SummarizedCallable c, int i | + c.clearsContent(i, _) and + p.isParameterOf(c, i) + ) + } + /** Provides a compilation of flow summaries to atomic data-flow steps. */ module Steps { /** @@ -504,11 +540,21 @@ module Private { // for `StringBuilder.append(x)` with a specified value flow from qualifier to // return value and taint flow from argument 0 to the qualifier, then this // allows us to infer taint flow from argument 0 to the return value. - succ instanceof ParamNode and summaryPostUpdateNode(pred, succ) and preservesValue = true + succ instanceof ParamNode and + summaryPostUpdateNode(pred, succ) and + preservesValue = true or // Similarly we would like to chain together summaries where values get passed // into callbacks along the way. - pred instanceof ArgNode and summaryPostUpdateNode(succ, pred) and preservesValue = true + pred instanceof ArgNode and + summaryPostUpdateNode(succ, pred) and + preservesValue = true + or + exists(SummarizedCallable c, int i | + pred.(ParamNode).isParameterOf(c, i) and + succ = summaryNode(c, TSummaryNodeClearsContentState(i, _)) and + preservesValue = true + ) } /** @@ -536,10 +582,39 @@ module Private { } /** - * Holds if values stored inside content `c` are cleared when passed as - * input of type `input` in `call`. + * Holds if values stored inside content `c` are cleared at `n`. `n` is a + * synthesized summary node, so in order for values to be cleared at calls + * to the relevant method, it is important that flow does not pass over + * the argument, either via use-use flow or def-use flow. + * + * Example: + * + * ``` + * a.b = taint; + * a.clearB(); // assume we have a flow summary for `clearB` that clears `b` on the qualifier + * sink(a.b); + * ``` + * + * In the above, flow should not pass from `a` on the first line (or the second + * line) to `a` on the third line. Instead, there will be synthesized flow from + * `a` on line 2 to the post-update node for `a` on that line (via an intermediate + * node where field `b` is cleared). */ - predicate summaryClearsContent(ArgNode arg, Content c) { + predicate summaryClearsContent(Node n, Content c) { + exists(SummarizedCallable sc, int i | + n = summaryNode(sc, TSummaryNodeClearsContentState(i, true)) and + sc.clearsContent(i, c) + ) + } + + /** + * Holds if values stored inside content `c` are cleared inside a + * callable to which `arg` is an argument. + * + * In such cases, it is important to prevent use-use flow out of + * `arg` (see comment for `summaryClearsContent`). + */ + predicate summaryClearsContentArg(ArgNode arg, Content c) { exists(DataFlowCall call, int i | viableCallable(call).(SummarizedCallable).clearsContent(i, c) and arg.argumentOf(call, i) @@ -599,25 +674,6 @@ module Private { ret.getKind() = rk ) } - - /** - * Holds if data is written into content `c` of argument `arg` using a flow summary. - * - * Depending on the type of `c`, this predicate may be relevant to include in the - * definition of `clearsContent()`. - */ - predicate summaryStoresIntoArg(Content c, Node arg) { - exists(ParamUpdateReturnKind rk, ReturnNodeExt ret, PostUpdateNode out | - exists(DataFlowCall call, SummarizedCallable callable | - getNodeEnclosingCallable(ret) = callable and - viableCallable(call) = callable and - summaryStoreStep(_, c, ret) and - ret.getKind() = pragma[only_bind_into](rk) and - out = rk.getAnOutNode(call) and - arg = out.getPreUpdateNode() - ) - ) - } } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll index 884f4406d01..eae5d23f544 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll @@ -141,24 +141,23 @@ private module Liveness { private import Liveness -/** Holds if `bb1` strictly dominates `bb2`. */ -private predicate strictlyDominates(BasicBlock bb1, BasicBlock bb2) { - bb1 = getImmediateBasicBlockDominator+(bb2) -} - -/** Holds if `bb1` dominates a predecessor of `bb2`. */ -private predicate dominatesPredecessor(BasicBlock bb1, BasicBlock bb2) { - exists(BasicBlock pred | pred = getABasicBlockPredecessor(bb2) | - bb1 = pred - or - strictlyDominates(bb1, pred) - ) -} - -/** Holds if `df` is in the dominance frontier of `bb`. */ +/** + * Holds if `df` is in the dominance frontier of `bb`. + * + * This is equivalent to: + * + * ```ql + * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and + * not bb = getImmediateBasicBlockDominator+(df) + * ``` + */ private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - dominatesPredecessor(bb, df) and - not strictlyDominates(bb, df) + bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) + or + exists(BasicBlock prev | inDominanceFrontier(prev, df) | + bb = getImmediateBasicBlockDominator(prev) and + not bb = getImmediateBasicBlockDominator(df) + ) } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll index 884f4406d01..eae5d23f544 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll @@ -141,24 +141,23 @@ private module Liveness { private import Liveness -/** Holds if `bb1` strictly dominates `bb2`. */ -private predicate strictlyDominates(BasicBlock bb1, BasicBlock bb2) { - bb1 = getImmediateBasicBlockDominator+(bb2) -} - -/** Holds if `bb1` dominates a predecessor of `bb2`. */ -private predicate dominatesPredecessor(BasicBlock bb1, BasicBlock bb2) { - exists(BasicBlock pred | pred = getABasicBlockPredecessor(bb2) | - bb1 = pred - or - strictlyDominates(bb1, pred) - ) -} - -/** Holds if `df` is in the dominance frontier of `bb`. */ +/** + * Holds if `df` is in the dominance frontier of `bb`. + * + * This is equivalent to: + * + * ```ql + * bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and + * not bb = getImmediateBasicBlockDominator+(df) + * ``` + */ private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { - dominatesPredecessor(bb, df) and - not strictlyDominates(bb, df) + bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df) + or + exists(BasicBlock prev | inDominanceFrontier(prev, df) | + bb = getImmediateBasicBlockDominator(prev) and + not bb = getImmediateBasicBlockDominator(df) + ) } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll index f007ba939e8..067a9b94f45 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll @@ -419,9 +419,9 @@ module ExprNode { * "else" expression of this conditional expression. */ ExprNode getBranchExpr(boolean branch) { - branch = true and result = getTrueExpr() + branch = true and result = this.getTrueExpr() or - branch = false and result = getFalseExpr() + branch = false and result = this.getFalseExpr() } } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll index 558ecd1b88b..e450c11b5ab 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll @@ -28,7 +28,7 @@ class SsaReadPositionBlock extends SsaReadPosition, TSsaReadPositionBlock { /** Gets the basic block corresponding to this position. */ BasicBlock getBlock() { this = TSsaReadPositionBlock(result) } - override predicate hasReadOfVar(SsaVariable v) { getBlock() = getAReadBasicBlock(v) } + override predicate hasReadOfVar(SsaVariable v) { this.getBlock() = getAReadBasicBlock(v) } override string toString() { result = "block" } } @@ -49,8 +49,8 @@ class SsaReadPositionPhiInputEdge extends SsaReadPosition, TSsaReadPositionPhiIn /** Holds if `inp` is an input to `phi` along this edge. */ predicate phiInput(SsaPhiNode phi, SsaVariable inp) { - phi.hasInputFromBlock(inp, getOrigBlock()) and - getPhiBlock() = phi.getBasicBlock() + phi.hasInputFromBlock(inp, this.getOrigBlock()) and + this.getPhiBlock() = phi.getBasicBlock() } override string toString() { result = "edge" } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll index f4f73b8247c..acb029c23d9 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll @@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration { predicate isSanitizer(DataFlow::Node node) { none() } final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or + this.isSanitizer(node) or defaultTaintSanitizer(node) } /** Holds if taint propagation into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) } /** Holds if taint propagation out of `node` is prohibited. */ predicate isSanitizerOut(DataFlow::Node node) { none() } - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) } /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + this.isSanitizerGuard(guard) + } /** * Holds if the additional taint propagation step from `node1` to `node2` @@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration { predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or + this.isAdditionalTaintStep(node1, node2) or defaultAdditionalTaintStep(node1, node2) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index d0b4ef45ce8..509bdfb5e04 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -11,10 +11,10 @@ private import RuntimeCallable /** A call. */ class DispatchCall extends Internal::TDispatchCall { /** Gets a textual representation of this call. */ - string toString() { result = getCall().toString() } + string toString() { result = this.getCall().toString() } /** Gets the location of this call. */ - Location getLocation() { result = getCall().getLocation() } + Location getLocation() { result = this.getCall().getLocation() } /** Gets the underlying expression of this call. */ Expr getCall() { result = Internal::getCall(this) } @@ -209,7 +209,7 @@ private module Internal { abstract Expr getArgument(int i); /** Gets the number of arguments of this call. */ - int getNumberOfArguments() { result = count(int i | exists(getArgument(i))) } + int getNumberOfArguments() { result = count(int i | exists(this.getArgument(i))) } /** Gets the qualifier of this call, if any. */ abstract Expr getQualifier(); @@ -506,12 +506,12 @@ private module Internal { } override RuntimeCallable getADynamicTarget() { - result = getAViableInherited() + result = this.getAViableInherited() or - result = getAViableOverrider() + result = this.getAViableOverrider() or // Simple case: target method cannot be overridden - result = getAStaticTarget() and + result = this.getAStaticTarget() and not result instanceof OverridableCallable } @@ -779,9 +779,9 @@ private module Internal { ) } - override Expr getQualifier() { result = getCall().getQualifier() } + override Expr getQualifier() { result = this.getCall().getQualifier() } - override Method getAStaticTarget() { result = getCall().getTarget() } + override Method getAStaticTarget() { result = this.getCall().getTarget() } } /** @@ -793,24 +793,24 @@ private module Internal { private class DispatchAccessorCall extends DispatchMethodOrAccessorCall, TDispatchAccessorCall { override AccessorCall getCall() { this = TDispatchAccessorCall(result) } - override Expr getArgument(int i) { result = getCall().getArgument(i) } + override Expr getArgument(int i) { result = this.getCall().getArgument(i) } - override Expr getQualifier() { result = getCall().(MemberAccess).getQualifier() } + override Expr getQualifier() { result = this.getCall().(MemberAccess).getQualifier() } - override Accessor getAStaticTarget() { result = getCall().getTarget() } + override Accessor getAStaticTarget() { result = this.getCall().getTarget() } override RuntimeAccessor getADynamicTarget() { result = DispatchMethodOrAccessorCall.super.getADynamicTarget() and // Calls to accessors may have `dynamic` expression arguments, // so we need to check that the types match - forall(Type argumentType, int i | hasDynamicArg(i, argumentType) | + forall(Type argumentType, int i | this.hasDynamicArg(i, argumentType) | argumentType.isImplicitlyConvertibleTo(result.getParameter(i).getType()) ) } private predicate hasDynamicArg(int i, Type argumentType) { exists(Expr argument | - argument = getArgument(i) and + argument = this.getArgument(i) and argument.stripImplicitCasts().getType() instanceof DynamicType and argumentType = getAPossibleType(argument, _) ) @@ -896,7 +896,7 @@ private module Internal { // names and number of parameters. This set is further reduced in // `getADynamicTarget()` by taking type information into account. override Callable getAStaticTarget() { - result = getACallableWithMatchingName() and + result = this.getACallableWithMatchingName() and exists(int minArgs | minArgs = count(Parameter p | @@ -904,16 +904,19 @@ private module Internal { not p.hasDefaultValue() and not p.isParams() ) and - getNumberOfArguments() >= minArgs and - (result.(Method).hasParams() or getNumberOfArguments() <= result.getNumberOfParameters()) + this.getNumberOfArguments() >= minArgs and + ( + result.(Method).hasParams() or + this.getNumberOfArguments() <= result.getNumberOfParameters() + ) ) } private RuntimeCallable getACallableWithMatchingName() { - result.(Operator).getFunctionName() = getName() + result.(Operator).getFunctionName() = this.getName() or not result instanceof Operator and - result.getUndecoratedName() = getName() + result.getUndecoratedName() = this.getName() } // A callable is viable if the following conditions are all satisfied: @@ -987,7 +990,7 @@ private module Internal { * type of one of the arguments. */ RuntimeCallable getADynamicTargetCandidate() { - result = getAStaticTarget() and + result = this.getAStaticTarget() and ( result = getADynamicTargetCandidateInstanceMethod(this.getAQualifierType()) or @@ -999,13 +1002,13 @@ private module Internal { result instanceof RuntimeInstanceAccessor and this.hasUnknownQualifierType() or - result = getADynamicTargetCandidateOperator() + result = this.getADynamicTargetCandidateOperator() ) } pragma[noinline] private RuntimeOperator getADynamicTargetCandidateOperator() { - result = getAStaticTarget() and + result = this.getAStaticTarget() and result.getDeclaringType() = result.getAParameter().getType() } } @@ -1138,8 +1141,8 @@ private module Internal { result = DispatchReflectionOrDynamicCall.super.getADynamicTargetCandidate() or // Static callables can be called using reflection as well - result = getAStaticTarget() and - result.getDeclaringType() = getStaticType() and + result = this.getAStaticTarget() and + result.getDeclaringType() = this.getStaticType() and result.(Modifiable).isStatic() } @@ -1147,7 +1150,7 @@ private module Internal { override Expr getArgument(int i) { exists(int args, ArrayCreation ac | this = TDispatchReflectionCall(_, _, _, _, args) and - ac = getAMethodCallArgSource(getCall().getArgument(args)) and + ac = getAMethodCallArgSource(this.getCall().getArgument(args)) and result = ac.getInitializer().getElement(i) ) } @@ -1158,20 +1161,20 @@ private module Internal { TDispatchDynamicMethodCall { override DynamicMethodCall getCall() { this = TDispatchDynamicMethodCall(result) } - override string getName() { result = getCall().getLateBoundTargetName() } + override string getName() { result = this.getCall().getLateBoundTargetName() } - override Expr getQualifier() { result = getCall().getQualifier() } + override Expr getQualifier() { result = this.getCall().getQualifier() } override RuntimeMethod getADynamicTargetCandidate() { - if exists(getCall().getTarget()) + if exists(this.getCall().getTarget()) then // static method call - result = getCall().getTarget() + result = this.getCall().getTarget() else result = DispatchReflectionOrDynamicCall.super.getADynamicTargetCandidate() } // Does not take named arguments into account - override Expr getArgument(int i) { result = getCall().getArgument(i) } + override Expr getArgument(int i) { result = this.getCall().getArgument(i) } } /** An operator call using dynamic types. */ @@ -1181,14 +1184,14 @@ private module Internal { override string getName() { exists(Operator o | - o.getName() = getCall().getLateBoundTargetName() and + o.getName() = this.getCall().getLateBoundTargetName() and result = o.getFunctionName() ) } override Expr getQualifier() { none() } - override Expr getArgument(int i) { result = getCall().getArgument(i) } + override Expr getArgument(int i) { result = this.getCall().getArgument(i) } } /** A (potential) call to a property accessor using dynamic types. */ @@ -1255,7 +1258,7 @@ private module Internal { any(DynamicMemberAccess dma | this = TDispatchDynamicEventAccess(_, dma, _)).getQualifier() } - override Expr getArgument(int i) { i = 0 and result = getCall().getRValue() } + override Expr getArgument(int i) { i = 0 and result = this.getCall().getRValue() } } /** A call to a constructor using dynamic types. */ @@ -1267,9 +1270,9 @@ private module Internal { override Expr getQualifier() { none() } - override Expr getArgument(int i) { result = getCall().getArgument(i) } + override Expr getArgument(int i) { result = this.getCall().getArgument(i) } - override RuntimeCallable getADynamicTargetCandidate() { result = getCall().getTarget() } + override RuntimeCallable getADynamicTargetCandidate() { result = this.getCall().getTarget() } } /** A call where the target can be resolved statically. */ @@ -1285,8 +1288,8 @@ private module Internal { ) } - override Callable getAStaticTarget() { result = getCall().getTarget() } + override Callable getAStaticTarget() { result = this.getCall().getTarget() } - override RuntimeCallable getADynamicTarget() { result = getCall().getTarget() } + override RuntimeCallable getADynamicTarget() { result = this.getCall().getTarget() } } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll index 4913ea2bc3c..dc963881cbf 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll @@ -58,13 +58,13 @@ class OverridableCallable extends Callable { * `I.M.getAnImplementorSubType(D) = C.M`. */ private Callable getAnImplementorSubType(ValueOrRefType t) { - result = getAnImplementor(t) + result = this.getAnImplementor(t) or exists(ValueOrRefType mid | - result = getAnImplementorSubType(mid) and + result = this.getAnImplementorSubType(mid) and t.getBaseClass() = mid and // There must be no other implementation of this callable in `t` - forall(Callable other | other = getAnImplementor(t) | other = result) + forall(Callable other | other = this.getAnImplementor(t) | other = result) ) } @@ -107,8 +107,8 @@ class OverridableCallable extends Callable { * implements this interface callable, if any. */ private Callable getAnOverridingImplementor() { - result = getAnUltimateImplementor() and - not result = getAnImplementor(_) + result = this.getAnUltimateImplementor() and + not result = this.getAnImplementor(_) } /** @@ -150,10 +150,10 @@ class OverridableCallable extends Callable { } private Callable getInherited1(ValueOrRefType t) { - result = getInherited0(t) + result = this.getInherited0(t) or // An interface implementation - result = getAnImplementorSubType(t) + result = this.getAnImplementorSubType(t) } pragma[noinline] @@ -171,7 +171,7 @@ class OverridableCallable extends Callable { private predicate isDeclaringSubType(ValueOrRefType t) { t = this.getDeclaringType() or - exists(ValueOrRefType mid | isDeclaringSubType(mid) | t = mid.getASubType()) + exists(ValueOrRefType mid | this.isDeclaringSubType(mid) | t = mid.getASubType()) } pragma[noinline] @@ -232,7 +232,7 @@ class OverridableAccessor extends Accessor, OverridableCallable { override Accessor getAnImplementor(ValueOrRefType t) { exists(Virtualizable implementor, int kind | - getAnImplementorAux(t, implementor, kind) and + this.getAnImplementorAux(t, implementor, kind) and result.getDeclaration() = implementor and getAccessorKind(result) = kind ) @@ -241,7 +241,7 @@ class OverridableAccessor extends Accessor, OverridableCallable { // predicate folding to get proper join order private predicate getAnImplementorAux(ValueOrRefType t, Virtualizable implementor, int kind) { exists(Virtualizable implementee | - implementee = getDeclaration() and + implementee = this.getDeclaration() and kind = getAccessorKind(this) and implementor = implementee.getAnImplementor(t) ) @@ -249,7 +249,7 @@ class OverridableAccessor extends Accessor, OverridableCallable { override Accessor getAnUltimateImplementor() { exists(Virtualizable implementor, int kind | - getAnUltimateImplementorAux(implementor, kind) and + this.getAnUltimateImplementorAux(implementor, kind) and result.getDeclaration() = implementor and getAccessorKind(result) = kind ) @@ -258,7 +258,7 @@ class OverridableAccessor extends Accessor, OverridableCallable { // predicate folding to get proper join order private predicate getAnUltimateImplementorAux(Virtualizable implementor, int kind) { exists(Virtualizable implementee | - implementee = getDeclaration() and + implementee = this.getDeclaration() and kind = getAccessorKind(this) and implementor = implementee.getAnUltimateImplementor() ) diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Access.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Access.qll index ab3ea182056..9d7cf3a5867 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Access.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Access.qll @@ -115,7 +115,7 @@ class MemberAccess extends Access, QualifiableExpr, @member_access_expr { not exists(MemberInitializer mi | mi.getLValue() = this) } - override Member getQualifiedDeclaration() { result = getTarget() } + override Member getQualifiedDeclaration() { result = this.getTarget() } override Member getTarget() { none() } } @@ -147,8 +147,8 @@ class AssignableAccess extends Access, @assignable_access_expr { * or a `ref` argument in a method call. */ predicate isOutOrRefArgument() { - isOutArgument() or - isRefArgument() + this.isOutArgument() or + this.isRefArgument() } /** @@ -507,7 +507,7 @@ class ElementAccess extends AssignableAccess, QualifiableExpr, @element_access_e * Gets an index expression of this element access, for example * `1` in `x[0, 1]`. */ - Expr getAnIndex() { result = getIndex(_) } + Expr getAnIndex() { result = this.getIndex(_) } /** * Gets the `i`th index expression of this element access, for example the @@ -515,7 +515,7 @@ class ElementAccess extends AssignableAccess, QualifiableExpr, @element_access_e */ Expr getIndex(int i) { result = this.getChild(i) and i >= 0 } - override Assignable getQualifiedDeclaration() { result = getTarget() } + override Assignable getQualifiedDeclaration() { result = this.getTarget() } } /** @@ -615,7 +615,7 @@ class IndexerWrite extends IndexerAccess, ElementWrite { } * ``` */ class VirtualIndexerAccess extends IndexerAccess { - VirtualIndexerAccess() { targetIsOverridableOrImplementable() } + VirtualIndexerAccess() { this.targetIsOverridableOrImplementable() } } /** @@ -647,7 +647,7 @@ library class EventAccessExpr extends Expr, @event_access_expr { * ``` */ class EventAccess extends AssignableMemberAccess, EventAccessExpr { - override Event getTarget() { result = getEvent() } + override Event getTarget() { result = this.getEvent() } override string getAPrimaryQlClass() { result = "EventAccess" } } @@ -707,7 +707,7 @@ class EventWrite extends EventAccess, AssignableWrite { } * ``` */ class VirtualEventAccess extends EventAccess { - VirtualEventAccess() { targetIsOverridableOrImplementable() } + VirtualEventAccess() { this.targetIsOverridableOrImplementable() } } /** @@ -787,7 +787,7 @@ class LocalFunctionAccess extends CallableAccess { * ``` */ class VirtualMethodAccess extends MethodAccess { - VirtualMethodAccess() { targetIsOverridableOrImplementable() } + VirtualMethodAccess() { this.targetIsOverridableOrImplementable() } } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll index ac98c0eafcf..f20bfba1589 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll @@ -138,10 +138,10 @@ class DivExpr extends BinaryArithmeticOperation, @div_expr { override string getOperator() { result = "/" } /** Gets the numerator of this division operation. */ - Expr getNumerator() { result = getLeftOperand() } + Expr getNumerator() { result = this.getLeftOperand() } /** Gets the denominator of this division operation. */ - Expr getDenominator() { result = getRightOperand() } + Expr getDenominator() { result = this.getRightOperand() } override string getAPrimaryQlClass() { result = "DivExpr" } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll index 88ef770160a..562a4dd9cd5 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll @@ -27,7 +27,7 @@ class Assignment extends Operation, @assign_expr { Expr getRValue() { result = this.getChild(0) } /** Gets the variable being assigned to, if any. */ - Variable getTargetVariable() { result.getAnAccess() = getLValue() } + Variable getTargetVariable() { result.getAnAccess() = this.getLValue() } override string getOperator() { none() } } @@ -38,7 +38,7 @@ class Assignment extends Operation, @assign_expr { class LocalVariableDeclAndInitExpr extends LocalVariableDeclExpr, Assignment { override string getOperator() { result = "=" } - override LocalVariable getTargetVariable() { result = getVariable() } + override LocalVariable getTargetVariable() { result = this.getVariable() } override LocalVariableAccess getLValue() { result = Assignment.super.getLValue() } @@ -86,7 +86,7 @@ class AssignOperation extends Assignment, @assign_op_expr { * If an expanded version exists, then it is used in the control * flow graph. */ - predicate hasExpandedAssignment() { exists(getExpandedAssignment()) } + predicate hasExpandedAssignment() { exists(this.getExpandedAssignment()) } override string toString() { result = "... " + this.getOperator() + " ..." } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll index 6dc88e941ef..a4c4ab1b670 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll @@ -47,7 +47,7 @@ class Call extends DotNet::Call, Expr, @call { override Expr getRawArgument(int i) { result = this.getArgument(i) } - override Expr getAnArgument() { result = getArgument(_) } + override Expr getAnArgument() { result = this.getArgument(_) } /** Gets the number of arguments of this call. */ int getNumberOfArguments() { result = count(this.getAnArgument()) } @@ -80,7 +80,7 @@ class Call extends DotNet::Call, Expr, @call { */ cached override Expr getArgumentForParameter(DotNet::Parameter p) { - getTarget().getAParameter() = p and + this.getTarget().getAParameter() = p and ( // Appears in the positional part of the call result = this.getImplicitArgument(p.getPosition()) and @@ -94,7 +94,7 @@ class Call extends DotNet::Call, Expr, @call { ) or // Appears in the named part of the call - result = getExplicitArgument(p.getName()) and + result = this.getExplicitArgument(p.getName()) and (p.(Parameter).isParams() implies isValidExplicitParamsType(p, result.getType())) ) } @@ -112,13 +112,13 @@ class Call extends DotNet::Call, Expr, @call { pragma[noinline] private Expr getImplicitArgument(int pos) { - result = getArgument(pos) and + result = this.getArgument(pos) and not exists(result.getExplicitArgumentName()) } pragma[nomagic] private Expr getExplicitArgument(string name) { - result = getAnArgument() and + result = this.getAnArgument() and result.getExplicitArgumentName() = name } @@ -131,7 +131,7 @@ class Call extends DotNet::Call, Expr, @call { */ Expr getArgumentForName(string name) { exists(Parameter p | - result = getArgumentForParameter(p) and + result = this.getArgumentForParameter(p) and p.hasName(name) ) } @@ -219,7 +219,7 @@ class Call extends DotNet::Call, Expr, @call { */ Expr getRuntimeArgumentForParameter(Parameter p) { exists(Callable c | - c = getARuntimeTarget() and + c = this.getARuntimeTarget() and p = c.getAParameter() and result = this.getRuntimeArgument(p.getPosition()) ) @@ -231,7 +231,7 @@ class Call extends DotNet::Call, Expr, @call { */ Expr getRuntimeArgumentForName(string name) { exists(Parameter p | - result = getRuntimeArgumentForParameter(p) and + result = this.getRuntimeArgumentForParameter(p) and p.hasName(name) ) } @@ -240,19 +240,19 @@ class Call extends DotNet::Call, Expr, @call { * Gets an argument that corresponds to a parameter of a potential * run-time target of this call. */ - Expr getARuntimeArgument() { result = getRuntimeArgument(_) } + Expr getARuntimeArgument() { result = this.getRuntimeArgument(_) } /** * Gets the number of arguments that correspond to a parameter of a potential * run-time target of this call. */ - int getNumberOfRuntimeArguments() { result = count(getARuntimeArgument()) } + int getNumberOfRuntimeArguments() { result = count(this.getARuntimeArgument()) } /** * Holds if this call has no arguments that correspond to a parameter of a * potential (run-time) target of this call. */ - predicate hasNoRuntimeArguments() { not exists(getARuntimeArgument()) } + predicate hasNoRuntimeArguments() { not exists(this.getARuntimeArgument()) } override string toString() { result = "call" } } @@ -295,19 +295,19 @@ private predicate isValidExplicitParamsType(Parameter p, Type t) { class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invocation_expr { override Method getTarget() { expr_call(this, result) } - override Method getQualifiedDeclaration() { result = getTarget() } + override Method getQualifiedDeclaration() { result = this.getTarget() } override string toString() { result = "call to method " + concat(this.getTarget().getName()) } override string getAPrimaryQlClass() { result = "MethodCall" } override Expr getRawArgument(int i) { - if exists(getQualifier()) + if exists(this.getQualifier()) then - i = 0 and result = getQualifier() + i = 0 and result = this.getQualifier() or - result = getArgument(i - 1) - else result = getArgument(i) + result = this.getArgument(i - 1) + else result = this.getArgument(i) } } @@ -336,7 +336,7 @@ class ExtensionMethodCall extends MethodCall { override Expr getArgument(int i) { exists(int j | result = this.getChildExpr(j) | - if isOrdinaryStaticCall() then (j = i and j >= 0) else (j = i - 1 and j >= -1) + if this.isOrdinaryStaticCall() then (j = i and j >= 0) else (j = i - 1 and j >= -1) ) } @@ -379,8 +379,8 @@ class ExtensionMethodCall extends MethodCall { */ class VirtualMethodCall extends MethodCall { VirtualMethodCall() { - not getQualifier() instanceof BaseAccess and - getTarget().isOverridableOrImplementable() + not this.getQualifier() instanceof BaseAccess and + this.getTarget().isOverridableOrImplementable() } } @@ -573,7 +573,7 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ { ) } - override Expr getRuntimeArgument(int i) { result = getArgument(i) } + override Expr getRuntimeArgument(int i) { result = this.getArgument(i) } } /** @@ -618,11 +618,11 @@ class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr { } deprecated private AddEventSource getAnAddEventSourceSameEnclosingCallable() { - result = getAnAddEventSource(this.getEnclosingCallable()) + result = this.getAnAddEventSource(this.getEnclosingCallable()) } deprecated private AddEventSource getAnAddEventSourceDifferentEnclosingCallable() { - exists(Callable c | result = getAnAddEventSource(c) | c != this.getEnclosingCallable()) + exists(Callable c | result = this.getAnAddEventSource(c) | c != this.getEnclosingCallable()) } /** @@ -683,7 +683,7 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr { */ class PropertyCall extends AccessorCall, PropertyAccessExpr { override Accessor getTarget() { - exists(PropertyAccess pa, Property p | pa = this and p = getProperty() | + exists(PropertyAccess pa, Property p | pa = this and p = this.getProperty() | pa instanceof AssignableRead and result = p.getGetter() or pa instanceof AssignableWrite and result = p.getSetter() @@ -718,7 +718,7 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr { */ class IndexerCall extends AccessorCall, IndexerAccessExpr { override Accessor getTarget() { - exists(IndexerAccess ia, Indexer i | ia = this and i = getIndexer() | + exists(IndexerAccess ia, Indexer i | ia = this and i = this.getIndexer() | ia instanceof AssignableRead and result = i.getGetter() or ia instanceof AssignableWrite and result = i.getSetter() @@ -761,7 +761,7 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr { class EventCall extends AccessorCall, EventAccessExpr { override EventAccessor getTarget() { exists(Event e, AddOrRemoveEventExpr aoree | - e = getEvent() and + e = this.getEvent() and aoree.getLValue() = this | aoree instanceof AddEventExpr and result = e.getAddEventAccessor() @@ -799,7 +799,7 @@ class EventCall extends AccessorCall, EventAccessExpr { class LocalFunctionCall extends Call, @local_function_invocation_expr { override LocalFunction getTarget() { expr_call(this, result) } - override string toString() { result = "call to local function " + getTarget().getName() } + override string toString() { result = "call to local function " + this.getTarget().getName() } override string getAPrimaryQlClass() { result = "LocalFunctionCall" } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Creation.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Creation.qll index c9ae3919004..84bcf7b87bc 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Creation.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Creation.qll @@ -45,7 +45,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr * } * ``` */ - MemberInitializer getAMemberInitializer() { result = getMemberInitializer(_) } + MemberInitializer getAMemberInitializer() { result = this.getMemberInitializer(_) } /** * Gets the `i`th member initializer of this object initializer. For example, @@ -122,7 +122,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * }; * ``` */ - ElementInitializer getAnElementInitializer() { result = getElementInitializer(_) } + ElementInitializer getAnElementInitializer() { result = this.getElementInitializer(_) } /** * Gets the `i`th element initializer of this collection initializer, for @@ -180,7 +180,7 @@ class ElementInitializer extends MethodCall { */ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr { /** Gets the type of the newly created object. */ - ValueOrRefType getObjectType() { result = getType() } + ValueOrRefType getObjectType() { result = this.getType() } override Constructor getTarget() { expr_call(this, result) } @@ -320,7 +320,7 @@ class ArrayInitializer extends Expr, @array_init_expr { * }; * ``` */ - Expr getAnElement() { result = getElement(_) } + Expr getAnElement() { result = this.getElement(_) } /** * Gets the `i`th element of this array initializer, for example the second @@ -365,7 +365,7 @@ class ArrayCreation extends Expr, @array_creation_expr { * new int[5, 10] * ``` */ - Expr getALengthArgument() { result = getLengthArgument(_) } + Expr getALengthArgument() { result = this.getLengthArgument(_) } /** * Gets the `i`th dimension's length argument of this array creation, for @@ -427,7 +427,7 @@ class AnonymousFunctionExpr extends Expr, Callable, Modifiable, @anonymous_funct override string toString() { result = Expr.super.toString() } - override string toStringWithTypes() { result = toString() } + override string toStringWithTypes() { result = this.toString() } } /** diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Dynamic.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Dynamic.qll index ea6012ca3e1..eda31432f38 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Dynamic.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Dynamic.qll @@ -15,7 +15,7 @@ private import semmle.code.csharp.dispatch.Dispatch * (`DynamicAccessorCall`), or a dynamic element access (`DynamicElementAccess`). */ class DynamicExpr extends LateBindableExpr { - DynamicExpr() { isLateBound() } + DynamicExpr() { this.isLateBound() } } /** @@ -67,7 +67,7 @@ class DynamicObjectCreation extends DynamicExpr, ObjectCreation { * may not be known at compile-time (as in the example above). */ class DynamicMethodCall extends DynamicExpr, MethodCall { - override string toString() { result = "dynamic call to method " + getLateBoundTargetName() } + override string toString() { result = "dynamic call to method " + this.getLateBoundTargetName() } override string getAPrimaryQlClass() { result = "DynamicMethodCall" } } @@ -97,7 +97,9 @@ class DynamicMethodCall extends DynamicExpr, MethodCall { * target operator may not be known at compile-time (as in the example above). */ class DynamicOperatorCall extends DynamicExpr, OperatorCall { - override string toString() { result = "dynamic call to operator " + getLateBoundTargetName() } + override string toString() { + result = "dynamic call to operator " + this.getLateBoundTargetName() + } override string getAPrimaryQlClass() { result = "DynamicOperatorCall" } } @@ -189,7 +191,9 @@ class DynamicAccess extends DynamicExpr { */ class DynamicMemberAccess extends DynamicAccess, MemberAccess, AssignableAccess, @dynamic_member_access_expr { - override string toString() { result = "dynamic access to member " + getLateBoundTargetName() } + override string toString() { + result = "dynamic access to member " + this.getLateBoundTargetName() + } override string getAPrimaryQlClass() { result = "DynamicMemberAccess" } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll index 0988bb84340..47477afe2b9 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll @@ -103,7 +103,7 @@ class Expr extends DotNet::Expr, ControlFlowElement, @expr { class LateBindableExpr extends Expr, @late_bindable_expr { /** Holds if this expression is late bound. */ predicate isLateBound() { - exists(getLateBoundTargetName()) or + exists(this.getLateBoundTargetName()) or isDynamicMemberAccess(this) or isDynamicElementAccess(this) } @@ -221,9 +221,9 @@ class BinaryOperation extends Operation, @bin_op { /** Gets the other operand of this binary operation, given operand `o`. */ Expr getOtherOperand(Expr o) { - o = getLeftOperand() and result = getRightOperand() + o = this.getLeftOperand() and result = this.getRightOperand() or - o = getRightOperand() and result = getLeftOperand() + o = this.getRightOperand() and result = this.getLeftOperand() } override string getOperator() { none() } @@ -368,7 +368,7 @@ class RelationalPatternExpr extends PatternExpr, @relational_pattern_expr { /** Gets the expression of this relational pattern. */ Expr getExpr() { result = this.getChild(0) } - override string toString() { result = getOperator() + " ..." } + override string toString() { result = this.getOperator() + " ..." } } /** A less-than pattern, for example `< 10` in `x is < 10`. */ @@ -520,7 +520,7 @@ class NotPatternExpr extends UnaryPatternExpr, @not_pattern_expr { /** A binary pattern. For example, `1 or 2`. */ class BinaryPatternExpr extends PatternExpr, @binary_pattern_expr { /** Gets a pattern. */ - PatternExpr getAnOperand() { result = getLeftOperand() or result = getRightOperand() } + PatternExpr getAnOperand() { result = this.getLeftOperand() or result = this.getRightOperand() } /** Gets the left pattern. */ PatternExpr getLeftOperand() { result = this.getChild(0) } @@ -743,7 +743,7 @@ class DefaultValueExpr extends Expr, @default_expr { TypeAccess getTypeAccess() { result = this.getChild(0) } override string toString() { - if exists(getTypeAccess()) then result = "default(...)" else result = "default" + if exists(this.getTypeAccess()) then result = "default(...)" else result = "default" } override string getAPrimaryQlClass() { result = "DefaultValueExpr" } @@ -757,7 +757,7 @@ class SizeofExpr extends UnaryOperation, @sizeof_expr { * Gets the type access in this `sizeof` expression, for example `int` in * `sizeof(int)`. */ - TypeAccess getTypeAccess() { result = getOperand() } + TypeAccess getTypeAccess() { result = this.getOperand() } override string getOperator() { result = "sizeof(..)" } @@ -830,7 +830,7 @@ class AddressOfExpr extends UnaryOperation, @address_of_expr { */ class AwaitExpr extends Expr, @await_expr { /** Gets the expression being awaited. */ - Expr getExpr() { result = getChild(0) } + Expr getExpr() { result = this.getChild(0) } override string toString() { result = "await ..." } @@ -881,7 +881,7 @@ class InterpolatedStringExpr extends Expr, @interpolated_string_expr { * element (`getText(0)` gets the text). */ Expr getInsert(int i) { - result = getChild(i) and + result = this.getChild(i) and not result instanceof StringLiteral } @@ -891,13 +891,13 @@ class InterpolatedStringExpr extends Expr, @interpolated_string_expr { * `$"Hello, {name}!"`. Note that there is no text element at index `i = 1`, * but instead an insert (`getInsert(1)` gets the insert). */ - StringLiteral getText(int i) { result = getChild(i) } + StringLiteral getText(int i) { result = this.getChild(i) } /** Gets an insert in this interpolated string. */ - Expr getAnInsert() { result = getInsert(_) } + Expr getAnInsert() { result = this.getInsert(_) } /** Gets a text element in this interpolated string. */ - StringLiteral getAText() { result = getText(_) } + StringLiteral getAText() { result = this.getText(_) } } /** @@ -914,7 +914,7 @@ class ThrowElement extends ControlFlowElement, DotNet::Throw, @throw_element { /** Gets the type of exception being thrown. */ Class getThrownExceptionType() { - result = getExpr().getType() + result = this.getExpr().getType() or // Corner case: `throw null` this.getExpr().getType() instanceof NullType and @@ -958,7 +958,7 @@ class QualifiableExpr extends Expr, @qualifiable_expr { Expr getQualifier() { result = this.getChildExpr(-1) } /** Holds if this expression is qualified. */ - final predicate hasQualifier() { exists(getQualifier()) } + final predicate hasQualifier() { exists(this.getQualifier()) } /** Holds if this expression has an implicit `this` qualifier. */ predicate hasImplicitThisQualifier() { this.getQualifier().(ThisAccess).isImplicit() } @@ -1029,10 +1029,10 @@ class TupleExpr extends Expr, @tuple_expr { override string toString() { result = "(..., ...)" } /** Gets the `i`th argument of this tuple. */ - Expr getArgument(int i) { result = getChild(i) } + Expr getArgument(int i) { result = this.getChild(i) } /** Gets an argument of this tuple. */ - Expr getAnArgument() { result = getArgument(_) } + Expr getAnArgument() { result = this.getArgument(_) } /** Holds if this tuple is a read access. */ deprecated predicate isReadAccess() { not this = getAnAssignOrForeachChild() } @@ -1057,11 +1057,11 @@ class TupleExpr extends Expr, @tuple_expr { */ class RefExpr extends Expr, @ref_expr { /** Gets the expression being referenced. */ - Expr getExpr() { result = getChild(0) } + Expr getExpr() { result = this.getChild(0) } override string toString() { result = "ref ..." } - override Type getType() { result = getExpr().getType() } + override Type getType() { result = this.getExpr().getType() } override string getAPrimaryQlClass() { result = "RefExpr" } } @@ -1154,7 +1154,7 @@ class DefineSymbolExpr extends Expr, @define_symbol_expr { /** Gets the name of the symbol. */ string getName() { directive_define_symbols(this, result) } - override string toString() { result = getName() } + override string toString() { result = this.getName() } override string getAPrimaryQlClass() { result = "DefineSymbolExpr" } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Literal.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Literal.qll index 0ca9f6d0db0..842e27fb96b 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Literal.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/exprs/Literal.qll @@ -23,9 +23,9 @@ class Literal extends DotNet::Literal, Expr, @literal_expr { class BoolLiteral extends Literal, @bool_literal_expr { /** Gets the value of this Boolean literal. */ boolean getBoolValue() { - getValue() = "true" and result = true + this.getValue() = "true" and result = true or - getValue() = "false" and result = false + this.getValue() = "false" and result = false } override string getAPrimaryQlClass() { result = "BoolLiteral" } @@ -105,7 +105,7 @@ class DecimalLiteral extends RealLiteral, @decimal_literal_expr { * A `string` literal, for example `"Hello, World!"`. */ class StringLiteral extends DotNet::StringLiteral, Literal, @string_literal_expr { - override string toString() { result = "\"" + getValue().replaceAll("\"", "\\\"") + "\"" } + override string toString() { result = "\"" + this.getValue().replaceAll("\"", "\\\"") + "\"" } override string getAPrimaryQlClass() { result = "StringLiteral" } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll index 36882d3b12e..723832906c6 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll @@ -239,7 +239,7 @@ module EntityFramework { private class SystemDataEntityDbSetSqlQuerySinkModelCsv extends SinkModelCsv { override predicate row(string row) { row = - ["System.Data.Entity;DbSet;false;SqlQuery;(System.String,System.Object[]);;Argument[0];sql"] + "System.Data.Entity;DbSet;false;SqlQuery;(System.String,System.Object[]);;Argument[0];sql" } } @@ -317,7 +317,7 @@ module EntityFramework { dist = 0 ) or - step(_, _, c1, t1, dist - 1) and + this.step(_, _, c1, t1, dist - 1) and dist < DataFlowPrivate::accessPathLimit() - 1 and not isNotMapped(t2) and ( @@ -374,11 +374,11 @@ module EntityFramework { } private predicate stepRev(Content c1, Type t1, Content c2, Type t2, int dist) { - step(c1, t1, c2, t2, dist) and - c2.(PropertyContent).getProperty() = getAColumnProperty(dist) + this.step(c1, t1, c2, t2, dist) and + c2.(PropertyContent).getProperty() = this.getAColumnProperty(dist) or - stepRev(c2, t2, _, _, dist + 1) and - step(c1, t1, c2, t2, dist) + this.stepRev(c2, t2, _, _, dist + 1) and + this.step(c1, t1, c2, t2, dist) } /** Gets a `SaveChanges[Async]` method. */ @@ -453,8 +453,8 @@ module EntityFramework { ) { exists(Property mapped | preservesValue = true and - input(input, mapped) and - output(output, mapped) + this.input(input, mapped) and + this.output(output, mapped) ) } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll index 3c659d86d46..2ffbfe6e7e1 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll @@ -155,13 +155,13 @@ class InvalidFormatString extends StringLiteral { int oldstartcolumn, int padding | this.getLocation().hasLocationInfo(filepath, startline, oldstartcolumn, endline, endcolumn) and - startcolumn = padding + oldstartcolumn + getInvalidOffset() and + startcolumn = padding + oldstartcolumn + this.getInvalidOffset() and toUrl(filepath, startline, startcolumn, endline, endcolumn, result) | // Single-line string literal beginning " or @" // Figure out the correct indent. startline = endline and - padding = endcolumn - oldstartcolumn - getValue().length() + padding = endcolumn - oldstartcolumn - this.getValue().length() or // Multi-line literal beginning @" startline != endline and diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/JsonNET.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/JsonNET.qll index abd820bdfe4..c0c1a765469 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/JsonNET.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/JsonNET.qll @@ -62,25 +62,25 @@ module JsonNET { boolean preservesValue ) { // ToString methods - c = getAToStringMethod() and + c = this.getAToStringMethod() and preservesValue = false and source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and sink instanceof CallableFlowSinkReturn or // Deserialize methods - c = getADeserializeMethod() and + c = this.getADeserializeMethod() and preservesValue = false and source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and sink instanceof CallableFlowSinkReturn or // Serialize methods - c = getASerializeMethod() and + c = this.getASerializeMethod() and preservesValue = false and source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and sink instanceof CallableFlowSinkReturn or // Populate methods - c = getAPopulateMethod() and + c = this.getAPopulateMethod() and preservesValue = false and source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and sink = any(CallableFlowSinkArg arg | arg.getArgumentIndex() = 1) @@ -120,21 +120,13 @@ module JsonNET { SerializedMember() { // This member has a Json attribute exists(Class attribute | attribute = this.getAnAttribute().getType() | - attribute.hasName("JsonPropertyAttribute") - or - attribute.hasName("JsonDictionaryAttribute") - or - attribute.hasName("JsonRequiredAttribute") - or - attribute.hasName("JsonArrayAttribute") - or - attribute.hasName("JsonConverterAttribute") - or - attribute.hasName("JsonExtensionDataAttribute") - or - attribute.hasName("SerializableAttribute") // System.SerializableAttribute - or - attribute.hasName("DataMemberAttribute") // System.DataMemberAttribute + attribute + .hasName([ + "JsonPropertyAttribute", "JsonDictionaryAttribute", "JsonRequiredAttribute", + "JsonArrayAttribute", "JsonConverterAttribute", "JsonExtensionDataAttribute", + "SerializableAttribute", // System.SerializableAttribute + "DataMemberAttribute" // System.DataMemberAttribute + ]) ) or // This field is a member of an explicitly serialized type @@ -175,7 +167,7 @@ module JsonNET { /** Any attribute class that marks a member to not be serialized. */ private class NotSerializedAttributeClass extends JsonClass { NotSerializedAttributeClass() { - this.hasName("JsonIgnoreAttribute") or this.hasName("NonSerializedAttribute") + this.hasName(["JsonIgnoreAttribute", "NonSerializedAttribute"]) } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/Moq.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/Moq.qll index 92811122696..e0705ac7d98 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/Moq.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/Moq.qll @@ -21,7 +21,7 @@ class ReturnsMethod extends Method { */ Expr getAReturnedExpr() { exists(MethodCall mc, Expr arg | - mc = getACall() and + mc = this.getACall() and arg = mc.getArgument(0) | if arg instanceof LambdaExpr then arg.(LambdaExpr).canReturn(result) else result = arg diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/NHibernate.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/NHibernate.qll index ddf7fd410bf..6ce6efb815f 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/NHibernate.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/NHibernate.qll @@ -28,15 +28,7 @@ module NHibernate { /** Gets a type parameter that specifies a mapped class. */ TypeParameter getAMappedObjectTp() { - exists(string methodName | - methodName = "Load<>" - or - methodName = "Merge<>" - or - methodName = "Get<>" - or - methodName = "Query<>" - | + exists(string methodName | methodName = ["Load<>", "Merge<>", "Get<>", "Query<>"] | result = this.getAMethod(methodName).(UnboundGenericMethod).getTypeParameter(0) ) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll index 20ab350ffd4..e33004f109d 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll @@ -157,7 +157,7 @@ class SystemIComparableTInterface extends SystemUnboundGenericInterface { result.getDeclaringType() = this and result.hasName("CompareTo") and result.getNumberOfParameters() = 1 and - result.getParameter(0).getType() = getTypeParameter(0) and + result.getParameter(0).getType() = this.getTypeParameter(0) and result.getReturnType() instanceof IntType } } @@ -171,7 +171,7 @@ class SystemIEquatableTInterface extends SystemUnboundGenericInterface { result.getDeclaringType() = this and result.hasName("Equals") and result.getNumberOfParameters() = 1 and - result.getParameter(0).getType() = getTypeParameter(0) and + result.getParameter(0).getType() = this.getTypeParameter(0) and result.getReturnType() instanceof BoolType } } @@ -239,7 +239,7 @@ class SystemLazyClass extends SystemUnboundGenericClass { Property getValueProperty() { result.getDeclaringType() = this and result.hasName("Value") and - result.getType() = getTypeParameter(0) + result.getType() = this.getTypeParameter(0) } } @@ -254,7 +254,7 @@ class SystemNullableStruct extends SystemUnboundGenericStruct { Property getValueProperty() { result.getDeclaringType() = this and result.hasName("Value") and - result.getType() = getTypeParameter(0) + result.getType() = this.getTypeParameter(0) } /** Gets the `HasValue` property. */ @@ -268,7 +268,7 @@ class SystemNullableStruct extends SystemUnboundGenericStruct { Method getAGetValueOrDefaultMethod() { result.getDeclaringType() = this and result.hasName("GetValueOrDefault") and - result.getReturnType() = getTypeParameter(0) + result.getReturnType() = this.getTypeParameter(0) } } @@ -588,7 +588,7 @@ class IEquatableEqualsMethod extends Method { m = any(SystemIEquatableTInterface i).getAConstructedGeneric().getAMethod() and m.getUnboundDeclaration() = any(SystemIEquatableTInterface i).getEqualsMethod() | - this = m or getAnUltimateImplementee() = m + this = m or this.getAnUltimateImplementee() = m ) } } @@ -677,7 +677,7 @@ class DisposeMethod extends Method { /** A method with the signature `void Dispose(bool)`. */ library class DisposeBoolMethod extends Method { DisposeBoolMethod() { - hasName("Dispose") and + this.hasName("Dispose") and this.getReturnType() instanceof VoidType and this.getNumberOfParameters() = 1 and this.getParameter(0).getType() instanceof BoolType diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/WCF.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/WCF.qll index 655648d88c9..befb5f3ae1f 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/WCF.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/WCF.qll @@ -49,7 +49,7 @@ class OperationMethod extends Method { i.getAnAttribute() instanceof ServiceContractAttribute and m.getDeclaringType() = i and m.getAnAttribute() instanceof OperationContractAttribute and - getImplementee() = m + this.getImplementee() = m ) } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll index 5fe6665bd47..a918b603818 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll @@ -6,129 +6,133 @@ import semmle.code.csharp.frameworks.Microsoft /** The `Microsoft.AspNetCore` namespace. */ class MicrosoftAspNetCoreNamespace extends Namespace { MicrosoftAspNetCoreNamespace() { - getParentNamespace() instanceof MicrosoftNamespace and - hasName("AspNetCore") + this.getParentNamespace() instanceof MicrosoftNamespace and + this.hasName("AspNetCore") } } /** The `Microsoft.AspNetCore.Mvc` namespace. */ class MicrosoftAspNetCoreMvcNamespace extends Namespace { MicrosoftAspNetCoreMvcNamespace() { - getParentNamespace() instanceof MicrosoftAspNetCoreNamespace and - hasName("Mvc") + this.getParentNamespace() instanceof MicrosoftAspNetCoreNamespace and + this.hasName("Mvc") } } /** The 'Microsoft.AspNetCore.Mvc.ViewFeatures' namespace. */ class MicrosoftAspNetCoreMvcViewFeatures extends Namespace { MicrosoftAspNetCoreMvcViewFeatures() { - getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and - hasName("ViewFeatures") + this.getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and + this.hasName("ViewFeatures") } } /** The 'Microsoft.AspNetCore.Mvc.Rendering' namespace. */ class MicrosoftAspNetCoreMvcRendering extends Namespace { MicrosoftAspNetCoreMvcRendering() { - getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and - hasName("Rendering") + this.getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and + this.hasName("Rendering") } } /** An attribute whose type is in the `Microsoft.AspNetCore.Mvc` namespace. */ class MicrosoftAspNetCoreMvcAttribute extends Attribute { MicrosoftAspNetCoreMvcAttribute() { - getType().getNamespace() instanceof MicrosoftAspNetCoreMvcNamespace + this.getType().getNamespace() instanceof MicrosoftAspNetCoreMvcNamespace } } /** A `Microsoft.AspNetCore.Mvc.HttpPost` attribute. */ class MicrosoftAspNetCoreMvcHttpPostAttribute extends MicrosoftAspNetCoreMvcAttribute { - MicrosoftAspNetCoreMvcHttpPostAttribute() { getType().hasName("HttpPostAttribute") } + MicrosoftAspNetCoreMvcHttpPostAttribute() { this.getType().hasName("HttpPostAttribute") } } /** A `Microsoft.AspNetCore.Mvc.HttpPut` attribute. */ class MicrosoftAspNetCoreMvcHttpPutAttribute extends MicrosoftAspNetCoreMvcAttribute { - MicrosoftAspNetCoreMvcHttpPutAttribute() { getType().hasName("HttpPutAttribute") } + MicrosoftAspNetCoreMvcHttpPutAttribute() { this.getType().hasName("HttpPutAttribute") } } /** A `Microsoft.AspNetCore.Mvc.HttpDelete` attribute. */ class MicrosoftAspNetCoreMvcHttpDeleteAttribute extends MicrosoftAspNetCoreMvcAttribute { - MicrosoftAspNetCoreMvcHttpDeleteAttribute() { getType().hasName("HttpDeleteAttribute") } + MicrosoftAspNetCoreMvcHttpDeleteAttribute() { this.getType().hasName("HttpDeleteAttribute") } } /** A `Microsoft.AspNetCore.Mvc.NonAction` attribute. */ class MicrosoftAspNetCoreMvcNonActionAttribute extends MicrosoftAspNetCoreMvcAttribute { - MicrosoftAspNetCoreMvcNonActionAttribute() { getType().hasName("NonActionAttribute") } + MicrosoftAspNetCoreMvcNonActionAttribute() { this.getType().hasName("NonActionAttribute") } } /** The `Microsoft.AspNetCore.Antiforgery` namespace. */ class MicrosoftAspNetCoreAntiforgeryNamespace extends Namespace { MicrosoftAspNetCoreAntiforgeryNamespace() { - getParentNamespace() instanceof MicrosoftAspNetCoreNamespace and - hasName("Antiforgery") + this.getParentNamespace() instanceof MicrosoftAspNetCoreNamespace and + this.hasName("Antiforgery") } } /** The `Microsoft.AspNetCore.Mvc.Filters` namespace. */ class MicrosoftAspNetCoreMvcFilters extends Namespace { MicrosoftAspNetCoreMvcFilters() { - getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and - hasName("Filters") + this.getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and + this.hasName("Filters") } } /** The `Microsoft.AspNetCore.Mvc.Filters.IFilterMetadataInterface` interface. */ class MicrosoftAspNetCoreMvcIFilterMetadataInterface extends Interface { MicrosoftAspNetCoreMvcIFilterMetadataInterface() { - getNamespace() instanceof MicrosoftAspNetCoreMvcFilters and - hasName("IFilterMetadata") + this.getNamespace() instanceof MicrosoftAspNetCoreMvcFilters and + this.hasName("IFilterMetadata") } } /** The `Microsoft.AspNetCore.IAuthorizationFilter` interface. */ class MicrosoftAspNetCoreIAuthorizationFilterInterface extends Interface { MicrosoftAspNetCoreIAuthorizationFilterInterface() { - getNamespace() instanceof MicrosoftAspNetCoreMvcFilters and - hasName("IAsyncAuthorizationFilter") + this.getNamespace() instanceof MicrosoftAspNetCoreMvcFilters and + this.hasName("IAsyncAuthorizationFilter") } /** Gets the `OnAuthorizationAsync` method. */ - Method getOnAuthorizationMethod() { result = getAMethod("OnAuthorizationAsync") } + Method getOnAuthorizationMethod() { result = this.getAMethod("OnAuthorizationAsync") } } /** The `Microsoft.AspNetCore.IAntiforgery` interface. */ class MicrosoftAspNetCoreIAntiForgeryInterface extends Interface { MicrosoftAspNetCoreIAntiForgeryInterface() { - getNamespace() instanceof MicrosoftAspNetCoreAntiforgeryNamespace and - hasName("IAntiforgery") + this.getNamespace() instanceof MicrosoftAspNetCoreAntiforgeryNamespace and + this.hasName("IAntiforgery") } /** Gets the `ValidateRequestAsync` method. */ - Method getValidateMethod() { result = getAMethod("ValidateRequestAsync") } + Method getValidateMethod() { result = this.getAMethod("ValidateRequestAsync") } } /** The `Microsoft.AspNetCore.DefaultAntiForgery` class, or another user-supplied class that implements `IAntiForgery`. */ class AntiForgeryClass extends Class { - AntiForgeryClass() { getABaseInterface*() instanceof MicrosoftAspNetCoreIAntiForgeryInterface } + AntiForgeryClass() { + this.getABaseInterface*() instanceof MicrosoftAspNetCoreIAntiForgeryInterface + } /** Gets the `ValidateRequestAsync` method. */ - Method getValidateMethod() { result = getAMethod("ValidateRequestAsync") } + Method getValidateMethod() { result = this.getAMethod("ValidateRequestAsync") } } /** An authorization filter class defined by AspNetCore or the user. */ class AuthorizationFilterClass extends Class { AuthorizationFilterClass() { - getABaseInterface*() instanceof MicrosoftAspNetCoreIAuthorizationFilterInterface + this.getABaseInterface*() instanceof MicrosoftAspNetCoreIAuthorizationFilterInterface } /** Gets the `OnAuthorization` method provided by this filter. */ - Method getOnAuthorizationMethod() { result = getAMethod("OnAuthorizationAsync") } + Method getOnAuthorizationMethod() { result = this.getAMethod("OnAuthorizationAsync") } } /** An attribute whose type has a name like `[Auto...]Validate[...]Anti[Ff]orgery[...Token]Attribute`. */ class ValidateAntiForgeryAttribute extends Attribute { - ValidateAntiForgeryAttribute() { getType().getName().matches("%Validate%Anti_orgery%Attribute") } + ValidateAntiForgeryAttribute() { + this.getType().getName().matches("%Validate%Anti_orgery%Attribute") + } } /** @@ -137,43 +141,43 @@ class ValidateAntiForgeryAttribute extends Attribute { */ class ValidateAntiforgeryTokenAuthorizationFilter extends Class { ValidateAntiforgeryTokenAuthorizationFilter() { - getABaseInterface*() instanceof MicrosoftAspNetCoreMvcIFilterMetadataInterface and - getName().matches("%Validate%Anti_orgery%") + this.getABaseInterface*() instanceof MicrosoftAspNetCoreMvcIFilterMetadataInterface and + this.getName().matches("%Validate%Anti_orgery%") } } /** The `Microsoft.AspNetCore.Mvc.Filters.FilterCollection` class. */ class MicrosoftAspNetCoreMvcFilterCollection extends Class { MicrosoftAspNetCoreMvcFilterCollection() { - getNamespace() instanceof MicrosoftAspNetCoreMvcFilters and - hasName("FilterCollection") + this.getNamespace() instanceof MicrosoftAspNetCoreMvcFilters and + this.hasName("FilterCollection") } /** Gets an `Add` method. */ Method getAddMethod() { - result = getAMethod("Add") or - result = getABaseType().getAMethod("Add") + result = this.getAMethod("Add") or + result = this.getABaseType().getAMethod("Add") } } /** The `Microsoft.AspNetCore.Mvc.MvcOptions` class. */ class MicrosoftAspNetCoreMvcOptions extends Class { MicrosoftAspNetCoreMvcOptions() { - getNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and - hasName("MvcOptions") + this.getNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and + this.hasName("MvcOptions") } /** Gets the `Filters` property. */ - Property getFilterCollectionProperty() { result = getProperty("Filters") } + Property getFilterCollectionProperty() { result = this.getProperty("Filters") } } /** The base class for controllers in MVC, i.e. `Microsoft.AspNetCore.Mvc.Controller` or `Microsoft.AspNetCore.Mvc.ControllerBase` class. */ class MicrosoftAspNetCoreMvcControllerBaseClass extends Class { MicrosoftAspNetCoreMvcControllerBaseClass() { - getNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and + this.getNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and ( - hasName("Controller") or - hasName("ControllerBase") + this.hasName("Controller") or + this.hasName("ControllerBase") ) } } @@ -181,12 +185,12 @@ class MicrosoftAspNetCoreMvcControllerBaseClass extends Class { /** A subtype of `Microsoft.AspNetCore.Mvc.Controller` or `Microsoft.AspNetCore.Mvc.ControllerBase`. */ class MicrosoftAspNetCoreMvcController extends Class { MicrosoftAspNetCoreMvcController() { - getABaseType*() instanceof MicrosoftAspNetCoreMvcControllerBaseClass + this.getABaseType*() instanceof MicrosoftAspNetCoreMvcControllerBaseClass } /** Gets an action method for this controller. */ Method getAnActionMethod() { - result = getAMethod() and + result = this.getAMethod() and result.isPublic() and not result.isStatic() and not result.getAnAttribute() instanceof MicrosoftAspNetCoreMvcNonActionAttribute @@ -208,12 +212,12 @@ class MicrosoftAspNetCoreMvcController extends Class { /** The `Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper` interface. */ class MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface extends Interface { MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface() { - getNamespace() instanceof MicrosoftAspNetCoreMvcRendering and - hasName("IHtmlHelper") + this.getNamespace() instanceof MicrosoftAspNetCoreMvcRendering and + this.hasName("IHtmlHelper") } /** Gets the `Raw` method. */ - Method getRawMethod() { result = getAMethod("Raw") } + Method getRawMethod() { result = this.getAMethod("Raw") } } /** A class deriving from `Microsoft.AspNetCore.Mvc.Razor.RazorPageBase`, implements Razor page in ASPNET Core. */ @@ -223,7 +227,7 @@ class MicrosoftAspNetCoreMvcRazorPageBase extends Class { } /** Gets the `WriteLiteral` method. */ - Method getWriteLiteralMethod() { result = getAMethod("WriteLiteral") } + Method getWriteLiteralMethod() { result = this.getAMethod("WriteLiteral") } } /** A class deriving from `Microsoft.AspNetCore.Http.HttpRequest`, implements `HttpRequest` in ASP.NET Core. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll index a3616e57522..2b632d2b07c 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll @@ -41,8 +41,8 @@ class SystemCollectionsGenericIComparerTInterface extends SystemCollectionsGener result.getDeclaringType() = this and result.hasName("Compare") and result.getNumberOfParameters() = 2 and - result.getParameter(0).getType() = getTypeParameter(0) and - result.getParameter(1).getType() = getTypeParameter(0) and + result.getParameter(0).getType() = this.getTypeParameter(0) and + result.getParameter(1).getType() = this.getTypeParameter(0) and result.getReturnType() instanceof IntType } } @@ -56,8 +56,8 @@ class SystemCollectionsGenericIEqualityComparerTInterface extends SystemCollecti result.getDeclaringType() = this and result.hasName("Equals") and result.getNumberOfParameters() = 2 and - result.getParameter(0).getType() = getTypeParameter(0) and - result.getParameter(1).getType() = getTypeParameter(0) and + result.getParameter(0).getType() = this.getTypeParameter(0) and + result.getParameter(1).getType() = this.getTypeParameter(0) and result.getReturnType() instanceof BoolType } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/data/SqlClient.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/data/SqlClient.qll index 858100fe7f7..c3b6f1fdd6d 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/data/SqlClient.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/data/SqlClient.qll @@ -13,7 +13,7 @@ class SystemDataSqlClientNamespace extends Namespace { /** A class in the `System.Data.SqlClient` namespace. */ class SystemDataSqlClientClass extends Class { - SystemDataSqlClientClass() { getNamespace() instanceof SystemDataSqlClientNamespace } + SystemDataSqlClientClass() { this.getNamespace() instanceof SystemDataSqlClientNamespace } } /** The `System.Data.SqlClient.SqlDataAdapter` class. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll index 1820192da11..531fa6ef721 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll @@ -67,7 +67,7 @@ class RegexOperation extends Call { */ Expr getInput() { if this instanceof MethodCall - then result = getArgumentForName("input") + then result = this.getArgumentForName("input") else exists(MethodCall call | call.getTarget() = any(SystemTextRegularExpressionsRegexClass rs).getAMethod() and diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/web/Mvc.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/web/Mvc.qll index 78aaa6dc065..b2051a8464f 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/web/Mvc.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/web/Mvc.qll @@ -6,8 +6,8 @@ private import semmle.code.csharp.frameworks.system.Web /** The `System.Web.Mvc` namespace. */ class SystemWebMvcNamespace extends Namespace { SystemWebMvcNamespace() { - getParentNamespace() instanceof SystemWebNamespace and - hasName("Mvc") + this.getParentNamespace() instanceof SystemWebNamespace and + this.hasName("Mvc") } } @@ -31,7 +31,7 @@ class SystemWebMvcHtmlHelperClass extends SystemWebMvcClass { /** An attribute whose type is in the `System.Web.Mvc` namespace. */ class SystemWebMvcAttribute extends Attribute { - SystemWebMvcAttribute() { getType().getNamespace() instanceof SystemWebMvcNamespace } + SystemWebMvcAttribute() { this.getType().getNamespace() instanceof SystemWebMvcNamespace } } /** An attribute whose type is `System.Web.Mvc.HttpPost`. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/web/WebPages.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/web/WebPages.qll index 0d43f76719b..915acbfe41f 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/web/WebPages.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/frameworks/system/web/WebPages.qll @@ -6,16 +6,16 @@ private import semmle.code.csharp.frameworks.system.Web /** The `System.Web.WebPages` namespace. */ class SystemWebWebPagesNamespace extends Namespace { SystemWebWebPagesNamespace() { - getParentNamespace() instanceof SystemWebNamespace and - hasName("WebPages") + this.getParentNamespace() instanceof SystemWebNamespace and + this.hasName("WebPages") } } /** The `System.Web.WebPages.WebPageExecutingBase` class. */ class SystemWebWebPagesWebPageExecutingBaseClass extends Class { SystemWebWebPagesWebPageExecutingBaseClass() { - getNamespace() instanceof SystemWebWebPagesNamespace and - hasName("WebPageExecutingBase") + this.getNamespace() instanceof SystemWebWebPagesNamespace and + this.hasName("WebPageExecutingBase") } } @@ -24,8 +24,8 @@ class WebPageClass extends Class { WebPageClass() { this.getBaseClass*() instanceof SystemWebWebPagesWebPageExecutingBaseClass } /** Gets the `WriteLiteral` method. */ - Method getWriteLiteralMethod() { result = getAMethod("WriteLiteral") } + Method getWriteLiteralMethod() { result = this.getAMethod("WriteLiteral") } /** Gets the `WriteLiteralTo` method. */ - Method getWriteLiteralToMethod() { result = getAMethod("WriteLiteralTo") } + Method getWriteLiteralToMethod() { result = this.getAMethod("WriteLiteralTo") } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/PrivateData.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/PrivateData.qll index 10bb06679b7..3ca81e614ad 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/PrivateData.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/PrivateData.qll @@ -14,26 +14,22 @@ import semmle.code.csharp.frameworks.system.windows.Forms /** A string for `match` that identifies strings that look like they represent private data. */ private string privateNames() { - // Inspired by the list on https://cwe.mitre.org/data/definitions/359.html - // Government identifiers, such as Social Security Numbers - result = "%social%security%number%" or - // Contact information, such as home addresses and telephone numbers - result = "%postcode%" or - result = "%zipcode%" or - result = "%telephone%" or - // Geographic location - where the user is (or was) - result = "%latitude%" or - result = "%longitude%" or - // Financial data - such as credit card numbers, salary, bank accounts, and debts - result = "%creditcard%" or - result = "%salary%" or - result = "%bankaccount%" or - // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. - result = "%email%" or - result = "%mobile%" or - result = "%employer%" or - // Health - medical conditions, insurance status, prescription records - result = "%medical%" + result = + [ + // Inspired by the list on https://cwe.mitre.org/data/definitions/359.html + // Government identifiers, such as Social Security Numbers + "%social%security%number%", + // Contact information, such as home addresses and telephone numbers + "%postcode%", "%zipcode%", "%telephone%", + // Geographic location - where the user is (or was) + "%latitude%", "%longitude%", + // Financial data - such as credit card numbers, salary, bank accounts, and debts + "%creditcard%", "%salary%", "%bankaccount%", + // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. + "%email%", "%mobile%", "%employer%", + // Health - medical conditions, insurance status, prescription records + "%medical%" + ] } /** An expression that might contain private data. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/SensitiveActions.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/SensitiveActions.qll index cc7701ad318..483000895aa 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/SensitiveActions.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/SensitiveActions.qll @@ -72,7 +72,7 @@ class SensitiveProperty extends Property { /** A parameter to a library method that may hold a sensitive value. */ class SensitiveLibraryParameter extends Parameter { SensitiveLibraryParameter() { - fromLibrary() and + this.fromLibrary() and exists(string s | this.getName().toLowerCase() = s | s.matches(suspicious())) } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/cryptography/HardcodedSymmetricEncryptionKey.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/cryptography/HardcodedSymmetricEncryptionKey.qll index 915dae12a9f..3cf3fa107bf 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/cryptography/HardcodedSymmetricEncryptionKey.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/cryptography/HardcodedSymmetricEncryptionKey.qll @@ -21,7 +21,7 @@ module HardcodedSymmetricEncryptionKey { abstract class Sanitizer extends DataFlow::ExprNode { } private class ByteArrayType extends ArrayType { - ByteArrayType() { getElementType() instanceof ByteType } + ByteArrayType() { this.getElementType() instanceof ByteType } } private class ByteArrayLiteralSource extends Source { @@ -49,7 +49,7 @@ module HardcodedSymmetricEncryptionKey { private class SymmetricEncryptionCreateEncryptorSink extends Sink { SymmetricEncryptionCreateEncryptorSink() { exists(SymmetricAlgorithm ag, MethodCall mc | mc = ag.getASymmetricEncryptor() | - asExpr() = mc.getArgumentForName("rgbKey") + this.asExpr() = mc.getArgumentForName("rgbKey") ) } @@ -59,7 +59,7 @@ module HardcodedSymmetricEncryptionKey { private class SymmetricEncryptionCreateDecryptorSink extends Sink { SymmetricEncryptionCreateDecryptorSink() { exists(SymmetricAlgorithm ag, MethodCall mc | mc = ag.getASymmetricDecryptor() | - asExpr() = mc.getArgumentForName("rgbKey") + this.asExpr() = mc.getArgumentForName("rgbKey") ) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll index bccd71d7096..fd643b5b7f0 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll @@ -69,7 +69,7 @@ class ExternalAPIDataNode extends DataFlow::Node { int getIndex() { result = i } /** Gets the description of the callable being called. */ - string getCallableDescription() { result = getCallable().getQualifiedName() } + string getCallableDescription() { result = this.getCallable().getQualifiedName() } } /** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */ @@ -108,7 +108,7 @@ class ExternalAPIUsedWithUntrustedData extends TExternalAPI { /** Gets the number of untrusted sources used with this external API. */ int getNumberOfUntrustedSources() { - result = count(getUntrustedDataNode().getAnUntrustedSource()) + result = count(this.getUntrustedDataNode().getAnUntrustedSource()) } /** Gets a textual representation of this element. */ diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll index 4be005be4de..d0999605b61 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll @@ -166,7 +166,7 @@ class AspInlineMember extends AspInlineCode { Member getMember() { result = member } /** Gets the type of this member. */ - Type getType() { result = getMemberType(getMember()) } + Type getType() { result = getMemberType(this.getMember()) } } /** Gets a value that is written to the member accessed by the given `AspInlineMember`. */ @@ -251,7 +251,7 @@ private class HttpResponseBaseSink extends Sink { */ private class StringContentSinkModelCsv extends SinkModelCsv { override predicate row(string row) { - row = ["System.Net.Http;StringContent;false;StringContent;;;Argument[0];xss"] + row = "System.Net.Http;StringContent;false;StringContent;;;Argument[0];xss" } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll index 673473eb49b..30736bdabf6 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll @@ -38,12 +38,7 @@ class TraceMessageSink extends ExternalLocationSink { trace.hasQualifiedName("System.Diagnostics", "TraceSource") | this.getExpr() = trace.getAMethod().getACall().getArgumentForName(parameterName) and - ( - parameterName = "format" or - parameterName = "args" or - parameterName = "message" or - parameterName = "category" - ) + parameterName = ["format", "args", "message", "category"] ) } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll index 25647e50f2e..2448f80e8ba 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll @@ -43,15 +43,8 @@ class AspNetQueryStringMember extends Member { * request. */ private string getHttpRequestFlowPropertyNames() { - result = "QueryString" or - result = "Headers" or - result = "RawUrl" or - result = "Url" or - result = "Cookies" or - result = "Form" or - result = "Params" or - result = "Path" or - result = "PathInfo" + result = + ["QueryString", "Headers", "RawUrl", "Url", "Cookies", "Form", "Params", "Path", "PathInfo"] } /** A data flow source of remote user input (ASP.NET query string). */ @@ -86,7 +79,7 @@ class AspNetUnvalidatedQueryStringRemoteFlowSource extends AspNetRemoteFlowSourc /** A data flow source of remote user input (ASP.NET user input). */ class AspNetUserInputRemoteFlowSource extends AspNetRemoteFlowSource, DataFlow::ExprNode { - AspNetUserInputRemoteFlowSource() { getType() instanceof SystemWebUIWebControlsTextBoxClass } + AspNetUserInputRemoteFlowSource() { this.getType() instanceof SystemWebUIWebControlsTextBoxClass } override string getSourceType() { result = "ASP.NET user input" } } @@ -113,7 +106,7 @@ class AspNetServiceRemoteFlowSource extends RemoteFlowSource, DataFlow::Paramete /** A data flow source of remote user input (ASP.NET request message). */ class SystemNetHttpRequestMessageRemoteFlowSource extends RemoteFlowSource, DataFlow::ExprNode { SystemNetHttpRequestMessageRemoteFlowSource() { - getType() instanceof SystemWebHttpRequestMessageClass + this.getType() instanceof SystemWebHttpRequestMessageClass } override string getSourceType() { result = "ASP.NET request message" } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/xml/InsecureXMLQuery.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/xml/InsecureXMLQuery.qll index 2483452113a..e885fdb2778 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/xml/InsecureXMLQuery.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/csharp/security/xml/InsecureXMLQuery.qll @@ -157,8 +157,8 @@ module XmlReader { override predicate isUnsafe(string reason) { exists(string dtdReason, string resolverReason | - dtdEnabled(dtdReason, _) and - insecureResolver(resolverReason, _) and + this.dtdEnabled(dtdReason, _) and + this.insecureResolver(resolverReason, _) and reason = dtdReason + ", " + resolverReason ) } @@ -209,9 +209,7 @@ module XmlReader { /** Provides predicates related to `System.Xml.XmlTextReader`. */ module XmlTextReader { private class InsecureXmlTextReader extends InsecureXmlProcessing, ObjectCreation { - InsecureXmlTextReader() { - this.getObjectType().(ValueOrRefType).hasQualifiedName("System.Xml.XmlTextReader") - } + InsecureXmlTextReader() { this.getObjectType().hasQualifiedName("System.Xml.XmlTextReader") } override predicate isUnsafe(string reason) { not exists(Expr xmlResolverVal | diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Callable.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Callable.qll index 2beccfe422c..0a63e5c95cd 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Callable.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Callable.qll @@ -75,7 +75,7 @@ class Callable extends Parameterizable, @dotnet_callable { } private string getReturnTypeLabel() { - result = getReturnType().getLabel() + result = this.getReturnType().getLabel() or not exists(this.getReturnType()) and result = "System.Void" } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Declaration.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Declaration.qll index 7f78077d766..60e434f9ae6 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Declaration.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Declaration.qll @@ -16,7 +16,7 @@ class Declaration extends NamedElement, @dotnet_declaration { string getUndecoratedName() { none() } /** Holds if this element has undecorated name 'name'. */ - final predicate hasUndecoratedName(string name) { name = getUndecoratedName() } + final predicate hasUndecoratedName(string name) { name = this.getUndecoratedName() } /** Gets the type containing this declaration, if any. */ Type getDeclaringType() { none() } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Element.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Element.qll index 3b1955887f9..d8c27f88e10 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Element.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Element.qll @@ -35,7 +35,7 @@ class Element extends @dotnet_element { * Gets the "language" of this program element, as defined by the extension of the filename. * For example, C# has language "cs", and Visual Basic has language "vb". */ - final string getLanguage() { result = getLocation().getFile().getExtension() } + final string getLanguage() { result = this.getLocation().getFile().getExtension() } /** Gets the full textual representation of this element, including type information. */ string toStringWithTypes() { result = this.toString() } @@ -43,7 +43,7 @@ class Element extends @dotnet_element { /** * Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. */ - final string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") } + final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } /** * Gets the name of a primary CodeQL class to which this element belongs. @@ -66,7 +66,7 @@ class NamedElement extends Element, @dotnet_named_element { string getName() { none() } /** Holds if this element has name 'name'. */ - final predicate hasName(string name) { name = getName() } + final predicate hasName(string name) { name = this.getName() } /** * Gets the fully qualified name of this element, for example the diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Expr.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Expr.qll index e5bea3a52d7..15d658f54c2 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Expr.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Expr.qll @@ -45,7 +45,7 @@ class Call extends Expr, @dotnet_call { Expr getArgument(int i) { none() } /** Gets an argument to this call. */ - Expr getAnArgument() { result = getArgument(_) } + Expr getAnArgument() { result = this.getArgument(_) } /** Gets the expression that is supplied for parameter `p`. */ Expr getArgumentForParameter(Parameter p) { none() } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Generics.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Generics.qll index 9b236cdbfb9..f84718d4b82 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Generics.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Generics.qll @@ -14,7 +14,7 @@ abstract class UnboundGeneric extends Generic { abstract TypeParameter getTypeParameter(int i); /** Gets a type parameter. */ - TypeParameter getATypeParameter() { result = getTypeParameter(_) } + TypeParameter getATypeParameter() { result = this.getTypeParameter(_) } /** * Gets one of the constructed versions of this declaration, @@ -32,7 +32,7 @@ abstract class ConstructedGeneric extends Generic { abstract Type getTypeArgument(int i); /** Gets a type argument. */ - Type getATypeArgument() { result = getTypeArgument(_) } + Type getATypeArgument() { result = this.getTypeArgument(_) } /** * Gets the unbound generic declaration from which this declaration was diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Namespace.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Namespace.qll index 55b42e737db..324448728de 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Namespace.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Namespace.qll @@ -33,7 +33,7 @@ class Namespace extends Declaration, @namespace { override string toString() { result = this.getQualifiedName() } /** Holds if this is the global namespace. */ - final predicate isGlobalNamespace() { getName() = "" } + final predicate isGlobalNamespace() { this.getName() = "" } /** Gets the simple name of this namespace, for example `IO` in `System.IO`. */ final override string getName() { namespaces(this, result) } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Type.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Type.qll index 5dc9c409c18..81fefa96550 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Type.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Type.qll @@ -24,11 +24,11 @@ class ValueOrRefType extends Type, @dotnet_valueorreftype { Namespace getDeclaringNamespace() { none() } private string getPrefixWithTypes() { - result = getDeclaringType().getLabel() + "." + result = this.getDeclaringType().getLabel() + "." or - if getDeclaringNamespace().isGlobalNamespace() + if this.getDeclaringNamespace().isGlobalNamespace() then result = "" - else result = getDeclaringNamespace().getQualifiedName() + "." + else result = this.getDeclaringNamespace().getQualifiedName() + "." } pragma[noinline] @@ -64,9 +64,9 @@ class TypeParameter extends Type, @dotnet_type_parameter { /** Gets the index of this type parameter. For example the index of `U` in `Func` is 1. */ int getIndex() { none() } - final override string getLabel() { result = "!" + getIndex() } + final override string getLabel() { result = "!" + this.getIndex() } - override string getUndecoratedName() { result = "!" + getIndex() } + override string getUndecoratedName() { result = "!" + this.getIndex() } } /** A pointer type. */ @@ -76,9 +76,9 @@ class PointerType extends Type, @dotnet_pointer_type { override string getName() { result = this.getReferentType().getName() + "*" } - final override string getLabel() { result = getReferentType().getLabel() + "*" } + final override string getLabel() { result = this.getReferentType().getLabel() + "*" } - override string toStringWithTypes() { result = getReferentType().toStringWithTypes() + "*" } + override string toStringWithTypes() { result = this.getReferentType().toStringWithTypes() + "*" } } /** An array type. */ @@ -86,7 +86,7 @@ class ArrayType extends ValueOrRefType, @dotnet_array_type { /** Gets the type of the array element. */ Type getElementType() { none() } - final override string getLabel() { result = getElementType().getLabel() + "[]" } + final override string getLabel() { result = this.getElementType().getLabel() + "[]" } - override string toStringWithTypes() { result = getElementType().toStringWithTypes() + "[]" } + override string toStringWithTypes() { result = this.getElementType().toStringWithTypes() + "[]" } } diff --git a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Variable.qll b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Variable.qll index 9f9a12e7d98..ee9ccebbbe6 100644 --- a/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Variable.qll +++ b/repo-tests/codeql/csharp/ql/lib/semmle/code/dotnet/Variable.qll @@ -15,10 +15,10 @@ class Field extends Variable, Member, @dotnet_field { } /** A parameter to a .Net callable, property or function pointer type. */ class Parameter extends Variable, @dotnet_parameter { /** Gets the raw position of this parameter, including the `this` parameter at index 0. */ - final int getRawPosition() { this = getDeclaringElement().getRawParameter(result) } + final int getRawPosition() { this = this.getDeclaringElement().getRawParameter(result) } /** Gets the position of this parameter, excluding the `this` parameter. */ - int getPosition() { this = getDeclaringElement().getParameter(result) } + int getPosition() { this = this.getDeclaringElement().getParameter(result) } /** Gets the callable defining this parameter. */ Callable getCallable() { result = this.getDeclaringElement() } diff --git a/repo-tests/codeql/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql b/repo-tests/codeql/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql index 2ade29f6fa4..e9f9b6cb8c6 100644 --- a/repo-tests/codeql/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql +++ b/repo-tests/codeql/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql @@ -29,17 +29,22 @@ predicate returnsCollection(Callable c, Field f) { not c.(Modifiable).isStatic() } -predicate mayWriteToCollection(Expr modified) { - modified instanceof CollectionModificationAccess +predicate nodeMayWriteToCollection(Node modified) { + modified.asExpr() instanceof CollectionModificationAccess or - exists(Expr mid | mayWriteToCollection(mid) | localExprFlow(modified, mid)) + exists(Node mid | nodeMayWriteToCollection(mid) | localFlowStep(modified, mid)) or - exists(MethodCall mid, Callable c | mayWriteToCollection(mid) | - mid.getTarget() = c and - c.canReturn(modified) + exists(Node mid, MethodCall mc, Callable c | nodeMayWriteToCollection(mid) | + mc = mid.asExpr() and + mc.getTarget() = c and + c.canReturn(modified.asExpr()) ) } +predicate mayWriteToCollection(Expr modified) { + nodeMayWriteToCollection(any(ExprNode n | n.getExpr() = modified)) +} + predicate modificationAfter(Expr before, Expr after) { mayWriteToCollection(after) and localFlowStep+(exprNode(before), exprNode(after)) diff --git a/repo-tests/codeql/csharp/ql/src/Bad Practices/Magic Constants/MagicConstants.qll b/repo-tests/codeql/csharp/ql/src/Bad Practices/Magic Constants/MagicConstants.qll index d604dfaeefe..b65cdcd1961 100644 --- a/repo-tests/codeql/csharp/ql/src/Bad Practices/Magic Constants/MagicConstants.qll +++ b/repo-tests/codeql/csharp/ql/src/Bad Practices/Magic Constants/MagicConstants.qll @@ -7,179 +7,30 @@ import semmle.code.csharp.frameworks.System */ private predicate trivialPositiveIntValue(string s) { - s = "0" or - s = "1" or - s = "2" or - s = "3" or - s = "4" or - s = "5" or - s = "6" or - s = "7" or - s = "8" or - s = "9" or - s = "10" or - s = "11" or - s = "12" or - s = "13" or - s = "14" or - s = "15" or - s = "16" or - s = "17" or - s = "18" or - s = "19" or - s = "20" or - s = "16" or - s = "32" or - s = "64" or - s = "128" or - s = "256" or - s = "512" or - s = "1024" or - s = "2048" or - s = "4096" or - s = "16384" or - s = "32768" or - s = "65536" or - s = "1048576" or - s = "2147483648" or - s = "4294967296" or - s = "15" or - s = "31" or - s = "63" or - s = "127" or - s = "255" or - s = "511" or - s = "1023" or - s = "2047" or - s = "4095" or - s = "16383" or - s = "32767" or - s = "65535" or - s = "1048577" or - s = "2147483647" or - s = "4294967295" or - s = "0x00000001" or - s = "0x00000002" or - s = "0x00000004" or - s = "0x00000008" or - s = "0x00000010" or - s = "0x00000020" or - s = "0x00000040" or - s = "0x00000080" or - s = "0x00000100" or - s = "0x00000200" or - s = "0x00000400" or - s = "0x00000800" or - s = "0x00001000" or - s = "0x00002000" or - s = "0x00004000" or - s = "0x00008000" or - s = "0x00010000" or - s = "0x00020000" or - s = "0x00040000" or - s = "0x00080000" or - s = "0x00100000" or - s = "0x00200000" or - s = "0x00400000" or - s = "0x00800000" or - s = "0x01000000" or - s = "0x02000000" or - s = "0x04000000" or - s = "0x08000000" or - s = "0x10000000" or - s = "0x20000000" or - s = "0x40000000" or - s = "0x80000000" or - s = "0x00000001" or - s = "0x00000003" or - s = "0x00000007" or - s = "0x0000000f" or - s = "0x0000001f" or - s = "0x0000003f" or - s = "0x0000007f" or - s = "0x000000ff" or - s = "0x000001ff" or - s = "0x000003ff" or - s = "0x000007ff" or - s = "0x00000fff" or - s = "0x00001fff" or - s = "0x00003fff" or - s = "0x00007fff" or - s = "0x0000ffff" or - s = "0x0001ffff" or - s = "0x0003ffff" or - s = "0x0007ffff" or - s = "0x000fffff" or - s = "0x001fffff" or - s = "0x003fffff" or - s = "0x007fffff" or - s = "0x00ffffff" or - s = "0x01ffffff" or - s = "0x03ffffff" or - s = "0x07ffffff" or - s = "0x0fffffff" or - s = "0x1fffffff" or - s = "0x3fffffff" or - s = "0x7fffffff" or - s = "0xffffffff" or - s = "0x0001" or - s = "0x0002" or - s = "0x0004" or - s = "0x0008" or - s = "0x0010" or - s = "0x0020" or - s = "0x0040" or - s = "0x0080" or - s = "0x0100" or - s = "0x0200" or - s = "0x0400" or - s = "0x0800" or - s = "0x1000" or - s = "0x2000" or - s = "0x4000" or - s = "0x8000" or - s = "0x0001" or - s = "0x0003" or - s = "0x0007" or - s = "0x000f" or - s = "0x001f" or - s = "0x003f" or - s = "0x007f" or - s = "0x00ff" or - s = "0x01ff" or - s = "0x03ff" or - s = "0x07ff" or - s = "0x0fff" or - s = "0x1fff" or - s = "0x3fff" or - s = "0x7fff" or - s = "0xffff" or - s = "0x01" or - s = "0x02" or - s = "0x04" or - s = "0x08" or - s = "0x10" or - s = "0x20" or - s = "0x40" or - s = "0x80" or - s = "0x01" or - s = "0x03" or - s = "0x07" or - s = "0x0f" or - s = "0x1f" or - s = "0x3f" or - s = "0x7f" or - s = "0xff" or - s = "0x00" or - s = "10" or - s = "100" or - s = "1000" or - s = "10000" or - s = "100000" or - s = "1000000" or - s = "10000000" or - s = "100000000" or - s = "1000000000" + s = + [ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", + "17", "18", "19", "20", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", + "16384", "32768", "65536", "1048576", "2147483648", "4294967296", "15", "31", "63", "127", + "255", "511", "1023", "2047", "4095", "16383", "32767", "65535", "1048577", "2147483647", + "4294967295", "0x00000001", "0x00000002", "0x00000004", "0x00000008", "0x00000010", + "0x00000020", "0x00000040", "0x00000080", "0x00000100", "0x00000200", "0x00000400", + "0x00000800", "0x00001000", "0x00002000", "0x00004000", "0x00008000", "0x00010000", + "0x00020000", "0x00040000", "0x00080000", "0x00100000", "0x00200000", "0x00400000", + "0x00800000", "0x01000000", "0x02000000", "0x04000000", "0x08000000", "0x10000000", + "0x20000000", "0x40000000", "0x80000000", "0x00000001", "0x00000003", "0x00000007", + "0x0000000f", "0x0000001f", "0x0000003f", "0x0000007f", "0x000000ff", "0x000001ff", + "0x000003ff", "0x000007ff", "0x00000fff", "0x00001fff", "0x00003fff", "0x00007fff", + "0x0000ffff", "0x0001ffff", "0x0003ffff", "0x0007ffff", "0x000fffff", "0x001fffff", + "0x003fffff", "0x007fffff", "0x00ffffff", "0x01ffffff", "0x03ffffff", "0x07ffffff", + "0x0fffffff", "0x1fffffff", "0x3fffffff", "0x7fffffff", "0xffffffff", "0x0001", "0x0002", + "0x0004", "0x0008", "0x0010", "0x0020", "0x0040", "0x0080", "0x0100", "0x0200", "0x0400", + "0x0800", "0x1000", "0x2000", "0x4000", "0x8000", "0x0001", "0x0003", "0x0007", "0x000f", + "0x001f", "0x003f", "0x007f", "0x00ff", "0x01ff", "0x03ff", "0x07ff", "0x0fff", "0x1fff", + "0x3fff", "0x7fff", "0xffff", "0x01", "0x02", "0x04", "0x08", "0x10", "0x20", "0x40", "0x80", + "0x01", "0x03", "0x07", "0x0f", "0x1f", "0x3f", "0x7f", "0xff", "0x00", "10", "100", "1000", + "10000", "100000", "1000000", "10000000", "100000000", "1000000000" + ] } private predicate trivialIntValue(string s) { @@ -193,15 +44,7 @@ private predicate intTrivial(Literal lit) { } private predicate powerOfTen(float f) { - f = 10 or - f = 100 or - f = 1000 or - f = 10000 or - f = 100000 or - f = 1000000 or - f = 10000000 or - f = 100000000 or - f = 1000000000 + f = [10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000] } private predicate floatTrivial(Literal lit) { diff --git a/repo-tests/codeql/csharp/ql/src/Bad Practices/Naming Conventions/DefaultControlNames.ql b/repo-tests/codeql/csharp/ql/src/Bad Practices/Naming Conventions/DefaultControlNames.ql index be381328582..2bf51653d99 100644 --- a/repo-tests/codeql/csharp/ql/src/Bad Practices/Naming Conventions/DefaultControlNames.ql +++ b/repo-tests/codeql/csharp/ql/src/Bad Practices/Naming Conventions/DefaultControlNames.ql @@ -13,16 +13,11 @@ import csharp predicate controlName(string prefix) { - prefix = "[Ll]abel" or - prefix = "[Bb]utton" or - prefix = "[Pp]anel" or - prefix = "[Rr]adio[Bb]utton" or - prefix = "[Pp]rop" or - prefix = "[Ss]atus[Ss]trip" or - prefix = "[Tt]able[Ll]ayout[Dd]esigner" or - prefix = "[Tt]ext[Bb]ox" or - prefix = "[Tt]ool[Ss]trip" or - prefix = "[Pp]icture[Bb]ox" + prefix = + [ + "[Ll]abel", "[Bb]utton", "[Pp]anel", "[Rr]adio[Bb]utton", "[Pp]rop", "[Ss]atus[Ss]trip", + "[Tt]able[Ll]ayout[Dd]esigner", "[Tt]ext[Bb]ox", "[Tt]ool[Ss]trip", "[Pp]icture[Bb]ox" + ] } predicate usedInHumanWrittenCode(Field f) { diff --git a/repo-tests/codeql/csharp/ql/src/Bad Practices/Naming Conventions/VariableNameTooShort.ql b/repo-tests/codeql/csharp/ql/src/Bad Practices/Naming Conventions/VariableNameTooShort.ql index f161edda6c4..cb778465df8 100644 --- a/repo-tests/codeql/csharp/ql/src/Bad Practices/Naming Conventions/VariableNameTooShort.ql +++ b/repo-tests/codeql/csharp/ql/src/Bad Practices/Naming Conventions/VariableNameTooShort.ql @@ -34,16 +34,7 @@ select variable, "Variable name '" + name + "' is too short." // Adjustable: acceptable short names // predicate allowedName(string name) { - name = "url" or - name = "cmd" or - name = "UK" or - name = "uri" or - name = "top" or - name = "row" or - name = "pin" or - name = "log" or - name = "key" or - name = "_" + name = ["url", "cmd", "UK", "uri", "top", "row", "pin", "log", "key", "_"] } // diff --git a/repo-tests/codeql/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql b/repo-tests/codeql/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql index 19766a550ec..4612091743f 100644 --- a/repo-tests/codeql/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql +++ b/repo-tests/codeql/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql @@ -37,21 +37,11 @@ Expr getADelegateExpr(Callable c) { */ predicate nonEscapingCall(Call c) { exists(string name | c.getTarget().hasName(name) | - name = "ForEach" or - name = "Count" or - name = "Any" or - name = "All" or - name = "Average" or - name = "Aggregate" or - name = "First" or - name = "Last" or - name = "FirstOrDefault" or - name = "LastOrDefault" or - name = "LongCount" or - name = "Max" or - name = "Single" or - name = "SingleOrDefault" or - name = "Sum" + name = + [ + "ForEach", "Count", "Any", "All", "Average", "Aggregate", "First", "Last", "FirstOrDefault", + "LastOrDefault", "LongCount", "Max", "Single", "SingleOrDefault", "Sum" + ] ) } @@ -116,12 +106,7 @@ class RelevantDefinition extends AssignableDefinition { private predicate isDefaultLikeInitializer() { this.isInitializer() and exists(Expr e | e = this.getSource().stripCasts() | - exists(string val | val = e.getValue() | - val = "0" or - val = "-1" or - val = "" or - val = "false" - ) + e.getValue() = ["0", "-1", "", "false"] or e instanceof NullLiteral or diff --git a/repo-tests/codeql/csharp/ql/src/Diagnostics/DiagnosticExtractionErrors.ql b/repo-tests/codeql/csharp/ql/src/Diagnostics/DiagnosticExtractionErrors.ql index 23943d8491f..e9e2a42bfa8 100644 --- a/repo-tests/codeql/csharp/ql/src/Diagnostics/DiagnosticExtractionErrors.ql +++ b/repo-tests/codeql/csharp/ql/src/Diagnostics/DiagnosticExtractionErrors.ql @@ -21,8 +21,8 @@ abstract private class DiagnosticError extends TDiagnosticError { abstract Location getLocation(); string getLocationMessage() { - if getLocation().getFile().fromSource() - then result = " in " + getLocation().getFile() + if this.getLocation().getFile().fromSource() + then result = " in " + this.getLocation().getFile() else result = "" } } diff --git a/repo-tests/codeql/csharp/ql/src/Security Features/CWE-020/ExternalAPIsUsedWithUntrustedData.ql b/repo-tests/codeql/csharp/ql/src/Security Features/CWE-020/ExternalAPIsUsedWithUntrustedData.ql index d34c8037e8b..8b6a657ecd4 100644 --- a/repo-tests/codeql/csharp/ql/src/Security Features/CWE-020/ExternalAPIsUsedWithUntrustedData.ql +++ b/repo-tests/codeql/csharp/ql/src/Security Features/CWE-020/ExternalAPIsUsedWithUntrustedData.ql @@ -3,7 +3,7 @@ * @description This reports the external APIs that are used with untrusted data, along with how * frequently the API is called, and how many unique sources of untrusted data flow * to it. - * @id csharp/count-untrusted-data-external-api + * @id cs/count-untrusted-data-external-api * @kind table * @tags security external/cwe/cwe-20 */ diff --git a/repo-tests/codeql/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql b/repo-tests/codeql/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql index 88709f2e0cc..3db73db09d4 100644 --- a/repo-tests/codeql/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql +++ b/repo-tests/codeql/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql @@ -1,7 +1,7 @@ /** * @name Untrusted data passed to external API * @description Data provided remotely is used in this external API without sanitization, which could be a security risk. - * @id csharp/untrusted-data-to-external-api + * @id cs/untrusted-data-to-external-api * @kind path-problem * @precision low * @problem.severity error diff --git a/repo-tests/codeql/csharp/ql/src/Stubs/Stubs.qll b/repo-tests/codeql/csharp/ql/src/Stubs/Stubs.qll index 6f92fb12f55..ea38367c876 100644 --- a/repo-tests/codeql/csharp/ql/src/Stubs/Stubs.qll +++ b/repo-tests/codeql/csharp/ql/src/Stubs/Stubs.qll @@ -128,6 +128,7 @@ abstract private class GeneratedType extends Type, GeneratedElement { /** Gets the entire C# stub code for this type. */ pragma[nomagic] final string getStub(Assembly assembly) { + this.isInAssembly(assembly) and if this.isDuplicate(assembly) then result = @@ -161,7 +162,7 @@ abstract private class GeneratedType extends Type, GeneratedElement { if this instanceof Enum then result = "" else - if exists(getAnInterestingBaseType()) + if exists(this.getAnInterestingBaseType()) then result = " : " + @@ -220,15 +221,15 @@ abstract private class GeneratedType extends Type, GeneratedElement { } final Type getAGeneratedType() { - result = getAnInterestingBaseType() + result = this.getAnInterestingBaseType() or - result = getAGeneratedMember().(Callable).getReturnType() + result = this.getAGeneratedMember().(Callable).getReturnType() or - result = getAGeneratedMember().(Callable).getAParameter().getType() + result = this.getAGeneratedMember().(Callable).getAParameter().getType() or - result = getAGeneratedMember().(Property).getType() + result = this.getAGeneratedMember().(Property).getType() or - result = getAGeneratedMember().(Field).getType() + result = this.getAGeneratedMember().(Field).getType() } } @@ -331,7 +332,8 @@ private class GeneratedNamespace extends Namespace, GeneratedElement { final string getStubs(Assembly assembly) { result = - getPreamble() + getTypeStubs(assembly) + getSubNamespaceStubs(assembly) + getPostAmble() + this.getPreamble() + this.getTypeStubs(assembly) + this.getSubNamespaceStubs(assembly) + + this.getPostAmble() } /** Gets the `n`th generated child namespace, indexed from 0. */ @@ -358,7 +360,7 @@ private class GeneratedNamespace extends Namespace, GeneratedElement { this.isInAssembly(assembly) and result = concat(GeneratedNamespace child, int i | - child = getChildNamespace(i) and child.isInAssembly(assembly) + child = this.getChildNamespace(i) and child.isInAssembly(assembly) | child.getStubs(assembly) order by i ) @@ -612,83 +614,18 @@ private string stubImplementation(Virtualizable c) { } private predicate isKeyword(string s) { - s = "abstract" or - s = "as" or - s = "base" or - s = "bool" or - s = "break" or - s = "byte" or - s = "case" or - s = "catch" or - s = "char" or - s = "checked" or - s = "class" or - s = "const" or - s = "continue" or - s = "decimal" or - s = "default" or - s = "delegate" or - s = "do" or - s = "double" or - s = "else" or - s = "enum" or - s = "event" or - s = "explicit" or - s = "extern" or - s = "false" or - s = "finally" or - s = "fixed" or - s = "float" or - s = "for" or - s = "foreach" or - s = "goto" or - s = "if" or - s = "implicit" or - s = "in" or - s = "int" or - s = "interface" or - s = "internal" or - s = "is" or - s = "lock" or - s = "long" or - s = "namespace" or - s = "new" or - s = "null" or - s = "object" or - s = "operator" or - s = "out" or - s = "override" or - s = "params" or - s = "private" or - s = "protected" or - s = "public" or - s = "readonly" or - s = "ref" or - s = "return" or - s = "sbyte" or - s = "sealed" or - s = "short" or - s = "sizeof" or - s = "stackalloc" or - s = "static" or - s = "string" or - s = "struct" or - s = "switch" or - s = "this" or - s = "throw" or - s = "true" or - s = "try" or - s = "typeof" or - s = "uint" or - s = "ulong" or - s = "unchecked" or - s = "unsafe" or - s = "ushort" or - s = "using" or - s = "virtual" or - s = "void" or - s = "volatile" or - s = "while" + s = + [ + "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", + "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", + "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", + "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", "long", + "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", + "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", + "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", + "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", + "volatile", "while" + ] } bindingset[s] @@ -760,7 +697,7 @@ private string stubMethod(Method m, Assembly assembly) { if not m.getDeclaringType() instanceof Enum then result = - " " + stubModifiers(m) + stubClassName(m.(Method).getReturnType()) + " " + + " " + stubModifiers(m) + stubClassName(m.getReturnType()) + " " + stubExplicitImplementation(m) + escapeIfKeyword(m.getUndecoratedName()) + stubGenericMethodParams(m) + "(" + stubParameters(m) + ")" + stubTypeParametersConstraints(m) + stubImplementation(m) + ";\n" diff --git a/repo-tests/codeql/csharp/ql/src/experimental/CWE-918/RequestForgery.ql b/repo-tests/codeql/csharp/ql/src/experimental/CWE-918/RequestForgery.ql new file mode 100644 index 00000000000..8b2025c4ce2 --- /dev/null +++ b/repo-tests/codeql/csharp/ql/src/experimental/CWE-918/RequestForgery.ql @@ -0,0 +1,19 @@ +/** + * @name Uncontrolled data used in network request + * @description Sending network requests with user-controlled data allows for request forgery attacks. + * @kind path-problem + * @problem.severity error + * @precision high + * @id cs/request-forgery + * @tags security + * external/cwe/cwe-918 + */ + +import csharp +import RequestForgery::RequestForgery +import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph + +from RequestForgeryConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to here and is used in a server side web request.", + source.getNode(), "User-provided value" diff --git a/repo-tests/codeql/csharp/ql/src/experimental/CWE-918/RequestForgery.qll b/repo-tests/codeql/csharp/ql/src/experimental/CWE-918/RequestForgery.qll new file mode 100644 index 00000000000..0f73e0f3d8b --- /dev/null +++ b/repo-tests/codeql/csharp/ql/src/experimental/CWE-918/RequestForgery.qll @@ -0,0 +1,234 @@ +import csharp + +module RequestForgery { + import semmle.code.csharp.controlflow.Guards + import semmle.code.csharp.frameworks.System + import semmle.code.csharp.frameworks.system.Web + import semmle.code.csharp.frameworks.Format + import semmle.code.csharp.security.dataflow.flowsources.Remote + + /** + * A data flow source for server side request forgery vulnerabilities. + */ + abstract private class Source extends DataFlow::Node { } + + /** + * A data flow sink for server side request forgery vulnerabilities. + */ + abstract private class Sink extends DataFlow::ExprNode { } + + /** + * A data flow BarrierGuard which blocks the flow of taint for + * server side request forgery vulnerabilities. + */ + abstract private class BarrierGuard extends DataFlow::BarrierGuard { } + + /** + * A data flow configuration for detecting server side request forgery vulnerabilities. + */ + class RequestForgeryConfiguration extends DataFlow::Configuration { + RequestForgeryConfiguration() { this = "Server Side Request forgery" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) { + interpolatedStringFlowStep(prev, succ) + or + stringReplaceStep(prev, succ) + or + uriCreationStep(prev, succ) + or + formatConvertStep(prev, succ) + or + toStringStep(prev, succ) + or + stringConcatStep(prev, succ) + or + stringFormatStep(prev, succ) + or + pathCombineStep(prev, succ) + } + + override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { + guard instanceof BarrierGuard + } + } + + /** + * A remote data flow source taken as a source + * for Server Side Request Forgery(SSRF) Vulnerabilities. + */ + private class RemoteFlowSourceAsSource extends Source { + RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } + } + + /** + * An url argument to a `HttpRequestMessage` constructor call + * taken as a sink for Server Side Request Forgery(SSRF) Vulnerabilities. + */ + private class SystemWebHttpRequestMessageSink extends Sink { + SystemWebHttpRequestMessageSink() { + exists(Class c | c.hasQualifiedName("System.Net.Http.HttpRequestMessage") | + c.getAConstructor().getACall().getArgument(1) = this.asExpr() + ) + } + } + + /** + * An argument to a `WebRequest.Create` call taken as a + * sink for Server Side Request Forgery(SSRF) Vulnerabilities. * + */ + private class SystemNetWebRequestCreateSink extends Sink { + SystemNetWebRequestCreateSink() { + exists(Method m | + m.getDeclaringType().hasQualifiedName("System.Net.WebRequest") and m.hasName("Create") + | + m.getACall().getArgument(0) = this.asExpr() + ) + } + } + + /** + * An argument to a new HTTP Request call of a `System.Net.Http.HttpClient` object + * taken as a sink for Server Side Request Forgery(SSRF) Vulnerabilities. + */ + private class SystemNetHttpClientSink extends Sink { + SystemNetHttpClientSink() { + exists(Method m | + m.getDeclaringType().hasQualifiedName("System.Net.Http.HttpClient") and + m.hasName([ + "DeleteAsync", "GetAsync", "GetByteArrayAsync", "GetStreamAsync", "GetStringAsync", + "PatchAsync", "PostAsync", "PutAsync" + ]) + | + m.getACall().getArgument(0) = this.asExpr() + ) + } + } + + /** + * An url argument to a method call of a `System.Net.WebClient` object + * taken as a sink for Server Side Request Forgery(SSRF) Vulnerabilities. + */ + private class SystemNetClientBaseAddressSink extends Sink { + SystemNetClientBaseAddressSink() { + exists(Property p | + p.hasName("BaseAddress") and + p.getDeclaringType() + .hasQualifiedName(["System.Net.WebClient", "System.Net.Http.HttpClient"]) + | + p.getAnAssignedValue() = this.asExpr() + ) + } + } + + /** + * A method call which checks the base of the tainted uri is assumed + * to be a guard for Server Side Request Forgery(SSRF) Vulnerabilities. + * This guard considers all checks as valid. + */ + private class BaseUriGuard extends BarrierGuard, MethodCall { + BaseUriGuard() { this.getTarget().hasQualifiedName("System.Uri", "IsBaseOf") } + + override predicate checks(Expr e, AbstractValue v) { + // we consider any checks against the tainted value to sainitize the taint. + // This implies any check such as shown below block the taint flow. + // Uri url = new Uri("whitelist.com") + // if (url.isBaseOf(`taint1)) + (e = this.getArgument(0) or e = this.getQualifier()) and + v.(AbstractValues::BooleanValue).getValue() = true + } + } + + /** + * A method call which checks if the Uri starts with a white-listed string is assumed + * to be a guard for Server Side Request Forgery(SSRF) Vulnerabilities. + * This guard considers all checks as valid. + */ + private class StringStartsWithBarrierGuard extends BarrierGuard, MethodCall { + StringStartsWithBarrierGuard() { + this.getTarget().hasQualifiedName("System.String", "StartsWith") + } + + override predicate checks(Expr e, AbstractValue v) { + // Any check such as the ones shown below + // "https://myurl.com/".startsWith(`taint`) + // `taint`.startsWith("https://myurl.com/") + // are assumed to sainitize the taint + (e = this.getQualifier() or this.getArgument(0) = e) and + v.(AbstractValues::BooleanValue).getValue() = true + } + } + + private predicate stringFormatStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(FormatCall c | c.getArgument(0) = prev.asExpr() and c = succ.asExpr()) + } + + private predicate pathCombineStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(MethodCall combineCall | + combineCall.getTarget().hasQualifiedName("System.IO.Path", "Combine") and + combineCall.getArgument(0) = prev.asExpr() and + combineCall = succ.asExpr() + ) + } + + private predicate uriCreationStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(ObjectCreation oc | + oc.getTarget().getDeclaringType().hasQualifiedName("System.Uri") and + oc.getArgument(0) = prev.asExpr() and + oc = succ.asExpr() + ) + } + + private predicate interpolatedStringFlowStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(InterpolatedStringExpr i | + // allow `$"http://{`taint`}/blabla/");"` or + // allow `$"https://{`taint`}/blabla/");"` + i.getText(0).getValue().matches(["http://", "http://"]) and + i.getInsert(1) = prev.asExpr() and + succ.asExpr() = i + or + // allow `$"{`taint`}/blabla/");"` + i.getInsert(0) = prev.asExpr() and + succ.asExpr() = i + ) + } + + private predicate stringReplaceStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(MethodCall mc, SystemStringClass s | + mc = s.getReplaceMethod().getACall() and + mc.getQualifier() = prev.asExpr() and + succ.asExpr() = mc + ) + } + + private predicate stringConcatStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(AddExpr a | + a.getLeftOperand() = prev.asExpr() + or + a.getRightOperand() = prev.asExpr() and + a.getLeftOperand().(StringLiteral).getValue() = ["http://", "https://"] + | + a = succ.asExpr() + ) + } + + private predicate formatConvertStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(Method m | + m.hasQualifiedName("System.Convert", + ["FromBase64String", "FromHexString", "FromBase64CharArray"]) and + m.getParameter(0) = prev.asParameter() and + succ.asExpr() = m.getACall() + ) + } + + private predicate toStringStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(MethodCall ma | + ma.getTarget().hasName("ToString") and + ma.getQualifier() = prev.asExpr() and + succ.asExpr() = ma + ) + } +} diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/IRConsistency.ql b/repo-tests/codeql/csharp/ql/src/experimental/ir/IRConsistency.ql index 375d38ec5de..6344b237dfd 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/IRConsistency.ql +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/IRConsistency.ql @@ -2,7 +2,7 @@ * @name IR Consistency Check * @description Performs consistency checks on the Intermediate Representation. This query should have no results. * @kind table - * @id csharp/ir-consistency-check + * @id cs/ir-consistency-check */ import implementation.raw.IRConsistency diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/PrintIR.ql b/repo-tests/codeql/csharp/ql/src/experimental/ir/PrintIR.ql index 1f93a39ad6f..3bc50831fd2 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/PrintIR.ql +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/PrintIR.ql @@ -1,7 +1,7 @@ /** * @name Print IR * @description Outputs a representation of the IR graph - * @id csharp/print-ir + * @id cs/print-ir * @kind graph */ diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index 4b86f9a7cec..bb8630a5e0c 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -24,7 +24,7 @@ class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ - final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() } /** * INTERNAL: Do not use. @@ -39,7 +39,7 @@ class IRBlockBase extends TIRBlock { ) and this = rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 | - funcBlock.getEnclosingFunction() = getEnclosingFunction() and + funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and // Ensure that the block containing `EnterFunction` always comes first. if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction @@ -59,15 +59,15 @@ class IRBlockBase extends TIRBlock { * Get the `Phi` instructions that appear at the start of this block. */ final PhiInstruction getAPhiInstruction() { - Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() + Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction() } /** * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { - result = getInstruction(_) or - result = getAPhiInstruction() + result = this.getInstruction(_) or + result = this.getAPhiInstruction() } /** @@ -78,7 +78,9 @@ class IRBlockBase extends TIRBlock { /** * Gets the last instruction in this block. */ - final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + final Instruction getLastInstruction() { + result = this.getInstruction(this.getInstructionCount() - 1) + } /** * Gets the number of non-`Phi` instructions in this block. @@ -149,7 +151,7 @@ class IRBlock extends IRBlockBase { * Block `A` dominates block `B` if any control flow path from the entry block of the function to * block `B` must pass through block `A`. A block always dominates itself. */ - final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block } /** * Gets a block on the dominance frontier of this block. @@ -159,8 +161,8 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock dominanceFrontier() { - dominates(result.getAPredecessor()) and - not strictlyDominates(result) + this.dominates(result.getAPredecessor()) and + not this.strictlyDominates(result) } /** @@ -189,7 +191,7 @@ class IRBlock extends IRBlockBase { * Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the * function must pass through block `A`. A block always post-dominates itself. */ - final predicate postDominates(IRBlock block) { strictlyPostDominates(block) or this = block } + final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block } /** * Gets a block on the post-dominance frontier of this block. @@ -199,16 +201,16 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock postPominanceFrontier() { - postDominates(result.getASuccessor()) and - not strictlyPostDominates(result) + this.postDominates(result.getASuccessor()) and + not this.strictlyPostDominates(result) } /** * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { - this = getEnclosingIRFunction().getEntryBlock() or - getAPredecessor().isReachableFromFunctionEntry() + this = this.getEnclosingIRFunction().getEntryBlock() or + this.getAPredecessor().isReachableFromFunctionEntry() } } diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql index a35d67a23ed..342e84a2b5e 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql @@ -2,7 +2,7 @@ * @name Raw IR Consistency Check * @description Performs consistency checks on the Intermediate Representation. This query should have no results. * @kind table - * @id csharp/raw-ir-consistency-check + * @id cs/raw-ir-consistency-check */ import IRConsistency diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 6f471d8a7e8..1c2cc493338 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction { } /** Gets a textual representation of this element. */ - final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } + final string toString() { result = this.getOpcode().toString() + ": " + this.getAST().toString() } /** * Gets a string showing the result, opcode, and operands of the instruction, equivalent to what @@ -50,7 +50,8 @@ class Instruction extends Construction::TStageInstruction { * `mu0_28(int) = Store r0_26, r0_27` */ final string getDumpString() { - result = getResultString() + " = " + getOperationString() + " " + getOperandsString() + result = + this.getResultString() + " = " + this.getOperationString() + " " + this.getOperandsString() } private predicate shouldGenerateDumpStrings() { @@ -66,10 +67,13 @@ class Instruction extends Construction::TStageInstruction { * VariableAddress[x] */ final string getOperationString() { - shouldGenerateDumpStrings() and - if exists(getImmediateString()) - then result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]" - else result = getOperationPrefix() + getOpcode().toString() + this.shouldGenerateDumpStrings() and + if exists(this.getImmediateString()) + then + result = + this.getOperationPrefix() + this.getOpcode().toString() + "[" + this.getImmediateString() + + "]" + else result = this.getOperationPrefix() + this.getOpcode().toString() } /** @@ -78,17 +82,17 @@ class Instruction extends Construction::TStageInstruction { string getImmediateString() { none() } private string getOperationPrefix() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and if this instanceof SideEffectInstruction then result = "^" else result = "" } private string getResultPrefix() { - shouldGenerateDumpStrings() and - if getResultIRType() instanceof IRVoidType + this.shouldGenerateDumpStrings() and + if this.getResultIRType() instanceof IRVoidType then result = "v" else - if hasMemoryResult() - then if isResultModeled() then result = "m" else result = "mu" + if this.hasMemoryResult() + then if this.isResultModeled() then result = "m" else result = "mu" else result = "r" } @@ -97,7 +101,7 @@ class Instruction extends Construction::TStageInstruction { * used by debugging and printing code only. */ int getDisplayIndexInBlock() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and exists(IRBlock block | this = block.getInstruction(result) or @@ -111,12 +115,12 @@ class Instruction extends Construction::TStageInstruction { } private int getLineRank() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and this = rank[result](Instruction instr | instr = - getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(), - getLocation().getStartLine()) + getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(), + this.getLocation().getStartLine()) | instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() ) @@ -130,8 +134,9 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1` */ string getResultId() { - shouldGenerateDumpStrings() and - result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank() + this.shouldGenerateDumpStrings() and + result = + this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank() } /** @@ -142,8 +147,8 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1(int*)` */ final string getResultString() { - shouldGenerateDumpStrings() and - result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + this.shouldGenerateDumpStrings() and + result = this.getResultId() + "(" + this.getResultLanguageType().getDumpString() + ")" } /** @@ -153,10 +158,10 @@ class Instruction extends Construction::TStageInstruction { * Example: `func:r3_4, this:r3_5` */ string getOperandsString() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and result = concat(Operand operand | - operand = getAnOperand() + operand = this.getAnOperand() | operand.getDumpString(), ", " order by operand.getDumpSortOrder() ) @@ -190,7 +195,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the function that contains this instruction. */ final Language::Function getEnclosingFunction() { - result = getEnclosingIRFunction().getFunction() + result = this.getEnclosingIRFunction().getFunction() } /** @@ -208,7 +213,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets the location of the source code for this instruction. */ - final Language::Location getLocation() { result = getAST().getLocation() } + final Language::Location getLocation() { result = this.getAST().getLocation() } /** * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a @@ -243,7 +248,7 @@ class Instruction extends Construction::TStageInstruction { * a result, its result type will be `IRVoidType`. */ cached - final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() } /** * Gets the type of the result produced by this instruction. If the @@ -254,7 +259,7 @@ class Instruction extends Construction::TStageInstruction { */ final Language::Type getResultType() { exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and + resultType = this.getResultLanguageType() and ( resultType.hasUnspecifiedType(result, _) or @@ -283,7 +288,7 @@ class Instruction extends Construction::TStageInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { getResultLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -292,7 +297,7 @@ class Instruction extends Construction::TStageInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = getResultLanguageType().getByteSize() } + final int getResultSize() { result = this.getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -314,14 +319,16 @@ class Instruction extends Construction::TStageInstruction { /** * Holds if this instruction produces a memory result. */ - final predicate hasMemoryResult() { exists(getResultMemoryAccess()) } + final predicate hasMemoryResult() { exists(this.getResultMemoryAccess()) } /** * Gets the kind of memory access performed by this instruction's result. * Holds only for instructions with a memory result. */ pragma[inline] - final MemoryAccessKind getResultMemoryAccess() { result = getOpcode().getWriteMemoryAccess() } + final MemoryAccessKind getResultMemoryAccess() { + result = this.getOpcode().getWriteMemoryAccess() + } /** * Holds if the memory access performed by this instruction's result will not always write to @@ -332,7 +339,7 @@ class Instruction extends Construction::TStageInstruction { * (for example, the global side effects of a function call). */ pragma[inline] - final predicate hasResultMayMemoryAccess() { getOpcode().hasMayWriteMemoryAccess() } + final predicate hasResultMayMemoryAccess() { this.getOpcode().hasMayWriteMemoryAccess() } /** * Gets the operand that holds the memory address to which this instruction stores its @@ -340,7 +347,7 @@ class Instruction extends Construction::TStageInstruction { * is `r1`. */ final AddressOperand getResultAddressOperand() { - getResultMemoryAccess().usesAddressOperand() and + this.getResultMemoryAccess().usesAddressOperand() and result.getUse() = this } @@ -349,7 +356,7 @@ class Instruction extends Construction::TStageInstruction { * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` * is the instruction that defines `r1`. */ - final Instruction getResultAddress() { result = getResultAddressOperand().getDef() } + final Instruction getResultAddress() { result = this.getResultAddressOperand().getDef() } /** * Holds if the result of this instruction is precisely modeled in SSA. Always @@ -368,7 +375,7 @@ class Instruction extends Construction::TStageInstruction { */ final predicate isResultModeled() { // Register results are always in SSA form. - not hasMemoryResult() or + not this.hasMemoryResult() or Construction::hasModeledMemoryResult(this) } @@ -412,7 +419,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct successors of this instruction. */ - final Instruction getASuccessor() { result = getSuccessor(_) } + final Instruction getASuccessor() { result = this.getSuccessor(_) } /** * Gets a predecessor of this instruction such that the predecessor reaches @@ -423,7 +430,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct predecessors of this instruction. */ - final Instruction getAPredecessor() { result = getPredecessor(_) } + final Instruction getAPredecessor() { result = this.getPredecessor(_) } } /** @@ -543,7 +550,7 @@ class IndexedInstruction extends Instruction { * at this instruction. This instruction has no predecessors. */ class EnterFunctionInstruction extends Instruction { - EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } + EnterFunctionInstruction() { this.getOpcode() instanceof Opcode::EnterFunction } } /** @@ -554,7 +561,7 @@ class EnterFunctionInstruction extends Instruction { * struct, or union, see `FieldAddressInstruction`. */ class VariableAddressInstruction extends VariableInstruction { - VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } + VariableAddressInstruction() { this.getOpcode() instanceof Opcode::VariableAddress } } /** @@ -566,7 +573,7 @@ class VariableAddressInstruction extends VariableInstruction { * The result has an `IRFunctionAddress` type. */ class FunctionAddressInstruction extends FunctionInstruction { - FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } + FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress } } /** @@ -577,7 +584,7 @@ class FunctionAddressInstruction extends FunctionInstruction { * initializes that parameter. */ class InitializeParameterInstruction extends VariableInstruction { - InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + InitializeParameterInstruction() { this.getOpcode() instanceof Opcode::InitializeParameter } /** * Gets the parameter initialized by this instruction. @@ -603,7 +610,7 @@ class InitializeParameterInstruction extends VariableInstruction { * initialized elsewhere, would not otherwise have a definition in this function. */ class InitializeNonLocalInstruction extends Instruction { - InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } + InitializeNonLocalInstruction() { this.getOpcode() instanceof Opcode::InitializeNonLocal } } /** @@ -611,7 +618,7 @@ class InitializeNonLocalInstruction extends Instruction { * with the value of that memory on entry to the function. */ class InitializeIndirectionInstruction extends VariableInstruction { - InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + InitializeIndirectionInstruction() { this.getOpcode() instanceof Opcode::InitializeIndirection } /** * Gets the parameter initialized by this instruction. @@ -635,24 +642,24 @@ class InitializeIndirectionInstruction extends VariableInstruction { * An instruction that initializes the `this` pointer parameter of the enclosing function. */ class InitializeThisInstruction extends Instruction { - InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } + InitializeThisInstruction() { this.getOpcode() instanceof Opcode::InitializeThis } } /** * An instruction that computes the address of a non-static field of an object. */ class FieldAddressInstruction extends FieldInstruction { - FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + FieldAddressInstruction() { this.getOpcode() instanceof Opcode::FieldAddress } /** * Gets the operand that provides the address of the object containing the field. */ - final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the object containing the field. */ - final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } + final Instruction getObjectAddress() { result = this.getObjectAddressOperand().getDef() } } /** @@ -661,17 +668,19 @@ class FieldAddressInstruction extends FieldInstruction { * This instruction is used for element access to C# arrays. */ class ElementsAddressInstruction extends UnaryInstruction { - ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + ElementsAddressInstruction() { this.getOpcode() instanceof Opcode::ElementsAddress } /** * Gets the operand that provides the address of the array object. */ - final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getArrayObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the array object. */ - final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } + final Instruction getArrayObjectAddress() { + result = this.getArrayObjectAddressOperand().getDef() + } } /** @@ -685,7 +694,7 @@ class ElementsAddressInstruction extends UnaryInstruction { * taken may want to ignore any function that contains an `ErrorInstruction`. */ class ErrorInstruction extends Instruction { - ErrorInstruction() { getOpcode() instanceof Opcode::Error } + ErrorInstruction() { this.getOpcode() instanceof Opcode::Error } } /** @@ -695,7 +704,7 @@ class ErrorInstruction extends Instruction { * an initializer, or whose initializer only partially initializes the variable. */ class UninitializedInstruction extends VariableInstruction { - UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } + UninitializedInstruction() { this.getOpcode() instanceof Opcode::Uninitialized } /** * Gets the variable that is uninitialized. @@ -710,7 +719,7 @@ class UninitializedInstruction extends VariableInstruction { * least one instruction, even when the AST has no semantic effect. */ class NoOpInstruction extends Instruction { - NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } + NoOpInstruction() { this.getOpcode() instanceof Opcode::NoOp } } /** @@ -732,32 +741,42 @@ class NoOpInstruction extends Instruction { * `void`-returning function. */ class ReturnInstruction extends Instruction { - ReturnInstruction() { getOpcode() instanceof ReturnOpcode } + ReturnInstruction() { this.getOpcode() instanceof ReturnOpcode } } /** * An instruction that returns control to the caller of the function, without returning a value. */ class ReturnVoidInstruction extends ReturnInstruction { - ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } + ReturnVoidInstruction() { this.getOpcode() instanceof Opcode::ReturnVoid } } /** * An instruction that returns control to the caller of the function, including a return value. */ class ReturnValueInstruction extends ReturnInstruction { - ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + ReturnValueInstruction() { this.getOpcode() instanceof Opcode::ReturnValue } /** * Gets the operand that provides the value being returned by the function. */ - final LoadOperand getReturnValueOperand() { result = getAnOperand() } + final LoadOperand getReturnValueOperand() { result = this.getAnOperand() } + + /** + * Gets the operand that provides the address of the value being returned by the function. + */ + final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value being returned by the function, if an * exact definition is available. */ - final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } + final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() } + + /** + * Gets the instruction whose result provides the address of the value being returned by the function. + */ + final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() } } /** @@ -770,28 +789,28 @@ class ReturnValueInstruction extends ReturnInstruction { * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { - ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + ReturnIndirectionInstruction() { this.getOpcode() instanceof Opcode::ReturnIndirection } /** * Gets the operand that provides the value of the pointed-to memory. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the pointed-to memory, if an exact * definition is available. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** * Gets the operand that provides the address of the pointed-to memory. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the pointed-to memory. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } /** * Gets the parameter for which this instruction reads the final pointed-to value within the @@ -826,7 +845,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { * - `StoreInstruction` - Copies a register operand to a memory result. */ class CopyInstruction extends Instruction { - CopyInstruction() { getOpcode() instanceof CopyOpcode } + CopyInstruction() { this.getOpcode() instanceof CopyOpcode } /** * Gets the operand that provides the input value of the copy. @@ -837,16 +856,16 @@ class CopyInstruction extends Instruction { * Gets the instruction whose result provides the input value of the copy, if an exact definition * is available. */ - final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } + final Instruction getSourceValue() { result = this.getSourceValueOperand().getDef() } } /** * An instruction that returns a register result containing a copy of its register operand. */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { - CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } + CopyValueInstruction() { this.getOpcode() instanceof Opcode::CopyValue } - final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } + final override UnaryOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -863,47 +882,49 @@ private string getAddressOperandDescription(AddressOperand operand) { * An instruction that returns a register result containing a copy of its memory operand. */ class LoadInstruction extends CopyInstruction { - LoadInstruction() { getOpcode() instanceof Opcode::Load } + LoadInstruction() { this.getOpcode() instanceof Opcode::Load } final override string getImmediateString() { - result = getAddressOperandDescription(getSourceAddressOperand()) + result = getAddressOperandDescription(this.getSourceAddressOperand()) } /** * Gets the operand that provides the address of the value being loaded. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the value being loaded. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - final override LoadOperand getSourceValueOperand() { result = getAnOperand() } + final override LoadOperand getSourceValueOperand() { result = this.getAnOperand() } } /** * An instruction that returns a memory result containing a copy of its register operand. */ class StoreInstruction extends CopyInstruction { - StoreInstruction() { getOpcode() instanceof Opcode::Store } + StoreInstruction() { this.getOpcode() instanceof Opcode::Store } final override string getImmediateString() { - result = getAddressOperandDescription(getDestinationAddressOperand()) + result = getAddressOperandDescription(this.getDestinationAddressOperand()) } /** * Gets the operand that provides the address of the location to which the value will be stored. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the location to which the value will * be stored, if an exact definition is available. */ - final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + final Instruction getDestinationAddress() { + result = this.getDestinationAddressOperand().getDef() + } - final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } + final override StoreValueOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -911,27 +932,27 @@ class StoreInstruction extends CopyInstruction { * operand. */ class ConditionalBranchInstruction extends Instruction { - ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + ConditionalBranchInstruction() { this.getOpcode() instanceof Opcode::ConditionalBranch } /** * Gets the operand that provides the Boolean condition controlling the branch. */ - final ConditionOperand getConditionOperand() { result = getAnOperand() } + final ConditionOperand getConditionOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the Boolean condition controlling the branch. */ - final Instruction getCondition() { result = getConditionOperand().getDef() } + final Instruction getCondition() { result = this.getConditionOperand().getDef() } /** * Gets the instruction to which control will flow if the condition is true. */ - final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + final Instruction getTrueSuccessor() { result = this.getSuccessor(EdgeKind::trueEdge()) } /** * Gets the instruction to which control will flow if the condition is false. */ - final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } + final Instruction getFalseSuccessor() { result = this.getSuccessor(EdgeKind::falseEdge()) } } /** @@ -943,14 +964,14 @@ class ConditionalBranchInstruction extends Instruction { * successors. */ class ExitFunctionInstruction extends Instruction { - ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } + ExitFunctionInstruction() { this.getOpcode() instanceof Opcode::ExitFunction } } /** * An instruction whose result is a constant value. */ class ConstantInstruction extends ConstantValueInstruction { - ConstantInstruction() { getOpcode() instanceof Opcode::Constant } + ConstantInstruction() { this.getOpcode() instanceof Opcode::Constant } } /** @@ -959,7 +980,7 @@ class ConstantInstruction extends ConstantValueInstruction { class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | - resultType = getResultIRType() and + resultType = this.getResultIRType() and (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) ) } @@ -969,7 +990,7 @@ class IntegerConstantInstruction extends ConstantInstruction { * An instruction whose result is a constant value of floating-point type. */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } + FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType } } /** @@ -978,7 +999,9 @@ class FloatConstantInstruction extends ConstantInstruction { class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; - final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + final override string getImmediateString() { + result = Language::getStringLiteralText(this.getValue()) + } /** * Gets the string literal whose address is returned by this instruction. @@ -990,37 +1013,37 @@ class StringConstantInstruction extends VariableInstruction { * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { - BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + BinaryInstruction() { this.getOpcode() instanceof BinaryOpcode } /** * Gets the left operand of this binary instruction. */ - final LeftOperand getLeftOperand() { result = getAnOperand() } + final LeftOperand getLeftOperand() { result = this.getAnOperand() } /** * Gets the right operand of this binary instruction. */ - final RightOperand getRightOperand() { result = getAnOperand() } + final RightOperand getRightOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the left operand of this binary * instruction. */ - final Instruction getLeft() { result = getLeftOperand().getDef() } + final Instruction getLeft() { result = this.getLeftOperand().getDef() } /** * Gets the instruction whose result provides the value of the right operand of this binary * instruction. */ - final Instruction getRight() { result = getRightOperand().getDef() } + final Instruction getRight() { result = this.getRightOperand().getDef() } /** * Holds if this instruction's operands are `op1` and `op2`, in either order. */ final predicate hasOperands(Operand op1, Operand op2) { - op1 = getLeftOperand() and op2 = getRightOperand() + op1 = this.getLeftOperand() and op2 = this.getRightOperand() or - op1 = getRightOperand() and op2 = getLeftOperand() + op1 = this.getRightOperand() and op2 = this.getLeftOperand() } } @@ -1028,7 +1051,7 @@ class BinaryInstruction extends Instruction { * An instruction that computes the result of an arithmetic operation. */ class ArithmeticInstruction extends Instruction { - ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } + ArithmeticInstruction() { this.getOpcode() instanceof ArithmeticOpcode } } /** @@ -1050,7 +1073,7 @@ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction * performed according to IEEE-754. */ class AddInstruction extends BinaryArithmeticInstruction { - AddInstruction() { getOpcode() instanceof Opcode::Add } + AddInstruction() { this.getOpcode() instanceof Opcode::Add } } /** @@ -1061,7 +1084,7 @@ class AddInstruction extends BinaryArithmeticInstruction { * according to IEEE-754. */ class SubInstruction extends BinaryArithmeticInstruction { - SubInstruction() { getOpcode() instanceof Opcode::Sub } + SubInstruction() { this.getOpcode() instanceof Opcode::Sub } } /** @@ -1072,7 +1095,7 @@ class SubInstruction extends BinaryArithmeticInstruction { * performed according to IEEE-754. */ class MulInstruction extends BinaryArithmeticInstruction { - MulInstruction() { getOpcode() instanceof Opcode::Mul } + MulInstruction() { this.getOpcode() instanceof Opcode::Mul } } /** @@ -1083,7 +1106,7 @@ class MulInstruction extends BinaryArithmeticInstruction { * to IEEE-754. */ class DivInstruction extends BinaryArithmeticInstruction { - DivInstruction() { getOpcode() instanceof Opcode::Div } + DivInstruction() { this.getOpcode() instanceof Opcode::Div } } /** @@ -1093,7 +1116,7 @@ class DivInstruction extends BinaryArithmeticInstruction { * division by zero or integer overflow is undefined. */ class RemInstruction extends BinaryArithmeticInstruction { - RemInstruction() { getOpcode() instanceof Opcode::Rem } + RemInstruction() { this.getOpcode() instanceof Opcode::Rem } } /** @@ -1104,14 +1127,14 @@ class RemInstruction extends BinaryArithmeticInstruction { * is performed according to IEEE-754. */ class NegateInstruction extends UnaryArithmeticInstruction { - NegateInstruction() { getOpcode() instanceof Opcode::Negate } + NegateInstruction() { this.getOpcode() instanceof Opcode::Negate } } /** * An instruction that computes the result of a bitwise operation. */ class BitwiseInstruction extends Instruction { - BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } + BitwiseInstruction() { this.getOpcode() instanceof BitwiseOpcode } } /** @@ -1130,7 +1153,7 @@ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } * Both operands must have the same integer type, which will also be the result type. */ class BitAndInstruction extends BinaryBitwiseInstruction { - BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } + BitAndInstruction() { this.getOpcode() instanceof Opcode::BitAnd } } /** @@ -1139,7 +1162,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitOrInstruction extends BinaryBitwiseInstruction { - BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } + BitOrInstruction() { this.getOpcode() instanceof Opcode::BitOr } } /** @@ -1148,7 +1171,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitXorInstruction extends BinaryBitwiseInstruction { - BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } + BitXorInstruction() { this.getOpcode() instanceof Opcode::BitXor } } /** @@ -1159,7 +1182,7 @@ class BitXorInstruction extends BinaryBitwiseInstruction { * rightmost bits are zero-filled. */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { - ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } + ShiftLeftInstruction() { this.getOpcode() instanceof Opcode::ShiftLeft } } /** @@ -1172,7 +1195,7 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { * of the left operand. */ class ShiftRightInstruction extends BinaryBitwiseInstruction { - ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } + ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight } } /** @@ -1183,7 +1206,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { - getOpcode() instanceof PointerArithmeticOpcode and + this.getOpcode() instanceof PointerArithmeticOpcode and elementSize = Raw::getInstructionElementSize(this) } @@ -1206,7 +1229,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { * An instruction that adds or subtracts an integer offset from a pointer. */ class PointerOffsetInstruction extends PointerArithmeticInstruction { - PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } + PointerOffsetInstruction() { this.getOpcode() instanceof PointerOffsetOpcode } } /** @@ -1217,7 +1240,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { * overflow is undefined. */ class PointerAddInstruction extends PointerOffsetInstruction { - PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } + PointerAddInstruction() { this.getOpcode() instanceof Opcode::PointerAdd } } /** @@ -1228,7 +1251,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { * pointer underflow is undefined. */ class PointerSubInstruction extends PointerOffsetInstruction { - PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } + PointerSubInstruction() { this.getOpcode() instanceof Opcode::PointerSub } } /** @@ -1241,31 +1264,31 @@ class PointerSubInstruction extends PointerOffsetInstruction { * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { - PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } + PointerDiffInstruction() { this.getOpcode() instanceof Opcode::PointerDiff } } /** * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { - UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + UnaryInstruction() { this.getOpcode() instanceof UnaryOpcode } /** * Gets the sole operand of this instruction. */ - final UnaryOperand getUnaryOperand() { result = getAnOperand() } + final UnaryOperand getUnaryOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the sole operand of this instruction. */ - final Instruction getUnary() { result = getUnaryOperand().getDef() } + final Instruction getUnary() { result = this.getUnaryOperand().getDef() } } /** * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { - ConvertInstruction() { getOpcode() instanceof Opcode::Convert } + ConvertInstruction() { this.getOpcode() instanceof Opcode::Convert } } /** @@ -1279,7 +1302,7 @@ class ConvertInstruction extends UnaryInstruction { * `as` expression. */ class CheckedConvertOrNullInstruction extends UnaryInstruction { - CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } + CheckedConvertOrNullInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** @@ -1293,7 +1316,7 @@ class CheckedConvertOrNullInstruction extends UnaryInstruction { * expression. */ class CheckedConvertOrThrowInstruction extends UnaryInstruction { - CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } + CheckedConvertOrThrowInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrThrow } } /** @@ -1306,7 +1329,7 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { * the most-derived object. */ class CompleteObjectAddressInstruction extends UnaryInstruction { - CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } + CompleteObjectAddressInstruction() { this.getOpcode() instanceof Opcode::CompleteObjectAddress } } /** @@ -1351,7 +1374,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { - ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } + ConvertToBaseInstruction() { this.getOpcode() instanceof ConvertToBaseOpcode } } /** @@ -1361,7 +1384,9 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } + ConvertToNonVirtualBaseInstruction() { + this.getOpcode() instanceof Opcode::ConvertToNonVirtualBase + } } /** @@ -1371,7 +1396,7 @@ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } + ConvertToVirtualBaseInstruction() { this.getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** @@ -1381,7 +1406,7 @@ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { - ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } + ConvertToDerivedInstruction() { this.getOpcode() instanceof Opcode::ConvertToDerived } } /** @@ -1390,7 +1415,7 @@ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { * The operand must have an integer type, which will also be the result type. */ class BitComplementInstruction extends UnaryBitwiseInstruction { - BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } + BitComplementInstruction() { this.getOpcode() instanceof Opcode::BitComplement } } /** @@ -1399,14 +1424,14 @@ class BitComplementInstruction extends UnaryBitwiseInstruction { * The operand must have a Boolean type, which will also be the result type. */ class LogicalNotInstruction extends UnaryInstruction { - LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } + LogicalNotInstruction() { this.getOpcode() instanceof Opcode::LogicalNot } } /** * An instruction that compares two numeric operands. */ class CompareInstruction extends BinaryInstruction { - CompareInstruction() { getOpcode() instanceof CompareOpcode } + CompareInstruction() { this.getOpcode() instanceof CompareOpcode } } /** @@ -1417,7 +1442,7 @@ class CompareInstruction extends BinaryInstruction { * unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareEQInstruction extends CompareInstruction { - CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } + CompareEQInstruction() { this.getOpcode() instanceof Opcode::CompareEQ } } /** @@ -1428,14 +1453,14 @@ class CompareEQInstruction extends CompareInstruction { * `left == right`. Floating-point comparison is performed according to IEEE-754. */ class CompareNEInstruction extends CompareInstruction { - CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } + CompareNEInstruction() { this.getOpcode() instanceof Opcode::CompareNE } } /** * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { - RelationalInstruction() { getOpcode() instanceof RelationalOpcode } + RelationalInstruction() { this.getOpcode() instanceof RelationalOpcode } /** * Gets the operand on the "greater" (or "greater-or-equal") side @@ -1467,11 +1492,11 @@ class RelationalInstruction extends CompareInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLTInstruction extends RelationalInstruction { - CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } + CompareLTInstruction() { this.getOpcode() instanceof Opcode::CompareLT } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { any() } } @@ -1484,11 +1509,11 @@ class CompareLTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGTInstruction extends RelationalInstruction { - CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } + CompareGTInstruction() { this.getOpcode() instanceof Opcode::CompareGT } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { any() } } @@ -1502,11 +1527,11 @@ class CompareGTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLEInstruction extends RelationalInstruction { - CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } + CompareLEInstruction() { this.getOpcode() instanceof Opcode::CompareLE } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { none() } } @@ -1520,11 +1545,11 @@ class CompareLEInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGEInstruction extends RelationalInstruction { - CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } + CompareGEInstruction() { this.getOpcode() instanceof Opcode::CompareGE } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { none() } } @@ -1543,78 +1568,78 @@ class CompareGEInstruction extends RelationalInstruction { * of any case edge. */ class SwitchInstruction extends Instruction { - SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + SwitchInstruction() { this.getOpcode() instanceof Opcode::Switch } /** Gets the operand that provides the integer value controlling the switch. */ - final ConditionOperand getExpressionOperand() { result = getAnOperand() } + final ConditionOperand getExpressionOperand() { result = this.getAnOperand() } /** Gets the instruction whose result provides the integer value controlling the switch. */ - final Instruction getExpression() { result = getExpressionOperand().getDef() } + final Instruction getExpression() { result = this.getExpressionOperand().getDef() } /** Gets the successor instructions along the case edges of the switch. */ - final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = this.getSuccessor(edge)) } /** Gets the successor instruction along the default edge of the switch, if any. */ - final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } + final Instruction getDefaultSuccessor() { result = this.getSuccessor(EdgeKind::defaultEdge()) } } /** * An instruction that calls a function. */ class CallInstruction extends Instruction { - CallInstruction() { getOpcode() instanceof Opcode::Call } + CallInstruction() { this.getOpcode() instanceof Opcode::Call } final override string getImmediateString() { - result = getStaticCallTarget().toString() + result = this.getStaticCallTarget().toString() or - not exists(getStaticCallTarget()) and result = "?" + not exists(this.getStaticCallTarget()) and result = "?" } /** * Gets the operand the specifies the target function of the call. */ - final CallTargetOperand getCallTargetOperand() { result = getAnOperand() } + final CallTargetOperand getCallTargetOperand() { result = this.getAnOperand() } /** * Gets the `Instruction` that computes the target function of the call. This is usually a * `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a * function pointer. */ - final Instruction getCallTarget() { result = getCallTargetOperand().getDef() } + final Instruction getCallTarget() { result = this.getCallTargetOperand().getDef() } /** * Gets all of the argument operands of the call, including the `this` pointer, if any. */ - final ArgumentOperand getAnArgumentOperand() { result = getAnOperand() } + final ArgumentOperand getAnArgumentOperand() { result = this.getAnOperand() } /** * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() + result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** * Gets all of the arguments of the call, including the `this` pointer, if any. */ - final Instruction getAnArgument() { result = getAnArgumentOperand().getDef() } + final Instruction getAnArgument() { result = this.getAnArgumentOperand().getDef() } /** * Gets the `this` pointer argument operand of the call, if any. */ - final ThisArgumentOperand getThisArgumentOperand() { result = getAnOperand() } + final ThisArgumentOperand getThisArgumentOperand() { result = this.getAnOperand() } /** * Gets the `this` pointer argument of the call, if any. */ - final Instruction getThisArgument() { result = getThisArgumentOperand().getDef() } + final Instruction getThisArgument() { result = this.getThisArgumentOperand().getDef() } /** * Gets the argument operand at the specified index. */ pragma[noinline] final PositionalArgumentOperand getPositionalArgumentOperand(int index) { - result = getAnOperand() and + result = this.getAnOperand() and result.getIndex() = index } @@ -1623,7 +1648,7 @@ class CallInstruction extends Instruction { */ pragma[noinline] final Instruction getPositionalArgument(int index) { - result = getPositionalArgumentOperand(index).getDef() + result = this.getPositionalArgumentOperand(index).getDef() } /** @@ -1631,16 +1656,16 @@ class CallInstruction extends Instruction { */ pragma[noinline] final ArgumentOperand getArgumentOperand(int index) { - index >= 0 and result = getPositionalArgumentOperand(index) + index >= 0 and result = this.getPositionalArgumentOperand(index) or - index = -1 and result = getThisArgumentOperand() + index = -1 and result = this.getThisArgumentOperand() } /** * Gets the argument at the specified index, or `this` if `index` is `-1`. */ pragma[noinline] - final Instruction getArgument(int index) { result = getArgumentOperand(index).getDef() } + final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() } /** * Gets the number of arguments of the call, including the `this` pointer, if any. @@ -1665,7 +1690,7 @@ class CallInstruction extends Instruction { * An instruction representing a side effect of a function call. */ class SideEffectInstruction extends Instruction { - SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + SideEffectInstruction() { this.getOpcode() instanceof SideEffectOpcode } /** * Gets the instruction whose execution causes this side effect. @@ -1680,7 +1705,7 @@ class SideEffectInstruction extends Instruction { * accessed by that call. */ class CallSideEffectInstruction extends SideEffectInstruction { - CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect } + CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect } } /** @@ -1691,7 +1716,7 @@ class CallSideEffectInstruction extends SideEffectInstruction { * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { - CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } + CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect } } /** @@ -1699,33 +1724,33 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * specific parameter. */ class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode } + ReadSideEffectInstruction() { this.getOpcode() instanceof ReadSideEffectOpcode } /** Gets the operand for the value that will be read from this instruction, if known. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** Gets the value that will be read from this instruction, if known. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** Gets the operand for the address from which this instruction may read. */ - final AddressOperand getArgumentOperand() { result = getAnOperand() } + final AddressOperand getArgumentOperand() { result = this.getAnOperand() } /** Gets the address from which this instruction may read. */ - final Instruction getArgumentDef() { result = getArgumentOperand().getDef() } + final Instruction getArgumentDef() { result = this.getArgumentOperand().getDef() } } /** * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::IndirectReadSideEffect } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::BufferReadSideEffect } } /** @@ -1733,18 +1758,18 @@ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { */ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { SizedBufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferReadSideEffect + this.getOpcode() instanceof Opcode::SizedBufferReadSideEffect } /** * Gets the operand that holds the number of bytes read from the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes read from the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1752,17 +1777,17 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { * specific parameter. */ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } + WriteSideEffectInstruction() { this.getOpcode() instanceof WriteSideEffectOpcode } /** * Get the operand that holds the address of the memory to be written. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the memory to be written. */ - Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + Instruction getDestinationAddress() { result = this.getDestinationAddressOperand().getDef() } } /** @@ -1770,7 +1795,7 @@ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstructi */ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMustWriteSideEffect } } @@ -1780,7 +1805,7 @@ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction */ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { BufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::BufferMustWriteSideEffect } } @@ -1790,18 +1815,18 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1812,7 +1837,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi */ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMayWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } } @@ -1822,7 +1847,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } + BufferMayWriteSideEffectInstruction() { + this.getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } } /** @@ -1832,18 +1859,18 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1852,80 +1879,80 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { InitializeDynamicAllocationInstruction() { - getOpcode() instanceof Opcode::InitializeDynamicAllocation + this.getOpcode() instanceof Opcode::InitializeDynamicAllocation } /** * Gets the operand that represents the address of the allocation this instruction is initializing. */ - final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + final AddressOperand getAllocationAddressOperand() { result = this.getAnOperand() } /** * Gets the address for the allocation this instruction is initializing. */ - final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } + final Instruction getAllocationAddress() { result = this.getAllocationAddressOperand().getDef() } } /** * An instruction representing a GNU or MSVC inline assembly statement. */ class InlineAsmInstruction extends Instruction { - InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm } + InlineAsmInstruction() { this.getOpcode() instanceof Opcode::InlineAsm } } /** * An instruction that throws an exception. */ class ThrowInstruction extends Instruction { - ThrowInstruction() { getOpcode() instanceof ThrowOpcode } + ThrowInstruction() { this.getOpcode() instanceof ThrowOpcode } } /** * An instruction that throws a new exception. */ class ThrowValueInstruction extends ThrowInstruction { - ThrowValueInstruction() { getOpcode() instanceof Opcode::ThrowValue } + ThrowValueInstruction() { this.getOpcode() instanceof Opcode::ThrowValue } /** * Gets the address operand of the exception thrown by this instruction. */ - final AddressOperand getExceptionAddressOperand() { result = getAnOperand() } + final AddressOperand getExceptionAddressOperand() { result = this.getAnOperand() } /** * Gets the address of the exception thrown by this instruction. */ - final Instruction getExceptionAddress() { result = getExceptionAddressOperand().getDef() } + final Instruction getExceptionAddress() { result = this.getExceptionAddressOperand().getDef() } /** * Gets the operand for the exception thrown by this instruction. */ - final LoadOperand getExceptionOperand() { result = getAnOperand() } + final LoadOperand getExceptionOperand() { result = this.getAnOperand() } /** * Gets the exception thrown by this instruction. */ - final Instruction getException() { result = getExceptionOperand().getDef() } + final Instruction getException() { result = this.getExceptionOperand().getDef() } } /** * An instruction that re-throws the current exception. */ class ReThrowInstruction extends ThrowInstruction { - ReThrowInstruction() { getOpcode() instanceof Opcode::ReThrow } + ReThrowInstruction() { this.getOpcode() instanceof Opcode::ReThrow } } /** * An instruction that exits the current function by propagating an exception. */ class UnwindInstruction extends Instruction { - UnwindInstruction() { getOpcode() instanceof Opcode::Unwind } + UnwindInstruction() { this.getOpcode() instanceof Opcode::Unwind } } /** * An instruction that starts a `catch` handler. */ class CatchInstruction extends Instruction { - CatchInstruction() { getOpcode() instanceof CatchOpcode } + CatchInstruction() { this.getOpcode() instanceof CatchOpcode } } /** @@ -1935,7 +1962,7 @@ class CatchByTypeInstruction extends CatchInstruction { Language::LanguageType exceptionType; CatchByTypeInstruction() { - getOpcode() instanceof Opcode::CatchByType and + this.getOpcode() instanceof Opcode::CatchByType and exceptionType = Raw::getInstructionExceptionType(this) } @@ -1951,21 +1978,21 @@ class CatchByTypeInstruction extends CatchInstruction { * An instruction that catches any exception. */ class CatchAnyInstruction extends CatchInstruction { - CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } + CatchAnyInstruction() { this.getOpcode() instanceof Opcode::CatchAny } } /** * An instruction that initializes all escaped memory. */ class AliasedDefinitionInstruction extends Instruction { - AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition } + AliasedDefinitionInstruction() { this.getOpcode() instanceof Opcode::AliasedDefinition } } /** * An instruction that consumes all escaped memory on exit from the function. */ class AliasedUseInstruction extends Instruction { - AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } + AliasedUseInstruction() { this.getOpcode() instanceof Opcode::AliasedUse } } /** @@ -1979,7 +2006,7 @@ class AliasedUseInstruction extends Instruction { * runtime. */ class PhiInstruction extends Instruction { - PhiInstruction() { getOpcode() instanceof Opcode::Phi } + PhiInstruction() { this.getOpcode() instanceof Opcode::Phi } /** * Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block. @@ -2047,29 +2074,29 @@ class PhiInstruction extends Instruction { * https://link.springer.com/content/pdf/10.1007%2F3-540-61053-7_66.pdf. */ class ChiInstruction extends Instruction { - ChiInstruction() { getOpcode() instanceof Opcode::Chi } + ChiInstruction() { this.getOpcode() instanceof Opcode::Chi } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final ChiTotalOperand getTotalOperand() { result = getAnOperand() } + final ChiTotalOperand getTotalOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final Instruction getTotal() { result = getTotalOperand().getDef() } + final Instruction getTotal() { result = this.getTotalOperand().getDef() } /** * Gets the operand that represents the new value written by the memory write. */ - final ChiPartialOperand getPartialOperand() { result = getAnOperand() } + final ChiPartialOperand getPartialOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the new value written by the memory write. */ - final Instruction getPartial() { result = getPartialOperand().getDef() } + final Instruction getPartial() { result = this.getPartialOperand().getDef() } /** * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. @@ -2093,7 +2120,7 @@ class ChiInstruction extends Instruction { * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { - UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } + UnreachedInstruction() { this.getOpcode() instanceof Opcode::Unreached } } /** @@ -2106,7 +2133,7 @@ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { - getOpcode() instanceof BuiltInOperationOpcode and + this.getOpcode() instanceof BuiltInOperationOpcode and operation = Raw::getInstructionBuiltInOperation(this) } @@ -2122,9 +2149,9 @@ class BuiltInOperationInstruction extends Instruction { * actual operation is specified by the `getBuiltInOperation()` predicate. */ class BuiltInInstruction extends BuiltInOperationInstruction { - BuiltInInstruction() { getOpcode() instanceof Opcode::BuiltIn } + BuiltInInstruction() { this.getOpcode() instanceof Opcode::BuiltIn } - final override string getImmediateString() { result = getBuiltInOperation().toString() } + final override string getImmediateString() { result = this.getBuiltInOperation().toString() } } /** @@ -2135,7 +2162,7 @@ class BuiltInInstruction extends BuiltInOperationInstruction { * to the `...` parameter. */ class VarArgsStartInstruction extends UnaryInstruction { - VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } + VarArgsStartInstruction() { this.getOpcode() instanceof Opcode::VarArgsStart } } /** @@ -2145,7 +2172,7 @@ class VarArgsStartInstruction extends UnaryInstruction { * a result. */ class VarArgsEndInstruction extends UnaryInstruction { - VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } + VarArgsEndInstruction() { this.getOpcode() instanceof Opcode::VarArgsEnd } } /** @@ -2155,7 +2182,7 @@ class VarArgsEndInstruction extends UnaryInstruction { * argument. */ class VarArgInstruction extends UnaryInstruction { - VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } + VarArgInstruction() { this.getOpcode() instanceof Opcode::VarArg } } /** @@ -2166,7 +2193,7 @@ class VarArgInstruction extends UnaryInstruction { * argument of the `...` parameter. */ class NextVarArgInstruction extends UnaryInstruction { - NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } + NextVarArgInstruction() { this.getOpcode() instanceof Opcode::NextVarArg } } /** @@ -2180,5 +2207,5 @@ class NextVarArgInstruction extends UnaryInstruction { * The result is the address of the newly allocated object. */ class NewObjInstruction extends Instruction { - NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } + NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index d7cf89ca9aa..85d217bd361 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -46,12 +46,12 @@ class Operand extends TStageOperand { /** * Gets the location of the source code for this operand. */ - final Language::Location getLocation() { result = getUse().getLocation() } + final Language::Location getLocation() { result = this.getUse().getLocation() } /** * Gets the function that contains this operand. */ - final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } + final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() } /** * Gets the `Instruction` that consumes this operand. @@ -74,7 +74,7 @@ class Operand extends TStageOperand { */ final Instruction getDef() { result = this.getAnyDef() and - getDefinitionOverlap() instanceof MustExactlyOverlap + this.getDefinitionOverlap() instanceof MustExactlyOverlap } /** @@ -82,7 +82,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` that consumes this operand. */ - deprecated final Instruction getUseInstruction() { result = getUse() } + deprecated final Instruction getUseInstruction() { result = this.getUse() } /** * DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this @@ -91,7 +91,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` whose result is the value of the operand. */ - deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() } + deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() } /** * Gets the overlap relationship between the operand's definition and its use. @@ -101,7 +101,9 @@ class Operand extends TStageOperand { /** * Holds if the result of the definition instruction does not exactly overlap this use. */ - final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap } + final predicate isDefinitionInexact() { + not this.getDefinitionOverlap() instanceof MustExactlyOverlap + } /** * Gets a prefix to use when dumping the operand in an operand list. @@ -121,7 +123,7 @@ class Operand extends TStageOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId() } /** @@ -129,9 +131,9 @@ class Operand extends TStageOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - result = getAnyDef().getResultId() + result = this.getAnyDef().getResultId() or - not exists(getAnyDef()) and result = "m?" + not exists(this.getAnyDef()) and result = "m?" } /** @@ -140,7 +142,7 @@ class Operand extends TStageOperand { * the empty string. */ private string getInexactSpecifier() { - if isDefinitionInexact() then result = "~" else result = "" + if this.isDefinitionInexact() then result = "~" else result = "" } /** @@ -155,7 +157,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() } /** * Gets the language-neutral type of the value consumed by this operand. This is usually the same @@ -164,7 +166,7 @@ class Operand extends TStageOperand { * from the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final IRType getIRType() { result = getLanguageType().getIRType() } + final IRType getIRType() { result = this.getLanguageType().getIRType() } /** * Gets the type of the value consumed by this operand. This is usually the same as the @@ -173,7 +175,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final Language::Type getType() { getLanguageType().hasType(result, _) } + final Language::Type getType() { this.getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this @@ -182,13 +184,13 @@ class Operand extends TStageOperand { * not hold, the value of the operand represents a value whose type is * given by `getType()`. */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - final int getSize() { result = getLanguageType().getByteSize() } + final int getSize() { result = this.getLanguageType().getByteSize() } } /** @@ -205,7 +207,7 @@ class MemoryOperand extends Operand { /** * Gets the kind of memory access performed by the operand. */ - MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() } + MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() } /** * Holds if the memory access performed by this operand will not always read from every bit in the @@ -215,7 +217,7 @@ class MemoryOperand extends Operand { * conservative estimate of the memory that might actually be accessed at runtime (for example, * the global side effects of a function call). */ - predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() } + predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() } /** * Returns the operand that holds the memory address from which the current operand loads its @@ -223,8 +225,8 @@ class MemoryOperand extends Operand { * is `r1`. */ final AddressOperand getAddressOperand() { - getMemoryAccess().usesAddressOperand() and - result.getUse() = getUse() + this.getMemoryAccess().usesAddressOperand() and + result.getUse() = this.getUse() } } @@ -294,7 +296,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe result = unique(Instruction defInstr | hasDefinition(defInstr, _)) } - final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) } pragma[noinline] private predicate hasDefinition(Instruction defInstr, Overlap overlap) { @@ -449,13 +451,17 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { final override Overlap getDefinitionOverlap() { result = overlap } - final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() } - - final override string getDumpLabel() { - result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + final override int getDumpSortOrder() { + result = 11 + this.getPredecessorBlock().getDisplayIndex() } - final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + final override string getDumpLabel() { + result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + final override string getDumpId() { + result = this.getPredecessorBlock().getDisplayIndex().toString() + } /** * Gets the predecessor block from which this value comes. diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql index 21ef4de1eae..ac77496f283 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql @@ -1,7 +1,7 @@ /** * @name Print Raw IR * @description Outputs a representation of the Raw IR graph - * @id csharp/print-raw-ir + * @id cs/print-raw-ir * @kind graph */ diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll index a172800b377..99833c70d0b 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll @@ -139,13 +139,13 @@ class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation { override LogicalOrExpr expr; override Instruction getChildTrueSuccessor(ConditionBase child) { - child = getAnOperand() and + child = this.getAnOperand() and result = this.getConditionContext().getChildTrueSuccessor(this) } override Instruction getChildFalseSuccessor(ConditionBase child) { child = this.getLeftOperand() and - result = getRightOperand().getFirstInstruction() + result = this.getRightOperand().getFirstInstruction() or child = this.getRightOperand() and result = this.getConditionContext().getChildFalseSuccessor(this) diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll index 86cbdbb4360..9b4fbbba723 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll @@ -48,7 +48,7 @@ class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration, override LocalVariable getDeclVar() { result = var } - override Type getVarType() { result = getVariableType(getDeclVar()) } + override Type getVarType() { result = getVariableType(this.getDeclVar()) } override Type getTargetType() { result = getVariableType(var) } @@ -58,7 +58,7 @@ class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration, or this.hasUninitializedInstruction() and tag = InitializerStoreTag() ) and - result = getIRUserVariable(getFunction(), getDeclVar()) + result = getIRUserVariable(this.getFunction(), this.getDeclVar()) } override TranslatedInitialization getInitialization() { diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll index 04e05dc9814..ea1ad7931cb 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll @@ -456,7 +456,7 @@ abstract class TranslatedElement extends TTranslatedElement { * there is no enclosing `try`. */ Instruction getExceptionSuccessorInstruction() { - result = getParent().getExceptionSuccessorInstruction() + result = this.getParent().getExceptionSuccessorInstruction() } /** @@ -558,7 +558,7 @@ abstract class TranslatedElement extends TTranslatedElement { * Gets the temporary variable generated by this element with tag `tag`. */ final IRTempVariable getTempVariable(TempVariableTag tag) { - result.getAST() = getAST() and + result.getAST() = this.getAST() and result.getTag() = tag and this.hasTempVariable(tag, _) } diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll index 72c408a3f2a..4f4c1a5f073 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll @@ -98,7 +98,7 @@ abstract class TranslatedCoreExpr extends TranslatedExpr { } final CSharpType getResultCSharpType() { - if isResultLValue() = true + if this.isResultLValue() = true then result = getTypeForGLValue(expr.getType()) else result = getTypeForPRValue(expr.getType()) } @@ -138,18 +138,18 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, tag = ConditionValueFalseConstantTag() ) and opcode instanceof Opcode::Constant and - resultType = getResultCSharpType() + resultType = this.getResultCSharpType() or ( tag = ConditionValueTrueStoreTag() or tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = getResultCSharpType() + resultType = this.getResultCSharpType() or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = getResultCSharpType() + resultType = this.getResultCSharpType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -258,7 +258,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { tag = LoadTag() and opcode instanceof Opcode::Load and - if producesExprResult() + if this.producesExprResult() then resultType = getTypeForPRValue(expr.getType()) else resultType = getTypeForGLValue(expr.getType()) } @@ -542,7 +542,7 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { } final override TranslatedElement getChild(int id) { - id = -1 and result = getBaseOperand() + id = -1 and result = this.getBaseOperand() or result = this.getOffsetOperand(id) } @@ -559,7 +559,7 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { or // The successor of the last `PointerAdd` instruction is // the successor of the `TranslatedArrayAccess`. - tag = PointerAddTag(getRank() - 1) and + tag = PointerAddTag(this.getRank() - 1) and result = this.getParent().getChildSuccessor(this) or // The successor of an `ElementsAddress` instruction is @@ -582,27 +582,29 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { result = this.getInstruction(PointerAddTag(child.getAST().getIndex())) } - override Instruction getResult() { result = this.getInstruction(PointerAddTag(getRank() - 1)) } + override Instruction getResult() { + result = this.getInstruction(PointerAddTag(this.getRank() - 1)) + } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { exists(int index | - inBounds(index) and + this.inBounds(index) and tag = PointerAddTag(index) and opcode instanceof Opcode::PointerAdd and - resultType = getTypeForPRValue(getArrayOfDim(getRank() - index, expr.getType())) + resultType = getTypeForPRValue(getArrayOfDim(this.getRank() - index, expr.getType())) ) or exists(int index | - inBounds(index) and + this.inBounds(index) and tag = ElementsAddressTag(index) and opcode instanceof Opcode::ElementsAddress and - resultType = getTypeForPRValue(getArrayOfDim(getRank() - index, expr.getType())) + resultType = getTypeForPRValue(getArrayOfDim(this.getRank() - index, expr.getType())) ) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { exists(int index | - inBounds(index) and + this.inBounds(index) and tag = PointerAddTag(index) and ( operandTag instanceof LeftOperandTag and @@ -632,7 +634,7 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { override int getInstructionElementSize(InstructionTag tag) { exists(int index | - inBounds(index) and + this.inBounds(index) and tag = PointerAddTag(index) and result = Language::getTypeSize(expr.getQualifier().getType().(ArrayType).getElementType()) ) @@ -989,9 +991,9 @@ abstract class TranslatedSingleInstructionExpr extends TranslatedNonConstantExpr abstract Opcode getOpcode(); final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - opcode = getOpcode() and + opcode = this.getOpcode() and tag = OnlyInstructionTag() and - resultType = getResultCSharpType() + resultType = this.getResultCSharpType() } final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } @@ -1081,7 +1083,7 @@ class TranslatedCast extends TranslatedNonConstantExpr { ) } - private TranslatedExpr getOperand() { result = getTranslatedExpr(expr.(Cast).getExpr()) } + private TranslatedExpr getOperand() { result = getTranslatedExpr(expr.getExpr()) } private Opcode getOpcode() { expr instanceof CastExpr and result instanceof Opcode::CheckedConvertOrThrow @@ -1181,15 +1183,15 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { } override Opcode getOpcode() { - result = binaryArithmeticOpcode(expr.(BinaryArithmeticOperation)) or - result = binaryBitwiseOpcode(expr.(BinaryBitwiseOperation)) or - result = comparisonOpcode(expr.(ComparisonOperation)) + result = binaryArithmeticOpcode(expr) or + result = binaryBitwiseOpcode(expr) or + result = comparisonOpcode(expr) } override int getInstructionElementSize(InstructionTag tag) { tag = OnlyInstructionTag() and exists(Opcode opcode | - opcode = getOpcode() and + opcode = this.getOpcode() and ( opcode instanceof Opcode::PointerAdd or opcode instanceof Opcode::PointerSub or @@ -1200,7 +1202,9 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { } private TranslatedExpr getPointerOperand() { - if swapOperandsOnOp() then result = this.getRightOperand() else result = this.getLeftOperand() + if this.swapOperandsOnOp() + then result = this.getRightOperand() + else result = this.getLeftOperand() } private predicate swapOperandsOnOp() { @@ -1425,7 +1429,7 @@ class TranslatedAssignOperation extends TranslatedAssignment { resultType = getTypeForPRValue(this.getLeftOperand().getResultType()) or tag = AssignOperationOpTag() and - opcode = getOpcode() and + opcode = this.getOpcode() and resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) or tag = AssignmentStoreTag() and @@ -1452,7 +1456,7 @@ class TranslatedAssignOperation extends TranslatedAssignment { opcode instanceof Opcode::PointerSub ) ) and - result = Language::getTypeSize(getResultType().(PointerType).getReferentType()) + result = Language::getTypeSize(this.getResultType().(PointerType).getReferentType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -1799,7 +1803,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { result = this.getInstruction(GeneratedConstantTag()) ) or - hasVar() and + this.hasVar() and tag = GeneratedBranchTag() and operandTag instanceof ConditionOperandTag and result = this.getInstruction(GeneratedNEQTag()) @@ -1848,7 +1852,7 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont } override Instruction getChildSuccessor(TranslatedElement child) { - child = getInitialization() and + child = this.getInitialization() and result = this.getInstruction(LoadTag()) } @@ -1922,7 +1926,7 @@ class TranslatedDelegateCall extends TranslatedNonConstantExpr { override Instruction getChildSuccessor(TranslatedElement child) { child = this.getInvokeCall() and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { @@ -1973,7 +1977,7 @@ abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreatio else result = this.getInstruction(NewObjTag()) } - override Instruction getReceiver() { result = getInstruction(NewObjTag()) } + override Instruction getReceiver() { result = this.getInstruction(NewObjTag()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { kind instanceof GotoEdge and @@ -1998,11 +2002,11 @@ abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreatio child = this.getConstructorCall() and if exists(this.getInitializerExpr()) then result = this.getInitializerExpr().getFirstInstruction() - else result = getLoadOrChildSuccessor() + else result = this.getLoadOrChildSuccessor() ) or child = this.getInitializerExpr() and - result = getLoadOrChildSuccessor() + result = this.getLoadOrChildSuccessor() } private Instruction getLoadOrChildSuccessor() { diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll index 65488a1b95d..94b48b0985d 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll @@ -68,20 +68,20 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or ( tag = AliasedDefinitionTag() and - if exists(getThisType()) + if exists(this.getThisType()) then result = this.getInstruction(InitializeThisTag()) else - if exists(getParameter(0)) + if exists(this.getParameter(0)) then result = this.getParameter(0).getFirstInstruction() else result = this.getBodyOrReturn() ) or ( tag = InitializeThisTag() and - if exists(getParameter(0)) + if exists(this.getParameter(0)) then result = this.getParameter(0).getFirstInstruction() else - if exists(getConstructorInitializer()) + if exists(this.getConstructorInitializer()) then result = this.getConstructorInitializer().getFirstInstruction() else result = this.getBodyOrReturn() ) @@ -106,7 +106,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { if exists(callable.getParameter(paramIndex + 1)) then result = this.getParameter(paramIndex + 1).getFirstInstruction() else - if exists(getConstructorInitializer()) + if exists(this.getConstructorInitializer()) then result = this.getConstructorInitializer().getFirstInstruction() else result = this.getBodyOrReturn() ) @@ -136,12 +136,12 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or tag = InitializeThisTag() and opcode instanceof Opcode::InitializeThis and - resultType = getTypeForGLValue(getThisType()) + resultType = getTypeForGLValue(this.getThisType()) or tag = ReturnValueAddressTag() and opcode instanceof Opcode::VariableAddress and - not getReturnType() instanceof VoidType and - resultType = getTypeForGLValue(getReturnType()) + not this.getReturnType() instanceof VoidType and + resultType = getTypeForGLValue(this.getReturnType()) or ( tag = ReturnTag() and @@ -201,7 +201,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ReturnValueTempVar() and type = getTypeForPRValue(this.getReturnType()) and - not getReturnType() instanceof VoidType + not this.getReturnType() instanceof VoidType } /** @@ -320,7 +320,7 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter { tag = InitializerStoreTag() or tag = InitializerVariableAddressTag() ) and - result = getIRUserVariable(getFunction(), param) + result = getIRUserVariable(this.getFunction(), param) } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll index cbe0e7c1d2a..77e41c15e72 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -139,7 +139,7 @@ class TranslatedDirectInitialization extends TranslatedInitialization { opcode instanceof Opcode::Store and resultType = getTypeForPRValue(this.getContext().getTargetType()) or - needsConversion() and + this.needsConversion() and tag = AssignmentConvertRightTag() and // For now only use `Opcode::Convert` to // crudely represent conversions. Could @@ -153,9 +153,9 @@ class TranslatedDirectInitialization extends TranslatedInitialization { result = this.getParent().getChildSuccessor(this) and kind instanceof GotoEdge or - needsConversion() and + this.needsConversion() and tag = AssignmentConvertRightTag() and - result = getInstruction(InitializerStoreTag()) and + result = this.getInstruction(InitializerStoreTag()) and kind instanceof GotoEdge } @@ -203,7 +203,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement { ArrayInitializer initList; final override string toString() { - result = initList.toString() + "[" + getElementIndex().toString() + "]" + result = initList.toString() + "[" + this.getElementIndex().toString() + "]" } final override Language::AST getAST() { result = initList } @@ -211,54 +211,54 @@ abstract class TranslatedElementInitialization extends TranslatedElement { final override Callable getFunction() { result = initList.getEnclosingCallable() } final override Instruction getFirstInstruction() { - result = this.getInstruction(getElementIndexTag()) + result = this.getInstruction(this.getElementIndexTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - tag = getElementIndexTag() and + tag = this.getElementIndexTag() and opcode instanceof Opcode::Constant and resultType = getIntType() or - tag = getElementAddressTag() and + tag = this.getElementAddressTag() and opcode instanceof Opcode::PointerAdd and - resultType = getTypeForGLValue(getElementType()) + resultType = getTypeForGLValue(this.getElementType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = getElementIndexTag() and - result = this.getInstruction(getElementAddressTag()) and + tag = this.getElementIndexTag() and + result = this.getInstruction(this.getElementAddressTag()) and kind instanceof GotoEdge } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = getElementAddressTag() and + tag = this.getElementAddressTag() and ( operandTag instanceof LeftOperandTag and result = this.getParent().(InitializationContext).getTargetAddress() or operandTag instanceof RightOperandTag and - result = this.getInstruction(getElementIndexTag()) + result = this.getInstruction(this.getElementIndexTag()) ) } override int getInstructionElementSize(InstructionTag tag) { - tag = getElementAddressTag() and - result = Language::getTypeSize(getElementType()) + tag = this.getElementAddressTag() and + result = Language::getTypeSize(this.getElementType()) } override string getInstructionConstantValue(InstructionTag tag) { - tag = getElementIndexTag() and - result = getElementIndex().toString() + tag = this.getElementIndexTag() and + result = this.getElementIndex().toString() } abstract int getElementIndex(); final InstructionTag getElementAddressTag() { - result = InitializerElementAddressTag(getElementIndex()) + result = InitializerElementAddressTag(this.getElementIndex()) } final InstructionTag getElementIndexTag() { - result = InitializerElementIndexTag(getElementIndex()) + result = InitializerElementIndexTag(this.getElementIndex()) } final ArrayInitializer getInitList() { result = initList } @@ -278,14 +278,16 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ this = TTranslatedExplicitElementInitialization(initList, elementIndex) } - override Instruction getTargetAddress() { result = this.getInstruction(getElementAddressTag()) } + override Instruction getTargetAddress() { + result = this.getInstruction(this.getElementAddressTag()) + } - override Type getTargetType() { result = getElementType() } + override Type getTargetType() { result = this.getElementType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { result = TranslatedElementInitialization.super.getInstructionSuccessor(tag, kind) or - tag = getElementAddressTag() and + tag = this.getElementAddressTag() and result = this.getInitialization().getFirstInstruction() and kind instanceof GotoEdge } @@ -340,7 +342,7 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons override string toString() { result = "constructor init: " + call.toString() } override Instruction getFirstInstruction() { - if needsConversion() + if this.needsConversion() then result = this.getInstruction(OnlyInstructionTag()) else result = this.getConstructorCall().getFirstInstruction() } @@ -361,13 +363,13 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons override Instruction getReceiver() { if this.needsConversion() then result = this.getInstruction(OnlyInstructionTag()) - else result = getTranslatedFunction(getFunction()).getInitializeThisInstruction() + else result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction() } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and - result = getTranslatedFunction(getFunction()).getInitializeThisInstruction() + result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction() } predicate needsConversion() { diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll index 81de9a6b7c9..ac69a9c0f28 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll @@ -79,7 +79,7 @@ class TranslatedDeclStmt extends TranslatedStmt { override Instruction getChildSuccessor(TranslatedElement child) { exists(int index | child = this.getLocalDeclaration(index) and - if index = (getChildCount() - 1) + if index = (this.getChildCount() - 1) then result = this.getParent().getChildSuccessor(this) else result = this.getLocalDeclaration(index + 1).getFirstInstruction() ) @@ -89,7 +89,7 @@ class TranslatedDeclStmt extends TranslatedStmt { class TranslatedExprStmt extends TranslatedStmt { override ExprStmt stmt; - TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.(ExprStmt).getExpr()) } + TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr()) } override TranslatedElement getChild(int id) { id = 0 and result = this.getExpr() } @@ -123,7 +123,7 @@ class TranslatedExprStmtAccessorSet extends TranslatedExprStmt { } override TranslatedExpr getExpr() { - result = getTranslatedExpr(stmt.(ExprStmt).getExpr().(AssignExpr).getLValue()) + result = getTranslatedExpr(stmt.getExpr().(AssignExpr).getLValue()) } override TranslatedElement getChild(int id) { id = 0 and result = this.getExpr() } @@ -276,14 +276,14 @@ class TranslatedBlock extends TranslatedStmt { override TranslatedElement getChild(int id) { result = this.getStmt(id) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { - isEmpty() and + this.isEmpty() and opcode instanceof Opcode::NoOp and tag = OnlyInstructionTag() and resultType = getVoidType() } override Instruction getFirstInstruction() { - if isEmpty() + if this.isEmpty() then result = this.getInstruction(OnlyInstructionTag()) else result = this.getStmt(0).getFirstInstruction() } @@ -303,7 +303,7 @@ class TranslatedBlock extends TranslatedStmt { override Instruction getChildSuccessor(TranslatedElement child) { exists(int index | child = this.getStmt(index) and - if index = (getStmtCount() - 1) + if index = (this.getStmtCount() - 1) then result = this.getParent().getChildSuccessor(this) else result = this.getStmt(index + 1).getFirstInstruction() ) @@ -347,7 +347,7 @@ class TranslatedCatchByTypeClause extends TranslatedClause { } override TranslatedElement getChild(int id) { - id = 0 and result = getParameter() + id = 0 and result = this.getParameter() or result = super.getChild(id) } @@ -355,14 +355,14 @@ class TranslatedCatchByTypeClause extends TranslatedClause { override Instruction getChildSuccessor(TranslatedElement child) { result = super.getChildSuccessor(child) or - child = getParameter() and result = this.getBlock().getFirstInstruction() + child = this.getParameter() and result = this.getBlock().getFirstInstruction() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = CatchTag() and ( kind instanceof GotoEdge and - result = getParameter().getFirstInstruction() + result = this.getParameter().getFirstInstruction() or kind instanceof ExceptionEdge and result = this.getParent().(TranslatedTryStmt).getNextHandler(this) @@ -559,8 +559,8 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext { final TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getBody()) } final Instruction getFirstConditionInstruction() { - if hasCondition() - then result = getCondition().getFirstInstruction() + if this.hasCondition() + then result = this.getCondition().getFirstInstruction() else result = this.getBody().getFirstInstruction() } @@ -611,13 +611,13 @@ class TranslatedForStmt extends TranslatedLoop { override ForStmt stmt; override TranslatedElement getChild(int id) { - initializerIndex(id) and result = this.getDeclAndInit(id) + this.initializerIndex(id) and result = this.getDeclAndInit(id) or - result = this.getUpdate(updateIndex(id)) + result = this.getUpdate(this.updateIndex(id)) or - id = initializersNo() + updatesNo() and result = this.getCondition() + id = this.initializersNo() + this.updatesNo() and result = this.getCondition() or - id = initializersNo() + updatesNo() + 1 and result = this.getBody() + id = this.initializersNo() + this.updatesNo() + 1 and result = this.getBody() } private TranslatedElement getDeclAndInit(int index) { @@ -636,11 +636,11 @@ class TranslatedForStmt extends TranslatedLoop { private int updatesNo() { result = count(stmt.getAnUpdate()) } - private predicate initializerIndex(int index) { index in [0 .. initializersNo() - 1] } + private predicate initializerIndex(int index) { index in [0 .. this.initializersNo() - 1] } private int updateIndex(int index) { - result in [0 .. updatesNo() - 1] and - index = initializersNo() + result + result in [0 .. this.updatesNo() - 1] and + index = this.initializersNo() + result } override Instruction getFirstInstruction() { @@ -652,11 +652,11 @@ class TranslatedForStmt extends TranslatedLoop { override Instruction getChildSuccessor(TranslatedElement child) { exists(int index | child = this.getDeclAndInit(index) and - index < initializersNo() - 1 and + index < this.initializersNo() - 1 and result = this.getDeclAndInit(index + 1).getFirstInstruction() ) or - child = this.getDeclAndInit(initializersNo() - 1) and + child = this.getDeclAndInit(this.initializersNo() - 1) and result = this.getFirstConditionInstruction() or ( @@ -671,7 +671,7 @@ class TranslatedForStmt extends TranslatedLoop { result = this.getUpdate(index + 1).getFirstInstruction() ) or - child = this.getUpdate(updatesNo() - 1) and + child = this.getUpdate(this.updatesNo() - 1) and result = this.getFirstConditionInstruction() } } @@ -693,7 +693,7 @@ abstract class TranslatedSpecificJump extends TranslatedStmt { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and kind instanceof GotoEdge and - result = getTargetInstruction() + result = this.getTargetInstruction() } override Instruction getChildSuccessor(TranslatedElement child) { none() } @@ -832,7 +832,7 @@ class TranslatedSwitchStmt extends TranslatedStmt { not exists(stmt.getDefaultCase()) and tag = SwitchBranchTag() and kind instanceof DefaultEdge and - result = getParent().getChildSuccessor(this) + result = this.getParent().getChildSuccessor(this) } private EdgeKind getCaseEdge(CaseStmt caseStmt) { @@ -862,19 +862,21 @@ class TranslatedEnumeratorForeach extends TranslatedLoop { override ForeachStmt stmt; override TranslatedElement getChild(int id) { - id = 0 and result = getTempEnumDecl() + id = 0 and result = this.getTempEnumDecl() or - id = 1 and result = getTry() + id = 1 and result = this.getTry() } - override Instruction getFirstInstruction() { result = getTempEnumDecl().getFirstInstruction() } + override Instruction getFirstInstruction() { + result = this.getTempEnumDecl().getFirstInstruction() + } override Instruction getChildSuccessor(TranslatedElement child) { - child = getTempEnumDecl() and - result = getTry().getFirstInstruction() + child = this.getTempEnumDecl() and + result = this.getTry().getFirstInstruction() or - child = getTry() and - result = getParent().getChildSuccessor(this) + child = this.getTry() and + result = this.getParent().getChildSuccessor(this) } private TranslatedElement getTry() { result = ForeachElements::getTry(stmt) } @@ -909,9 +911,9 @@ class TranslatedFixedStmt extends TranslatedStmt { override FixedStmt stmt; override TranslatedElement getChild(int id) { - result = getDecl(id) + result = this.getDecl(id) or - id = noDecls() and result = this.getBody() + id = this.noDecls() and result = this.getBody() } override Instruction getFirstInstruction() { result = this.getDecl(0).getFirstInstruction() } @@ -947,24 +949,26 @@ class TranslatedLockStmt extends TranslatedStmt { override LockStmt stmt; override TranslatedElement getChild(int id) { - id = 0 and result = getLockedVarDecl() + id = 0 and result = this.getLockedVarDecl() or - id = 1 and result = getLockWasTakenDecl() + id = 1 and result = this.getLockWasTakenDecl() or - id = 2 and result = getTry() + id = 2 and result = this.getTry() } - override Instruction getFirstInstruction() { result = getLockedVarDecl().getFirstInstruction() } + override Instruction getFirstInstruction() { + result = this.getLockedVarDecl().getFirstInstruction() + } override Instruction getChildSuccessor(TranslatedElement child) { - child = getLockedVarDecl() and - result = getLockWasTakenDecl().getFirstInstruction() + child = this.getLockedVarDecl() and + result = this.getLockWasTakenDecl().getFirstInstruction() or - child = getLockWasTakenDecl() and - result = getTry().getFirstInstruction() + child = this.getLockWasTakenDecl() and + result = this.getTry().getFirstInstruction() or - child = getTry() and - result = getParent().getChildSuccessor(this) + child = this.getTry() and + result = this.getParent().getChildSuccessor(this) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { @@ -1017,13 +1021,13 @@ class TranslatedUsingBlockStmt extends TranslatedStmt { override UsingBlockStmt stmt; override TranslatedElement getChild(int id) { - result = getDecl(id) + result = this.getDecl(id) or - id = getNumberOfDecls() and result = this.getBody() + id = this.getNumberOfDecls() and result = this.getBody() } override Instruction getFirstInstruction() { - if getNumberOfDecls() > 0 + if this.getNumberOfDecls() > 0 then result = this.getDecl(0).getFirstInstruction() else result = this.getBody().getFirstInstruction() } @@ -1060,7 +1064,7 @@ class TranslatedUsingBlockStmt extends TranslatedStmt { class TranslatedUsingDeclStmt extends TranslatedStmt { override UsingDeclStmt stmt; - override TranslatedElement getChild(int id) { result = getDecl(id) } + override TranslatedElement getChild(int id) { result = this.getDecl(id) } override Instruction getFirstInstruction() { result = this.getDecl(0).getFirstInstruction() } diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index 4b86f9a7cec..bb8630a5e0c 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -24,7 +24,7 @@ class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ - final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() } /** * INTERNAL: Do not use. @@ -39,7 +39,7 @@ class IRBlockBase extends TIRBlock { ) and this = rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 | - funcBlock.getEnclosingFunction() = getEnclosingFunction() and + funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and // Ensure that the block containing `EnterFunction` always comes first. if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction @@ -59,15 +59,15 @@ class IRBlockBase extends TIRBlock { * Get the `Phi` instructions that appear at the start of this block. */ final PhiInstruction getAPhiInstruction() { - Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() + Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction() } /** * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { - result = getInstruction(_) or - result = getAPhiInstruction() + result = this.getInstruction(_) or + result = this.getAPhiInstruction() } /** @@ -78,7 +78,9 @@ class IRBlockBase extends TIRBlock { /** * Gets the last instruction in this block. */ - final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + final Instruction getLastInstruction() { + result = this.getInstruction(this.getInstructionCount() - 1) + } /** * Gets the number of non-`Phi` instructions in this block. @@ -149,7 +151,7 @@ class IRBlock extends IRBlockBase { * Block `A` dominates block `B` if any control flow path from the entry block of the function to * block `B` must pass through block `A`. A block always dominates itself. */ - final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block } /** * Gets a block on the dominance frontier of this block. @@ -159,8 +161,8 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock dominanceFrontier() { - dominates(result.getAPredecessor()) and - not strictlyDominates(result) + this.dominates(result.getAPredecessor()) and + not this.strictlyDominates(result) } /** @@ -189,7 +191,7 @@ class IRBlock extends IRBlockBase { * Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the * function must pass through block `A`. A block always post-dominates itself. */ - final predicate postDominates(IRBlock block) { strictlyPostDominates(block) or this = block } + final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block } /** * Gets a block on the post-dominance frontier of this block. @@ -199,16 +201,16 @@ class IRBlock extends IRBlockBase { */ pragma[noinline] final IRBlock postPominanceFrontier() { - postDominates(result.getASuccessor()) and - not strictlyPostDominates(result) + this.postDominates(result.getASuccessor()) and + not this.strictlyPostDominates(result) } /** * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { - this = getEnclosingIRFunction().getEntryBlock() or - getAPredecessor().isReachableFromFunctionEntry() + this = this.getEnclosingIRFunction().getEntryBlock() or + this.getAPredecessor().isReachableFromFunctionEntry() } } diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 6f471d8a7e8..1c2cc493338 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction { } /** Gets a textual representation of this element. */ - final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } + final string toString() { result = this.getOpcode().toString() + ": " + this.getAST().toString() } /** * Gets a string showing the result, opcode, and operands of the instruction, equivalent to what @@ -50,7 +50,8 @@ class Instruction extends Construction::TStageInstruction { * `mu0_28(int) = Store r0_26, r0_27` */ final string getDumpString() { - result = getResultString() + " = " + getOperationString() + " " + getOperandsString() + result = + this.getResultString() + " = " + this.getOperationString() + " " + this.getOperandsString() } private predicate shouldGenerateDumpStrings() { @@ -66,10 +67,13 @@ class Instruction extends Construction::TStageInstruction { * VariableAddress[x] */ final string getOperationString() { - shouldGenerateDumpStrings() and - if exists(getImmediateString()) - then result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]" - else result = getOperationPrefix() + getOpcode().toString() + this.shouldGenerateDumpStrings() and + if exists(this.getImmediateString()) + then + result = + this.getOperationPrefix() + this.getOpcode().toString() + "[" + this.getImmediateString() + + "]" + else result = this.getOperationPrefix() + this.getOpcode().toString() } /** @@ -78,17 +82,17 @@ class Instruction extends Construction::TStageInstruction { string getImmediateString() { none() } private string getOperationPrefix() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and if this instanceof SideEffectInstruction then result = "^" else result = "" } private string getResultPrefix() { - shouldGenerateDumpStrings() and - if getResultIRType() instanceof IRVoidType + this.shouldGenerateDumpStrings() and + if this.getResultIRType() instanceof IRVoidType then result = "v" else - if hasMemoryResult() - then if isResultModeled() then result = "m" else result = "mu" + if this.hasMemoryResult() + then if this.isResultModeled() then result = "m" else result = "mu" else result = "r" } @@ -97,7 +101,7 @@ class Instruction extends Construction::TStageInstruction { * used by debugging and printing code only. */ int getDisplayIndexInBlock() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and exists(IRBlock block | this = block.getInstruction(result) or @@ -111,12 +115,12 @@ class Instruction extends Construction::TStageInstruction { } private int getLineRank() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and this = rank[result](Instruction instr | instr = - getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(), - getLocation().getStartLine()) + getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(), + this.getLocation().getStartLine()) | instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() ) @@ -130,8 +134,9 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1` */ string getResultId() { - shouldGenerateDumpStrings() and - result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank() + this.shouldGenerateDumpStrings() and + result = + this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank() } /** @@ -142,8 +147,8 @@ class Instruction extends Construction::TStageInstruction { * Example: `r1_1(int*)` */ final string getResultString() { - shouldGenerateDumpStrings() and - result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + this.shouldGenerateDumpStrings() and + result = this.getResultId() + "(" + this.getResultLanguageType().getDumpString() + ")" } /** @@ -153,10 +158,10 @@ class Instruction extends Construction::TStageInstruction { * Example: `func:r3_4, this:r3_5` */ string getOperandsString() { - shouldGenerateDumpStrings() and + this.shouldGenerateDumpStrings() and result = concat(Operand operand | - operand = getAnOperand() + operand = this.getAnOperand() | operand.getDumpString(), ", " order by operand.getDumpSortOrder() ) @@ -190,7 +195,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the function that contains this instruction. */ final Language::Function getEnclosingFunction() { - result = getEnclosingIRFunction().getFunction() + result = this.getEnclosingIRFunction().getFunction() } /** @@ -208,7 +213,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets the location of the source code for this instruction. */ - final Language::Location getLocation() { result = getAST().getLocation() } + final Language::Location getLocation() { result = this.getAST().getLocation() } /** * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a @@ -243,7 +248,7 @@ class Instruction extends Construction::TStageInstruction { * a result, its result type will be `IRVoidType`. */ cached - final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() } /** * Gets the type of the result produced by this instruction. If the @@ -254,7 +259,7 @@ class Instruction extends Construction::TStageInstruction { */ final Language::Type getResultType() { exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and + resultType = this.getResultLanguageType() and ( resultType.hasUnspecifiedType(result, _) or @@ -283,7 +288,7 @@ class Instruction extends Construction::TStageInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { getResultLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -292,7 +297,7 @@ class Instruction extends Construction::TStageInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = getResultLanguageType().getByteSize() } + final int getResultSize() { result = this.getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -314,14 +319,16 @@ class Instruction extends Construction::TStageInstruction { /** * Holds if this instruction produces a memory result. */ - final predicate hasMemoryResult() { exists(getResultMemoryAccess()) } + final predicate hasMemoryResult() { exists(this.getResultMemoryAccess()) } /** * Gets the kind of memory access performed by this instruction's result. * Holds only for instructions with a memory result. */ pragma[inline] - final MemoryAccessKind getResultMemoryAccess() { result = getOpcode().getWriteMemoryAccess() } + final MemoryAccessKind getResultMemoryAccess() { + result = this.getOpcode().getWriteMemoryAccess() + } /** * Holds if the memory access performed by this instruction's result will not always write to @@ -332,7 +339,7 @@ class Instruction extends Construction::TStageInstruction { * (for example, the global side effects of a function call). */ pragma[inline] - final predicate hasResultMayMemoryAccess() { getOpcode().hasMayWriteMemoryAccess() } + final predicate hasResultMayMemoryAccess() { this.getOpcode().hasMayWriteMemoryAccess() } /** * Gets the operand that holds the memory address to which this instruction stores its @@ -340,7 +347,7 @@ class Instruction extends Construction::TStageInstruction { * is `r1`. */ final AddressOperand getResultAddressOperand() { - getResultMemoryAccess().usesAddressOperand() and + this.getResultMemoryAccess().usesAddressOperand() and result.getUse() = this } @@ -349,7 +356,7 @@ class Instruction extends Construction::TStageInstruction { * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` * is the instruction that defines `r1`. */ - final Instruction getResultAddress() { result = getResultAddressOperand().getDef() } + final Instruction getResultAddress() { result = this.getResultAddressOperand().getDef() } /** * Holds if the result of this instruction is precisely modeled in SSA. Always @@ -368,7 +375,7 @@ class Instruction extends Construction::TStageInstruction { */ final predicate isResultModeled() { // Register results are always in SSA form. - not hasMemoryResult() or + not this.hasMemoryResult() or Construction::hasModeledMemoryResult(this) } @@ -412,7 +419,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct successors of this instruction. */ - final Instruction getASuccessor() { result = getSuccessor(_) } + final Instruction getASuccessor() { result = this.getSuccessor(_) } /** * Gets a predecessor of this instruction such that the predecessor reaches @@ -423,7 +430,7 @@ class Instruction extends Construction::TStageInstruction { /** * Gets all direct predecessors of this instruction. */ - final Instruction getAPredecessor() { result = getPredecessor(_) } + final Instruction getAPredecessor() { result = this.getPredecessor(_) } } /** @@ -543,7 +550,7 @@ class IndexedInstruction extends Instruction { * at this instruction. This instruction has no predecessors. */ class EnterFunctionInstruction extends Instruction { - EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } + EnterFunctionInstruction() { this.getOpcode() instanceof Opcode::EnterFunction } } /** @@ -554,7 +561,7 @@ class EnterFunctionInstruction extends Instruction { * struct, or union, see `FieldAddressInstruction`. */ class VariableAddressInstruction extends VariableInstruction { - VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } + VariableAddressInstruction() { this.getOpcode() instanceof Opcode::VariableAddress } } /** @@ -566,7 +573,7 @@ class VariableAddressInstruction extends VariableInstruction { * The result has an `IRFunctionAddress` type. */ class FunctionAddressInstruction extends FunctionInstruction { - FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } + FunctionAddressInstruction() { this.getOpcode() instanceof Opcode::FunctionAddress } } /** @@ -577,7 +584,7 @@ class FunctionAddressInstruction extends FunctionInstruction { * initializes that parameter. */ class InitializeParameterInstruction extends VariableInstruction { - InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + InitializeParameterInstruction() { this.getOpcode() instanceof Opcode::InitializeParameter } /** * Gets the parameter initialized by this instruction. @@ -603,7 +610,7 @@ class InitializeParameterInstruction extends VariableInstruction { * initialized elsewhere, would not otherwise have a definition in this function. */ class InitializeNonLocalInstruction extends Instruction { - InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } + InitializeNonLocalInstruction() { this.getOpcode() instanceof Opcode::InitializeNonLocal } } /** @@ -611,7 +618,7 @@ class InitializeNonLocalInstruction extends Instruction { * with the value of that memory on entry to the function. */ class InitializeIndirectionInstruction extends VariableInstruction { - InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + InitializeIndirectionInstruction() { this.getOpcode() instanceof Opcode::InitializeIndirection } /** * Gets the parameter initialized by this instruction. @@ -635,24 +642,24 @@ class InitializeIndirectionInstruction extends VariableInstruction { * An instruction that initializes the `this` pointer parameter of the enclosing function. */ class InitializeThisInstruction extends Instruction { - InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } + InitializeThisInstruction() { this.getOpcode() instanceof Opcode::InitializeThis } } /** * An instruction that computes the address of a non-static field of an object. */ class FieldAddressInstruction extends FieldInstruction { - FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + FieldAddressInstruction() { this.getOpcode() instanceof Opcode::FieldAddress } /** * Gets the operand that provides the address of the object containing the field. */ - final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the object containing the field. */ - final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } + final Instruction getObjectAddress() { result = this.getObjectAddressOperand().getDef() } } /** @@ -661,17 +668,19 @@ class FieldAddressInstruction extends FieldInstruction { * This instruction is used for element access to C# arrays. */ class ElementsAddressInstruction extends UnaryInstruction { - ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + ElementsAddressInstruction() { this.getOpcode() instanceof Opcode::ElementsAddress } /** * Gets the operand that provides the address of the array object. */ - final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + final UnaryOperand getArrayObjectAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the array object. */ - final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } + final Instruction getArrayObjectAddress() { + result = this.getArrayObjectAddressOperand().getDef() + } } /** @@ -685,7 +694,7 @@ class ElementsAddressInstruction extends UnaryInstruction { * taken may want to ignore any function that contains an `ErrorInstruction`. */ class ErrorInstruction extends Instruction { - ErrorInstruction() { getOpcode() instanceof Opcode::Error } + ErrorInstruction() { this.getOpcode() instanceof Opcode::Error } } /** @@ -695,7 +704,7 @@ class ErrorInstruction extends Instruction { * an initializer, or whose initializer only partially initializes the variable. */ class UninitializedInstruction extends VariableInstruction { - UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } + UninitializedInstruction() { this.getOpcode() instanceof Opcode::Uninitialized } /** * Gets the variable that is uninitialized. @@ -710,7 +719,7 @@ class UninitializedInstruction extends VariableInstruction { * least one instruction, even when the AST has no semantic effect. */ class NoOpInstruction extends Instruction { - NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } + NoOpInstruction() { this.getOpcode() instanceof Opcode::NoOp } } /** @@ -732,32 +741,42 @@ class NoOpInstruction extends Instruction { * `void`-returning function. */ class ReturnInstruction extends Instruction { - ReturnInstruction() { getOpcode() instanceof ReturnOpcode } + ReturnInstruction() { this.getOpcode() instanceof ReturnOpcode } } /** * An instruction that returns control to the caller of the function, without returning a value. */ class ReturnVoidInstruction extends ReturnInstruction { - ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } + ReturnVoidInstruction() { this.getOpcode() instanceof Opcode::ReturnVoid } } /** * An instruction that returns control to the caller of the function, including a return value. */ class ReturnValueInstruction extends ReturnInstruction { - ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + ReturnValueInstruction() { this.getOpcode() instanceof Opcode::ReturnValue } /** * Gets the operand that provides the value being returned by the function. */ - final LoadOperand getReturnValueOperand() { result = getAnOperand() } + final LoadOperand getReturnValueOperand() { result = this.getAnOperand() } + + /** + * Gets the operand that provides the address of the value being returned by the function. + */ + final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value being returned by the function, if an * exact definition is available. */ - final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } + final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() } + + /** + * Gets the instruction whose result provides the address of the value being returned by the function. + */ + final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() } } /** @@ -770,28 +789,28 @@ class ReturnValueInstruction extends ReturnInstruction { * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { - ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + ReturnIndirectionInstruction() { this.getOpcode() instanceof Opcode::ReturnIndirection } /** * Gets the operand that provides the value of the pointed-to memory. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the pointed-to memory, if an exact * definition is available. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** * Gets the operand that provides the address of the pointed-to memory. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the pointed-to memory. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } /** * Gets the parameter for which this instruction reads the final pointed-to value within the @@ -826,7 +845,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { * - `StoreInstruction` - Copies a register operand to a memory result. */ class CopyInstruction extends Instruction { - CopyInstruction() { getOpcode() instanceof CopyOpcode } + CopyInstruction() { this.getOpcode() instanceof CopyOpcode } /** * Gets the operand that provides the input value of the copy. @@ -837,16 +856,16 @@ class CopyInstruction extends Instruction { * Gets the instruction whose result provides the input value of the copy, if an exact definition * is available. */ - final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } + final Instruction getSourceValue() { result = this.getSourceValueOperand().getDef() } } /** * An instruction that returns a register result containing a copy of its register operand. */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { - CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } + CopyValueInstruction() { this.getOpcode() instanceof Opcode::CopyValue } - final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } + final override UnaryOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -863,47 +882,49 @@ private string getAddressOperandDescription(AddressOperand operand) { * An instruction that returns a register result containing a copy of its memory operand. */ class LoadInstruction extends CopyInstruction { - LoadInstruction() { getOpcode() instanceof Opcode::Load } + LoadInstruction() { this.getOpcode() instanceof Opcode::Load } final override string getImmediateString() { - result = getAddressOperandDescription(getSourceAddressOperand()) + result = getAddressOperandDescription(this.getSourceAddressOperand()) } /** * Gets the operand that provides the address of the value being loaded. */ - final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + final AddressOperand getSourceAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the value being loaded. */ - final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + final Instruction getSourceAddress() { result = this.getSourceAddressOperand().getDef() } - final override LoadOperand getSourceValueOperand() { result = getAnOperand() } + final override LoadOperand getSourceValueOperand() { result = this.getAnOperand() } } /** * An instruction that returns a memory result containing a copy of its register operand. */ class StoreInstruction extends CopyInstruction { - StoreInstruction() { getOpcode() instanceof Opcode::Store } + StoreInstruction() { this.getOpcode() instanceof Opcode::Store } final override string getImmediateString() { - result = getAddressOperandDescription(getDestinationAddressOperand()) + result = getAddressOperandDescription(this.getDestinationAddressOperand()) } /** * Gets the operand that provides the address of the location to which the value will be stored. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the location to which the value will * be stored, if an exact definition is available. */ - final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + final Instruction getDestinationAddress() { + result = this.getDestinationAddressOperand().getDef() + } - final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } + final override StoreValueOperand getSourceValueOperand() { result = this.getAnOperand() } } /** @@ -911,27 +932,27 @@ class StoreInstruction extends CopyInstruction { * operand. */ class ConditionalBranchInstruction extends Instruction { - ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + ConditionalBranchInstruction() { this.getOpcode() instanceof Opcode::ConditionalBranch } /** * Gets the operand that provides the Boolean condition controlling the branch. */ - final ConditionOperand getConditionOperand() { result = getAnOperand() } + final ConditionOperand getConditionOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the Boolean condition controlling the branch. */ - final Instruction getCondition() { result = getConditionOperand().getDef() } + final Instruction getCondition() { result = this.getConditionOperand().getDef() } /** * Gets the instruction to which control will flow if the condition is true. */ - final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + final Instruction getTrueSuccessor() { result = this.getSuccessor(EdgeKind::trueEdge()) } /** * Gets the instruction to which control will flow if the condition is false. */ - final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } + final Instruction getFalseSuccessor() { result = this.getSuccessor(EdgeKind::falseEdge()) } } /** @@ -943,14 +964,14 @@ class ConditionalBranchInstruction extends Instruction { * successors. */ class ExitFunctionInstruction extends Instruction { - ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } + ExitFunctionInstruction() { this.getOpcode() instanceof Opcode::ExitFunction } } /** * An instruction whose result is a constant value. */ class ConstantInstruction extends ConstantValueInstruction { - ConstantInstruction() { getOpcode() instanceof Opcode::Constant } + ConstantInstruction() { this.getOpcode() instanceof Opcode::Constant } } /** @@ -959,7 +980,7 @@ class ConstantInstruction extends ConstantValueInstruction { class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | - resultType = getResultIRType() and + resultType = this.getResultIRType() and (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) ) } @@ -969,7 +990,7 @@ class IntegerConstantInstruction extends ConstantInstruction { * An instruction whose result is a constant value of floating-point type. */ class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } + FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType } } /** @@ -978,7 +999,9 @@ class FloatConstantInstruction extends ConstantInstruction { class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; - final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + final override string getImmediateString() { + result = Language::getStringLiteralText(this.getValue()) + } /** * Gets the string literal whose address is returned by this instruction. @@ -990,37 +1013,37 @@ class StringConstantInstruction extends VariableInstruction { * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { - BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + BinaryInstruction() { this.getOpcode() instanceof BinaryOpcode } /** * Gets the left operand of this binary instruction. */ - final LeftOperand getLeftOperand() { result = getAnOperand() } + final LeftOperand getLeftOperand() { result = this.getAnOperand() } /** * Gets the right operand of this binary instruction. */ - final RightOperand getRightOperand() { result = getAnOperand() } + final RightOperand getRightOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the value of the left operand of this binary * instruction. */ - final Instruction getLeft() { result = getLeftOperand().getDef() } + final Instruction getLeft() { result = this.getLeftOperand().getDef() } /** * Gets the instruction whose result provides the value of the right operand of this binary * instruction. */ - final Instruction getRight() { result = getRightOperand().getDef() } + final Instruction getRight() { result = this.getRightOperand().getDef() } /** * Holds if this instruction's operands are `op1` and `op2`, in either order. */ final predicate hasOperands(Operand op1, Operand op2) { - op1 = getLeftOperand() and op2 = getRightOperand() + op1 = this.getLeftOperand() and op2 = this.getRightOperand() or - op1 = getRightOperand() and op2 = getLeftOperand() + op1 = this.getRightOperand() and op2 = this.getLeftOperand() } } @@ -1028,7 +1051,7 @@ class BinaryInstruction extends Instruction { * An instruction that computes the result of an arithmetic operation. */ class ArithmeticInstruction extends Instruction { - ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } + ArithmeticInstruction() { this.getOpcode() instanceof ArithmeticOpcode } } /** @@ -1050,7 +1073,7 @@ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction * performed according to IEEE-754. */ class AddInstruction extends BinaryArithmeticInstruction { - AddInstruction() { getOpcode() instanceof Opcode::Add } + AddInstruction() { this.getOpcode() instanceof Opcode::Add } } /** @@ -1061,7 +1084,7 @@ class AddInstruction extends BinaryArithmeticInstruction { * according to IEEE-754. */ class SubInstruction extends BinaryArithmeticInstruction { - SubInstruction() { getOpcode() instanceof Opcode::Sub } + SubInstruction() { this.getOpcode() instanceof Opcode::Sub } } /** @@ -1072,7 +1095,7 @@ class SubInstruction extends BinaryArithmeticInstruction { * performed according to IEEE-754. */ class MulInstruction extends BinaryArithmeticInstruction { - MulInstruction() { getOpcode() instanceof Opcode::Mul } + MulInstruction() { this.getOpcode() instanceof Opcode::Mul } } /** @@ -1083,7 +1106,7 @@ class MulInstruction extends BinaryArithmeticInstruction { * to IEEE-754. */ class DivInstruction extends BinaryArithmeticInstruction { - DivInstruction() { getOpcode() instanceof Opcode::Div } + DivInstruction() { this.getOpcode() instanceof Opcode::Div } } /** @@ -1093,7 +1116,7 @@ class DivInstruction extends BinaryArithmeticInstruction { * division by zero or integer overflow is undefined. */ class RemInstruction extends BinaryArithmeticInstruction { - RemInstruction() { getOpcode() instanceof Opcode::Rem } + RemInstruction() { this.getOpcode() instanceof Opcode::Rem } } /** @@ -1104,14 +1127,14 @@ class RemInstruction extends BinaryArithmeticInstruction { * is performed according to IEEE-754. */ class NegateInstruction extends UnaryArithmeticInstruction { - NegateInstruction() { getOpcode() instanceof Opcode::Negate } + NegateInstruction() { this.getOpcode() instanceof Opcode::Negate } } /** * An instruction that computes the result of a bitwise operation. */ class BitwiseInstruction extends Instruction { - BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } + BitwiseInstruction() { this.getOpcode() instanceof BitwiseOpcode } } /** @@ -1130,7 +1153,7 @@ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } * Both operands must have the same integer type, which will also be the result type. */ class BitAndInstruction extends BinaryBitwiseInstruction { - BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } + BitAndInstruction() { this.getOpcode() instanceof Opcode::BitAnd } } /** @@ -1139,7 +1162,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitOrInstruction extends BinaryBitwiseInstruction { - BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } + BitOrInstruction() { this.getOpcode() instanceof Opcode::BitOr } } /** @@ -1148,7 +1171,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { * Both operands must have the same integer type, which will also be the result type. */ class BitXorInstruction extends BinaryBitwiseInstruction { - BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } + BitXorInstruction() { this.getOpcode() instanceof Opcode::BitXor } } /** @@ -1159,7 +1182,7 @@ class BitXorInstruction extends BinaryBitwiseInstruction { * rightmost bits are zero-filled. */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { - ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } + ShiftLeftInstruction() { this.getOpcode() instanceof Opcode::ShiftLeft } } /** @@ -1172,7 +1195,7 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { * of the left operand. */ class ShiftRightInstruction extends BinaryBitwiseInstruction { - ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } + ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight } } /** @@ -1183,7 +1206,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; PointerArithmeticInstruction() { - getOpcode() instanceof PointerArithmeticOpcode and + this.getOpcode() instanceof PointerArithmeticOpcode and elementSize = Raw::getInstructionElementSize(this) } @@ -1206,7 +1229,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { * An instruction that adds or subtracts an integer offset from a pointer. */ class PointerOffsetInstruction extends PointerArithmeticInstruction { - PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } + PointerOffsetInstruction() { this.getOpcode() instanceof PointerOffsetOpcode } } /** @@ -1217,7 +1240,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { * overflow is undefined. */ class PointerAddInstruction extends PointerOffsetInstruction { - PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } + PointerAddInstruction() { this.getOpcode() instanceof Opcode::PointerAdd } } /** @@ -1228,7 +1251,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { * pointer underflow is undefined. */ class PointerSubInstruction extends PointerOffsetInstruction { - PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } + PointerSubInstruction() { this.getOpcode() instanceof Opcode::PointerSub } } /** @@ -1241,31 +1264,31 @@ class PointerSubInstruction extends PointerOffsetInstruction { * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { - PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } + PointerDiffInstruction() { this.getOpcode() instanceof Opcode::PointerDiff } } /** * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { - UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + UnaryInstruction() { this.getOpcode() instanceof UnaryOpcode } /** * Gets the sole operand of this instruction. */ - final UnaryOperand getUnaryOperand() { result = getAnOperand() } + final UnaryOperand getUnaryOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the sole operand of this instruction. */ - final Instruction getUnary() { result = getUnaryOperand().getDef() } + final Instruction getUnary() { result = this.getUnaryOperand().getDef() } } /** * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { - ConvertInstruction() { getOpcode() instanceof Opcode::Convert } + ConvertInstruction() { this.getOpcode() instanceof Opcode::Convert } } /** @@ -1279,7 +1302,7 @@ class ConvertInstruction extends UnaryInstruction { * `as` expression. */ class CheckedConvertOrNullInstruction extends UnaryInstruction { - CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } + CheckedConvertOrNullInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** @@ -1293,7 +1316,7 @@ class CheckedConvertOrNullInstruction extends UnaryInstruction { * expression. */ class CheckedConvertOrThrowInstruction extends UnaryInstruction { - CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } + CheckedConvertOrThrowInstruction() { this.getOpcode() instanceof Opcode::CheckedConvertOrThrow } } /** @@ -1306,7 +1329,7 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { * the most-derived object. */ class CompleteObjectAddressInstruction extends UnaryInstruction { - CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } + CompleteObjectAddressInstruction() { this.getOpcode() instanceof Opcode::CompleteObjectAddress } } /** @@ -1351,7 +1374,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { - ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } + ConvertToBaseInstruction() { this.getOpcode() instanceof ConvertToBaseOpcode } } /** @@ -1361,7 +1384,9 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } + ConvertToNonVirtualBaseInstruction() { + this.getOpcode() instanceof Opcode::ConvertToNonVirtualBase + } } /** @@ -1371,7 +1396,7 @@ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { - ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } + ConvertToVirtualBaseInstruction() { this.getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** @@ -1381,7 +1406,7 @@ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { - ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } + ConvertToDerivedInstruction() { this.getOpcode() instanceof Opcode::ConvertToDerived } } /** @@ -1390,7 +1415,7 @@ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { * The operand must have an integer type, which will also be the result type. */ class BitComplementInstruction extends UnaryBitwiseInstruction { - BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } + BitComplementInstruction() { this.getOpcode() instanceof Opcode::BitComplement } } /** @@ -1399,14 +1424,14 @@ class BitComplementInstruction extends UnaryBitwiseInstruction { * The operand must have a Boolean type, which will also be the result type. */ class LogicalNotInstruction extends UnaryInstruction { - LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } + LogicalNotInstruction() { this.getOpcode() instanceof Opcode::LogicalNot } } /** * An instruction that compares two numeric operands. */ class CompareInstruction extends BinaryInstruction { - CompareInstruction() { getOpcode() instanceof CompareOpcode } + CompareInstruction() { this.getOpcode() instanceof CompareOpcode } } /** @@ -1417,7 +1442,7 @@ class CompareInstruction extends BinaryInstruction { * unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareEQInstruction extends CompareInstruction { - CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } + CompareEQInstruction() { this.getOpcode() instanceof Opcode::CompareEQ } } /** @@ -1428,14 +1453,14 @@ class CompareEQInstruction extends CompareInstruction { * `left == right`. Floating-point comparison is performed according to IEEE-754. */ class CompareNEInstruction extends CompareInstruction { - CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } + CompareNEInstruction() { this.getOpcode() instanceof Opcode::CompareNE } } /** * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { - RelationalInstruction() { getOpcode() instanceof RelationalOpcode } + RelationalInstruction() { this.getOpcode() instanceof RelationalOpcode } /** * Gets the operand on the "greater" (or "greater-or-equal") side @@ -1467,11 +1492,11 @@ class RelationalInstruction extends CompareInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLTInstruction extends RelationalInstruction { - CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } + CompareLTInstruction() { this.getOpcode() instanceof Opcode::CompareLT } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { any() } } @@ -1484,11 +1509,11 @@ class CompareLTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGTInstruction extends RelationalInstruction { - CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } + CompareGTInstruction() { this.getOpcode() instanceof Opcode::CompareGT } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { any() } } @@ -1502,11 +1527,11 @@ class CompareGTInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareLEInstruction extends RelationalInstruction { - CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } + CompareLEInstruction() { this.getOpcode() instanceof Opcode::CompareLE } - override Instruction getLesser() { result = getLeft() } + override Instruction getLesser() { result = this.getLeft() } - override Instruction getGreater() { result = getRight() } + override Instruction getGreater() { result = this.getRight() } override predicate isStrict() { none() } } @@ -1520,11 +1545,11 @@ class CompareLEInstruction extends RelationalInstruction { * are unordered. Floating-point comparison is performed according to IEEE-754. */ class CompareGEInstruction extends RelationalInstruction { - CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } + CompareGEInstruction() { this.getOpcode() instanceof Opcode::CompareGE } - override Instruction getLesser() { result = getRight() } + override Instruction getLesser() { result = this.getRight() } - override Instruction getGreater() { result = getLeft() } + override Instruction getGreater() { result = this.getLeft() } override predicate isStrict() { none() } } @@ -1543,78 +1568,78 @@ class CompareGEInstruction extends RelationalInstruction { * of any case edge. */ class SwitchInstruction extends Instruction { - SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + SwitchInstruction() { this.getOpcode() instanceof Opcode::Switch } /** Gets the operand that provides the integer value controlling the switch. */ - final ConditionOperand getExpressionOperand() { result = getAnOperand() } + final ConditionOperand getExpressionOperand() { result = this.getAnOperand() } /** Gets the instruction whose result provides the integer value controlling the switch. */ - final Instruction getExpression() { result = getExpressionOperand().getDef() } + final Instruction getExpression() { result = this.getExpressionOperand().getDef() } /** Gets the successor instructions along the case edges of the switch. */ - final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = this.getSuccessor(edge)) } /** Gets the successor instruction along the default edge of the switch, if any. */ - final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } + final Instruction getDefaultSuccessor() { result = this.getSuccessor(EdgeKind::defaultEdge()) } } /** * An instruction that calls a function. */ class CallInstruction extends Instruction { - CallInstruction() { getOpcode() instanceof Opcode::Call } + CallInstruction() { this.getOpcode() instanceof Opcode::Call } final override string getImmediateString() { - result = getStaticCallTarget().toString() + result = this.getStaticCallTarget().toString() or - not exists(getStaticCallTarget()) and result = "?" + not exists(this.getStaticCallTarget()) and result = "?" } /** * Gets the operand the specifies the target function of the call. */ - final CallTargetOperand getCallTargetOperand() { result = getAnOperand() } + final CallTargetOperand getCallTargetOperand() { result = this.getAnOperand() } /** * Gets the `Instruction` that computes the target function of the call. This is usually a * `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a * function pointer. */ - final Instruction getCallTarget() { result = getCallTargetOperand().getDef() } + final Instruction getCallTarget() { result = this.getCallTargetOperand().getDef() } /** * Gets all of the argument operands of the call, including the `this` pointer, if any. */ - final ArgumentOperand getAnArgumentOperand() { result = getAnOperand() } + final ArgumentOperand getAnArgumentOperand() { result = this.getAnOperand() } /** * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() + result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** * Gets all of the arguments of the call, including the `this` pointer, if any. */ - final Instruction getAnArgument() { result = getAnArgumentOperand().getDef() } + final Instruction getAnArgument() { result = this.getAnArgumentOperand().getDef() } /** * Gets the `this` pointer argument operand of the call, if any. */ - final ThisArgumentOperand getThisArgumentOperand() { result = getAnOperand() } + final ThisArgumentOperand getThisArgumentOperand() { result = this.getAnOperand() } /** * Gets the `this` pointer argument of the call, if any. */ - final Instruction getThisArgument() { result = getThisArgumentOperand().getDef() } + final Instruction getThisArgument() { result = this.getThisArgumentOperand().getDef() } /** * Gets the argument operand at the specified index. */ pragma[noinline] final PositionalArgumentOperand getPositionalArgumentOperand(int index) { - result = getAnOperand() and + result = this.getAnOperand() and result.getIndex() = index } @@ -1623,7 +1648,7 @@ class CallInstruction extends Instruction { */ pragma[noinline] final Instruction getPositionalArgument(int index) { - result = getPositionalArgumentOperand(index).getDef() + result = this.getPositionalArgumentOperand(index).getDef() } /** @@ -1631,16 +1656,16 @@ class CallInstruction extends Instruction { */ pragma[noinline] final ArgumentOperand getArgumentOperand(int index) { - index >= 0 and result = getPositionalArgumentOperand(index) + index >= 0 and result = this.getPositionalArgumentOperand(index) or - index = -1 and result = getThisArgumentOperand() + index = -1 and result = this.getThisArgumentOperand() } /** * Gets the argument at the specified index, or `this` if `index` is `-1`. */ pragma[noinline] - final Instruction getArgument(int index) { result = getArgumentOperand(index).getDef() } + final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() } /** * Gets the number of arguments of the call, including the `this` pointer, if any. @@ -1665,7 +1690,7 @@ class CallInstruction extends Instruction { * An instruction representing a side effect of a function call. */ class SideEffectInstruction extends Instruction { - SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + SideEffectInstruction() { this.getOpcode() instanceof SideEffectOpcode } /** * Gets the instruction whose execution causes this side effect. @@ -1680,7 +1705,7 @@ class SideEffectInstruction extends Instruction { * accessed by that call. */ class CallSideEffectInstruction extends SideEffectInstruction { - CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect } + CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect } } /** @@ -1691,7 +1716,7 @@ class CallSideEffectInstruction extends SideEffectInstruction { * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { - CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } + CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect } } /** @@ -1699,33 +1724,33 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * specific parameter. */ class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode } + ReadSideEffectInstruction() { this.getOpcode() instanceof ReadSideEffectOpcode } /** Gets the operand for the value that will be read from this instruction, if known. */ - final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() } /** Gets the value that will be read from this instruction, if known. */ - final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + final Instruction getSideEffect() { result = this.getSideEffectOperand().getDef() } /** Gets the operand for the address from which this instruction may read. */ - final AddressOperand getArgumentOperand() { result = getAnOperand() } + final AddressOperand getArgumentOperand() { result = this.getAnOperand() } /** Gets the address from which this instruction may read. */ - final Instruction getArgumentDef() { result = getArgumentOperand().getDef() } + final Instruction getArgumentDef() { result = this.getArgumentOperand().getDef() } } /** * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::IndirectReadSideEffect } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::BufferReadSideEffect } } /** @@ -1733,18 +1758,18 @@ class BufferReadSideEffectInstruction extends ReadSideEffectInstruction { */ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { SizedBufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferReadSideEffect + this.getOpcode() instanceof Opcode::SizedBufferReadSideEffect } /** * Gets the operand that holds the number of bytes read from the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes read from the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1752,17 +1777,17 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { * specific parameter. */ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { - WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } + WriteSideEffectInstruction() { this.getOpcode() instanceof WriteSideEffectOpcode } /** * Get the operand that holds the address of the memory to be written. */ - final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the address of the memory to be written. */ - Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + Instruction getDestinationAddress() { result = this.getDestinationAddressOperand().getDef() } } /** @@ -1770,7 +1795,7 @@ class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstructi */ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMustWriteSideEffect } } @@ -1780,7 +1805,7 @@ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction */ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { BufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::BufferMustWriteSideEffect } } @@ -1790,18 +1815,18 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMustWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1812,7 +1837,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi */ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectMayWriteSideEffect + this.getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } } @@ -1822,7 +1847,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } + BufferMayWriteSideEffectInstruction() { + this.getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } } /** @@ -1832,18 +1859,18 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { SizedBufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + this.getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } /** * Gets the operand that holds the number of bytes written to the buffer. */ - final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + final BufferSizeOperand getBufferSizeOperand() { result = this.getAnOperand() } /** * Gets the instruction whose result provides the number of bytes written to the buffer. */ - final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } + final Instruction getBufferSize() { result = this.getBufferSizeOperand().getDef() } } /** @@ -1852,80 +1879,80 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { InitializeDynamicAllocationInstruction() { - getOpcode() instanceof Opcode::InitializeDynamicAllocation + this.getOpcode() instanceof Opcode::InitializeDynamicAllocation } /** * Gets the operand that represents the address of the allocation this instruction is initializing. */ - final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + final AddressOperand getAllocationAddressOperand() { result = this.getAnOperand() } /** * Gets the address for the allocation this instruction is initializing. */ - final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } + final Instruction getAllocationAddress() { result = this.getAllocationAddressOperand().getDef() } } /** * An instruction representing a GNU or MSVC inline assembly statement. */ class InlineAsmInstruction extends Instruction { - InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm } + InlineAsmInstruction() { this.getOpcode() instanceof Opcode::InlineAsm } } /** * An instruction that throws an exception. */ class ThrowInstruction extends Instruction { - ThrowInstruction() { getOpcode() instanceof ThrowOpcode } + ThrowInstruction() { this.getOpcode() instanceof ThrowOpcode } } /** * An instruction that throws a new exception. */ class ThrowValueInstruction extends ThrowInstruction { - ThrowValueInstruction() { getOpcode() instanceof Opcode::ThrowValue } + ThrowValueInstruction() { this.getOpcode() instanceof Opcode::ThrowValue } /** * Gets the address operand of the exception thrown by this instruction. */ - final AddressOperand getExceptionAddressOperand() { result = getAnOperand() } + final AddressOperand getExceptionAddressOperand() { result = this.getAnOperand() } /** * Gets the address of the exception thrown by this instruction. */ - final Instruction getExceptionAddress() { result = getExceptionAddressOperand().getDef() } + final Instruction getExceptionAddress() { result = this.getExceptionAddressOperand().getDef() } /** * Gets the operand for the exception thrown by this instruction. */ - final LoadOperand getExceptionOperand() { result = getAnOperand() } + final LoadOperand getExceptionOperand() { result = this.getAnOperand() } /** * Gets the exception thrown by this instruction. */ - final Instruction getException() { result = getExceptionOperand().getDef() } + final Instruction getException() { result = this.getExceptionOperand().getDef() } } /** * An instruction that re-throws the current exception. */ class ReThrowInstruction extends ThrowInstruction { - ReThrowInstruction() { getOpcode() instanceof Opcode::ReThrow } + ReThrowInstruction() { this.getOpcode() instanceof Opcode::ReThrow } } /** * An instruction that exits the current function by propagating an exception. */ class UnwindInstruction extends Instruction { - UnwindInstruction() { getOpcode() instanceof Opcode::Unwind } + UnwindInstruction() { this.getOpcode() instanceof Opcode::Unwind } } /** * An instruction that starts a `catch` handler. */ class CatchInstruction extends Instruction { - CatchInstruction() { getOpcode() instanceof CatchOpcode } + CatchInstruction() { this.getOpcode() instanceof CatchOpcode } } /** @@ -1935,7 +1962,7 @@ class CatchByTypeInstruction extends CatchInstruction { Language::LanguageType exceptionType; CatchByTypeInstruction() { - getOpcode() instanceof Opcode::CatchByType and + this.getOpcode() instanceof Opcode::CatchByType and exceptionType = Raw::getInstructionExceptionType(this) } @@ -1951,21 +1978,21 @@ class CatchByTypeInstruction extends CatchInstruction { * An instruction that catches any exception. */ class CatchAnyInstruction extends CatchInstruction { - CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } + CatchAnyInstruction() { this.getOpcode() instanceof Opcode::CatchAny } } /** * An instruction that initializes all escaped memory. */ class AliasedDefinitionInstruction extends Instruction { - AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition } + AliasedDefinitionInstruction() { this.getOpcode() instanceof Opcode::AliasedDefinition } } /** * An instruction that consumes all escaped memory on exit from the function. */ class AliasedUseInstruction extends Instruction { - AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } + AliasedUseInstruction() { this.getOpcode() instanceof Opcode::AliasedUse } } /** @@ -1979,7 +2006,7 @@ class AliasedUseInstruction extends Instruction { * runtime. */ class PhiInstruction extends Instruction { - PhiInstruction() { getOpcode() instanceof Opcode::Phi } + PhiInstruction() { this.getOpcode() instanceof Opcode::Phi } /** * Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block. @@ -2047,29 +2074,29 @@ class PhiInstruction extends Instruction { * https://link.springer.com/content/pdf/10.1007%2F3-540-61053-7_66.pdf. */ class ChiInstruction extends Instruction { - ChiInstruction() { getOpcode() instanceof Opcode::Chi } + ChiInstruction() { this.getOpcode() instanceof Opcode::Chi } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final ChiTotalOperand getTotalOperand() { result = getAnOperand() } + final ChiTotalOperand getTotalOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the previous state of all memory that might be aliased by the * memory write. */ - final Instruction getTotal() { result = getTotalOperand().getDef() } + final Instruction getTotal() { result = this.getTotalOperand().getDef() } /** * Gets the operand that represents the new value written by the memory write. */ - final ChiPartialOperand getPartialOperand() { result = getAnOperand() } + final ChiPartialOperand getPartialOperand() { result = this.getAnOperand() } /** * Gets the operand that represents the new value written by the memory write. */ - final Instruction getPartial() { result = getPartialOperand().getDef() } + final Instruction getPartial() { result = this.getPartialOperand().getDef() } /** * Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand. @@ -2093,7 +2120,7 @@ class ChiInstruction extends Instruction { * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { - UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } + UnreachedInstruction() { this.getOpcode() instanceof Opcode::Unreached } } /** @@ -2106,7 +2133,7 @@ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; BuiltInOperationInstruction() { - getOpcode() instanceof BuiltInOperationOpcode and + this.getOpcode() instanceof BuiltInOperationOpcode and operation = Raw::getInstructionBuiltInOperation(this) } @@ -2122,9 +2149,9 @@ class BuiltInOperationInstruction extends Instruction { * actual operation is specified by the `getBuiltInOperation()` predicate. */ class BuiltInInstruction extends BuiltInOperationInstruction { - BuiltInInstruction() { getOpcode() instanceof Opcode::BuiltIn } + BuiltInInstruction() { this.getOpcode() instanceof Opcode::BuiltIn } - final override string getImmediateString() { result = getBuiltInOperation().toString() } + final override string getImmediateString() { result = this.getBuiltInOperation().toString() } } /** @@ -2135,7 +2162,7 @@ class BuiltInInstruction extends BuiltInOperationInstruction { * to the `...` parameter. */ class VarArgsStartInstruction extends UnaryInstruction { - VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } + VarArgsStartInstruction() { this.getOpcode() instanceof Opcode::VarArgsStart } } /** @@ -2145,7 +2172,7 @@ class VarArgsStartInstruction extends UnaryInstruction { * a result. */ class VarArgsEndInstruction extends UnaryInstruction { - VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } + VarArgsEndInstruction() { this.getOpcode() instanceof Opcode::VarArgsEnd } } /** @@ -2155,7 +2182,7 @@ class VarArgsEndInstruction extends UnaryInstruction { * argument. */ class VarArgInstruction extends UnaryInstruction { - VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } + VarArgInstruction() { this.getOpcode() instanceof Opcode::VarArg } } /** @@ -2166,7 +2193,7 @@ class VarArgInstruction extends UnaryInstruction { * argument of the `...` parameter. */ class NextVarArgInstruction extends UnaryInstruction { - NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } + NextVarArgInstruction() { this.getOpcode() instanceof Opcode::NextVarArg } } /** @@ -2180,5 +2207,5 @@ class NextVarArgInstruction extends UnaryInstruction { * The result is the address of the newly allocated object. */ class NewObjInstruction extends Instruction { - NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } + NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll index d7cf89ca9aa..85d217bd361 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -46,12 +46,12 @@ class Operand extends TStageOperand { /** * Gets the location of the source code for this operand. */ - final Language::Location getLocation() { result = getUse().getLocation() } + final Language::Location getLocation() { result = this.getUse().getLocation() } /** * Gets the function that contains this operand. */ - final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } + final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() } /** * Gets the `Instruction` that consumes this operand. @@ -74,7 +74,7 @@ class Operand extends TStageOperand { */ final Instruction getDef() { result = this.getAnyDef() and - getDefinitionOverlap() instanceof MustExactlyOverlap + this.getDefinitionOverlap() instanceof MustExactlyOverlap } /** @@ -82,7 +82,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` that consumes this operand. */ - deprecated final Instruction getUseInstruction() { result = getUse() } + deprecated final Instruction getUseInstruction() { result = this.getUse() } /** * DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this @@ -91,7 +91,7 @@ class Operand extends TStageOperand { * * Gets the `Instruction` whose result is the value of the operand. */ - deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() } + deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() } /** * Gets the overlap relationship between the operand's definition and its use. @@ -101,7 +101,9 @@ class Operand extends TStageOperand { /** * Holds if the result of the definition instruction does not exactly overlap this use. */ - final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap } + final predicate isDefinitionInexact() { + not this.getDefinitionOverlap() instanceof MustExactlyOverlap + } /** * Gets a prefix to use when dumping the operand in an operand list. @@ -121,7 +123,7 @@ class Operand extends TStageOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId() } /** @@ -129,9 +131,9 @@ class Operand extends TStageOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - result = getAnyDef().getResultId() + result = this.getAnyDef().getResultId() or - not exists(getAnyDef()) and result = "m?" + not exists(this.getAnyDef()) and result = "m?" } /** @@ -140,7 +142,7 @@ class Operand extends TStageOperand { * the empty string. */ private string getInexactSpecifier() { - if isDefinitionInexact() then result = "~" else result = "" + if this.isDefinitionInexact() then result = "~" else result = "" } /** @@ -155,7 +157,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() } /** * Gets the language-neutral type of the value consumed by this operand. This is usually the same @@ -164,7 +166,7 @@ class Operand extends TStageOperand { * from the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final IRType getIRType() { result = getLanguageType().getIRType() } + final IRType getIRType() { result = this.getLanguageType().getIRType() } /** * Gets the type of the value consumed by this operand. This is usually the same as the @@ -173,7 +175,7 @@ class Operand extends TStageOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - final Language::Type getType() { getLanguageType().hasType(result, _) } + final Language::Type getType() { this.getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this @@ -182,13 +184,13 @@ class Operand extends TStageOperand { * not hold, the value of the operand represents a value whose type is * given by `getType()`. */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } + final predicate isGLValue() { this.getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - final int getSize() { result = getLanguageType().getByteSize() } + final int getSize() { result = this.getLanguageType().getByteSize() } } /** @@ -205,7 +207,7 @@ class MemoryOperand extends Operand { /** * Gets the kind of memory access performed by the operand. */ - MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() } + MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() } /** * Holds if the memory access performed by this operand will not always read from every bit in the @@ -215,7 +217,7 @@ class MemoryOperand extends Operand { * conservative estimate of the memory that might actually be accessed at runtime (for example, * the global side effects of a function call). */ - predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() } + predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() } /** * Returns the operand that holds the memory address from which the current operand loads its @@ -223,8 +225,8 @@ class MemoryOperand extends Operand { * is `r1`. */ final AddressOperand getAddressOperand() { - getMemoryAccess().usesAddressOperand() and - result.getUse() = getUse() + this.getMemoryAccess().usesAddressOperand() and + result.getUse() = this.getUse() } } @@ -294,7 +296,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe result = unique(Instruction defInstr | hasDefinition(defInstr, _)) } - final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) } pragma[noinline] private predicate hasDefinition(Instruction defInstr, Overlap overlap) { @@ -449,13 +451,17 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { final override Overlap getDefinitionOverlap() { result = overlap } - final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() } - - final override string getDumpLabel() { - result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + final override int getDumpSortOrder() { + result = 11 + this.getPredecessorBlock().getDisplayIndex() } - final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() } + final override string getDumpLabel() { + result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + final override string getDumpId() { + result = this.getPredecessorBlock().getDisplayIndex().toString() + } /** * Gets the predecessor block from which this value comes. diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll index e0bf271dcc7..b0eb5ec98cb 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll @@ -36,7 +36,7 @@ module AliasModels { * Holds if this is the input value of the parameter with index `index`. * DEPRECATED: Use `isParameter(index)` instead. */ - deprecated final predicate isInParameter(ParameterIndex index) { isParameter(index) } + deprecated final predicate isInParameter(ParameterIndex index) { this.isParameter(index) } /** * Holds if this is the input value pointed to by a pointer parameter to a function, or the input @@ -63,7 +63,7 @@ module AliasModels { * DEPRECATED: Use `isParameterDeref(index)` instead. */ deprecated final predicate isInParameterPointer(ParameterIndex index) { - isParameterDeref(index) + this.isParameterDeref(index) } /** @@ -86,7 +86,7 @@ module AliasModels { * function. * DEPRECATED: Use `isQualifierObject()` instead. */ - deprecated final predicate isInQualifier() { isQualifierObject() } + deprecated final predicate isInQualifier() { this.isQualifierObject() } /** * Holds if this is the input value of the `this` pointer of an instance member function. @@ -184,7 +184,7 @@ module AliasModels { * DEPRECATED: Use `isParameterDeref(index)` instead. */ deprecated final predicate isOutParameterPointer(ParameterIndex index) { - isParameterDeref(index) + this.isParameterDeref(index) } /** @@ -207,7 +207,7 @@ module AliasModels { * function. * DEPRECATED: Use `isQualifierObject()` instead. */ - deprecated final predicate isOutQualifier() { isQualifierObject() } + deprecated final predicate isOutQualifier() { this.isQualifierObject() } /** * Holds if this is the value returned by a function. @@ -232,7 +232,7 @@ module AliasModels { * Holds if this is the value returned by a function. * DEPRECATED: Use `isReturnValue()` instead. */ - deprecated final predicate isOutReturnValue() { isReturnValue() } + deprecated final predicate isOutReturnValue() { this.isReturnValue() } /** * Holds if this is the output value pointed to by the return value of a function, if the function @@ -260,7 +260,7 @@ module AliasModels { * function returns a reference. * DEPRECATED: Use `isReturnValueDeref()` instead. */ - deprecated final predicate isOutReturnPointer() { isReturnValueDeref() } + deprecated final predicate isOutReturnPointer() { this.isReturnValueDeref() } /** * Holds if `i >= 0` and `isParameterDeref(i)` holds for this is the value, or diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql index cee1274eb19..d4d8e29fb31 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql @@ -2,7 +2,7 @@ * @name Unaliased SSA Consistency Check * @description Performs consistency checks on the SSA construction. This query should have no results. * @kind table - * @id csharp/unaliased-ssa-consistency-check + * @id cs/unaliased-ssa-consistency-check */ import SSAConsistency diff --git a/repo-tests/codeql/csharp/ql/src/experimental/ir/internal/IRGuards.qll b/repo-tests/codeql/csharp/ql/src/experimental/ir/internal/IRGuards.qll index d01dcbed1e1..2a530b71357 100644 --- a/repo-tests/codeql/csharp/ql/src/experimental/ir/internal/IRGuards.qll +++ b/repo-tests/codeql/csharp/ql/src/experimental/ir/internal/IRGuards.qll @@ -107,7 +107,7 @@ private predicate impliesValue( wholeIsTrue = true and partIsTrue = true and part = blo.getAnOperand() or wholeIsTrue = true and - impliesValue(blo.getAnOperand().(BinaryLogicalOperation), part, partIsTrue, true) + impliesValue(blo.getAnOperand(), part, partIsTrue, true) ) or blo instanceof LogicalOrExpr and @@ -115,7 +115,7 @@ private predicate impliesValue( wholeIsTrue = false and partIsTrue = false and part = blo.getAnOperand() or wholeIsTrue = false and - impliesValue(blo.getAnOperand().(BinaryLogicalOperation), part, partIsTrue, false) + impliesValue(blo.getAnOperand(), part, partIsTrue, false) ) } @@ -139,7 +139,7 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition { override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { exists(boolean partIsTrue, GuardCondition part | - impliesValue(this.(BinaryLogicalOperation), part, partIsTrue, testIsTrue) + impliesValue(this, part, partIsTrue, testIsTrue) | part.comparesLt(left, right, k, isLessThan, partIsTrue) ) @@ -147,13 +147,13 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition { override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { exists(boolean testIsTrue | - comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) + this.comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) ) } override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { exists(boolean partIsTrue, GuardCondition part | - impliesValue(this.(BinaryLogicalOperation), part, partIsTrue, testIsTrue) + impliesValue(this, part, partIsTrue, testIsTrue) | part.comparesEq(left, right, k, areEqual, partIsTrue) ) @@ -161,7 +161,7 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition { override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { exists(boolean testIsTrue | - comparesEq(left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue) + this.comparesEq(left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue) ) } } @@ -326,9 +326,9 @@ class IRGuardCondition extends Instruction { cached predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) { pred.getASuccessor() = succ and - controls(pred, testIsTrue) + this.controls(pred, testIsTrue) or - hasBranchEdge(succ, testIsTrue) and + this.hasBranchEdge(succ, testIsTrue) and branch.getCondition() = this and branch.getBlock() = pred } diff --git a/repo-tests/codeql/csharp/ql/src/printAst.ql b/repo-tests/codeql/csharp/ql/src/printAst.ql index dd27069d84d..380f4b4024b 100644 --- a/repo-tests/codeql/csharp/ql/src/printAst.ql +++ b/repo-tests/codeql/csharp/ql/src/printAst.ql @@ -2,7 +2,7 @@ * @name Print AST * @description Outputs a representation of a file's Abstract Syntax Tree. This * query is used by the VS Code extension. - * @id csharp/print-ast + * @id cs/print-ast * @kind graph * @tags ide-contextual-queries/print-ast */ diff --git a/repo-tests/codeql/java/ql/lib/config/semmlecode.dbscheme b/repo-tests/codeql/java/ql/lib/config/semmlecode.dbscheme index 017ac1ed2df..89a76edebff 100755 --- a/repo-tests/codeql/java/ql/lib/config/semmlecode.dbscheme +++ b/repo-tests/codeql/java/ql/lib/config/semmlecode.dbscheme @@ -393,7 +393,7 @@ typeVars( string nodeName: string ref, int pos: int ref, int kind: int ref, // deprecated - int parentid: @typeorcallable ref + int parentid: @classorinterfaceorcallable ref ); wildcards( @@ -414,7 +414,7 @@ typeBounds( typeArgs( int argumentid: @reftype ref, int pos: int ref, - int parentid: @typeorcallable ref + int parentid: @classorinterfaceorcallable ref ); isParameterized( @@ -487,7 +487,7 @@ hasModifier( imports( unique int id: @import, - int holder: @typeorpackage ref, + int holder: @classorinterfaceorpackage ref, string name: string ref, int kind: int ref ); @@ -857,10 +857,9 @@ javadocText( @javadocParent = @javadoc | @javadocTag; @javadocElement = @javadocTag | @javadocText; -@typeorpackage = @type | @package; - -@typeorcallable = @type | @callable; @classorinterface = @interface | @class; +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; @boundedtype = @typevariable | @wildcard; @reftype = @classorinterface | @array | @boundedtype; @classorarray = @class | @array; diff --git a/repo-tests/codeql/java/ql/lib/external/ExternalArtifact.qll b/repo-tests/codeql/java/ql/lib/external/ExternalArtifact.qll index 5359b99c7c8..2e782a6a4da 100644 --- a/repo-tests/codeql/java/ql/lib/external/ExternalArtifact.qll +++ b/repo-tests/codeql/java/ql/lib/external/ExternalArtifact.qll @@ -3,24 +3,25 @@ import java class ExternalData extends @externalDataElement { string getDataPath() { externalData(this, result, _, _) } - string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } + string getQueryPath() { result = this.getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } string getField(int index) { externalData(this, _, index, result) } - int getFieldAsInt(int index) { result = getField(index).toInt() } + int getFieldAsInt(int index) { result = this.getField(index).toInt() } - float getFieldAsFloat(int index) { result = getField(index).toFloat() } + float getFieldAsFloat(int index) { result = this.getField(index).toFloat() } - date getFieldAsDate(int index) { result = getField(index).toDate() } + date getFieldAsDate(int index) { result = this.getField(index).toDate() } - string toString() { result = getQueryPath() + ": " + buildTupleString(0) } + string toString() { result = this.getQueryPath() + ": " + this.buildTupleString(0) } private string buildTupleString(int start) { - start = getNumFields() - 1 and result = getField(start) + start = this.getNumFields() - 1 and result = this.getField(start) or - start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1) + start < this.getNumFields() - 1 and + result = this.getField(start) + "," + this.buildTupleString(start + 1) } } @@ -33,7 +34,7 @@ class DefectExternalData extends ExternalData { this.getNumFields() = 2 } - string getURL() { result = getField(0) } + string getURL() { result = this.getField(0) } - string getMessage() { result = getField(1) } + string getMessage() { result = this.getField(1) } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/FileSystem.qll b/repo-tests/codeql/java/ql/lib/semmle/code/FileSystem.qll index 6c252d569e9..cace20f63e1 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/FileSystem.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/FileSystem.qll @@ -47,7 +47,7 @@ class Container extends @container, Top { */ string getRelativePath() { exists(string absPath, string pref | - absPath = getAbsolutePath() and sourceLocationPrefix(pref) + absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) | absPath = pref and result = "" or @@ -74,7 +74,7 @@ class Container extends @container, Top { * */ string getBaseName() { - result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) + result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) } /** @@ -100,7 +100,9 @@ class Container extends @container, Top { * "/tmp/x.tar.gz""gz" * */ - string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) } + string getExtension() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) + } /** * Gets the stem of this container, that is, the prefix of its base name up to @@ -119,7 +121,9 @@ class Container extends @container, Top { * "/tmp/x.tar.gz""x.tar" * */ - string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) } + string getStem() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) + } /** Gets the parent container of this file or folder, if any. */ Container getParentContainer() { containerparent(result, this) } @@ -128,20 +132,20 @@ class Container extends @container, Top { Container getAChildContainer() { this = result.getParentContainer() } /** Gets a file in this container. */ - File getAFile() { result = getAChildContainer() } + File getAFile() { result = this.getAChildContainer() } /** Gets the file in this container that has the given `baseName`, if any. */ File getFile(string baseName) { - result = getAFile() and + result = this.getAFile() and result.getBaseName() = baseName } /** Gets a sub-folder in this container. */ - Folder getAFolder() { result = getAChildContainer() } + Folder getAFolder() { result = this.getAChildContainer() } /** Gets the sub-folder in this container that has the given `baseName`, if any. */ Folder getFolder(string baseName) { - result = getAFolder() and + result = this.getAFolder() and result.getBaseName() = baseName } @@ -152,7 +156,7 @@ class Container extends @container, Top { * to provide a different result. To get the absolute path of any `Container`, call * `Container.getAbsolutePath()` directly. */ - override string toString() { result = getAbsolutePath() } + override string toString() { result = this.getAbsolutePath() } } /** A folder. */ @@ -160,7 +164,7 @@ class Folder extends Container, @folder { override string getAbsolutePath() { folders(this, result) } /** Gets the URL of this folder. */ - override string getURL() { result = "folder://" + getAbsolutePath() } + override string getURL() { result = "folder://" + this.getAbsolutePath() } override string getAPrimaryQlClass() { result = "Folder" } } @@ -183,7 +187,7 @@ class File extends Container, @file { * A Java archive file with a ".jar" extension. */ class JarFile extends File { - JarFile() { getExtension() = "jar" } + JarFile() { this.getExtension() = "jar" } /** * Gets the main attribute with the specified `key` @@ -195,13 +199,17 @@ class JarFile extends File { * Gets the "Specification-Version" main attribute * from this JAR file's manifest. */ - string getSpecificationVersion() { result = getManifestMainAttribute("Specification-Version") } + string getSpecificationVersion() { + result = this.getManifestMainAttribute("Specification-Version") + } /** * Gets the "Implementation-Version" main attribute * from this JAR file's manifest. */ - string getImplementationVersion() { result = getManifestMainAttribute("Implementation-Version") } + string getImplementationVersion() { + result = this.getManifestMainAttribute("Implementation-Version") + } /** * Gets the per-entry attribute for the specified `entry` and `key` diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/Location.qll b/repo-tests/codeql/java/ql/lib/semmle/code/Location.qll index 2af4f8712e0..d90a189acb7 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/Location.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/Location.qll @@ -63,10 +63,10 @@ class Top extends @top { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - hasLocationInfoAux(filepath, startline, startcolumn, endline, endcolumn) + this.hasLocationInfoAux(filepath, startline, startcolumn, endline, endcolumn) or exists(string outFilepath, int outStartline, int outEndline | - hasLocationInfoAux(outFilepath, outStartline, _, outEndline, _) and + this.hasLocationInfoAux(outFilepath, outStartline, _, outEndline, _) and hasSmapLocationInfo(filepath, startline, startcolumn, endline, endcolumn, outFilepath, outStartline, outEndline) ) @@ -103,7 +103,7 @@ class Top extends @top { /** * Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. */ - final string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") } + final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } /** * Gets the name of a primary CodeQL class to which this element belongs. diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/SMAP.qll b/repo-tests/codeql/java/ql/lib/semmle/code/SMAP.qll index 006f5ad5e38..575d54f92de 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/SMAP.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/SMAP.qll @@ -52,6 +52,6 @@ predicate hasSmapLocationInfo( smap(inputFile, isl, outputFile, osl) and smap(inputFile, iel - 1, outputFile, oel) and isc = 1 and - iec = 0 + iec = 1 ) } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Annotation.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Annotation.qll index 2ee7c6403b4..342a2bd6e0d 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Annotation.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Annotation.qll @@ -51,7 +51,7 @@ class Annotation extends @annotation, Expr { Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) } /** Gets the element being annotated. */ - Element getTarget() { result = getAnnotatedElement() } + Element getTarget() { result = this.getAnnotatedElement() } override string toString() { result = this.getType().getName() } @@ -67,8 +67,8 @@ class Annotation extends @annotation, Expr { * expression defined for the value. */ Expr getAValue(string name) { - getType().getAnnotationElement(name).getType() instanceof Array and - exists(Expr value | value = getValue(name) | + this.getType().getAnnotationElement(name).getType() instanceof Array and + exists(Expr value | value = this.getValue(name) | if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value ) } @@ -104,7 +104,7 @@ class Annotatable extends Element { /** Holds if this element has the specified annotation. */ predicate hasAnnotation(string package, string name) { - exists(AnnotationType at | at = getAnAnnotation().getType() | + exists(AnnotationType at | at = this.getAnAnnotation().getType() | at.nestedName() = name and at.getPackage().getName() = package ) } @@ -118,7 +118,7 @@ class Annotatable extends Element { * annotation attached to it for the specified `category`. */ predicate suppressesWarningsAbout(string category) { - category = getAnAnnotation().(SuppressWarningsAnnotation).getASuppressedWarning() + category = this.getAnAnnotation().(SuppressWarningsAnnotation).getASuppressedWarning() or this.(Member).getDeclaringType().suppressesWarningsAbout(category) or diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index ff60abb4e73..14738dda96f 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -150,7 +150,7 @@ private module ControlFlowGraphImpl { * `TypeThrowable` which results in both `TypeError` and `TypeRuntimeException`. */ UncheckedThrowableType getAnUncheckedSubtype() { - result = this.(UncheckedThrowableType) + result = this or result instanceof TypeError and this instanceof TypeThrowable or @@ -528,13 +528,13 @@ private module ControlFlowGraphImpl { /** Gets the first child node, if any. */ ControlFlowNode firstChild() { - result = getChildNode(-1) + result = this.getChildNode(-1) or - result = getChildNode(0) and not exists(getChildNode(-1)) + result = this.getChildNode(0) and not exists(this.getChildNode(-1)) } /** Holds if this CFG node has any child nodes. */ - predicate isLeafNode() { not exists(getChildNode(_)) } + predicate isLeafNode() { not exists(this.getChildNode(_)) } /** Holds if this node can finish with a `normalCompletion`. */ predicate mayCompleteNormally() { @@ -1222,10 +1222,10 @@ class ConditionNode extends ControlFlowNode { ControlFlowNode getABranchSuccessor(boolean branch) { result = branchSuccessor(this, branch) } /** Gets a true-successor of the `ConditionNode`. */ - ControlFlowNode getATrueSuccessor() { result = getABranchSuccessor(true) } + ControlFlowNode getATrueSuccessor() { result = this.getABranchSuccessor(true) } /** Gets a false-successor of the `ConditionNode`. */ - ControlFlowNode getAFalseSuccessor() { result = getABranchSuccessor(false) } + ControlFlowNode getAFalseSuccessor() { result = this.getABranchSuccessor(false) } /** Gets the condition of this `ConditionNode`. This is equal to the node itself. */ Expr getCondition() { result = this } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Conversions.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Conversions.qll index 9d55f1297fc..b7cd80c4906 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Conversions.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Conversions.qll @@ -27,7 +27,7 @@ abstract class ConversionSite extends Expr { /** * Whether this conversion site actually induces a conversion. */ - predicate isTrivial() { getConversionTarget() = getConversionSource() } + predicate isTrivial() { this.getConversionTarget() = this.getConversionSource() } /** * Whether this conversion is implicit. diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Element.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Element.qll index 12a08f8eb9d..14e48fc0d40 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Element.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Element.qll @@ -34,10 +34,10 @@ class Element extends @element, Top { * Elements pertaining to source files may include generated elements * not visible in source code, such as implicit default constructors. */ - predicate fromSource() { getCompilationUnit().getExtension() = "java" } + predicate fromSource() { this.getCompilationUnit().getExtension() = "java" } /** Gets the compilation unit that this element belongs to. */ - CompilationUnit getCompilationUnit() { result = getFile() } + CompilationUnit getCompilationUnit() { result = this.getFile() } /** Cast this element to a `Documentable`. */ Documentable getDoc() { result = this } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Expr.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Expr.qll index b83f5332756..8aad29dec09 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Expr.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Expr.qll @@ -86,13 +86,15 @@ class Expr extends ExprParent, @expr { * explicit constructor invocation statement. */ - getEnclosingCallable().isStatic() + this.getEnclosingCallable().isStatic() or - getParent+() instanceof ThisConstructorInvocationStmt + this.getParent+() instanceof ThisConstructorInvocationStmt or - getParent+() instanceof SuperConstructorInvocationStmt + this.getParent+() instanceof SuperConstructorInvocationStmt or - exists(LambdaExpr lam | lam.asMethod() = getEnclosingCallable() and lam.isInStaticContext()) + exists(LambdaExpr lam | + lam.asMethod() = this.getEnclosingCallable() and lam.isInStaticContext() + ) } /** Holds if this expression is parenthesized. */ @@ -116,7 +118,7 @@ private predicate primitiveOrString(Type t) { */ class CompileTimeConstantExpr extends Expr { CompileTimeConstantExpr() { - primitiveOrString(getType()) and + primitiveOrString(this.getType()) and ( // Literals of primitive type and literals of type `String`. this instanceof Literal @@ -164,7 +166,7 @@ class CompileTimeConstantExpr extends Expr { */ pragma[nomagic] string getStringValue() { - result = this.(StringLiteral).getRepresentedString() + result = this.(StringLiteral).getValue() or result = this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringValue() + @@ -296,18 +298,15 @@ class CompileTimeConstantExpr extends Expr { * * Note that this does not handle the following cases: * - * - values of type `long`, - * - `char` literals. + * - values of type `long`. */ cached int getIntValue() { exists(IntegralType t | this.getType() = t | t.getName().toLowerCase() != "long") and ( - exists(string lit | lit = this.(Literal).getValue() | - // `char` literals may get parsed incorrectly, so disallow. - not this instanceof CharacterLiteral and - result = lit.toInt() - ) + result = this.(IntegerLiteral).getIntValue() + or + result = this.(CharacterLiteral).getCodePointValue() or exists(CastExpr cast, int val | cast = this and val = cast.getExpr().(CompileTimeConstantExpr).getIntValue() @@ -425,9 +424,9 @@ class ArrayCreationExpr extends Expr, @arraycreationexpr { * Gets the size of the first dimension, if it can be statically determined. */ int getFirstDimensionSize() { - if exists(getInit()) - then result = getInit().getSize() - else result = getDimension(0).(CompileTimeConstantExpr).getIntValue() + if exists(this.getInit()) + then result = this.getInit().getSize() + else result = this.getDimension(0).(CompileTimeConstantExpr).getIntValue() } /** Gets a printable representation of this expression. */ @@ -463,7 +462,7 @@ class ArrayInit extends Expr, @arrayinit { * Gets the number of expressions in this initializer, that is, the size the * created array will have. */ - int getSize() { result = count(getAnInit()) } + int getSize() { result = count(this.getAnInit()) } /** Gets a printable representation of this expression. */ override string toString() { result = "{...}" } @@ -632,9 +631,9 @@ class Literal extends Expr, @literal { class BooleanLiteral extends Literal, @booleanliteral { /** Gets the boolean representation of this literal. */ boolean getBooleanValue() { - result = true and getValue() = "true" + result = true and this.getValue() = "true" or - result = false and getValue() = "false" + result = false and this.getValue() = "false" } override string getAPrimaryQlClass() { result = "BooleanLiteral" } @@ -657,7 +656,7 @@ class BooleanLiteral extends Literal, @booleanliteral { */ class IntegerLiteral extends Literal, @integerliteral { /** Gets the int representation of this literal. */ - int getIntValue() { result = getValue().toInt() } + int getIntValue() { result = this.getValue().toInt() } override string getAPrimaryQlClass() { result = "IntegerLiteral" } } @@ -693,7 +692,7 @@ class FloatingPointLiteral extends Literal, @floatingpointliteral { * Gets the value of this literal as CodeQL 64-bit `float`. The value will * be parsed as Java 32-bit `float` and then converted to a CodeQL `float`. */ - float getFloatValue() { result = getValue().toFloat() } + float getFloatValue() { result = this.getValue().toFloat() } override string getAPrimaryQlClass() { result = "FloatingPointLiteral" } } @@ -709,7 +708,7 @@ class DoubleLiteral extends Literal, @doubleliteral { * Gets the value of this literal as CodeQL 64-bit `float`. The result will * have the same effective value as the Java `double` literal. */ - float getDoubleValue() { result = getValue().toFloat() } + float getDoubleValue() { result = this.getValue().toFloat() } override string getAPrimaryQlClass() { result = "DoubleLiteral" } } @@ -717,6 +716,22 @@ class DoubleLiteral extends Literal, @doubleliteral { /** A character literal. For example, `'\n'`. */ class CharacterLiteral extends Literal, @characterliteral { override string getAPrimaryQlClass() { result = "CharacterLiteral" } + + /** + * Gets a string which consists of the single character represented by + * this literal. + * + * Unicode surrogate characters (U+D800 to U+DFFF) have the replacement character + * U+FFFD as result instead. + */ + override string getValue() { result = super.getValue() } + + /** + * Gets the Unicode code point value of the character represented by + * this literal. The result is the same as if the Java code had cast + * the character to an `int`. + */ + int getCodePointValue() { result.toUnicode() = this.getValue() } } /** @@ -730,12 +745,24 @@ class CharacterLiteral extends Literal, @characterliteral { */ class StringLiteral extends Literal, @stringliteral { /** + * Gets the string represented by this string literal, that is, the content + * of the literal without enclosing quotes and with escape sequences translated. + * + * Unpaired Unicode surrogate characters (U+D800 to U+DFFF) are replaced with the + * replacement character U+FFFD. + */ + override string getValue() { result = super.getValue() } + + /** + * DEPRECATED: This predicate will be removed in a future version because + * it is just an alias for `getValue()`; that predicate should be used instead. + * * Gets the literal string without the quotes. */ - string getRepresentedString() { result = getValue() } + deprecated string getRepresentedString() { result = this.getValue() } /** Holds if this string literal is a text block (`""" ... """`). */ - predicate isTextBlock() { getLiteral().matches("\"\"\"%") } + predicate isTextBlock() { this.getLiteral().matches("\"\"\"%") } override string getAPrimaryQlClass() { result = "StringLiteral" } } @@ -1184,7 +1211,7 @@ class LambdaExpr extends FunctionalExpr, @lambdaexpr { * Gets the implicit method corresponding to this lambda expression. * The parameters of the lambda expression are the parameters of this method. */ - override Method asMethod() { result = getAnonymousClass().getAMethod() } + override Method asMethod() { result = this.getAnonymousClass().getAMethod() } /** Holds if the body of this lambda is an expression. */ predicate hasExprBody() { lambdaKind(this, 0) } @@ -1194,11 +1221,11 @@ class LambdaExpr extends FunctionalExpr, @lambdaexpr { /** Gets the body of this lambda expression, if it is an expression. */ Expr getExprBody() { - hasExprBody() and result = asMethod().getBody().getAChild().(ReturnStmt).getResult() + this.hasExprBody() and result = this.asMethod().getBody().getAChild().(ReturnStmt).getResult() } /** Gets the body of this lambda expression, if it is a statement. */ - BlockStmt getStmtBody() { hasStmtBody() and result = asMethod().getBody() } + BlockStmt getStmtBody() { this.hasStmtBody() and result = this.asMethod().getBody() } /** Gets a printable representation of this expression. */ override string toString() { result = "...->..." } @@ -1223,7 +1250,29 @@ class MemberRefExpr extends FunctionalExpr, @memberref { * (if the reference is to a constructor) or an array creation expression (if the reference * is to an array constructor). */ - override Method asMethod() { result = getAnonymousClass().getAMethod() } + override Method asMethod() { result = this.getAnonymousClass().getAMethod() } + + /** + * Gets the receiver type whose member this expression refers to. The result might not be + * the type which actually declares the member. For example, for the member reference `ArrayList::toString`, + * this predicate has the result `java.util.ArrayList`, the type explicitly referred to, while + * `getReferencedCallable` will have `java.util.AbstractCollection.toString` as result, which `ArrayList` inherits. + */ + RefType getReceiverType() { + exists(Stmt stmt, Expr resultExpr | + stmt = asMethod().getBody().(SingletonBlock).getStmt() and + ( + resultExpr = stmt.(ReturnStmt).getResult() + or + // Note: Currently never an ExprStmt, but might change once https://github.com/github/codeql/issues/3605 is fixed + resultExpr = stmt.(ExprStmt).getExpr() + ) + | + result = resultExpr.(MethodAccess).getReceiverType() or + result = resultExpr.(ClassInstanceExpr).getConstructedType() or + result = resultExpr.(ArrayCreationExpr).getType() + ) + } /** * Gets the method or constructor referenced by this member reference expression. @@ -1274,16 +1323,16 @@ class ConditionalExpr extends Expr, @conditionalexpr { * it is `getFalseExpr()`. */ Expr getBranchExpr(boolean branch) { - branch = true and result = getTrueExpr() + branch = true and result = this.getTrueExpr() or - branch = false and result = getFalseExpr() + branch = false and result = this.getFalseExpr() } /** * Gets the expressions that is evaluated by one of the branches (`true` * or `false` branch) of this conditional expression. */ - Expr getABranchExpr() { result = getBranchExpr(_) } + Expr getABranchExpr() { result = this.getBranchExpr(_) } /** Gets a printable representation of this expression. */ override string toString() { result = "...?...:..." } @@ -1308,7 +1357,7 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr { * Gets a case of this `switch` expression, * which may be either a normal `case` or a `default`. */ - SwitchCase getACase() { result = getAConstCase() or result = getDefaultCase() } + SwitchCase getACase() { result = this.getAConstCase() or result = this.getDefaultCase() } /** Gets a (non-default) `case` of this `switch` expression. */ ConstCase getAConstCase() { result.getParent() = this } @@ -1321,7 +1370,7 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr { /** Gets a result expression of this `switch` expression. */ Expr getAResult() { - result = getACase().getRuleExpression() + result = this.getACase().getRuleExpression() or exists(YieldStmt yield | yield.(JumpStmt).getTarget() = this and result = yield.getValue()) } @@ -1336,21 +1385,17 @@ class SwitchExpr extends Expr, StmtParent, @switchexpr { class InstanceOfExpr extends Expr, @instanceofexpr { /** Gets the expression on the left-hand side of the `instanceof` operator. */ Expr getExpr() { - if isPattern() - then result = getLocalVariableDeclExpr().getInit() + if this.isPattern() + then result = this.getLocalVariableDeclExpr().getInit() else result.isNthChildOf(this, 0) } /** - * PREVIEW FEATURE in Java 14. Subject to removal in a future release. - * * Holds if this `instanceof` expression uses pattern matching. */ - predicate isPattern() { exists(getLocalVariableDeclExpr()) } + predicate isPattern() { exists(this.getLocalVariableDeclExpr()) } /** - * PREVIEW FEATURE in Java 14. Subject to removal in a future release. - * * Gets the local variable declaration of this `instanceof` expression if pattern matching is used. */ LocalVariableDeclExpr getLocalVariableDeclExpr() { result.isNthChildOf(this, 0) } @@ -1359,7 +1404,7 @@ class InstanceOfExpr extends Expr, @instanceofexpr { Expr getTypeName() { result.isNthChildOf(this, 1) } /** Gets the type this `instanceof` expression checks for. */ - RefType getCheckedType() { result = getTypeName().getType() } + RefType getCheckedType() { result = this.getTypeName().getType() } /** Gets a printable representation of this expression. */ override string toString() { result = "...instanceof..." } @@ -1457,7 +1502,7 @@ class TypeLiteral extends Expr, @typeliteral { * Gets the type this type literal refers to. For example for `String.class` the * result is the type representing `String`. */ - Type getReferencedType() { result = getTypeName().getType() } + Type getReferencedType() { result = this.getTypeName().getType() } /** Gets a printable representation of this expression. */ override string toString() { result = this.getTypeName().toString() + ".class" } @@ -1482,15 +1527,15 @@ abstract class InstanceAccess extends Expr { * This never holds for accesses in lambda expressions as they cannot access * their own instance directly. */ - predicate isOwnInstanceAccess() { not isEnclosingInstanceAccess(_) } + predicate isOwnInstanceAccess() { not this.isEnclosingInstanceAccess(_) } /** Holds if this instance access is to an enclosing instance of type `t`. */ predicate isEnclosingInstanceAccess(RefType t) { - t = getQualifier().getType().(RefType).getSourceDeclaration() and - t != getEnclosingCallable().getDeclaringType() + t = this.getQualifier().getType().(RefType).getSourceDeclaration() and + t != this.getEnclosingCallable().getDeclaringType() or - not exists(getQualifier()) and - exists(LambdaExpr lam | lam.asMethod() = getEnclosingCallable() | + not exists(this.getQualifier()) and + exists(LambdaExpr lam | lam.asMethod() = this.getEnclosingCallable() | t = lam.getAnonymousClass().getEnclosingType() ) } @@ -1538,7 +1583,7 @@ class VarAccess extends Expr, @varaccess { Expr getQualifier() { result.getParent() = this } /** Holds if this variable access has a qualifier. */ - predicate hasQualifier() { exists(getQualifier()) } + predicate hasQualifier() { exists(this.getQualifier()) } /** Gets the variable accessed by this variable access. */ Variable getVariable() { variableBinding(this, result) } @@ -1580,11 +1625,11 @@ class VarAccess extends Expr, @varaccess { */ predicate isLocal() { // The access has no qualifier, or... - not hasQualifier() + not this.hasQualifier() or // the qualifier is either `this` or `A.this`, where `A` is the enclosing type, or // the qualifier is either `super` or `A.super`, where `A` is the enclosing type. - getQualifier().(InstanceAccess).isOwnInstanceAccess() + this.getQualifier().(InstanceAccess).isOwnInstanceAccess() } override string getAPrimaryQlClass() { result = "VarAccess" } @@ -1626,7 +1671,7 @@ class MethodAccess extends Expr, Call, @methodaccess { override Expr getQualifier() { result.isNthChildOf(this, -1) } /** Holds if this method access has a qualifier. */ - predicate hasQualifier() { exists(getQualifier()) } + predicate hasQualifier() { exists(this.getQualifier()) } /** Gets an argument supplied to the method that is invoked using this method access. */ override Expr getAnArgument() { result.getIndex() >= 0 and result.getParent() = this } @@ -1663,9 +1708,9 @@ class MethodAccess extends Expr, Call, @methodaccess { * the enclosing type if there is no qualifier. */ RefType getReceiverType() { - result = getQualifier().getType() + result = this.getQualifier().getType() or - not hasQualifier() and result = getEnclosingCallable().getDeclaringType() + not this.hasQualifier() and result = this.getEnclosingCallable().getDeclaringType() } /** @@ -1841,7 +1886,7 @@ class Call extends ExprParent, @caller { Callable getCallee() { callableBinding(this, result) } /** Gets the callable invoking this call. */ - Callable getCaller() { result = getEnclosingCallable() } + Callable getCaller() { result = this.getEnclosingCallable() } } /** A polymorphic call to an instance method. */ @@ -2042,14 +2087,14 @@ class Argument extends Expr { } /** Holds if this argument is part of an implicit varargs array. */ - predicate isVararg() { isNthVararg(_) } + predicate isVararg() { this.isNthVararg(_) } /** * Holds if this argument is part of an implicit varargs array at the * given array index. */ predicate isNthVararg(int arrayindex) { - not isExplicitVarargsArray() and + not this.isExplicitVarargsArray() and exists(Callable tgt | call.getCallee() = tgt and tgt.isVarargs() and diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Generics.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Generics.qll index a15c47b1f8f..e1bf32d475b 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Generics.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Generics.qll @@ -38,7 +38,7 @@ import Type * * For example, `X` in `class X { }`. */ -class GenericType extends RefType { +class GenericType extends ClassOrInterface { GenericType() { typeVars(_, _, _, _, this) } /** @@ -69,12 +69,12 @@ class GenericType extends RefType { /** * Gets a type parameter of this generic type. */ - TypeVariable getATypeParameter() { result = getTypeParameter(_) } + TypeVariable getATypeParameter() { result = this.getTypeParameter(_) } /** * Gets the number of type parameters of this generic type. */ - int getNumberOfTypeParameters() { result = strictcount(getATypeParameter()) } + int getNumberOfTypeParameters() { result = strictcount(this.getATypeParameter()) } override string getAPrimaryQlClass() { result = "GenericType" } } @@ -107,7 +107,7 @@ abstract class BoundedType extends RefType, @boundedtype { TypeBound getATypeBound() { result.getBoundedType() = this } /** Gets the first type bound for this type, if any. */ - TypeBound getFirstTypeBound() { result = getATypeBound() and result.getPosition() = 0 } + TypeBound getFirstTypeBound() { result = this.getATypeBound() and result.getPosition() = 0 } /** * Gets an upper type bound of this type, or `Object` @@ -123,9 +123,9 @@ abstract class BoundedType extends RefType, @boundedtype { /** Gets a transitive upper bound for this type that is not itself a bounded type. */ RefType getAnUltimateUpperBoundType() { - result = getUpperBoundType() and not result instanceof BoundedType + result = this.getUpperBoundType() and not result instanceof BoundedType or - result = getUpperBoundType().(BoundedType).getAnUltimateUpperBoundType() + result = this.getUpperBoundType().(BoundedType).getAnUltimateUpperBoundType() } override string getAPrimaryQlClass() { result = "BoundedType" } @@ -139,7 +139,7 @@ abstract class BoundedType extends RefType, @boundedtype { */ class TypeVariable extends BoundedType, @typevariable { /** Gets the generic type that is parameterized by this type parameter, if any. */ - RefType getGenericType() { typeVars(this, _, _, _, result) } + GenericType getGenericType() { typeVars(this, _, _, _, result) } /** Gets the generic callable that is parameterized by this type parameter, if any. */ GenericCallable getGenericCallable() { typeVars(this, _, _, _, result) } @@ -168,8 +168,8 @@ class TypeVariable extends BoundedType, @typevariable { /** Gets the lexically enclosing package of this type parameter, if any. */ override Package getPackage() { - result = getGenericType().getPackage() or - result = getGenericCallable().getDeclaringType().getPackage() + result = this.getGenericType().getPackage() or + result = this.getGenericCallable().getDeclaringType().getPackage() } /** Finds a type that was supplied for this parameter. */ @@ -190,9 +190,9 @@ class TypeVariable extends BoundedType, @typevariable { /** Finds a non-typevariable type that was transitively supplied for this parameter. */ RefType getAnUltimatelySuppliedType() { - result = getASuppliedType() and not result instanceof TypeVariable + result = this.getASuppliedType() and not result instanceof TypeVariable or - result = getASuppliedType().(TypeVariable).getAnUltimatelySuppliedType() + result = this.getASuppliedType().(TypeVariable).getAnUltimatelySuppliedType() } override string getAPrimaryQlClass() { result = "TypeVariable" } @@ -261,7 +261,7 @@ class Wildcard extends BoundedType, @wildcard { * Holds if this is the unconstrained wildcard `?`. */ predicate isUnconstrained() { - not hasLowerBound() and + not this.hasLowerBound() and wildcards(this, "?", _) } @@ -321,7 +321,7 @@ class TypeBound extends @typebound { * For example, `List` is a parameterization of * the generic type `List`, where `E` is a type parameter. */ -class ParameterizedType extends RefType { +class ParameterizedType extends ClassOrInterface { ParameterizedType() { typeArgs(_, _, this) or typeVars(_, _, _, _, this) @@ -367,7 +367,9 @@ class ParameterizedType extends RefType { } /** Holds if this type originates from source code. */ - override predicate fromSource() { typeVars(_, _, _, _, this) and RefType.super.fromSource() } + override predicate fromSource() { + typeVars(_, _, _, _, this) and ClassOrInterface.super.fromSource() + } override string getAPrimaryQlClass() { result = "ParameterizedType" } } @@ -451,12 +453,12 @@ class GenericCallable extends Callable { /** * Gets a type parameter of this generic callable. */ - TypeVariable getATypeParameter() { result = getTypeParameter(_) } + TypeVariable getATypeParameter() { result = this.getTypeParameter(_) } /** * Gets the number of type parameters of this generic callable. */ - int getNumberOfTypeParameters() { result = strictcount(getATypeParameter()) } + int getNumberOfTypeParameters() { result = strictcount(this.getATypeParameter()) } } /** @@ -484,10 +486,10 @@ class GenericCall extends Call { /** Gets a type argument of the call for the given `TypeVariable`. */ RefType getATypeArgument(TypeVariable v) { - result = getAnExplicitTypeArgument(v) + result = this.getAnExplicitTypeArgument(v) or - not exists(getAnExplicitTypeArgument(v)) and - result = getAnInferredTypeArgument(v) + not exists(this.getAnExplicitTypeArgument(v)) and + result = this.getAnInferredTypeArgument(v) } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Import.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Import.qll index fbcfea4f905..75b9d157d25 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Import.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Import.qll @@ -25,7 +25,7 @@ class ImportType extends Import { ImportType() { imports(this, _, _, 1) } /** Gets the imported type. */ - RefType getImportedType() { imports(this, result, _, _) } + ClassOrInterface getImportedType() { imports(this, result, _, _) } override string toString() { result = "import " + this.getImportedType().toString() } @@ -44,7 +44,7 @@ class ImportOnDemandFromType extends Import { ImportOnDemandFromType() { imports(this, _, _, 2) } /** Gets the type from which accessible nested types are imported. */ - RefType getTypeHoldingImport() { imports(this, result, _, _) } + ClassOrInterface getTypeHoldingImport() { imports(this, result, _, _) } /** Gets an imported type. */ NestedType getAnImport() { result.getEnclosingType() = this.getTypeHoldingImport() } @@ -87,7 +87,7 @@ class ImportStaticOnDemand extends Import { ImportStaticOnDemand() { imports(this, _, _, 4) } /** Gets the type from which accessible static members are imported. */ - RefType getTypeHoldingImport() { imports(this, result, _, _) } + ClassOrInterface getTypeHoldingImport() { imports(this, result, _, _) } /** Gets an imported type. */ NestedType getATypeImport() { result.getEnclosingType() = this.getTypeHoldingImport() } @@ -118,7 +118,7 @@ class ImportStaticTypeMember extends Import { ImportStaticTypeMember() { imports(this, _, _, 5) } /** Gets the type from which static members with a given name are imported. */ - RefType getTypeHoldingImport() { imports(this, result, _, _) } + ClassOrInterface getTypeHoldingImport() { imports(this, result, _, _) } /** Gets the name of the imported member(s). */ override string getName() { imports(this, _, result, _) } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/JDK.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/JDK.qll index 2e14ab7b898..e497740a489 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/JDK.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/JDK.qll @@ -19,12 +19,12 @@ class TypeCloneable extends Interface { /** The class `java.lang.ProcessBuilder`. */ class TypeProcessBuilder extends Class { - TypeProcessBuilder() { hasQualifiedName("java.lang", "ProcessBuilder") } + TypeProcessBuilder() { this.hasQualifiedName("java.lang", "ProcessBuilder") } } /** The class `java.lang.Runtime`. */ class TypeRuntime extends Class { - TypeRuntime() { hasQualifiedName("java.lang", "Runtime") } + TypeRuntime() { this.hasQualifiedName("java.lang", "Runtime") } } /** The class `java.lang.String`. */ @@ -143,22 +143,22 @@ class ImmutableType extends Type { // --- Java IO --- /** The interface `java.io.Serializable`. */ class TypeSerializable extends Interface { - TypeSerializable() { hasQualifiedName("java.io", "Serializable") } + TypeSerializable() { this.hasQualifiedName("java.io", "Serializable") } } /** The interface `java.io.ObjectOutput`. */ class TypeObjectOutput extends Interface { - TypeObjectOutput() { hasQualifiedName("java.io", "ObjectOutput") } + TypeObjectOutput() { this.hasQualifiedName("java.io", "ObjectOutput") } } /** The type `java.io.ObjectOutputStream`. */ class TypeObjectOutputStream extends RefType { - TypeObjectOutputStream() { hasQualifiedName("java.io", "ObjectOutputStream") } + TypeObjectOutputStream() { this.hasQualifiedName("java.io", "ObjectOutputStream") } } /** The type `java.io.ObjectInputStream`. */ class TypeObjectInputStream extends RefType { - TypeObjectInputStream() { hasQualifiedName("java.io", "ObjectInputStream") } + TypeObjectInputStream() { this.hasQualifiedName("java.io", "ObjectInputStream") } } /** The class `java.nio.file.Paths`. */ @@ -196,8 +196,8 @@ class ProcessBuilderConstructor extends Constructor, ExecCallable { */ class MethodProcessBuilderCommand extends Method, ExecCallable { MethodProcessBuilderCommand() { - hasName("command") and - getDeclaringType() instanceof TypeProcessBuilder + this.hasName("command") and + this.getDeclaringType() instanceof TypeProcessBuilder } override int getAnExecutedArgument() { result = 0 } @@ -208,8 +208,8 @@ class MethodProcessBuilderCommand extends Method, ExecCallable { */ class MethodRuntimeExec extends Method, ExecCallable { MethodRuntimeExec() { - hasName("exec") and - getDeclaringType() instanceof TypeRuntime + this.hasName("exec") and + this.getDeclaringType() instanceof TypeRuntime } override int getAnExecutedArgument() { result = 0 } @@ -220,8 +220,8 @@ class MethodRuntimeExec extends Method, ExecCallable { */ class MethodSystemGetenv extends Method { MethodSystemGetenv() { - hasName("getenv") and - getDeclaringType() instanceof TypeSystem + this.hasName("getenv") and + this.getDeclaringType() instanceof TypeSystem } } @@ -230,8 +230,8 @@ class MethodSystemGetenv extends Method { */ class MethodSystemGetProperty extends Method { MethodSystemGetProperty() { - hasName("getProperty") and - getDeclaringType() instanceof TypeSystem + this.hasName("getProperty") and + this.getDeclaringType() instanceof TypeSystem } } @@ -239,7 +239,7 @@ class MethodSystemGetProperty extends Method { * An access to a method named `getProperty` on class `java.lang.System`. */ class MethodAccessSystemGetProperty extends MethodAccess { - MethodAccessSystemGetProperty() { getMethod() instanceof MethodSystemGetProperty } + MethodAccessSystemGetProperty() { this.getMethod() instanceof MethodSystemGetProperty } /** * Holds if this call has a compile-time constant first argument with the value `propertyName`. @@ -255,8 +255,11 @@ class MethodAccessSystemGetProperty extends MethodAccess { */ class MethodExit extends Method { MethodExit() { - hasName("exit") and - (getDeclaringType() instanceof TypeRuntime or getDeclaringType() instanceof TypeSystem) + this.hasName("exit") and + ( + this.getDeclaringType() instanceof TypeRuntime or + this.getDeclaringType() instanceof TypeSystem + ) } } @@ -266,10 +269,10 @@ class MethodExit extends Method { */ class WriteObjectMethod extends Method { WriteObjectMethod() { - hasName("writeObject") and + this.hasName("writeObject") and ( - getDeclaringType() instanceof TypeObjectOutputStream or - getDeclaringType() instanceof TypeObjectOutput + this.getDeclaringType() instanceof TypeObjectOutputStream or + this.getDeclaringType() instanceof TypeObjectOutput ) } } @@ -293,16 +296,16 @@ class ReadObjectMethod extends Method { /** The method `Class.getName()`. */ class ClassNameMethod extends Method { ClassNameMethod() { - hasName("getName") and - getDeclaringType() instanceof TypeClass + this.hasName("getName") and + this.getDeclaringType() instanceof TypeClass } } /** The method `Class.getSimpleName()`. */ class ClassSimpleNameMethod extends Method { ClassSimpleNameMethod() { - hasName("getSimpleName") and - getDeclaringType() instanceof TypeClass + this.hasName("getSimpleName") and + this.getDeclaringType() instanceof TypeClass } } @@ -334,24 +337,24 @@ class MethodMathMax extends Method { /** The field `System.in`. */ class SystemIn extends Field { SystemIn() { - hasName("in") and - getDeclaringType() instanceof TypeSystem + this.hasName("in") and + this.getDeclaringType() instanceof TypeSystem } } /** The field `System.out`. */ class SystemOut extends Field { SystemOut() { - hasName("out") and - getDeclaringType() instanceof TypeSystem + this.hasName("out") and + this.getDeclaringType() instanceof TypeSystem } } /** The field `System.err`. */ class SystemErr extends Field { SystemErr() { - hasName("err") and - getDeclaringType() instanceof TypeSystem + this.hasName("err") and + this.getDeclaringType() instanceof TypeSystem } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/JDKAnnotations.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/JDKAnnotations.qll index 49776a570f2..2dff70c4d8e 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/JDKAnnotations.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/JDKAnnotations.qll @@ -25,7 +25,7 @@ class SuppressWarningsAnnotation extends Annotation { } /** Gets the name of a warning suppressed by this annotation. */ - string getASuppressedWarning() { result = getASuppressedWarningLiteral().getRepresentedString() } + string getASuppressedWarning() { result = this.getASuppressedWarningLiteral().getValue() } } /** A `@Target` annotation. */ diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/JMX.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/JMX.qll index 77194d24767..16c8736059f 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/JMX.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/JMX.qll @@ -26,27 +26,27 @@ class MXBean extends ManagedBean { */ class RegisteredManagedBeanImpl extends Class { RegisteredManagedBeanImpl() { - getAnAncestor() instanceof ManagedBean and + this.getAnAncestor() instanceof ManagedBean and exists(JMXRegistrationCall registerCall | registerCall.getObjectArgument().getType() = this) } /** * Gets a managed bean that this registered bean class implements. */ - ManagedBean getAnImplementedManagedBean() { result = getAnAncestor() } + ManagedBean getAnImplementedManagedBean() { result = this.getAnAncestor() } } /** * A call that registers an object with the `MBeanServer`, directly or indirectly. */ class JMXRegistrationCall extends MethodAccess { - JMXRegistrationCall() { getCallee() instanceof JMXRegistrationMethod } + JMXRegistrationCall() { this.getCallee() instanceof JMXRegistrationMethod } /** * Gets the argument that represents the object in the registration call. */ Expr getObjectArgument() { - result = getArgument(getCallee().(JMXRegistrationMethod).getObjectPosition()) + result = this.getArgument(this.getCallee().(JMXRegistrationMethod).getObjectPosition()) } } @@ -59,15 +59,15 @@ class JMXRegistrationCall extends MethodAccess { class JMXRegistrationMethod extends Method { JMXRegistrationMethod() { // A direct registration with the `MBeanServer`. - getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and - getName() = "registerMBean" + this.getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and + this.getName() = "registerMBean" or // The `MBeanServer` is often wrapped by an application specific management class, so identify // methods that wrap a call to another `JMXRegistrationMethod`. exists(JMXRegistrationCall c | // This must be a call to another JMX registration method, where the object argument is an access // of one of the parameters of this method. - c.getObjectArgument().(VarAccess).getVariable() = getAParameter() + c.getObjectArgument().(VarAccess).getVariable() = this.getAParameter() ) } @@ -76,13 +76,13 @@ class JMXRegistrationMethod extends Method { */ int getObjectPosition() { // Passed as the first argument to `registerMBean`. - getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and - getName() = "registerMBean" and + this.getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and + this.getName() = "registerMBean" and result = 0 or // Identify the position in this method where the object parameter should be passed. exists(JMXRegistrationCall c | - c.getObjectArgument().(VarAccess).getVariable() = getParameter(result) + c.getObjectArgument().(VarAccess).getVariable() = this.getParameter(result) ) } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Javadoc.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Javadoc.qll index 61d978fbd35..8f7b1dbf580 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Javadoc.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Javadoc.qll @@ -14,7 +14,7 @@ class JavadocParent extends @javadocParent, Top { JavadocElement getChild(int index) { result = this.getAChild() and result.getIndex() = index } /** Gets the number of documentation elements attached to this parent. */ - int getNumChild() { result = count(getAChild()) } + int getNumChild() { result = count(this.getAChild()) } /** Gets a documentation element with the specified Javadoc tag name. */ JavadocTag getATag(string name) { result = this.getAChild() and result.getTagName() = name } @@ -33,7 +33,9 @@ class Javadoc extends JavadocParent, @javadoc { /** Gets the value of the `@author` tag, if any. */ string getAuthor() { result = this.getATag("@author").getChild(0).toString() } - override string toString() { result = toStringPrefix() + getChild(0) + toStringPostfix() } + override string toString() { + result = this.toStringPrefix() + this.getChild(0) + this.toStringPostfix() + } private string toStringPrefix() { if isEolComment(this) @@ -47,7 +49,7 @@ class Javadoc extends JavadocParent, @javadoc { if isEolComment(this) then result = "" else ( - if strictcount(getAChild()) = 1 then result = " */" else result = " ... */" + if strictcount(this.getAChild()) = 1 then result = " */" else result = " ... */" ) } @@ -119,10 +121,10 @@ class ThrowsTag extends JavadocTag { /** A Javadoc `@see` tag. */ class SeeTag extends JavadocTag { - SeeTag() { getTagName() = "@see" } + SeeTag() { this.getTagName() = "@see" } /** Gets the name of the entity referred to. */ - string getReference() { result = getChild(0).toString() } + string getReference() { result = this.getChild(0).toString() } } /** A Javadoc `@author` tag. */ diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Maps.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Maps.qll index c86cb0ef47a..784db84fb98 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Maps.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Maps.qll @@ -76,11 +76,11 @@ class FreshMap extends ClassInstanceExpr { * A call to `Map.put(key, value)`. */ class MapPutCall extends MethodAccess { - MapPutCall() { getCallee().(MapMethod).hasName("put") } + MapPutCall() { this.getCallee().(MapMethod).hasName("put") } /** Gets the key argument of this call. */ - Expr getKey() { result = getArgument(0) } + Expr getKey() { result = this.getArgument(0) } /** Gets the value argument of this call. */ - Expr getValue() { result = getArgument(1) } + Expr getValue() { result = this.getArgument(1) } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Member.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Member.qll index da136c577f8..bbafde2c9ba 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Member.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Member.qll @@ -21,7 +21,7 @@ class Member extends Element, Annotatable, Modifiable, @member { RefType getDeclaringType() { declaresMember(result, this) } /** Gets the qualified name of this member. */ - string getQualifiedName() { result = getDeclaringType().getName() + "." + getName() } + string getQualifiedName() { result = this.getDeclaringType().getName() + "." + this.getName() } /** * Holds if this member has the specified name and is declared in the @@ -33,9 +33,9 @@ class Member extends Element, Annotatable, Modifiable, @member { /** Holds if this member is package protected, that is, neither public nor private nor protected. */ predicate isPackageProtected() { - not isPrivate() and - not isProtected() and - not isPublic() + not this.isPrivate() and + not this.isProtected() and + not this.isPublic() } /** @@ -78,7 +78,7 @@ class Callable extends StmtParent, Member, @callable { */ string getMethodDescriptor() { exists(string return | return = this.getReturnType().getTypeDescriptor() | - result = "(" + descriptorUpTo(this.getNumberOfParameters()) + ")" + return + result = "(" + this.descriptorUpTo(this.getNumberOfParameters()) + ")" + return ) } @@ -86,19 +86,19 @@ class Callable extends StmtParent, Member, @callable { n = 0 and result = "" or exists(Parameter p | p = this.getParameter(n - 1) | - result = descriptorUpTo(n - 1) + p.getType().getTypeDescriptor() + result = this.descriptorUpTo(n - 1) + p.getType().getTypeDescriptor() ) } /** Holds if this callable calls `target`. */ - predicate calls(Callable target) { exists(getACallSite(target)) } + predicate calls(Callable target) { exists(this.getACallSite(target)) } /** * Holds if this callable calls `target` * using a `super(...)` constructor call. */ predicate callsSuperConstructor(Constructor target) { - getACallSite(target) instanceof SuperConstructorInvocationStmt + this.getACallSite(target) instanceof SuperConstructorInvocationStmt } /** @@ -106,14 +106,14 @@ class Callable extends StmtParent, Member, @callable { * using a `this(...)` constructor call. */ predicate callsThis(Constructor target) { - getACallSite(target) instanceof ThisConstructorInvocationStmt + this.getACallSite(target) instanceof ThisConstructorInvocationStmt } /** * Holds if this callable calls `target` * using a `super` method call. */ - predicate callsSuper(Method target) { getACallSite(target) instanceof SuperMethodAccess } + predicate callsSuper(Method target) { this.getACallSite(target) instanceof SuperMethodAccess } /** * Holds if this callable calls `c` using @@ -165,13 +165,13 @@ class Callable extends StmtParent, Member, @callable { Field getAnAccessedField() { this.accesses(result) } /** Gets the type of a formal parameter of this callable. */ - Type getAParamType() { result = getParameterType(_) } + Type getAParamType() { result = this.getParameterType(_) } /** Holds if this callable does not have any formal parameters. */ - predicate hasNoParameters() { not exists(getAParameter()) } + predicate hasNoParameters() { not exists(this.getAParameter()) } /** Gets the number of formal parameters of this callable. */ - int getNumberOfParameters() { result = count(getAParameter()) } + int getNumberOfParameters() { result = count(this.getAParameter()) } /** Gets a formal parameter of this callable. */ Parameter getAParameter() { result.getCallable() = this } @@ -205,7 +205,7 @@ class Callable extends StmtParent, Member, @callable { */ pragma[nomagic] string paramsString() { - exists(int n | n = getNumberOfParameters() | + exists(int n | n = this.getNumberOfParameters() | n = 0 and result = "()" or n > 0 and result = "(" + this.paramUpTo(n - 1) + ")" @@ -217,9 +217,9 @@ class Callable extends StmtParent, Member, @callable { * from left to right, up to (and including) the `n`-th parameter. */ private string paramUpTo(int n) { - n = 0 and result = getParameterType(0).toString() + n = 0 and result = this.getParameterType(0).toString() or - n > 0 and result = paramUpTo(n - 1) + ", " + getParameterType(n) + n > 0 and result = this.paramUpTo(n - 1) + ", " + this.getParameterType(n) } /** @@ -234,7 +234,7 @@ class Callable extends StmtParent, Member, @callable { Exception getAnException() { exceptions(result, _, this) } /** Gets an exception type that occurs in the `throws` clause of this callable. */ - RefType getAThrownExceptionType() { result = getAnException().getType() } + RefType getAThrownExceptionType() { result = this.getAnException().getType() } /** Gets a call site that references this callable. */ Call getAReference() { result.getCallee() = this } @@ -285,7 +285,20 @@ private predicate overrides(Method m1, Method m2) { or m2.isProtected() or - m2.isPackageProtected() and t1.getPackage() = t2.getPackage() + m2.isPackageProtected() and + pragma[only_bind_out](t1.getPackage()) = pragma[only_bind_out](t2.getPackage()) + ) +} + +pragma[nomagic] +private predicate overridesCandidateType(RefType tsup, string sig, RefType t, Method m) { + virtualMethodWithSignature(sig, t, m) and + t.extendsOrImplements(tsup) + or + exists(RefType mid | + overridesCandidateType(mid, sig, t, m) and + mid.extendsOrImplements(tsup) and + not virtualMethodWithSignature(sig, mid, _) ) } @@ -294,11 +307,10 @@ private predicate overrides(Method m1, Method m2) { * ignoring any access modifiers. Additionally, this predicate binds * `t1` to the type declaring `m1` and `t2` to the type declaring `m2`. */ -pragma[noopt] +cached predicate overridesIgnoringAccess(Method m1, RefType t1, Method m2, RefType t2) { exists(string sig | - virtualMethodWithSignature(sig, t1, m1) and - t1.extendsOrImplements+(t2) and + overridesCandidateType(t2, sig, t1, m1) and virtualMethodWithSignature(sig, t2, m2) ) } @@ -392,7 +404,7 @@ class Method extends Callable, @method { or // JLS 9.4: Every method declaration in the body of an interface without an // access modifier is implicitly public. - getDeclaringType() instanceof Interface and + this.getDeclaringType() instanceof Interface and not this.isPrivate() or exists(FunctionalExpr func | func.asMethod() = this) @@ -413,7 +425,7 @@ class Method extends Callable, @method { Callable.super.isStrictfp() or // JLS 8.1.1.3, JLS 9.1.1.2 - getDeclaringType().isStrictfp() + this.getDeclaringType().isStrictfp() } /** @@ -421,8 +433,8 @@ class Method extends Callable, @method { * nor an initializer method, and hence could be inherited. */ predicate isInheritable() { - not isPrivate() and - not (isStatic() and getDeclaringType() instanceof Interface) and + not this.isPrivate() and + not (this.isStatic() and this.getDeclaringType() instanceof Interface) and not this instanceof InitializerMethod } @@ -430,13 +442,13 @@ class Method extends Callable, @method { * Holds if this method is neither private nor static, and hence * uses dynamic dispatch. */ - predicate isVirtual() { not isPrivate() and not isStatic() } + predicate isVirtual() { not this.isPrivate() and not this.isStatic() } /** Holds if this method can be overridden. */ predicate isOverridable() { - isVirtual() and - not isFinal() and - not getDeclaringType().isFinal() + this.isVirtual() and + not this.isFinal() and + not this.getDeclaringType().isFinal() } override string getAPrimaryQlClass() { result = "Method" } @@ -549,7 +561,7 @@ abstract class InitializerMethod extends Method { } * field initializations and static initializer blocks. */ class StaticInitializer extends InitializerMethod { - StaticInitializer() { hasName("") } + StaticInitializer() { this.hasName("") } } /** @@ -629,7 +641,7 @@ class Field extends Member, ExprParent, @field, Variable { or // JLS 9.3: Every field declaration in the body of an interface is // implicitly public, static, and final - getDeclaringType() instanceof Interface + this.getDeclaringType() instanceof Interface } override predicate isStatic() { diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Modifier.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Modifier.qll index 39cbe5a3c29..11317ef8537 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Modifier.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Modifier.qll @@ -25,7 +25,7 @@ abstract class Modifiable extends Element { * abstract, so `isAbstract()` will hold for them even if `hasModifier("abstract")` * does not. */ - predicate hasModifier(string m) { modifiers(getAModifier(), m) } + predicate hasModifier(string m) { modifiers(this.getAModifier(), m) } /** Holds if this element has no modifier. */ predicate hasNoModifier() { not hasModifier(this, _) } @@ -34,31 +34,31 @@ abstract class Modifiable extends Element { Modifier getAModifier() { this = result.getElement() } /** Holds if this element has an `abstract` modifier or is implicitly abstract. */ - predicate isAbstract() { hasModifier("abstract") } + predicate isAbstract() { this.hasModifier("abstract") } /** Holds if this element has a `static` modifier or is implicitly static. */ - predicate isStatic() { hasModifier("static") } + predicate isStatic() { this.hasModifier("static") } /** Holds if this element has a `final` modifier or is implicitly final. */ - predicate isFinal() { hasModifier("final") } + predicate isFinal() { this.hasModifier("final") } /** Holds if this element has a `public` modifier or is implicitly public. */ - predicate isPublic() { hasModifier("public") } + predicate isPublic() { this.hasModifier("public") } /** Holds if this element has a `protected` modifier. */ - predicate isProtected() { hasModifier("protected") } + predicate isProtected() { this.hasModifier("protected") } /** Holds if this element has a `private` modifier or is implicitly private. */ - predicate isPrivate() { hasModifier("private") } + predicate isPrivate() { this.hasModifier("private") } /** Holds if this element has a `volatile` modifier. */ - predicate isVolatile() { hasModifier("volatile") } + predicate isVolatile() { this.hasModifier("volatile") } /** Holds if this element has a `synchronized` modifier. */ - predicate isSynchronized() { hasModifier("synchronized") } + predicate isSynchronized() { this.hasModifier("synchronized") } /** Holds if this element has a `native` modifier. */ - predicate isNative() { hasModifier("native") } + predicate isNative() { this.hasModifier("native") } /** Holds if this element has a `default` modifier. */ predicate isDefault() { this.hasModifier("default") } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/PrettyPrintAst.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/PrettyPrintAst.qll index 45e683a2466..6cb5769184a 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/PrettyPrintAst.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/PrettyPrintAst.qll @@ -169,27 +169,27 @@ private class PpArrayCreationExpr extends PpAst, ArrayCreationExpr { override string getPart(int i) { i = 0 and result = "new " or - i = 1 and result = baseType() + i = 1 and result = this.baseType() or - i = 2 + 3 * dimensionIndex() and result = "[" + i = 2 + 3 * this.dimensionIndex() and result = "[" or - i = 4 + 3 * dimensionIndex() and result = "]" + i = 4 + 3 * this.dimensionIndex() and result = "]" or - i = 4 + 3 * exprDims() + [1 .. nonExprDims()] and result = "[]" + i = 4 + 3 * this.exprDims() + [1 .. this.nonExprDims()] and result = "[]" } private string baseType() { result = this.getType().(Array).getElementType().toString() } private int dimensionIndex() { exists(this.getDimension(result)) } - private int exprDims() { result = max(int j | j = 0 or j = 1 + dimensionIndex()) } + private int exprDims() { result = max(int j | j = 0 or j = 1 + this.dimensionIndex()) } - private int nonExprDims() { result = this.getType().(Array).getDimension() - exprDims() } + private int nonExprDims() { result = this.getType().(Array).getDimension() - this.exprDims() } override PpAst getChild(int i) { exists(int j | result = this.getDimension(j) and i = 3 + 3 * j) or - i = 5 + 3 * exprDims() + nonExprDims() and result = this.getInit() + i = 5 + 3 * this.exprDims() + this.nonExprDims() and result = this.getInit() } } @@ -539,27 +539,27 @@ private class PpForStmt extends PpAst, ForStmt { or exists(int j | j > 0 and exists(this.getInit(j)) and i = 2 + 2 * j and result = ", ") or - i = 1 + lastInitIndex() and result = "; " + i = 1 + this.lastInitIndex() and result = "; " or - i = 3 + lastInitIndex() and result = "; " + i = 3 + this.lastInitIndex() and result = "; " or exists(int j | - j > 0 and exists(this.getUpdate(j)) and i = 3 + lastInitIndex() + 2 * j and result = ", " + j > 0 and exists(this.getUpdate(j)) and i = 3 + this.lastInitIndex() + 2 * j and result = ", " ) or - i = 1 + lastUpdateIndex() and result = ")" + i = 1 + this.lastUpdateIndex() and result = ")" or - i = 2 + lastUpdateIndex() and result = " " and this.getStmt() instanceof BlockStmt + i = 2 + this.lastUpdateIndex() and result = " " and this.getStmt() instanceof BlockStmt } private int lastInitIndex() { result = 3 + 2 * max(int j | exists(this.getInit(j))) } private int lastUpdateIndex() { - result = 4 + lastInitIndex() + 2 * max(int j | exists(this.getUpdate(j))) + result = 4 + this.lastInitIndex() + 2 * max(int j | exists(this.getUpdate(j))) } override predicate newline(int i) { - i = 2 + lastUpdateIndex() and not this.getStmt() instanceof BlockStmt + i = 2 + this.lastUpdateIndex() and not this.getStmt() instanceof BlockStmt } override PpAst getChild(int i) { @@ -567,15 +567,15 @@ private class PpForStmt extends PpAst, ForStmt { or exists(int j | result = this.getInit(j) and i = 3 + 2 * j) or - i = 2 + lastInitIndex() and result = this.getCondition() + i = 2 + this.lastInitIndex() and result = this.getCondition() or - exists(int j | result = this.getUpdate(j) and i = 4 + lastInitIndex() + 2 * j) + exists(int j | result = this.getUpdate(j) and i = 4 + this.lastInitIndex() + 2 * j) or - i = 3 + lastUpdateIndex() and result = this.getStmt() + i = 3 + this.lastUpdateIndex() and result = this.getStmt() } override predicate indents(int i) { - i = 3 + lastUpdateIndex() and not this.getStmt() instanceof BlockStmt + i = 3 + this.lastUpdateIndex() and not this.getStmt() instanceof BlockStmt } } @@ -654,9 +654,9 @@ private class PpTryStmt extends PpAst, TryStmt { or exists(int j | exists(this.getResourceExpr(j)) and i = 3 + 2 * j and result = ";") or - i = 2 + lastResourceIndex() and result = ") " and exists(this.getAResource()) + i = 2 + this.lastResourceIndex() and result = ") " and exists(this.getAResource()) or - i = 1 + lastCatchIndex() and result = " finally " and exists(this.getFinally()) + i = 1 + this.lastCatchIndex() and result = " finally " and exists(this.getFinally()) } private int lastResourceIndex() { @@ -664,17 +664,17 @@ private class PpTryStmt extends PpAst, TryStmt { } private int lastCatchIndex() { - result = 4 + lastResourceIndex() + max(int j | exists(this.getCatchClause(j)) or j = 0) + result = 4 + this.lastResourceIndex() + max(int j | exists(this.getCatchClause(j)) or j = 0) } override PpAst getChild(int i) { exists(int j | i = 2 + 2 * j and result = this.getResource(j)) or - i = 3 + lastResourceIndex() and result = this.getBlock() + i = 3 + this.lastResourceIndex() and result = this.getBlock() or - exists(int j | i = 4 + lastResourceIndex() + j and result = this.getCatchClause(j)) + exists(int j | i = 4 + this.lastResourceIndex() + j and result = this.getCatchClause(j)) or - i = 2 + lastCatchIndex() and result = this.getFinally() + i = 2 + this.lastCatchIndex() and result = this.getFinally() } } @@ -728,11 +728,11 @@ private class PpSwitchCase extends PpAst, SwitchCase { or exists(int j | i = 2 * j and j != 0 and result = ", " and exists(this.(ConstCase).getValue(j))) or - i = 1 + lastConstCaseValueIndex() and result = ":" and not this.isRule() + i = 1 + this.lastConstCaseValueIndex() and result = ":" and not this.isRule() or - i = 1 + lastConstCaseValueIndex() and result = " -> " and this.isRule() + i = 1 + this.lastConstCaseValueIndex() and result = " -> " and this.isRule() or - i = 3 + lastConstCaseValueIndex() and result = ";" and exists(this.getRuleExpression()) + i = 3 + this.lastConstCaseValueIndex() and result = ";" and exists(this.getRuleExpression()) } private int lastConstCaseValueIndex() { @@ -742,9 +742,9 @@ private class PpSwitchCase extends PpAst, SwitchCase { override PpAst getChild(int i) { exists(int j | i = 1 + 2 * j and result = this.(ConstCase).getValue(j)) or - i = 2 + lastConstCaseValueIndex() and result = this.getRuleExpression() + i = 2 + this.lastConstCaseValueIndex() and result = this.getRuleExpression() or - i = 2 + lastConstCaseValueIndex() and result = this.getRuleStatement() + i = 2 + this.lastConstCaseValueIndex() and result = this.getRuleStatement() } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/PrintAst.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/PrintAst.qll index d22065177bc..9527787e3a4 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/PrintAst.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/PrintAst.qll @@ -151,7 +151,7 @@ class PrintAstNode extends TPrintAstNode { /** * Gets a child of this node. */ - final PrintAstNode getAChild() { result = getChild(_) } + final PrintAstNode getAChild() { result = this.getChild(_) } /** * Gets the parent of this node, if any. @@ -169,7 +169,7 @@ class PrintAstNode extends TPrintAstNode { */ string getProperty(string key) { key = "semmle.label" and - result = toString() + result = this.toString() } /** @@ -178,7 +178,7 @@ class PrintAstNode extends TPrintAstNode { * this. */ string getChildEdgeLabel(int childIndex) { - exists(getChild(childIndex)) and + exists(this.getChild(childIndex)) and result = childIndex.toString() } } @@ -259,7 +259,7 @@ final class AnnotationPartNode extends ExprStmtNode { override ElementNode getChild(int childIndex) { result.getElement() = rank[childIndex](Element ch, string file, int line, int column | - ch = getAnAnnotationChild() and locationSortKeys(ch, file, line, column) + ch = this.getAnAnnotationChild() and locationSortKeys(ch, file, line, column) | ch order by file, line, column ) @@ -352,7 +352,7 @@ private class SingleLocalVarDeclParent extends ExprOrStmt { LocalVariableDeclExpr getVariable() { result.getParent() = this } /** Gets the type access of the variable */ - Expr getTypeAccess() { result = getVariable().getTypeAccess() } + Expr getTypeAccess() { result = this.getVariable().getTypeAccess() } } /** @@ -460,7 +460,7 @@ final class ClassInterfaceNode extends ElementNode { childIndex >= 0 and result.(ElementNode).getElement() = rank[childIndex](Element e, string file, int line, int column | - e = getADeclaration() and locationSortKeys(e, file, line, column) + e = this.getADeclaration() and locationSortKeys(e, file, line, column) | e order by file, line, column ) @@ -507,7 +507,7 @@ final class CompilationUnitNode extends ElementNode { childIndex >= 0 and result.(ElementNode).getElement() = rank[childIndex](Element e, string file, int line, int column | - e = getADeclaration() and locationSortKeys(e, file, line, column) + e = this.getADeclaration() and locationSortKeys(e, file, line, column) | e order by file, line, column ) @@ -665,7 +665,7 @@ final class GenericTypeNode extends PrintAstNode, TGenericTypeNode { override Location getLocation() { none() } override ElementNode getChild(int childIndex) { - result.getElement().(TypeVariable) = ty.getTypeParameter(childIndex) + result.getElement() = ty.getTypeParameter(childIndex) } /** @@ -686,7 +686,7 @@ final class GenericCallableNode extends PrintAstNode, TGenericCallableNode { override string toString() { result = "(Generic Parameters)" } override ElementNode getChild(int childIndex) { - result.getElement().(TypeVariable) = c.getTypeParameter(childIndex) + result.getElement() = c.getTypeParameter(childIndex) } /** diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Reflection.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Reflection.qll index ac6046824f6..1817eaa729f 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Reflection.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Reflection.qll @@ -55,7 +55,7 @@ abstract private class ReflectiveClassIdentifier extends Expr { private class ReflectiveClassIdentifierLiteral extends ReflectiveClassIdentifier, TypeLiteral { override RefType getReflectivelyIdentifiedClass() { - result = getReferencedType().(RefType).getSourceDeclaration() + result = this.getReferencedType().(RefType).getSourceDeclaration() } } @@ -65,21 +65,21 @@ private class ReflectiveClassIdentifierLiteral extends ReflectiveClassIdentifier class ReflectiveClassIdentifierMethodAccess extends ReflectiveClassIdentifier, MethodAccess { ReflectiveClassIdentifierMethodAccess() { // A call to `Class.forName(...)`, from which we can infer `T` in the returned type `Class`. - getCallee().getDeclaringType() instanceof TypeClass and getCallee().hasName("forName") + this.getCallee().getDeclaringType() instanceof TypeClass and this.getCallee().hasName("forName") or // A call to `ClassLoader.loadClass(...)`, from which we can infer `T` in the returned type `Class`. - getCallee().getDeclaringType().hasQualifiedName("java.lang", "ClassLoader") and - getCallee().hasName("loadClass") + this.getCallee().getDeclaringType().hasQualifiedName("java.lang", "ClassLoader") and + this.getCallee().hasName("loadClass") } /** * If the argument to this call is a `StringLiteral`, then return that string. */ - string getTypeName() { result = getArgument(0).(StringLiteral).getRepresentedString() } + string getTypeName() { result = this.getArgument(0).(StringLiteral).getValue() } override RefType getReflectivelyIdentifiedClass() { // We only handle cases where the class is specified as a string literal to this call. - result.getQualifiedName() = getTypeName() + result.getQualifiedName() = this.getTypeName() } } @@ -150,7 +150,7 @@ private Type parameterForSubTypes(ParameterizedType type) { lowerBound = arg.(Wildcard).getLowerBoundType() | // `T super Foo` implies that `Foo`, or any super-type of `Foo`, may be represented. - lowerBound.(RefType).getAnAncestor() = result + lowerBound.getAnAncestor() = result ) ) } @@ -214,10 +214,10 @@ private predicate expectsEnclosingInstance(RefType r) { class NewInstance extends MethodAccess { NewInstance() { ( - getCallee().getDeclaringType() instanceof TypeClass or - getCallee().getDeclaringType() instanceof TypeConstructor + this.getCallee().getDeclaringType() instanceof TypeClass or + this.getCallee().getDeclaringType() instanceof TypeConstructor ) and - getCallee().hasName("newInstance") + this.getCallee().hasName("newInstance") } /** @@ -225,26 +225,26 @@ class NewInstance extends MethodAccess { * called. */ Constructor getInferredConstructor() { - result = getInferredConstructedType().getAConstructor() and - if getCallee().getDeclaringType() instanceof TypeClass + result = this.getInferredConstructedType().getAConstructor() and + if this.getCallee().getDeclaringType() instanceof TypeClass then result.getNumberOfParameters() = 0 else - if getNumArgument() = 1 and getArgument(0).getType() instanceof Array + if this.getNumArgument() = 1 and this.getArgument(0).getType() instanceof Array then // This is a var-args array argument. If array argument is initialized inline, then identify // the number of arguments specified in the array. - if exists(getArgument(0).(ArrayCreationExpr).getInit()) + if exists(this.getArgument(0).(ArrayCreationExpr).getInit()) then // Count the number of elements in the initializer, and find the matching constructors. - matchConstructorArguments(result, - count(getArgument(0).(ArrayCreationExpr).getInit().getAnInit())) + this.matchConstructorArguments(result, + count(this.getArgument(0).(ArrayCreationExpr).getInit().getAnInit())) else // Could be any of the constructors on this class. any() else // No var-args in play, just use the number of arguments to the `newInstance(..)` to determine // which constructors may be called. - matchConstructorArguments(result, getNumArgument()) + this.matchConstructorArguments(result, this.getNumArgument()) } /** @@ -273,13 +273,13 @@ class NewInstance extends MethodAccess { not result instanceof TypeVariable and ( // If this is called on a `Class` instance, return the inferred type `T`. - result = inferClassParameterType(getQualifier()) + result = inferClassParameterType(this.getQualifier()) or // If this is called on a `Constructor` instance, return the inferred type `T`. - result = inferConstructorParameterType(getQualifier()) + result = inferConstructorParameterType(this.getQualifier()) or // If the result of this is cast to a particular type, then use that type. - result = getCastInferredConstructedTypes() + result = this.getCastInferredConstructedTypes() ) } @@ -313,7 +313,7 @@ class ClassMethodAccess extends MethodAccess { // `TypeVariable`s do not have methods themselves. not result instanceof TypeVariable and // If this is called on a `Class` instance, return the inferred type `T`. - result = inferClassParameterType(getQualifier()) + result = inferClassParameterType(this.getQualifier()) } } @@ -354,13 +354,13 @@ class ReflectiveMethodAccess extends ClassMethodAccess { if this.getCallee().hasName("getDeclaredMethod") then // The method must be declared on the type itself. - result.getDeclaringType() = getInferredClassType() + result.getDeclaringType() = this.getInferredClassType() else // The method may be declared on an inferred type or a super-type. - getInferredClassType().inherits(result) + this.getInferredClassType().inherits(result) ) and // Only consider instances where the method name is provided as a `StringLiteral`. - result.hasName(getArgument(0).(StringLiteral).getRepresentedString()) + result.hasName(this.getArgument(0).(StringLiteral).getValue()) } } @@ -373,7 +373,9 @@ class ReflectiveAnnotationAccess extends ClassMethodAccess { /** * Gets a possible annotation type for this reflective annotation access. */ - AnnotationType getAPossibleAnnotationType() { result = inferClassParameterType(getArgument(0)) } + AnnotationType getAPossibleAnnotationType() { + result = inferClassParameterType(this.getArgument(0)) + } } /** @@ -391,13 +393,13 @@ class ReflectiveFieldAccess extends ClassMethodAccess { if this.getCallee().hasName("getDeclaredField") then // Declared fields must be on the type itself. - result.getDeclaringType() = getInferredClassType() + result.getDeclaringType() = this.getInferredClassType() else ( // This field must be public, and be inherited by one of the inferred class types. result.isPublic() and - getInferredClassType().inherits(result) + this.getInferredClassType().inherits(result) ) ) and - result.hasName(getArgument(0).(StringLiteral).getRepresentedString()) + result.hasName(this.getArgument(0).(StringLiteral).getValue()) } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Statement.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Statement.qll index a5f9eb81080..082fb2ab295 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Statement.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Statement.qll @@ -71,7 +71,7 @@ class BlockStmt extends Stmt, @block { int getNumStmt() { result = count(this.getAStmt()) } /** Gets the last statement in this block. */ - Stmt getLastStmt() { result = getStmt(getNumStmt() - 1) } + Stmt getLastStmt() { result = this.getStmt(this.getNumStmt() - 1) } override string pp() { result = "{ ... }" } @@ -93,7 +93,7 @@ class SingletonBlock extends BlockStmt { SingletonBlock() { this.getNumStmt() = 1 } /** Gets the single statement in this block. */ - Stmt getStmt() { result = getStmt(0) } + Stmt getStmt() { result = this.getStmt(0) } } /** @@ -125,7 +125,7 @@ class IfStmt extends ConditionalStmt, @ifstmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to `true`. */ - deprecated override Stmt getTrueSuccessor() { result = getThen() } + deprecated override Stmt getTrueSuccessor() { result = this.getThen() } /** Gets the `else` branch of this `if` statement. */ Stmt getElse() { result.isNthChildOf(this, 2) } @@ -155,7 +155,7 @@ class ForStmt extends ConditionalStmt, @forstmt { /** Gets the initializer expression of the loop at the specified (zero-based) position. */ Expr getInit(int index) { - result = getAnInit() and + result = this.getAnInit() and index = -1 - result.getIndex() } @@ -167,7 +167,7 @@ class ForStmt extends ConditionalStmt, @forstmt { /** Gets the update expression of this loop at the specified (zero-based) position. */ Expr getUpdate(int index) { - result = getAnUpdate() and + result = this.getAnUpdate() and index = result.getIndex() - 3 } @@ -178,7 +178,7 @@ class ForStmt extends ConditionalStmt, @forstmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to true. */ - deprecated override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = this.getStmt() } /** * Gets a variable that is used as an iteration variable: it is defined, @@ -193,12 +193,12 @@ class ForStmt extends ConditionalStmt, @forstmt { */ Variable getAnIterationVariable() { // Check that the variable is assigned to, incremented or decremented in the update expression, and... - exists(Expr update | update = getAnUpdate().getAChildExpr*() | + exists(Expr update | update = this.getAnUpdate().getAChildExpr*() | update.(UnaryAssignExpr).getExpr() = result.getAnAccess() or update = result.getAnAssignedValue() ) and // ...that it is checked or used in the condition. - getCondition().getAChildExpr*() = result.getAnAccess() + this.getCondition().getAChildExpr*() = result.getAnAccess() } override string pp() { result = "for (...;...;...) " + this.getStmt().pp() } @@ -242,7 +242,7 @@ class WhileStmt extends ConditionalStmt, @whilestmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to true. */ - deprecated override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = this.getStmt() } override string pp() { result = "while (...) " + this.getStmt().pp() } @@ -265,7 +265,7 @@ class DoStmt extends ConditionalStmt, @dostmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to `true`. */ - deprecated override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = this.getStmt() } override string pp() { result = "do " + this.getStmt().pp() + " while (...)" } @@ -343,17 +343,17 @@ class TryStmt extends Stmt, @trystmt { } /** Gets a resource in this `try` statement, if any. */ - ExprParent getAResource() { result = getAResourceDecl() or result = getAResourceExpr() } + ExprParent getAResource() { result = this.getAResourceDecl() or result = this.getAResourceExpr() } /** Gets the resource at the specified position in this `try` statement. */ ExprParent getResource(int index) { - result = getResourceDecl(index) or result = getResourceExpr(index) + result = this.getResourceDecl(index) or result = this.getResourceExpr(index) } /** Gets a resource variable, if any, either from a resource variable declaration or resource expression. */ Variable getAResourceVariable() { - result = getAResourceDecl().getAVariable().getVariable() or - result = getAResourceExpr().getVariable() + result = this.getAResourceDecl().getAVariable().getVariable() or + result = this.getAResourceExpr().getVariable() } override string pp() { result = "try " + this.getBlock().pp() + " catch (...)" } @@ -381,7 +381,7 @@ class CatchClause extends Stmt, @catchclause { /** Gets a type caught by this `catch` clause. */ RefType getACaughtType() { - exists(Expr ta | ta = getVariable().getTypeAccess() | + exists(Expr ta | ta = this.getVariable().getTypeAccess() | result = ta.(TypeAccess).getType() or result = ta.(UnionTypeAccess).getAnAlternative().getType() ) @@ -411,7 +411,7 @@ class SwitchStmt extends Stmt, @switchstmt { * Gets a case of this `switch` statement, * which may be either a normal `case` or a `default`. */ - SwitchCase getACase() { result = getAConstCase() or result = getDefaultCase() } + SwitchCase getACase() { result = this.getAConstCase() or result = this.getDefaultCase() } /** Gets a (non-default) `case` of this `switch` statement. */ ConstCase getAConstCase() { result.getParent() = this } @@ -550,7 +550,7 @@ class ThrowStmt extends Stmt, @throwstmt { override string getHalsteadID() { result = "ThrowStmt" } /** Gets the type of the expression thrown by this `throw` statement. */ - RefType getThrownExceptionType() { result = getExpr().getType() } + RefType getThrownExceptionType() { result = this.getExpr().getType() } /** * Gets the `catch` clause that catches the exception @@ -559,15 +559,15 @@ class ThrowStmt extends Stmt, @throwstmt { * provided such a `catch` exists. */ CatchClause getLexicalCatchIfAny() { - exists(TryStmt try | try = findEnclosing() and result = catchClauseForThis(try)) + exists(TryStmt try | try = this.findEnclosing() and result = this.catchClauseForThis(try)) } private Stmt findEnclosing() { - result = getEnclosingStmt() + result = this.getEnclosingStmt() or exists(Stmt mid | - mid = findEnclosing() and - not exists(this.catchClauseForThis(mid.(TryStmt))) and + mid = this.findEnclosing() and + not exists(this.catchClauseForThis(mid)) and result = mid.getEnclosingStmt() ) } @@ -575,7 +575,7 @@ class ThrowStmt extends Stmt, @throwstmt { private CatchClause catchClauseForThis(TryStmt try) { result = try.getACatchClause() and result.getEnclosingCallable() = this.getEnclosingCallable() and - getExpr().getType().(RefType).hasSupertype*(result.getVariable().getType().(RefType)) and + this.getExpr().getType().(RefType).hasSupertype*(result.getVariable().getType()) and not this.getEnclosingStmt+() = result } @@ -599,7 +599,7 @@ class JumpStmt extends Stmt { namestrings(result.getLabel(), _, this) } - private Stmt getLabelTarget() { result = getTargetLabel().getStmt() } + private Stmt getLabelTarget() { result = this.getTargetLabel().getStmt() } private Stmt getAPotentialTarget() { this.getEnclosingStmt+() = result and @@ -613,20 +613,20 @@ class JumpStmt extends Stmt { private SwitchExpr getSwitchExprTarget() { result = this.(YieldStmt).getParent+() } private StmtParent getEnclosingTarget() { - result = getSwitchExprTarget() + result = this.getSwitchExprTarget() or - not exists(getSwitchExprTarget()) and - result = getAPotentialTarget() and - not exists(Stmt other | other = getAPotentialTarget() | other.getEnclosingStmt+() = result) + not exists(this.getSwitchExprTarget()) and + result = this.getAPotentialTarget() and + not exists(Stmt other | other = this.getAPotentialTarget() | other.getEnclosingStmt+() = result) } /** * Gets the statement or `switch` expression that this `break`, `yield` or `continue` jumps to. */ StmtParent getTarget() { - result = getLabelTarget() + result = this.getLabelTarget() or - not exists(getLabelTarget()) and result = getEnclosingTarget() + not exists(this.getLabelTarget()) and result = this.getEnclosingTarget() } } @@ -714,9 +714,9 @@ class ExprStmt extends Stmt, @exprstmt { /** Holds if this statement represents a field declaration with an initializer. */ predicate isFieldDecl() { - getEnclosingCallable() instanceof InitializerMethod and + this.getEnclosingCallable() instanceof InitializerMethod and exists(FieldDeclaration fd, Location fdl, Location sl | - fdl = fd.getLocation() and sl = getLocation() + fdl = fd.getLocation() and sl = this.getLocation() | fdl.getFile() = sl.getFile() and fdl.getStartLine() = sl.getStartLine() and @@ -775,7 +775,7 @@ class LocalVariableDeclStmt extends Stmt, @localvariabledeclstmt { } /** Gets an index of a variable declared in this local variable declaration statement. */ - int getAVariableIndex() { exists(getVariable(result)) } + int getAVariableIndex() { exists(this.getVariable(result)) } override string pp() { result = "var ...;" } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/StringFormat.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/StringFormat.qll index cc37ee8212a..2938f5255fa 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/StringFormat.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/StringFormat.qll @@ -152,15 +152,15 @@ class FormattingCall extends Call { private Expr getLastArg() { exists(Expr last | last = this.getArgument(this.getNumArgument() - 1) | if this.hasExplicitVarargsArray() - then result = last.(ArrayCreationExpr).getInit().getInit(getVarargsCount() - 1) + then result = last.(ArrayCreationExpr).getInit().getInit(this.getVarargsCount() - 1) else result = last ) } /** Holds if this uses the "logger ({})" format syntax and the last argument is a `Throwable`. */ predicate hasTrailingThrowableArgument() { - getSyntax() = TFmtLogger() and - getLastArg().getType().(RefType).getASourceSupertype*() instanceof TypeThrowable + this.getSyntax() = TFmtLogger() and + this.getLastArg().getType().(RefType).getASourceSupertype*() instanceof TypeThrowable } /** Gets the argument to this call in the position of the format string */ @@ -171,7 +171,7 @@ class FormattingCall extends Call { exists(int i | result = this.getArgument(i) and i > this.getFormatStringIndex() and - not hasExplicitVarargsArray() + not this.hasExplicitVarargsArray() ) } @@ -279,7 +279,7 @@ private predicate formatStringFragment(Expr fmt) { private predicate formatStringValue(Expr e, string fmtvalue) { formatStringFragment(e) and ( - e.(StringLiteral).getRepresentedString() = fmtvalue + e.(StringLiteral).getValue() = fmtvalue or e.getType() instanceof IntegralType and fmtvalue = "1" // dummy value or @@ -318,7 +318,7 @@ private predicate formatStringValue(Expr e, string fmtvalue) { getprop.hasName("getProperty") and getprop.getDeclaringType().hasQualifiedName("java.lang", "System") and getprop.getNumberOfParameters() = 1 and - ma.getAnArgument().(StringLiteral).getRepresentedString() = prop and + ma.getAnArgument().(StringLiteral).getValue() = prop and (prop = "line.separator" or prop = "file.separator" or prop = "path.separator") and fmtvalue = "x" // dummy value ) @@ -433,15 +433,15 @@ private class PrintfFormatString extends FormatString { override int getMaxFmtSpecIndex() { result = max(int ix | - ix = fmtSpecRefersToSpecificIndex(_) or - ix = count(int i | fmtSpecRefersToSequentialIndex(i)) + ix = this.fmtSpecRefersToSpecificIndex(_) or + ix = count(int i | this.fmtSpecRefersToSequentialIndex(i)) ) } override int getASkippedFmtSpecIndex() { - result in [1 .. getMaxFmtSpecIndex()] and - result > count(int i | fmtSpecRefersToSequentialIndex(i)) and - not result = fmtSpecRefersToSpecificIndex(_) + result in [1 .. this.getMaxFmtSpecIndex()] and + result > count(int i | this.fmtSpecRefersToSequentialIndex(i)) and + not result = this.fmtSpecRefersToSpecificIndex(_) } private int getFmtSpecRank(int specOffset) { @@ -449,14 +449,14 @@ private class PrintfFormatString extends FormatString { } override int getAnArgUsageOffset(int argNo) { - argNo = fmtSpecRefersToSpecificIndex(result) + argNo = this.fmtSpecRefersToSpecificIndex(result) or - result = rank[argNo](int i | fmtSpecRefersToSequentialIndex(i)) + result = rank[argNo](int i | this.fmtSpecRefersToSequentialIndex(i)) or - fmtSpecRefersToPrevious(result) and + this.fmtSpecRefersToPrevious(result) and exists(int previousOffset | - getFmtSpecRank(previousOffset) = getFmtSpecRank(result) - 1 and - previousOffset = getAnArgUsageOffset(argNo) + this.getFmtSpecRank(previousOffset) = this.getFmtSpecRank(result) - 1 and + previousOffset = this.getAnArgUsageOffset(argNo) ) } } @@ -479,10 +479,12 @@ private class LoggerFormatString extends FormatString { private predicate fmtPlaceholder(int i) { this.charAt(i) = "{" and this.charAt(i + 1) = "}" and - not true = isUnescapedBackslash(i - 1) + not true = this.isUnescapedBackslash(i - 1) } - override int getMaxFmtSpecIndex() { result = count(int i | fmtPlaceholder(i)) } + override int getMaxFmtSpecIndex() { result = count(int i | this.fmtPlaceholder(i)) } - override int getAnArgUsageOffset(int argNo) { result = rank[argNo](int i | fmtPlaceholder(i)) } + override int getAnArgUsageOffset(int argNo) { + result = rank[argNo](int i | this.fmtPlaceholder(i)) + } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Type.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Type.qll index 492d1b546cb..1755442545d 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Type.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Type.qll @@ -31,7 +31,7 @@ predicate hasSubtype(RefType t, Type sub) { arraySubtype(t, sub) and t != sub or // Type parameter containment for parameterized types. - parContainmentSubtype(t, sub) and t != sub + parContainmentSubtype(t, sub) or // Type variables are subtypes of their upper bounds. typeVarSubtypeBound(t, sub) and t != sub @@ -59,19 +59,23 @@ private predicate arraySubtype(Array sup, Array sub) { * ) * ``` * For performance several transformations are made. First, the `forex` is - * written as a loop where `typeArgumentsContain(_, pt, psub, n)` encode that - * the `forex` holds for `i in [0..n]`. Second, the relation is split into two - * cases depending on whether `pt.getNumberOfTypeArguments()` is 1 or 2+, as - * this allows us to unroll the loop and collapse the first two iterations. The - * base case for `typeArgumentsContain` is therefore `n=1` and this allows an - * improved join order implemented by `contains01`. + * written as a loop where `typePrefixContains(ppt, ppsub)` encode that + * `ppt` and `ppsub` are prefixes of `pt` and `ptsub` and that + * the `forex` holds for `i in [0..n-1]` where `n` is the length of the prefixes. + * Second, the recursive case that determines containment of length `n+1` + * prefixes is split into three cases depending on whether there is + * non-reflexive type parameter containment: + * - only in the length `n` prefix, + * - only in the `n`th position, + * - both in the length `n` prefix and the `n`th position. */ private predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) { - pt != psub and - typeArgumentsContain(_, pt, psub, pt.getNumberOfTypeArguments() - 1) - or - typeArgumentsContain0(_, pt, psub) + exists(ParameterizedPrefix ppt, ParameterizedPrefix ppsub | + typePrefixContains(ppt, ppsub) and + ppt.equals(pt) and + ppsub.equals(psub) + ) } /** @@ -94,100 +98,116 @@ private RefType parameterisationTypeArgumentVarianceCand( varianceCandidate(t) } -/** - * Holds if every type argument of `s` (up to `n` with `n >= 1`) contains the - * corresponding type argument of `t`. Both `s` and `t` are constrained to - * being parameterizations of `g`. - */ -pragma[nomagic] -private predicate typeArgumentsContain( - GenericType g, ParameterizedType s, ParameterizedType t, int n -) { - contains01(g, s, t) and n = 1 +private newtype TParameterizedPrefix = + TGenericType(GenericType g) or + TTypeParam(ParameterizedPrefix pp, RefType t) { prefixMatches(pp, t, _, _) } + +/** Holds if `pp` is a length `n` prefix of `pt`. */ +private predicate prefixMatches(ParameterizedPrefix pp, ParameterizedType pt, int n) { + pp = TGenericType(pt.getGenericType()) and n = 0 or - contains(g, s, t, n) and - typeArgumentsContain(g, s, t, n - 1) -} - -private predicate typeArgumentsContain0( - GenericType g, ParameterizedType sParm, ParameterizedType tParm -) { - exists(RefType s, RefType t | - containsAux0(g, tParm, s, t) and - s = parameterisationTypeArgument(g, sParm, 0) and - s != t + exists(ParameterizedPrefix pp0, RefType t | + pp = TTypeParam(pp0, t) and prefixMatches(pp0, t, pt, n - 1) ) } /** - * Holds if the `n`-th type argument of `sParm` contain the `n`-th type - * argument of `tParm` for both `n = 0` and `n = 1`, where both `sParm` and - * `tParm` are parameterizations of the same generic type `g`. - * - * This is equivalent to - * ``` - * contains(g, sParm, tParm, 0) and - * contains(g, sParm, tParm, 1) - * ``` - * except `contains` is restricted to only include `n >= 2`. + * Holds if `pp` is a length `n` prefix of `pt` and `t` is the `n`th type + * argument of `pt`. */ -private predicate contains01(GenericType g, ParameterizedType sParm, ParameterizedType tParm) { - exists(RefType s0, RefType t0, RefType s1, RefType t1 | - contains01Aux0(g, tParm, s0, t0, t1) and - contains01Aux1(g, sParm, s0, s1, t1) - ) -} - -pragma[nomagic] -private predicate contains01Aux0( - GenericType g, ParameterizedType tParm, RefType s0, RefType t0, RefType t1 -) { - typeArgumentContains(g, s0, t0, 0) and - t0 = parameterisationTypeArgument(g, tParm, 0) and - t1 = parameterisationTypeArgument(g, tParm, 1) -} - -pragma[nomagic] -private predicate contains01Aux1( - GenericType g, ParameterizedType sParm, RefType s0, RefType s1, RefType t1 -) { - typeArgumentContains(g, s1, t1, 1) and - s0 = parameterisationTypeArgumentVarianceCand(g, sParm, 0) and - s1 = parameterisationTypeArgumentVarianceCand(g, sParm, 1) -} - -pragma[nomagic] -private predicate containsAux0(GenericType g, ParameterizedType tParm, RefType s, RefType t) { - typeArgumentContains(g, s, t, 0) and - t = parameterisationTypeArgument(g, tParm, 0) and - g.getNumberOfTypeParameters() = 1 +private predicate prefixMatches(ParameterizedPrefix pp, RefType t, ParameterizedType pt, int n) { + prefixMatches(pp, pt, n) and + t = pt.getTypeArgument(n) } /** - * Holds if the `n`-th type argument of `sParm` contain the `n`-th type - * argument of `tParm`, where both `sParm` and `tParm` are parameterizations of - * the same generic type `g`. The index `n` is restricted to `n >= 2`, the - * cases `n < 2` are handled by `contains01`. - * - * See JLS 4.5.1, Type Arguments of Parameterized Types. + * A prefix of a `ParameterizedType`. This encodes the corresponding + * `GenericType` and the first `n` type arguments where `n` is the prefix + * length. */ -private predicate contains(GenericType g, ParameterizedType sParm, ParameterizedType tParm, int n) { - exists(RefType s, RefType t | - containsAux(g, tParm, n, s, t) and - s = parameterisationTypeArgumentVarianceCand(g, sParm, n) +private class ParameterizedPrefix extends TParameterizedPrefix { + string toString() { result = "ParameterizedPrefix" } + + predicate equals(ParameterizedType pt) { prefixMatches(this, pt, pt.getNumberOfTypeArguments()) } + + /** Holds if this prefix has length `n`, applies to `g`, and equals `TTypeParam(pp, t)`. */ + predicate split(GenericType g, ParameterizedPrefix pp, RefType t, int n) { + this = TTypeParam(pp, t) and + ( + pp = TGenericType(g) and n = 0 + or + pp.split(g, _, _, n - 1) + ) + } +} + +/** + * Holds if every type argument of `pps` contains the corresponding type + * argument of `ppt`. Both `pps` and `ppt` are constrained to be equal-length + * prefixes of parameterizations of the same `GenericType`. + */ +pragma[nomagic] +private predicate typePrefixContains(ParameterizedPrefix pps, ParameterizedPrefix ppt) { + // Let `pps = TTypeParam(pps0, s)` and `ppt = TTypeParam(ppt0, t)`. + // Case 1: pps0 = ppt0 and typeArgumentContains(_, s, t, _) + typePrefixContains_base(pps, ppt) + or + // Case 2: typePrefixContains(pps0, ppt0) and s = t + typePrefixContains_ext_eq(pps, ppt) + or + // Case 3: typePrefixContains(pps0, ppt0) and typeArgumentContains(_, s, t, _) + typePrefixContains_ext_neq(pps, ppt) +} + +private predicate typePrefixContains_base(ParameterizedPrefix pps, ParameterizedPrefix ppt) { + exists(ParameterizedPrefix pp, RefType s | + pps = TTypeParam(pp, s) and + typePrefixContainsAux2(ppt, pp, s) + ) +} + +private predicate typePrefixContains_ext_eq(ParameterizedPrefix pps, ParameterizedPrefix ppt) { + exists(ParameterizedPrefix pps0, ParameterizedPrefix ppt0, RefType t | + typePrefixContains(pragma[only_bind_into](pps0), pragma[only_bind_into](ppt0)) and + pps = TTypeParam(pragma[only_bind_into](pps0), t) and + ppt = TTypeParam(ppt0, t) + ) +} + +private predicate typePrefixContains_ext_neq(ParameterizedPrefix pps, ParameterizedPrefix ppt) { + exists(ParameterizedPrefix ppt0, RefType s | + typePrefixContainsAux1(pps, ppt0, s) and + typePrefixContainsAux2(ppt, ppt0, s) ) } pragma[nomagic] -private predicate containsAux(GenericType g, ParameterizedType tParm, int n, RefType s, RefType t) { - typeArgumentContains(g, s, t, n) and - t = parameterisationTypeArgument(g, tParm, n) and - n >= 2 +private predicate typePrefixContainsAux1( + ParameterizedPrefix pps, ParameterizedPrefix ppt0, RefType s +) { + exists(ParameterizedPrefix pps0 | + typePrefixContains(pps0, ppt0) and + pps = TTypeParam(pps0, s) and + s instanceof Wildcard // manual magic, implied by `typeArgumentContains(_, s, t, _)` + ) +} + +pragma[nomagic] +private predicate typePrefixContainsAux2( + ParameterizedPrefix ppt, ParameterizedPrefix ppt0, RefType s +) { + exists(GenericType g, int n, RefType t | + // Implies `ppt = TTypeParam(ppt0, t)` + ppt.split(g, ppt0, t, n) and + typeArgumentContains(g, s, t, n) + ) } /** * Holds if the type argument `s` contains the type argument `t`, where both * type arguments occur as index `n` in an instantiation of `g`. + * + * The case `s = t` is not included. */ pragma[noinline] private predicate typeArgumentContains(GenericType g, RefType s, RefType t, int n) { @@ -205,18 +225,18 @@ private predicate typeArgumentContainsAux2(GenericType g, RefType s, RefType t, * Holds if the type argument `s` contains the type argument `t`, where both * type arguments occur as index `n` in some parameterized types. * + * The case `s = t` is not included. + * * See JLS 4.5.1, Type Arguments of Parameterized Types. */ private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) { - exists(int i | - s = parameterisationTypeArgumentVarianceCand(_, _, i) and - t = parameterisationTypeArgument(_, _, n) and - i <= n and - n <= i - | + s = parameterisationTypeArgumentVarianceCand(_, _, pragma[only_bind_into](n)) and + t = parameterisationTypeArgument(_, _, pragma[only_bind_into](n)) and + s != t and + ( exists(RefType tUpperBound | tUpperBound = t.(Wildcard).getUpperBound().getType() | // ? extends T <= ? extends S if T <: S - hasSubtypeStar(s.(Wildcard).getUpperBound().getType(), tUpperBound) + hasSubtypeStar1(s.(Wildcard).getUpperBound().getType(), tUpperBound) or // ? extends T <= ? s.(Wildcard).isUnconstrained() @@ -224,7 +244,7 @@ private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) { or exists(RefType tLowerBound | tLowerBound = t.(Wildcard).getLowerBound().getType() | // ? super T <= ? super S if s <: T - hasSubtypeStar(tLowerBound, s.(Wildcard).getLowerBound().getType()) + hasSubtypeStar2(tLowerBound, s.(Wildcard).getLowerBound().getType()) or // ? super T <= ? s.(Wildcard).isUnconstrained() @@ -233,14 +253,14 @@ private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) { wildcardExtendsObject(s) ) or - // T <= T - s = t - or // T <= ? extends T - hasSubtypeStar(s.(Wildcard).getUpperBound().getType(), t) + hasSubtypeStar1(s.(Wildcard).getUpperBound().getType(), t) or // T <= ? super T - hasSubtypeStar(t, s.(Wildcard).getLowerBound().getType()) + hasSubtypeStar2(t, s.(Wildcard).getLowerBound().getType()) + // or + // T <= T + // but this case is handled directly in `typePrefixContains` ) } @@ -249,12 +269,38 @@ private predicate wildcardExtendsObject(Wildcard wc) { wc.getUpperBound().getType() instanceof TypeObject } -private predicate hasSubtypeStar(RefType t, RefType sub) { - sub = t +// manual magic for `hasSubtypeStar1` +private predicate getAWildcardUpperBound(RefType t) { + t = any(Wildcard w).getUpperBound().getType() +} + +// manual magic for `hasSubtypeStar2` +private predicate getAWildcardLowerBound(RefType t) { + t = any(Wildcard w).getLowerBound().getType() +} + +/** + * Holds if `hasSubtype*(t, sub)`, but manual-magic'ed with `getAWildcardUpperBound(t)`. + */ +pragma[nomagic] +private predicate hasSubtypeStar1(RefType t, RefType sub) { + sub = t and getAWildcardUpperBound(t) or - hasSubtype(t, sub) + hasSubtype(t, sub) and getAWildcardUpperBound(t) or - exists(RefType mid | hasSubtypeStar(t, mid) and hasSubtype(mid, sub)) + exists(RefType mid | hasSubtypeStar1(t, mid) and hasSubtype(mid, sub)) +} + +/** + * Holds if `hasSubtype*(t, sub)`, but manual-magic'ed with `getAWildcardLowerBound(sub)`. + */ +pragma[nomagic] +private predicate hasSubtypeStar2(RefType t, RefType sub) { + sub = t and getAWildcardLowerBound(sub) + or + hasSubtype(t, sub) and getAWildcardLowerBound(sub) + or + exists(RefType mid | hasSubtype(t, mid) and hasSubtypeStar2(mid, sub)) } /** Holds if type `t` declares member `m`. */ @@ -379,7 +425,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { } /** Holds if this type declares any members. */ - predicate hasMember() { exists(getAMember()) } + predicate hasMember() { exists(this.getAMember()) } /** Gets a member declared in this type. */ Member getAMember() { this = result.getDeclaringType() } @@ -511,7 +557,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { this.getSourceDeclaration().inherits(f) ) or - this.hasMethod(m.(Method), _) + this.hasMethod(m, _) } /** Holds if this is a top-level type, which is not nested inside any other types. */ @@ -545,8 +591,10 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { * `java.lang.Thread$State`. */ string getQualifiedName() { - exists(string pkgName | pkgName = getPackage().getName() | - if pkgName = "" then result = nestedName() else result = pkgName + "." + nestedName() + exists(string pkgName | pkgName = this.getPackage().getName() | + if pkgName = "" + then result = this.nestedName() + else result = pkgName + "." + this.nestedName() ) } @@ -656,7 +704,7 @@ class IntersectionType extends RefType, @class { /** Gets a textual representation of this type that includes all the intersected types. */ string getLongName() { - result = superType().toString() + concat(" & " + superInterface().toString()) + result = this.superType().toString() + concat(" & " + this.superInterface().toString()) } /** Gets the first bound of this intersection type. */ @@ -690,7 +738,8 @@ class AnonymousClass extends NestedClass { override string getTypeDescriptor() { exists(RefType parent | parent = this.getEnclosingType() | exists(int num | - num = 1 + count(AnonymousClass other | other.rankInParent(parent) < rankInParent(parent)) + num = + 1 + count(AnonymousClass other | other.rankInParent(parent) < this.rankInParent(parent)) | exists(string parentWithSemi | parentWithSemi = parent.getTypeDescriptor() | result = parentWithSemi.prefix(parentWithSemi.length() - 1) + "$" + num + ";" @@ -760,8 +809,8 @@ class NestedType extends RefType { /** Gets the nesting depth of this nested type. Top-level types have nesting depth 0. */ int getNestingDepth() { - if getEnclosingType() instanceof NestedType - then result = getEnclosingType().(NestedType).getNestingDepth() + 1 + if this.getEnclosingType() instanceof NestedType + then result = this.getEnclosingType().(NestedType).getNestingDepth() + 1 else result = 1 } @@ -776,7 +825,7 @@ class NestedType extends RefType { super.isStrictfp() or // JLS 8.1.1.3, JLS 9.1.1.2 - getEnclosingType().isStrictfp() + this.getEnclosingType().isStrictfp() } override predicate isStatic() { @@ -860,9 +909,9 @@ class ClassOrInterface extends RefType, @classorinterface { /** Holds if this class or interface is package protected, that is, neither public nor private nor protected. */ predicate isPackageProtected() { - not isPrivate() and - not isProtected() and - not isPublic() + not this.isPrivate() and + not this.isProtected() and + not this.isPublic() } } @@ -948,12 +997,12 @@ class PrimitiveType extends Type, @primitive { * require an explicit cast. */ Literal getADefaultValue() { - getName() = "boolean" and result.getLiteral() = "false" + this.getName() = "boolean" and result.getLiteral() = "false" or - getName() = "char" and + this.getName() = "char" and (result.getLiteral() = "'\\0'" or result.getLiteral() = "'\\u0000'") or - getName().regexpMatch("(float|double|int|short|byte|long)") and + this.getName().regexpMatch("(float|double|int|short|byte|long)") and result.getLiteral().regexpMatch("0(\\.0)?+[lLfFdD]?+") } @@ -1047,7 +1096,7 @@ class EnumType extends Class { override predicate isFinal() { // JLS 8.9: An enum declaration is implicitly `final` unless it contains // at least one enum constant that has a class body. - not getAnEnumConstant().getAnAssignedValue().getType() instanceof AnonymousClass + not this.getAnEnumConstant().getAnAssignedValue().getType() instanceof AnonymousClass } } @@ -1120,7 +1169,10 @@ predicate erasedHaveIntersection(RefType t1, RefType t2) { t2 = erase(_) } -/** An integral type, which may be either a primitive or a boxed type. */ +/** + * An integral type, which may be either a primitive or a boxed type. + * This includes the types `char` and `Character`. + */ class IntegralType extends Type { IntegralType() { exists(string name | diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/UnitTests.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/UnitTests.qll index 1adc88d35f7..e56b9a6dc23 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/UnitTests.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/UnitTests.qll @@ -38,11 +38,12 @@ class TearDownMethod extends Method { private class TestRelatedAnnotation extends Annotation { TestRelatedAnnotation() { - this.getType().getPackage().hasName("org.testng.annotations") or - this.getType().getPackage().hasName("org.junit") or - this.getType().getPackage().hasName("org.junit.runner") or - this.getType().getPackage().hasName("org.junit.jupiter.api") or - this.getType().getPackage().hasName("org.junit.jupiter.params") + this.getType() + .getPackage() + .hasName([ + "org.testng.annotations", "org.junit", "org.junit.runner", "org.junit.jupiter.api", + "org.junit.jupiter.params" + ]) } } @@ -115,7 +116,7 @@ class JUnitJupiterTestMethod extends Method { * A JUnit `@Ignore` annotation. */ class JUnitIgnoreAnnotation extends Annotation { - JUnitIgnoreAnnotation() { getType().hasQualifiedName("org.junit", "Ignore") } + JUnitIgnoreAnnotation() { this.getType().hasQualifiedName("org.junit", "Ignore") } } /** @@ -124,7 +125,7 @@ class JUnitIgnoreAnnotation extends Annotation { */ class JUnitIgnoredMethod extends Method { JUnitIgnoredMethod() { - getAnAnnotation() instanceof JUnitIgnoreAnnotation + this.getAnAnnotation() instanceof JUnitIgnoreAnnotation or exists(Class c | c = this.getDeclaringType() | c.getAnAnnotation() instanceof JUnitIgnoreAnnotation @@ -136,14 +137,14 @@ class JUnitIgnoredMethod extends Method { * An annotation in TestNG. */ class TestNGAnnotation extends Annotation { - TestNGAnnotation() { getType().getPackage().hasName("org.testng.annotations") } + TestNGAnnotation() { this.getType().getPackage().hasName("org.testng.annotations") } } /** * An annotation of type `org.test.ng.annotations.Test`. */ class TestNGTestAnnotation extends TestNGAnnotation { - TestNGTestAnnotation() { getType().hasName("Test") } + TestNGTestAnnotation() { this.getType().hasName("Test") } } /** @@ -158,13 +159,13 @@ class TestNGTestMethod extends Method { */ TestNGDataProviderMethod getADataProvider() { exists(TestNGTestAnnotation testAnnotation | - testAnnotation = getAnAnnotation() and + testAnnotation = this.getAnAnnotation() and // The data provider must have the same name as the referenced data provider result.getDataProviderName() = - testAnnotation.getValue("dataProvider").(StringLiteral).getRepresentedString() + testAnnotation.getValue("dataProvider").(StringLiteral).getValue() | // Either the data provider should be on the current class, or a supertype - getDeclaringType().getAnAncestor() = result.getDeclaringType() + this.getDeclaringType().getAnAncestor() = result.getDeclaringType() or // Or the data provider class should be declared result.getDeclaringType() = @@ -190,14 +191,14 @@ class TestMethod extends Method { * A TestNG annotation used to mark a method that runs "before". */ class TestNGBeforeAnnotation extends TestNGAnnotation { - TestNGBeforeAnnotation() { getType().getName().matches("Before%") } + TestNGBeforeAnnotation() { this.getType().getName().matches("Before%") } } /** * A TestNG annotation used to mark a method that runs "after". */ class TestNGAfterAnnotation extends TestNGAnnotation { - TestNGAfterAnnotation() { getType().getName().matches("After%") } + TestNGAfterAnnotation() { this.getType().getName().matches("After%") } } /** @@ -205,7 +206,7 @@ class TestNGAfterAnnotation extends TestNGAnnotation { * them as data provider methods for TestNG. */ class TestNGDataProviderAnnotation extends TestNGAnnotation { - TestNGDataProviderAnnotation() { getType().hasName("DataProvider") } + TestNGDataProviderAnnotation() { this.getType().hasName("DataProvider") } } /** @@ -213,7 +214,7 @@ class TestNGDataProviderAnnotation extends TestNGAnnotation { * them as factory methods for TestNG. */ class TestNGFactoryAnnotation extends TestNGAnnotation { - TestNGFactoryAnnotation() { getType().hasName("Factory") } + TestNGFactoryAnnotation() { this.getType().hasName("Factory") } } /** @@ -221,13 +222,13 @@ class TestNGFactoryAnnotation extends TestNGAnnotation { * which listeners apply to them. */ class TestNGListenersAnnotation extends TestNGAnnotation { - TestNGListenersAnnotation() { getType().hasName("Listeners") } + TestNGListenersAnnotation() { this.getType().hasName("Listeners") } /** * Gets a listener defined in this annotation. */ TestNGListenerImpl getAListener() { - result = getAValue("value").(TypeLiteral).getReferencedType() + result = this.getAValue("value").(TypeLiteral).getReferencedType() } } @@ -235,7 +236,7 @@ class TestNGListenersAnnotation extends TestNGAnnotation { * A concrete implementation class of one or more of the TestNG listener interfaces. */ class TestNGListenerImpl extends Class { - TestNGListenerImpl() { getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener") } + TestNGListenerImpl() { this.getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener") } } /** @@ -246,18 +247,18 @@ class TestNGListenerImpl extends Class { * an instance of a particular value when running a test method. */ class TestNGDataProviderMethod extends Method { - TestNGDataProviderMethod() { getAnAnnotation() instanceof TestNGDataProviderAnnotation } + TestNGDataProviderMethod() { this.getAnAnnotation() instanceof TestNGDataProviderAnnotation } /** * Gets the name associated with this data provider. */ string getDataProviderName() { result = - getAnAnnotation() + this.getAnAnnotation() .(TestNGDataProviderAnnotation) .getValue("name") .(StringLiteral) - .getRepresentedString() + .getValue() } } @@ -268,7 +269,7 @@ class TestNGDataProviderMethod extends Method { * This factory callable is used to generate instances of parameterized test classes. */ class TestNGFactoryCallable extends Callable { - TestNGFactoryCallable() { getAnAnnotation() instanceof TestNGFactoryAnnotation } + TestNGFactoryCallable() { this.getAnAnnotation() instanceof TestNGFactoryAnnotation } } /** @@ -276,7 +277,7 @@ class TestNGFactoryCallable extends Callable { */ class ParameterizedJUnitTest extends Class { ParameterizedJUnitTest() { - getAnAnnotation() + this.getAnAnnotation() .(RunWithAnnotation) .getRunner() .(Class) @@ -289,7 +290,7 @@ class ParameterizedJUnitTest extends Class { */ class JUnitCategoryAnnotation extends Annotation { JUnitCategoryAnnotation() { - getType().hasQualifiedName("org.junit.experimental.categories", "Category") + this.getType().hasQualifiedName("org.junit.experimental.categories", "Category") } /** @@ -297,7 +298,7 @@ class JUnitCategoryAnnotation extends Annotation { */ Type getACategory() { exists(TypeLiteral literal, Expr value | - value = getValue("value") and + value = this.getValue("value") and ( literal = value or literal = value.(ArrayCreationExpr).getInit().getAnInit() @@ -313,7 +314,7 @@ class JUnitCategoryAnnotation extends Annotation { */ class JUnitTheoryTest extends Class { JUnitTheoryTest() { - getAnAnnotation() + this.getAnAnnotation() .(RunWithAnnotation) .getRunner() .(Class) diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/Variable.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/Variable.qll index 439ee5d3f6b..530ddd4eae7 100755 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/Variable.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/Variable.qll @@ -47,12 +47,12 @@ class LocalVariableDecl extends @localvar, LocalScopeVariable { override Callable getCallable() { result = this.getParent().getEnclosingCallable() } /** Gets the callable in which this declaration occurs. */ - Callable getEnclosingCallable() { result = getCallable() } + Callable getEnclosingCallable() { result = this.getCallable() } override string toString() { result = this.getType().getName() + " " + this.getName() } /** Gets the initializer expression of this local variable declaration. */ - override Expr getInitializer() { result = getDeclExpr().getInit() } + override Expr getInitializer() { result = this.getDeclExpr().getInit() } override string getAPrimaryQlClass() { result = "LocalVariableDecl" } } @@ -63,7 +63,7 @@ class Parameter extends Element, @param, LocalScopeVariable { override Type getType() { params(this, result, _, _, _) } /** Holds if the parameter is never assigned a value in the body of the callable. */ - predicate isEffectivelyFinal() { not exists(getAnAssignedValue()) } + predicate isEffectivelyFinal() { not exists(this.getAnAssignedValue()) } /** Gets the (zero-based) index of this formal parameter. */ int getPosition() { params(this, _, result, _, _) } @@ -87,8 +87,8 @@ class Parameter extends Element, @param, LocalScopeVariable { * Varargs parameters will have no results for this method. */ Expr getAnArgument() { - not isVarargs() and - result = getACallArgument(getPosition()) + not this.isVarargs() and + result = this.getACallArgument(this.getPosition()) } pragma[noinline] diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/arithmetic/Overflow.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/arithmetic/Overflow.qll index 7227c6da398..4e9eb75ec13 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/arithmetic/Overflow.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/arithmetic/Overflow.qll @@ -2,9 +2,9 @@ import java /** A subclass of `PrimitiveType` with width-based ordering methods. */ class OrdPrimitiveType extends PrimitiveType { - predicate widerThan(OrdPrimitiveType that) { getWidthRank() > that.getWidthRank() } + predicate widerThan(OrdPrimitiveType that) { this.getWidthRank() > that.getWidthRank() } - predicate widerThanOrEqualTo(OrdPrimitiveType that) { getWidthRank() >= that.getWidthRank() } + predicate widerThanOrEqualTo(OrdPrimitiveType that) { this.getWidthRank() >= that.getWidthRank() } OrdPrimitiveType maxType(OrdPrimitiveType that) { this.widerThan(that) and result = this diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll index c0b227ba9ba..5f1ed3438b5 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll @@ -25,13 +25,13 @@ class BasicBlock extends ControlFlowNode { /** Gets an immediate successor of this basic block. */ cached - BasicBlock getABBSuccessor() { result = getLastNode().getASuccessor() } + BasicBlock getABBSuccessor() { result = this.getLastNode().getASuccessor() } /** Gets an immediate predecessor of this basic block. */ BasicBlock getABBPredecessor() { result.getABBSuccessor() = this } /** Gets a control-flow node contained in this basic block. */ - ControlFlowNode getANode() { result = getNode(_) } + ControlFlowNode getANode() { result = this.getNode(_) } /** Gets the control-flow node at a specific (zero-indexed) position in this basic block. */ cached @@ -39,7 +39,7 @@ class BasicBlock extends ControlFlowNode { result = this and pos = 0 or exists(ControlFlowNode mid, int mid_pos | pos = mid_pos + 1 | - getNode(mid_pos) = mid and + this.getNode(mid_pos) = mid and mid.getASuccessor() = result and not result instanceof BasicBlock ) @@ -49,11 +49,11 @@ class BasicBlock extends ControlFlowNode { ControlFlowNode getFirstNode() { result = this } /** Gets the last control-flow node in this basic block. */ - ControlFlowNode getLastNode() { result = getNode(length() - 1) } + ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) } /** Gets the number of control-flow nodes contained in this basic block. */ cached - int length() { result = strictcount(getANode()) } + int length() { result = strictcount(this.getANode()) } /** Holds if this basic block strictly dominates `node`. */ predicate bbStrictlyDominates(BasicBlock node) { bbStrictlyDominates(this, node) } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/UnreachableBlocks.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/UnreachableBlocks.qll index 5ce27fda434..8e9d90769f3 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/UnreachableBlocks.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/UnreachableBlocks.qll @@ -12,13 +12,13 @@ import semmle.code.java.controlflow.Guards */ class ConstantField extends Field { ConstantField() { - getType() instanceof ImmutableType and + this.getType() instanceof ImmutableType and // Assigned once - count(getAnAssignedValue()) = 1 and + count(this.getAnAssignedValue()) = 1 and // And that assignment is either in the appropriate initializer, or, for instance fields on // classes with one constructor, in the constructor. - forall(FieldWrite fa | fa = getAnAccess() | - if isStatic() + forall(FieldWrite fa | fa = this.getAnAccess() | + if this.isStatic() then fa.getEnclosingCallable() instanceof StaticInitializer else ( // Defined in the instance initializer. @@ -26,7 +26,7 @@ class ConstantField extends Field { or // It can be defined in the constructor if there is only one constructor. fa.getEnclosingCallable() instanceof Constructor and - count(getDeclaringType().getAConstructor()) = 1 + count(this.getDeclaringType().getAConstructor()) = 1 ) ) } @@ -36,7 +36,7 @@ class ConstantField extends Field { * * Note: although this value is constant, we may not be able to statically determine the value. */ - ConstantExpr getConstantValue() { result = getAnAssignedValue() } + ConstantExpr getConstantValue() { result = this.getAnAssignedValue() } } /** @@ -162,18 +162,18 @@ class ConstSwitchStmt extends SwitchStmt { /** Gets the `ConstCase` that matches, if any. */ ConstCase getMatchingConstCase() { - result = getAConstCase() and + result = this.getAConstCase() and // Only handle the int case for now - result.getValue().(ConstantExpr).getIntValue() = getExpr().(ConstantExpr).getIntValue() + result.getValue().(ConstantExpr).getIntValue() = this.getExpr().(ConstantExpr).getIntValue() } /** Gets the matching case, if it can be deduced. */ SwitchCase getMatchingCase() { // Must be a value we can deduce - exists(getExpr().(ConstantExpr).getIntValue()) and - if exists(getMatchingConstCase()) - then result = getMatchingConstCase() - else result = getDefaultCase() + exists(this.getExpr().(ConstantExpr).getIntValue()) and + if exists(this.getMatchingConstCase()) + then result = this.getMatchingConstCase() + else result = this.getDefaultCase() } /** @@ -184,8 +184,8 @@ class ConstSwitchStmt extends SwitchStmt { SwitchCase getAFailingCase() { exists(SwitchCase matchingCase | // We must have found the matching case, otherwise we can't deduce which cases are not matched - matchingCase = getMatchingCase() and - result = getACase() and + matchingCase = this.getMatchingCase() and + result = this.getACase() and result != matchingCase ) } @@ -208,7 +208,7 @@ class UnreachableBasicBlock extends BasicBlock { or // This block is not reachable in the CFG, and is not a callable, a body of a callable, an // expression in an annotation, an expression in an assert statement, or a catch clause. - forall(BasicBlock bb | bb = getABBPredecessor() | bb instanceof UnreachableBasicBlock) and + forall(BasicBlock bb | bb = this.getABBPredecessor() | bb instanceof UnreachableBasicBlock) and not exists(Callable c | c.getBody() = this) and not this instanceof Callable and not exists(Annotation a | a.getAChildExpr*() = this) and @@ -231,12 +231,12 @@ class UnreachableBasicBlock extends BasicBlock { * An unreachable expression is an expression contained in an `UnreachableBasicBlock`. */ class UnreachableExpr extends Expr { - UnreachableExpr() { getBasicBlock() instanceof UnreachableBasicBlock } + UnreachableExpr() { this.getBasicBlock() instanceof UnreachableBasicBlock } } /** * An unreachable statement is a statement contained in an `UnreachableBasicBlock`. */ class UnreachableStmt extends Stmt { - UnreachableStmt() { getBasicBlock() instanceof UnreachableBasicBlock } + UnreachableStmt() { this.getBasicBlock() instanceof UnreachableBasicBlock } } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/unreachableblocks/ExcludeDebuggingProfilingLogging.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/unreachableblocks/ExcludeDebuggingProfilingLogging.qll index a9f75924c55..3494e813c74 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/unreachableblocks/ExcludeDebuggingProfilingLogging.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/controlflow/unreachableblocks/ExcludeDebuggingProfilingLogging.qll @@ -17,16 +17,11 @@ import semmle.code.java.controlflow.UnreachableBlocks class ExcludeDebuggingProfilingLogging extends ExcludedConstantField { ExcludeDebuggingProfilingLogging() { exists(string validFieldName | - validFieldName = "debug" or - validFieldName = "profiling" or - validFieldName = "profile" or - validFieldName = "time" or - validFieldName = "verbose" or - validFieldName = "report" or - validFieldName = "dbg" or - validFieldName = "timing" or - validFieldName = "assert" or - validFieldName = "log" + validFieldName = + [ + "debug", "profiling", "profile", "time", "verbose", "report", "dbg", "timing", "assert", + "log" + ] | getName().regexpMatch(".*(?i)" + validFieldName + ".*") ) and diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index cfbcd16f75e..70858ce2911 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -79,9 +79,11 @@ private module Frameworks { private import internal.ContainerFlow private import semmle.code.java.frameworks.android.Android private import semmle.code.java.frameworks.android.Intent + private import semmle.code.java.frameworks.android.SQLite private import semmle.code.java.frameworks.android.XssSinks private import semmle.code.java.frameworks.ApacheHttp private import semmle.code.java.frameworks.apache.Collections + private import semmle.code.java.frameworks.apache.IO private import semmle.code.java.frameworks.apache.Lang private import semmle.code.java.frameworks.Flexjson private import semmle.code.java.frameworks.guava.Guava @@ -95,6 +97,8 @@ private module Frameworks { private import semmle.code.java.frameworks.Optional private import semmle.code.java.frameworks.Stream private import semmle.code.java.frameworks.Strings + private import semmle.code.java.frameworks.ratpack.Ratpack + private import semmle.code.java.frameworks.ratpack.RatpackExec private import semmle.code.java.frameworks.spring.SpringCache private import semmle.code.java.frameworks.spring.SpringHttp private import semmle.code.java.frameworks.spring.SpringUtil @@ -104,6 +108,7 @@ private module Frameworks { private import semmle.code.java.frameworks.spring.SpringBeans private import semmle.code.java.frameworks.spring.SpringWebMultipart private import semmle.code.java.frameworks.spring.SpringWebUtil + private import semmle.code.java.security.AndroidIntentRedirection private import semmle.code.java.security.ResponseSplitting private import semmle.code.java.security.InformationLeak private import semmle.code.java.security.GroovyInjection @@ -114,8 +119,6 @@ private module Frameworks { private import semmle.code.java.security.OgnlInjection private import semmle.code.java.security.XPath private import semmle.code.java.security.XsltInjection - private import semmle.code.java.frameworks.android.Android - private import semmle.code.java.frameworks.android.SQLite private import semmle.code.java.frameworks.Jdbc private import semmle.code.java.frameworks.SpringJdbc private import semmle.code.java.frameworks.MyBatis @@ -320,33 +323,11 @@ private predicate summaryModelCsv(string row) { "org.apache.commons.codec;BinaryDecoder;true;decode;(byte[]);;Argument[0];ReturnValue;taint", "org.apache.commons.codec;StringEncoder;true;encode;(String);;Argument[0];ReturnValue;taint", "org.apache.commons.codec;StringDecoder;true;decode;(String);;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;buffer;;;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;readLines;;;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;readFully;(InputStream,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;toBufferedInputStream;;;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;toBufferedReader;;;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;toByteArray;;;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;toCharArray;;;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;toInputStream;;;Argument[0];ReturnValue;taint", - "org.apache.commons.io;IOUtils;false;toString;;;Argument[0];ReturnValue;taint", "java.net;URLDecoder;false;decode;;;Argument[0];ReturnValue;taint", "java.net;URI;false;create;;;Argument[0];ReturnValue;taint", "javax.xml.transform.sax;SAXSource;false;sourceToInputSource;;;Argument[0];ReturnValue;taint", // arg to arg "java.lang;System;false;arraycopy;;;Argument[0];Argument[2];taint", - "org.apache.commons.io;IOUtils;false;copy;;;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;copyLarge;;;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;read;;;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;readFully;(InputStream,byte[]);;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;readFully;(InputStream,byte[],int,int);;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;readFully;(InputStream,ByteBuffer);;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;readFully;(ReadableByteChannel,ByteBuffer);;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;readFully;(Reader,char[]);;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;readFully;(Reader,char[],int,int);;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;write;;;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;writeChunked;;;Argument[0];Argument[1];taint", - "org.apache.commons.io;IOUtils;false;writeLines;;;Argument[0];Argument[2];taint", - "org.apache.commons.io;IOUtils;false;writeLines;;;Argument[1];Argument[2];taint", // constructor flow "java.io;File;false;File;;;Argument[0];Argument[-1];taint", "java.io;File;false;File;;;Argument[1];Argument[-1];taint", @@ -371,7 +352,11 @@ private predicate summaryModelCsv(string row) { "java.io;StringReader;false;StringReader;;;Argument[0];Argument[-1];taint", "java.io;CharArrayReader;false;CharArrayReader;;;Argument[0];Argument[-1];taint", "java.io;BufferedReader;false;BufferedReader;;;Argument[0];Argument[-1];taint", - "java.io;InputStreamReader;false;InputStreamReader;;;Argument[0];Argument[-1];taint" + "java.io;InputStreamReader;false;InputStreamReader;;;Argument[0];Argument[-1];taint", + "java.io;OutputStream;true;write;(byte[]);;Argument[0];Argument[-1];taint", + "java.io;OutputStream;true;write;(byte[],int,int);;Argument[0];Argument[-1];taint", + "java.io;OutputStream;true;write;(int);;Argument[0];Argument[-1];taint", + "java.io;FilterOutputStream;true;FilterOutputStream;(OutputStream);;Argument[0];Argument[-1];taint" ] } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll index a8f15a103c8..d8d02f995a6 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll @@ -45,8 +45,8 @@ private class RmiMethodParameterSource extends RemoteFlowSource { exists(RemoteCallableMethod method | method.getAParameter() = this.asParameter() and ( - getType() instanceof PrimitiveType or - getType() instanceof TypeString + this.getType() instanceof PrimitiveType or + this.getType() instanceof TypeString ) ) } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll index ae9c88fb118..ec62ec42c44 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll @@ -11,6 +11,7 @@ private import semmle.code.java.dataflow.DataFlow */ private module Frameworks { private import semmle.code.java.frameworks.jackson.JacksonSerializability + private import semmle.code.java.frameworks.android.AsyncTask private import semmle.code.java.frameworks.android.Intent private import semmle.code.java.frameworks.android.SQLite private import semmle.code.java.frameworks.Guice @@ -64,6 +65,20 @@ class AdditionalTaintStep extends Unit { abstract predicate step(DataFlow::Node node1, DataFlow::Node node2); } +/** + * A unit class for adding additional value steps. + * + * Extend this class to add additional value-preserving steps that should apply + * to all data flow configurations. + */ +class AdditionalValueStep extends Unit { + /** + * Holds if the step from `node1` to `node2` is a value-preserving step and + * should apply to all data flow configurations. + */ + abstract predicate step(DataFlow::Node node1, DataFlow::Node node2); +} + /** * A method or constructor that preserves taint. * diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/SSA.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/SSA.qll index 9a2a1df0915..dbcaafd3071 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/SSA.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/SSA.qll @@ -97,7 +97,7 @@ class SsaSourceVariable extends TSsaSourceVariable { else result = c.getName() + "(..)." + v.getName() ) or - result = this.(SsaSourceField).ppQualifier() + "." + getVariable().toString() + result = this.(SsaSourceField).ppQualifier() + "." + this.getVariable().toString() } /** @@ -117,7 +117,7 @@ class SsaSourceVariable extends TSsaSourceVariable { Location getLocation() { exists(LocalScopeVariable v | this = TLocalVar(_, v) and result = v.getLocation()) or - this instanceof SsaSourceField and result = getFirstAccess().getLocation() + this instanceof SsaSourceField and result = this.getFirstAccess().getLocation() } /** Gets the type of this variable. */ @@ -140,7 +140,7 @@ class SsaSourceField extends SsaSourceVariable { } /** Gets the field corresponding to this named field. */ - Field getField() { result = getVariable() } + Field getField() { result = this.getVariable() } /** Gets a string representation of the qualifier. */ string ppQualifier() { @@ -155,8 +155,8 @@ class SsaSourceField extends SsaSourceVariable { /** Holds if the field itself or any of the fields part of the qualifier are volatile. */ predicate isVolatile() { - getField().isVolatile() or - getQualifier().(SsaSourceField).isVolatile() + this.getField().isVolatile() or + this.getQualifier().(SsaSourceField).isVolatile() } } @@ -932,10 +932,10 @@ class SsaVariable extends TSsaVariable { string toString() { none() } /** Gets the source location for this element. */ - Location getLocation() { result = getCFGNode().getLocation() } + Location getLocation() { result = this.getCFGNode().getLocation() } /** Gets the `BasicBlock` in which this SSA variable is defined. */ - BasicBlock getBasicBlock() { result = getCFGNode().getBasicBlock() } + BasicBlock getBasicBlock() { result = this.getCFGNode().getBasicBlock() } /** Gets an access of this SSA variable. */ RValue getAUse() { @@ -989,14 +989,16 @@ class SsaUpdate extends SsaVariable { /** An SSA variable that is defined by a `VariableUpdate`. */ class SsaExplicitUpdate extends SsaUpdate, TSsaCertainUpdate { SsaExplicitUpdate() { - exists(VariableUpdate upd | upd = this.getCFGNode() and getDestVar(upd) = getSourceVariable()) + exists(VariableUpdate upd | + upd = this.getCFGNode() and getDestVar(upd) = this.getSourceVariable() + ) } - override string toString() { result = "SSA def(" + getSourceVariable() + ")" } + override string toString() { result = "SSA def(" + this.getSourceVariable() + ")" } /** Gets the `VariableUpdate` defining the SSA variable. */ VariableUpdate getDefiningExpr() { - result = this.getCFGNode() and getDestVar(result) = getSourceVariable() + result = this.getCFGNode() and getDestVar(result) = this.getSourceVariable() } } @@ -1010,22 +1012,22 @@ class SsaImplicitUpdate extends SsaUpdate { SsaImplicitUpdate() { not this instanceof SsaExplicitUpdate } override string toString() { - result = "SSA impl upd[" + getKind() + "](" + getSourceVariable() + ")" + result = "SSA impl upd[" + this.getKind() + "](" + this.getSourceVariable() + ")" } private string getKind() { this = TSsaUntracked(_, _) and result = "untracked" or - certainVariableUpdate(getSourceVariable().getQualifier(), getCFGNode(), _, _) and + certainVariableUpdate(this.getSourceVariable().getQualifier(), this.getCFGNode(), _, _) and result = "explicit qualifier" or - if uncertainVariableUpdate(getSourceVariable().getQualifier(), getCFGNode(), _, _) + if uncertainVariableUpdate(this.getSourceVariable().getQualifier(), this.getCFGNode(), _, _) then - if exists(getANonLocalUpdate()) + if exists(this.getANonLocalUpdate()) then result = "nonlocal + nonlocal qualifier" else result = "nonlocal qualifier" else ( - exists(getANonLocalUpdate()) and result = "nonlocal" + exists(this.getANonLocalUpdate()) and result = "nonlocal" ) } @@ -1034,9 +1036,9 @@ class SsaImplicitUpdate extends SsaUpdate { */ FieldWrite getANonLocalUpdate() { exists(SsaSourceField f, Callable setter | - f = getSourceVariable() and + f = this.getSourceVariable() and relevantFieldUpdate(setter, f.getField(), result) and - updatesNamedField(getCFGNode(), f, setter) + updatesNamedField(this.getCFGNode(), f, setter) ) } @@ -1049,8 +1051,8 @@ class SsaImplicitUpdate extends SsaUpdate { */ predicate assignsUnknownValue() { this = TSsaUntracked(_, _) or - certainVariableUpdate(getSourceVariable().getQualifier(), getCFGNode(), _, _) or - uncertainVariableUpdate(getSourceVariable().getQualifier(), getCFGNode(), _, _) + certainVariableUpdate(this.getSourceVariable().getQualifier(), this.getCFGNode(), _, _) or + uncertainVariableUpdate(this.getSourceVariable().getQualifier(), this.getCFGNode(), _, _) } } @@ -1072,30 +1074,31 @@ class SsaUncertainImplicitUpdate extends SsaImplicitUpdate, TSsaUncertainUpdate * includes initial values of parameters, fields, and closure variables. */ class SsaImplicitInit extends SsaVariable, TSsaEntryDef { - override string toString() { result = "SSA init(" + getSourceVariable() + ")" } + override string toString() { result = "SSA init(" + this.getSourceVariable() + ")" } /** Holds if this is a closure variable that captures the value of `capturedvar`. */ predicate captures(SsaVariable capturedvar) { - ssaDefReachesCapture(_, capturedvar, getSourceVariable()) + ssaDefReachesCapture(_, capturedvar, this.getSourceVariable()) } /** * Holds if the SSA variable is a parameter defined by its initial value in the callable. */ predicate isParameterDefinition(Parameter p) { - getSourceVariable() = TLocalVar(p.getCallable(), p) and p.getCallable().getBody() = getCFGNode() + this.getSourceVariable() = TLocalVar(p.getCallable(), p) and + p.getCallable().getBody() = this.getCFGNode() } } /** An SSA phi node. */ class SsaPhiNode extends SsaVariable, TSsaPhiNode { - override string toString() { result = "SSA phi(" + getSourceVariable() + ")" } + override string toString() { result = "SSA phi(" + this.getSourceVariable() + ")" } /** Gets an input to the phi node defining the SSA variable. */ SsaVariable getAPhiInput() { exists(BasicBlock phiPred, TrackedVar v | - v = getSourceVariable() and - getCFGNode().(BasicBlock).getABBPredecessor() = phiPred and + v = this.getSourceVariable() and + this.getCFGNode().(BasicBlock).getABBPredecessor() = phiPred and ssaDefReachesEndOfBlock(v, result, phiPred) ) } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/StringPrefixes.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/StringPrefixes.qll new file mode 100644 index 00000000000..755deaba532 --- /dev/null +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/StringPrefixes.qll @@ -0,0 +1,178 @@ +/** + * Provides classes and predicates for identifying expressions that may be appended to an interesting prefix. + * + * To use this library, extend the abstract class `InterestingPrefix` to have the library identify expressions that + * may be appended to it, then check `InterestingPrefix.getAnAppendedExpression(Expr)` to get your results. + * + * For example, to identify expressions that may follow "foo:" in some string, we could define: + * + * ``` + * private class FooPrefix extends InterestingPrefix { + * int offset; + * FooPrefix() { this.getStringValue().substring("foo:") = offset }; + * override int getOffset() { result = offset } + * }; + * + * predicate mayFollowFoo(Expr e) { e = any(FooPrefix fp).getAnAppendedExpression() } + * ``` + * + * This will identify all the `suffix` expressions in contexts such as: + * + * ``` + * "foo:" + suffix1 + * "barfoo:" + suffix2 + * stringBuilder.append("foo:").append(suffix3); + * String.format("%sfoo:%s", notSuffix, suffix4); + * ``` + */ + +import java +private import semmle.code.java.dataflow.TaintTracking +private import semmle.code.java.StringFormat + +/** + * A string constant that contains a prefix whose possibly-appended strings are + * returned by `getAnAppendedExpression`. + * + * Extend this class to specify prefixes whose possibly-appended strings should be analysed. + */ +abstract class InterestingPrefix extends CompileTimeConstantExpr { + /** + * Gets the offset in this constant string where the interesting prefix begins. + */ + abstract int getOffset(); + + /** + * Gets an expression that may follow this prefix in a derived string. + */ + Expr getAnAppendedExpression() { mayFollowInterestingPrefix(this, result) } +} + +private Expr getAnInterestingPrefix(InterestingPrefix root) { + result = root + or + result.(AddExpr).getAnOperand() = getAnInterestingPrefix(root) +} + +private class StringBuilderAppend extends MethodAccess { + StringBuilderAppend() { + this.getMethod().getDeclaringType() instanceof StringBuildingType and + this.getMethod().hasName("append") + } +} + +private class StringBuilderConstructorOrAppend extends Call { + StringBuilderConstructorOrAppend() { + this instanceof StringBuilderAppend or + this.(ClassInstanceExpr).getConstructedType() instanceof StringBuildingType + } +} + +private Expr getQualifier(Expr e) { result = e.(MethodAccess).getQualifier() } + +/** + * An extension of `StringBuilderVar` that also accounts for strings appended in StringBuilder/Buffer's constructor + * and in `append` calls chained onto the constructor call. + * + * The original `StringBuilderVar` doesn't care about these because it is designed to model taint, and + * in taint rules terms these are not needed, as the connection between construction, appends and the + * eventual `toString` is more obvious. + */ +private class StringBuilderVarExt extends StringBuilderVar { + /** + * Returns a first assignment after this StringBuilderVar is first assigned. + * + * For example, for `StringBuilder sbv = new StringBuilder("1").append("2"); sbv.append("3").append("4");` + * this returns the append of `"3"`. + */ + private StringBuilderAppend getAFirstAppendAfterAssignment() { + result = this.getAnAppend() and not result = this.getNextAppend(_) + } + + /** + * Gets the next `append` after `prev`, where `prev` is, perhaps after some more `append` or other + * chained calls, assigned to this `StringBuilderVar`. + */ + private StringBuilderAppend getNextAssignmentChainedAppend(StringBuilderConstructorOrAppend prev) { + getQualifier*(result) = this.getAnAssignedValue() and + result.getQualifier() = prev + } + + /** + * Get a constructor call or `append` call that contributes a string to this string builder. + */ + StringBuilderConstructorOrAppend getAConstructorOrAppend() { + exists(this.getNextAssignmentChainedAppend(result)) or + result = this.getAnAssignedValue() or + result = this.getAnAppend() + } + + /** + * Like `StringBuilderVar.getNextAppend`, except including appends and constructors directly + * assigned to this `StringBuilderVar`. + */ + private StringBuilderAppend getNextAppendIncludingAssignmentChains( + StringBuilderConstructorOrAppend prev + ) { + result = this.getNextAssignmentChainedAppend(prev) + or + prev = this.getAnAssignedValue() and + result = this.getAFirstAppendAfterAssignment() + or + result = this.getNextAppend(prev) + } + + /** + * Implements `StringBuilderVarExt.getNextAppendIncludingAssignmentChains+(prev)`. + */ + pragma[nomagic] + StringBuilderAppend getSubsequentAppendIncludingAssignmentChains( + StringBuilderConstructorOrAppend prev + ) { + result = this.getNextAppendIncludingAssignmentChains(prev) or + result = + this.getSubsequentAppendIncludingAssignmentChains(this.getNextAppendIncludingAssignmentChains(prev)) + } +} + +/** + * Holds if `follows` may be concatenated after `prefix`. + */ +private predicate mayFollowInterestingPrefix(InterestingPrefix prefix, Expr follows) { + // Expressions that come after an interesting prefix in a tree of string additions: + follows = + any(AddExpr add | add.getLeftOperand() = getAnInterestingPrefix(prefix)).getRightOperand() + or + // Sanitize expressions that come after an interesting prefix in a sequence of StringBuilder operations: + exists( + StringBuilderConstructorOrAppend appendSanitizingConstant, StringBuilderAppend subsequentAppend, + StringBuilderVarExt v + | + appendSanitizingConstant = v.getAConstructorOrAppend() and + appendSanitizingConstant.getArgument(0) = getAnInterestingPrefix(prefix) and + v.getSubsequentAppendIncludingAssignmentChains(appendSanitizingConstant) = subsequentAppend and + follows = subsequentAppend.getArgument(0) + ) + or + // Sanitize expressions that come after an interesting prefix in the args to a format call: + exists( + FormattingCall formatCall, FormatString formatString, int prefixOffset, int laterOffset, + int sanitizedArg + | + formatString = unique(FormatString fs | fs = formatCall.getAFormatString()) and + ( + // An interesting prefix argument comes before this: + exists(int argIdx | + formatCall.getArgumentToBeFormatted(argIdx) = prefix and + prefixOffset = formatString.getAnArgUsageOffset(argIdx) + ) + or + // The format string itself contains an interesting prefix that precedes subsequent arguments: + formatString = prefix.getStringValue() and + prefixOffset = prefix.getOffset() + ) and + laterOffset > prefixOffset and + laterOffset = formatString.getAnArgUsageOffset(sanitizedArg) and + follows = formatCall.getArgumentToBeFormatted(sanitizedArg) + ) +} diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll index 8193a33bcb3..e0e6e64321f 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll @@ -484,10 +484,10 @@ class BaseSsaVariable extends TBaseSsaVariable { string toString() { none() } - Location getLocation() { result = getCFGNode().getLocation() } + Location getLocation() { result = this.getCFGNode().getLocation() } /** Gets the `BasicBlock` in which this SSA variable is defined. */ - BasicBlock getBasicBlock() { result = getCFGNode().getBasicBlock() } + BasicBlock getBasicBlock() { result = this.getCFGNode().getBasicBlock() } /** Gets an access of this SSA variable. */ RValue getAUse() { ssaDefReachesUse(_, this, result) } @@ -532,14 +532,16 @@ class BaseSsaVariable extends TBaseSsaVariable { /** An SSA variable that is defined by a `VariableUpdate`. */ class BaseSsaUpdate extends BaseSsaVariable, TSsaUpdate { BaseSsaUpdate() { - exists(VariableUpdate upd | upd = this.getCFGNode() and getDestVar(upd) = getSourceVariable()) + exists(VariableUpdate upd | + upd = this.getCFGNode() and getDestVar(upd) = this.getSourceVariable() + ) } - override string toString() { result = "SSA def(" + getSourceVariable() + ")" } + override string toString() { result = "SSA def(" + this.getSourceVariable() + ")" } /** Gets the `VariableUpdate` defining the SSA variable. */ VariableUpdate getDefiningExpr() { - result = this.getCFGNode() and getDestVar(result) = getSourceVariable() + result = this.getCFGNode() and getDestVar(result) = this.getSourceVariable() } } @@ -548,30 +550,31 @@ class BaseSsaUpdate extends BaseSsaVariable, TSsaUpdate { * includes initial values of parameters, fields, and closure variables. */ class BaseSsaImplicitInit extends BaseSsaVariable, TSsaEntryDef { - override string toString() { result = "SSA init(" + getSourceVariable() + ")" } + override string toString() { result = "SSA init(" + this.getSourceVariable() + ")" } /** Holds if this is a closure variable that captures the value of `capturedvar`. */ predicate captures(BaseSsaVariable capturedvar) { - ssaDefReachesCapture(_, capturedvar, getSourceVariable()) + ssaDefReachesCapture(_, capturedvar, this.getSourceVariable()) } /** * Holds if the SSA variable is a parameter defined by its initial value in the callable. */ predicate isParameterDefinition(Parameter p) { - getSourceVariable() = TLocalVar(p.getCallable(), p) and p.getCallable().getBody() = getCFGNode() + this.getSourceVariable() = TLocalVar(p.getCallable(), p) and + p.getCallable().getBody() = this.getCFGNode() } } /** An SSA phi node. */ class BaseSsaPhiNode extends BaseSsaVariable, TSsaPhiNode { - override string toString() { result = "SSA phi(" + getSourceVariable() + ")" } + override string toString() { result = "SSA phi(" + this.getSourceVariable() + ")" } /** Gets an input to the phi node defining the SSA variable. */ BaseSsaVariable getAPhiInput() { exists(BasicBlock phiPred, BaseSsaSourceVariable v | - v = getSourceVariable() and - getCFGNode().(BasicBlock).getABBPredecessor() = phiPred and + v = this.getSourceVariable() and + this.getCFGNode().(BasicBlock).getABBPredecessor() = phiPred and ssaDefReachesEndOfBlock(v, result, phiPred) ) } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/ContainerFlow.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/ContainerFlow.qll index 6c72bbd451b..79fea09de4c 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -104,7 +104,9 @@ private class ContainerFlowSummaries extends SummaryModelCsv { "java.util;Map$Entry;true;setValue;;;Argument[0];MapValue of Argument[-1];value", "java.lang;Iterable;true;iterator;();;Element of Argument[-1];Element of ReturnValue;value", "java.lang;Iterable;true;spliterator;();;Element of Argument[-1];Element of ReturnValue;value", + "java.lang;Iterable;true;forEach;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value", "java.util;Iterator;true;next;;;Element of Argument[-1];ReturnValue;value", + "java.util;Iterator;true;forEachRemaining;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value", "java.util;ListIterator;true;previous;;;Element of Argument[-1];ReturnValue;value", "java.util;ListIterator;true;add;(Object);;Argument[0];Element of Argument[-1];value", "java.util;ListIterator;true;set;(Object);;Argument[0];Element of Argument[-1];value", @@ -135,6 +137,8 @@ private class ContainerFlowSummaries extends SummaryModelCsv { "java.util;Map;true;merge;(Object,Object,BiFunction);;Argument[1];MapValue of Argument[-1];value", "java.util;Map;true;putAll;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value", "java.util;Map;true;putAll;(Map);;MapValue of Argument[0];MapValue of Argument[-1];value", + "java.util;Map;true;forEach;(BiConsumer);;MapKey of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Map;true;forEach;(BiConsumer);;MapValue of Argument[-1];Parameter[1] of Argument[0];value", "java.util;Collection;true;parallelStream;();;Element of Argument[-1];Element of ReturnValue;value", "java.util;Collection;true;stream;();;Element of Argument[-1];Element of ReturnValue;value", "java.util;Collection;true;toArray;;;Element of Argument[-1];ArrayElement of ReturnValue;value", diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll index 0e61dc4582f..91b8b391df5 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll @@ -8,9 +8,9 @@ private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch private module DispatchImpl { /** Gets a viable implementation of the target of the given `Call`. */ DataFlowCallable viableCallable(DataFlowCall c) { - result = VirtualDispatch::viableCallable(c.asCall()) + result.asCallable() = VirtualDispatch::viableCallable(c.asCall()) or - result.(SummarizedCallable) = c.asCall().getCallee().getSourceDeclaration() + result.(SummarizedCallable).asCallable() = c.asCall().getCallee().getSourceDeclaration() } /** @@ -93,31 +93,32 @@ private module DispatchImpl { * qualifier is a parameter of the enclosing callable `c`. */ predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) { - mayBenefitFromCallContext(call.asCall(), c, _) + mayBenefitFromCallContext(call.asCall(), c.asCallable(), _) } /** * Gets a viable dispatch target of `call` in the context `ctx`. This is * restricted to those `call`s for which a context might make a difference. */ - Method viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { result = viableCallable(call) and exists(int i, Callable c, Method def, RefType t, boolean exact, MethodAccess ma | ma = call.asCall() and mayBenefitFromCallContext(ma, c, i) and - c = viableCallable(ctx) and + c = viableCallable(ctx).asCallable() and contextArgHasType(ctx.asCall(), i, t, exact) and ma.getMethod().getSourceDeclaration() = def | - exact = true and result = VirtualDispatch::exactMethodImpl(def, t.getSourceDeclaration()) + exact = true and + result.asCallable() = VirtualDispatch::exactMethodImpl(def, t.getSourceDeclaration()) or exact = false and exists(RefType t2 | - result = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and + result.asCallable() = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and not failsUnification(t, t2) ) or - result = def and def instanceof SummarizedCallable + result.asCallable() = def and result instanceof SummarizedCallable ) } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index f43a550af57..c28ceabb438 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -2,6 +2,42 @@ private import DataFlowImplSpecific::Private private import DataFlowImplSpecific::Public import Cached +module DataFlowImplCommonPublic { + private newtype TFlowFeature = + TFeatureHasSourceCallContext() or + TFeatureHasSinkCallContext() or + TFeatureEqualSourceSinkCallContext() + + /** A flow configuration feature for use in `Configuration::getAFeature()`. */ + class FlowFeature extends TFlowFeature { + string toString() { none() } + } + + /** + * A flow configuration feature that implies that sources have some existing + * call context. + */ + class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext { + override string toString() { result = "FeatureHasSourceCallContext" } + } + + /** + * A flow configuration feature that implies that sinks have some existing + * call context. + */ + class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext { + override string toString() { result = "FeatureHasSinkCallContext" } + } + + /** + * A flow configuration feature that implies that source-sink pairs have some + * shared existing call context. + */ + class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext { + override string toString() { result = "FeatureEqualSourceSinkCallContext" } + } +} + /** * The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion. * @@ -251,7 +287,7 @@ private module Cached { predicate forceCachingInSameStage() { any() } cached - predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() } + predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) } cached predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) { @@ -316,9 +352,7 @@ private module Cached { } cached - predicate parameterNode(Node n, DataFlowCallable c, int i) { - n.(ParameterNode).isParameterOf(c, i) - } + predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) } cached predicate argumentNode(Node n, DataFlowCall call, int pos) { @@ -801,6 +835,9 @@ private module Cached { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } + cached + predicate allowParameterReturnInSelfCached(ParamNode p) { allowParameterReturnInSelf(p) } + cached newtype TCallContext = TAnyCallContext() or @@ -937,7 +974,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { } override predicate relevantFor(DataFlowCallable callable) { - recordDataFlowCallSite(getCall(), callable) + recordDataFlowCallSite(this.getCall(), callable) } override predicate matchesCall(DataFlowCall call) { call = this.getCall() } @@ -1257,7 +1294,7 @@ abstract class AccessPathFront extends TAccessPathFront { TypedContent getHead() { this = TFrontHead(result) } - predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) } + predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll index a55e65a81f6..acf31338f9a 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll @@ -31,7 +31,7 @@ module Consistency { query predicate uniqueEnclosingCallable(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getEnclosingCallable()) and + c = count(nodeGetEnclosingCallable(n)) and c != 1 and msg = "Node should have one enclosing callable but has " + c + "." ) @@ -85,13 +85,13 @@ module Consistency { } query predicate parameterCallable(ParameterNode p, string msg) { - exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and + exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and msg = "Callable mismatch for parameter." } query predicate localFlowIsLocal(Node n1, Node n2, string msg) { simpleLocalFlowStep(n1, n2) and - n1.getEnclosingCallable() != n2.getEnclosingCallable() and + nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and msg = "Local flow step does not preserve enclosing callable." } @@ -106,7 +106,7 @@ module Consistency { query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) { isUnreachableInCall(n, call) and exists(DataFlowCallable c | - c = n.getEnclosingCallable() and + c = nodeGetEnclosingCallable(n) and not viableCallable(call) = c ) and msg = "Call context for isUnreachableInCall is inconsistent with call graph." @@ -120,7 +120,7 @@ module Consistency { n.(ArgumentNode).argumentOf(call, _) and msg = "ArgumentNode and call does not share enclosing callable." ) and - n.getEnclosingCallable() != call.getEnclosingCallable() + nodeGetEnclosingCallable(n) != call.getEnclosingCallable() } // This predicate helps the compiler forget that in some languages @@ -151,7 +151,7 @@ module Consistency { } query predicate postIsInSameCallable(PostUpdateNode n, string msg) { - n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and + nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and msg = "PostUpdateNode does not share callable with its pre-update node." } @@ -175,6 +175,7 @@ module Consistency { query predicate postWithInFlow(Node n, string msg) { isPostUpdateNode(n) and + not clearsContent(n, _) and simpleLocalFlowStep(_, n) and msg = "PostUpdateNode should not be the target of local flow." } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll index 4ca06c93362..08030e0b35b 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll @@ -10,6 +10,7 @@ private import DataFlowImplCommon private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public +import DataFlowImplCommonPublic /** * A configuration of interprocedural data flow analysis. This defines @@ -94,6 +95,22 @@ abstract class Configuration extends string { */ int fieldFlowBranchLimit() { result = 2 } + /** + * Gets a data flow configuration feature to add restrictions to the set of + * valid flow paths. + * + * - `FeatureHasSourceCallContext`: + * Assume that sources have some existing call context to disallow + * conflicting return-flow directly following the source. + * - `FeatureHasSinkCallContext`: + * Assume that sinks have some existing call context to disallow + * conflicting argument-to-parameter flow directly preceding the sink. + * - `FeatureEqualSourceSinkCallContext`: + * Implies both of the above and additionally ensures that the entire flow + * path preserves the call context. + */ + FlowFeature getAFeature() { none() } + /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -110,12 +127,12 @@ abstract class Configuration extends string { /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) } /** * Holds if data may flow from some source to `sink` for this configuration. */ - predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } /** * Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev` @@ -244,6 +261,8 @@ private class ParamNodeEx extends NodeEx { } int getPosition() { this.isParameterOf(_, result) } + + predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) } } private class RetNodeEx extends NodeEx { @@ -347,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -363,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and - not fullBarrier(node2, config) + not fullBarrier(node2, config) and + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) } @@ -399,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } +private predicate hasSourceCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSourceCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + +private predicate hasSinkCallCtx(Configuration config) { + exists(FlowFeature feature | feature = config.getAFeature() | + feature instanceof FeatureHasSinkCallContext or + feature instanceof FeatureEqualSourceSinkCallContext + ) +} + private module Stage1 { class ApApprox = Unit; @@ -419,7 +454,7 @@ private module Stage1 { not fullBarrier(node, config) and ( sourceNode(node, config) and - cc = false + if hasSourceCallCtx(config) then cc = true else cc = false or exists(NodeEx mid | fwdFlow(mid, cc, config) and @@ -549,7 +584,7 @@ private module Stage1 { private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) { fwdFlow(node, config) and sinkNode(node, config) and - toReturn = false + if hasSinkCallCtx(config) then toReturn = true else toReturn = false or exists(NodeEx mid | localFlowStep(node, mid, config) and @@ -744,8 +779,12 @@ private module Stage1 { returnFlowCallableNodeCand(c, kind, config) and p.getEnclosingCallable() = c and exists(ap) and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition() + or + p.allowParameterReturnInSelf() + ) ) } @@ -931,6 +970,8 @@ private module Stage2 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -998,7 +1039,7 @@ private module Stage2 { predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1209,7 +1250,7 @@ private module Stage2 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -1394,8 +1435,12 @@ private module Stage2 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -1606,6 +1651,8 @@ private module Stage3 { Cc ccNone() { result = false } + CcCall ccSomeCall() { result = true } + private class LocalCc = Unit; bindingset[call, c, outercc] @@ -1687,7 +1734,7 @@ private module Stage3 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -1898,7 +1945,7 @@ private module Stage3 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2083,8 +2130,12 @@ private module Stage3 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2352,6 +2403,8 @@ private module Stage4 { Cc ccNone() { result instanceof CallContextAny } + CcCall ccSomeCall() { result instanceof CallContextSomeCall } + private class LocalCc = LocalCallContext; bindingset[call, c, outercc] @@ -2447,7 +2500,7 @@ private module Stage4 { private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) { flowCand(node, _, config) and sourceNode(node, config) and - cc = ccNone() and + (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and argAp = apNone() and ap = getApNil(node) or @@ -2658,7 +2711,7 @@ private module Stage4 { ) { fwdFlow(node, _, _, ap, config) and sinkNode(node, config) and - toReturn = false and + (if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and returnAp = apNone() and ap instanceof ApNil or @@ -2843,8 +2896,12 @@ private module Stage4 { fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and kind = ret.getKind() and p.getPosition() = pos and - // we don't expect a parameter to return stored in itself - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + p.allowParameterReturnInSelf() + ) ) } @@ -2917,6 +2974,8 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { int getParameterPos() { p.isParameterOf(_, result) } + ParamNodeEx getParamNode() { result = p } + override string toString() { result = p + ": " + ap } predicate hasLocationInfo( @@ -3044,7 +3103,11 @@ private newtype TPathNode = // A PathNode is introduced by a source ... Stage4::revFlow(node, config) and sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap = TAccessPathNil(node.getDataFlowType()) or @@ -3056,17 +3119,10 @@ private newtype TPathNode = ) } or TPathNodeSink(NodeEx node, Configuration config) { - sinkNode(node, pragma[only_bind_into](config)) and - Stage4::revFlow(node, pragma[only_bind_into](config)) and - ( - // A sink that is also a source ... - sourceNode(node, config) - or - // ... or a sink that can be reached from a source - exists(PathNodeMid mid | - pathStep(mid, node, _, _, TAccessPathNil(_)) and - pragma[only_bind_into](config) = mid.getConfiguration() - ) + exists(PathNodeMid sink | + sink.isAtSink() and + node = sink.getNodeEx() and + config = sink.getConfiguration() ) } @@ -3170,7 +3226,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons { } override string toString() { - result = "[" + this.toStringImpl(true) + length().toString() + ")]" + result = "[" + this.toStringImpl(true) + this.length().toString() + ")]" or result = "[" + this.toStringImpl(false) } @@ -3309,9 +3365,11 @@ abstract private class PathNodeImpl extends PathNode { result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" } - override string toString() { result = this.getNodeEx().toString() + ppAp() } + override string toString() { result = this.getNodeEx().toString() + this.ppAp() } - override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() } + override string toStringWithContext() { + result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() + } override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn @@ -3379,24 +3437,48 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node - result = getSuccMid() + result = this.getSuccMid() or - // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges - exists(PathNodeMid mid, PathNodeSink sink | - mid = getSuccMid() and - mid.getNodeEx() = sink.getNodeEx() and - mid.getAp() instanceof AccessPathNil and - sink.getConfiguration() = unbindConf(mid.getConfiguration()) and - result = sink - ) + // a final step to a sink + result = this.getSuccMid().projectToSink() } override predicate isSource() { sourceNode(node, config) and - cc instanceof CallContextAny and + ( + if hasSourceCallCtx(config) + then cc instanceof CallContextSomeCall + else cc instanceof CallContextAny + ) and sc instanceof SummaryCtxNone and ap instanceof AccessPathNil } + + predicate isAtSink() { + sinkNode(node, config) and + ap instanceof AccessPathNil and + if hasSinkCallCtx(config) + then + // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall` + // is exactly what we need to check. This also implies + // `sc instanceof SummaryCtxNone`. + // For `FeatureEqualSourceSinkCallContext` the initial call context was + // set to `CallContextSomeCall` and jumps are disallowed, so + // `cc instanceof CallContextNoCall` never holds. On the other hand, + // in this case there's never any need to enter a call except to identify + // a summary, so the condition in `pathIntoCallable` enforces this, which + // means that `sc instanceof SummaryCtxNone` holds if and only if we are + // in the call context of the source. + sc instanceof SummaryCtxNone or + cc instanceof CallContextNoCall + else any() + } + + PathNodeSink projectToSink() { + this.isAtSink() and + result.getNodeEx() = node and + result.getConfiguration() = unbindConf(config) + } } /** @@ -3460,7 +3542,7 @@ private predicate pathStep( exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and sc = mid.getSummaryCtx() or - pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp() or pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone or @@ -3537,18 +3619,20 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc) */ pragma[noinline] private predicate pathIntoArg( - PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa, + Configuration config ) { exists(ArgNode arg | arg = mid.getNodeEx().asNode() and cc = mid.getCallContext() and arg.argumentOf(call, i) and ap = mid.getAp() and - apa = ap.getApprox() + apa = ap.getApprox() and + config = mid.getConfiguration() ) } -pragma[noinline] +pragma[nomagic] private predicate parameterCand( DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config ) { @@ -3561,12 +3645,14 @@ private predicate parameterCand( pragma[nomagic] private predicate pathIntoCallable0( PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, - AccessPath ap + AccessPath ap, Configuration config ) { exists(AccessPathApprox apa | - pathIntoArg(mid, i, outercc, call, ap, apa) and + pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa), + pragma[only_bind_into](config)) and callable = resolveCall(call, outercc) and - parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration()) + parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa), + pragma[only_bind_into](config)) ) } @@ -3575,18 +3661,23 @@ private predicate pathIntoCallable0( * before and after entering the callable are `outercc` and `innercc`, * respectively. */ +pragma[nomagic] private predicate pathIntoCallable( PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, - DataFlowCall call + DataFlowCall call, Configuration config ) { exists(int i, DataFlowCallable callable, AccessPath ap | - pathIntoCallable0(mid, callable, i, outercc, call, ap) and + pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and p.isParameterOf(callable, i) and ( sc = TSummaryCtxSome(p, ap) or not exists(TSummaryCtxSome(p, ap)) and - sc = TSummaryCtxNone() + sc = TSummaryCtxNone() and + // When the call contexts of source and sink needs to match then there's + // never any reason to enter a callable except to find a summary. See also + // the comment in `PathNodeMid::isAtSink`. + not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) | if recordDataFlowCallSite(call, callable) @@ -3610,18 +3701,23 @@ private predicate paramFlowsThrough( ap = mid.getAp() and apa = ap.getApprox() and pos = sc.getParameterPos() and - not kind.(ParamUpdateReturnKind).getPosition() = pos + // we don't expect a parameter to return stored in itself, unless explicitly allowed + ( + not kind.(ParamUpdateReturnKind).getPosition() = pos + or + sc.getParamNode().allowParameterReturnInSelf() + ) ) } pragma[nomagic] private predicate pathThroughCallable0( DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap, - AccessPathApprox apa + AccessPathApprox apa, Configuration config ) { exists(CallContext innercc, SummaryCtx sc | - pathIntoCallable(mid, _, cc, innercc, sc, call) and - paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration())) + pathIntoCallable(mid, _, cc, innercc, sc, call, config) and + paramFlowsThrough(kind, innercc, sc, ap, apa, config) ) } @@ -3631,9 +3727,9 @@ private predicate pathThroughCallable0( */ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) { - exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa | - pathThroughCallable0(call, mid, kind, cc, ap, apa) and - out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration())) + exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config | + pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and + out = getAnOutNodeFlow(kind, call, apa, config) ) } @@ -3644,13 +3740,15 @@ private module Subpaths { */ pragma[nomagic] private predicate subpaths01( - PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, + PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and - pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, - unbindConf(arg.getConfiguration())) + exists(Configuration config | + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and + pathIntoCallable(arg, par, _, innercc, sc, _, config) and + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and + not arg.isHidden() + ) } /** @@ -3683,8 +3781,17 @@ private module Subpaths { innercc = ret.getCallContext() and sc = ret.getSummaryCtx() and ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and - apout = ret.getAp() and - not ret.isHidden() + apout = ret.getAp() + ) + } + + private PathNodeImpl localStepToHidden(PathNodeImpl n) { + n.getASuccessorImpl() = result and + result.isHidden() and + exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() | + localFlowBigStep(n1, n2, _, _, _, _) or + store(n1, _, n2, _, _) or + read(n1, _, n2, _) ) } @@ -3693,11 +3800,12 @@ private module Subpaths { * a subpath between `par` and `ret` with the connecting edges `arg -> par` and * `ret -> out` is summarized as the edge `arg -> out`. */ - predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { + predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | pragma[only_bind_into](arg).getASuccessor() = par and pragma[only_bind_into](arg).getASuccessor() = out and - subpaths03(arg, p, ret, o, apout) and + subpaths03(arg, p, localStepToHidden*(ret), o, apout) and + not ret.isHidden() and par.getNodeEx() = p and out.getNodeEx() = o and out.getAp() = apout diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll index 622ef595792..3509b38108e 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll @@ -14,14 +14,14 @@ newtype TNode = not e.getParent*() instanceof Annotation } or TExplicitParameterNode(Parameter p) { - exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable + exists(p.getCallable().getBody()) or p.getCallable() = any(SummarizedCallable sc).asCallable() } or TImplicitVarargsArray(Call c) { c.getCallee().isVarargs() and not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray()) } or TInstanceParameterNode(Callable c) { - (exists(c.getBody()) or c instanceof SummarizedCallable) and + (exists(c.getBody()) or c = any(SummarizedCallable sc).asCallable()) and not c.isStatic() } or TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or @@ -44,7 +44,8 @@ newtype TNode = } or TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) { FlowSummaryImpl::Private::summaryNodeRange(c, state) - } + } or + TFieldValueNode(Field f) private predicate explicitInstanceArgument(Call call, Expr instarg) { call instanceof MethodAccess and @@ -94,19 +95,12 @@ module Public { result = this.(MallocNode).getClassInstanceExpr().getType() or result = this.(ImplicitPostUpdateNode).getPreUpdateNode().getType() + or + result = this.(FieldValueNode).getField().getType() } /** Gets the callable in which this node occurs. */ - Callable getEnclosingCallable() { - result = this.asExpr().getEnclosingCallable() or - result = this.asParameter().getCallable() or - result = this.(ImplicitVarargsArray).getCall().getEnclosingCallable() or - result = this.(InstanceParameterNode).getCallable() or - result = this.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or - result = this.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or - result = this.(ImplicitPostUpdateNode).getPreUpdateNode().getEnclosingCallable() or - this = TSummaryInternalNode(result, _) - } + Callable getEnclosingCallable() { result = nodeGetEnclosingCallable(this).asCallable() } private Type getImprovedTypeBound() { exprTypeFlow(this.asExpr(), result, _) or @@ -117,9 +111,9 @@ module Public { * Gets an upper bound on the type of this node. */ Type getTypeBound() { - result = getImprovedTypeBound() + result = this.getImprovedTypeBound() or - result = getType() and not exists(getImprovedTypeBound()) + result = this.getType() and not exists(this.getImprovedTypeBound()) } /** @@ -132,7 +126,7 @@ module Public { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } } @@ -257,6 +251,18 @@ module Public { abstract Node getPreUpdateNode(); } + /** + * A node representing the value of a field. + */ + class FieldValueNode extends Node, TFieldValueNode { + /** Gets the field corresponding to this node. */ + Field getField() { this = TFieldValueNode(result) } + + override string toString() { result = getField().toString() } + + override Location getLocation() { result = getField().getLocation() } + } + /** * Gets the node that occurs as the qualifier of `fa`. */ @@ -288,9 +294,9 @@ private class NewExpr extends PostUpdateNode, TExprNode { * A `PostUpdateNode` that is not a `ClassInstanceExpr`. */ abstract private class ImplicitPostUpdateNode extends PostUpdateNode { - override Location getLocation() { result = getPreUpdateNode().getLocation() } + override Location getLocation() { result = this.getPreUpdateNode().getLocation() } - override string toString() { result = getPreUpdateNode().toString() + " [post update]" } + override string toString() { result = this.getPreUpdateNode().toString() + " [post update]" } } private class ExplicitExprPostUpdate extends ImplicitPostUpdateNode, TExplicitExprPostUpdate { @@ -304,6 +310,24 @@ private class ImplicitExprPostUpdate extends ImplicitPostUpdateNode, TImplicitEx } module Private { + /** Gets the callable in which this node occurs. */ + DataFlowCallable nodeGetEnclosingCallable(Node n) { + result.asCallable() = n.asExpr().getEnclosingCallable() or + result.asCallable() = n.asParameter().getCallable() or + result.asCallable() = n.(ImplicitVarargsArray).getCall().getEnclosingCallable() or + result.asCallable() = n.(InstanceParameterNode).getCallable() or + result.asCallable() = n.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or + result.asCallable() = n.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or + result = nodeGetEnclosingCallable(n.(ImplicitPostUpdateNode).getPreUpdateNode()) or + n = TSummaryInternalNode(result, _) or + result.asFieldScope() = n.(FieldValueNode).getField() + } + + /** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */ + predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { + p.isParameterOf(c.asCallable(), pos) + } + /** * A data flow node that occurs as the argument of a call and is passed as-is * to the callable. Arguments that are wrapped in an implicit varargs array diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index d35610ecf4a..4473adccb58 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -5,6 +5,7 @@ private import DataFlowDispatch private import semmle.code.java.controlflow.Guards private import semmle.code.java.dataflow.SSA private import ContainerFlow +private import semmle.code.java.dataflow.FlowSteps private import semmle.code.java.dataflow.FlowSummary private import FlowSummaryImpl as FlowSummaryImpl import DataFlowNodes::Private @@ -32,12 +33,18 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { /** * Holds if data can flow from `node1` to `node2` through a static field. */ -private predicate staticFieldStep(ExprNode node1, ExprNode node2) { +private predicate staticFieldStep(Node node1, Node node2) { + exists(Field f | + f.isStatic() and + f.getAnAssignedValue() = node1.asExpr() and + node2.(FieldValueNode).getField() = f + ) + or exists(Field f, FieldRead fr | f.isStatic() and - f.getAnAssignedValue() = node1.getExpr() and + node1.(FieldValueNode).getField() = f and fr.getField() = f and - fr = node2.getExpr() and + fr = node2.asExpr() and hasNonlocalValue(fr) ) } @@ -67,9 +74,14 @@ private predicate variableCaptureStep(Node node1, ExprNode node2) { * variable capture. */ predicate jumpStep(Node node1, Node node2) { - staticFieldStep(node1, node2) or - variableCaptureStep(node1, node2) or + staticFieldStep(node1, node2) + or + variableCaptureStep(node1, node2) + or variableCaptureStep(node1.(PostUpdateNode).getPreUpdateNode(), node2) + or + any(AdditionalValueStep a).step(node1, node2) and + node1.getEnclosingCallable() != node2.getEnclosingCallable() } /** @@ -139,11 +151,7 @@ predicate readStep(Node node1, Content f, Node node2) { */ predicate clearsContent(Node n, Content c) { c instanceof FieldContent and - ( - n = any(PostUpdateNode pun | storeStep(_, c, pun)).getPreUpdateNode() - or - FlowSummaryImpl::Private::Steps::summaryStoresIntoArg(c, n) - ) + n = any(PostUpdateNode pun | storeStep(_, c, pun)).getPreUpdateNode() or FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c) } @@ -209,7 +217,30 @@ class CastNode extends ExprNode { CastNode() { this.getExpr() instanceof CastExpr } } -class DataFlowCallable = Callable; +private newtype TDataFlowCallable = + TCallable(Callable c) or + TFieldScope(Field f) + +class DataFlowCallable extends TDataFlowCallable { + Callable asCallable() { this = TCallable(result) } + + Field asFieldScope() { this = TFieldScope(result) } + + RefType getDeclaringType() { + result = asCallable().getDeclaringType() or + result = asFieldScope().getDeclaringType() + } + + string toString() { + result = asCallable().toString() or + result = "Field scope: " + asFieldScope().toString() + } + + Location getLocation() { + result = asCallable().getLocation() or + result = asFieldScope().getLocation() + } +} class DataFlowExpr = Expr; @@ -255,7 +286,9 @@ class SrcCall extends DataFlowCall, TCall { SrcCall() { this = TCall(call) } - override DataFlowCallable getEnclosingCallable() { result = call.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallable() { + result.asCallable() = call.getEnclosingCallable() + } override string toString() { result = call.toString() } @@ -341,7 +374,11 @@ predicate isImmutableOrUnobservable(Node n) { } /** Holds if `n` should be hidden from path explanations. */ -predicate nodeIsHidden(Node n) { n instanceof SummaryNode } +predicate nodeIsHidden(Node n) { + n instanceof SummaryNode + or + n.(ParameterNode).isParameterOf(any(SummarizedCallable c).asCallable(), _) +} class LambdaCallKind = Method; // the "apply" method in the functional interface @@ -349,10 +386,10 @@ class LambdaCallKind = Method; // the "apply" method in the functional interface predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { exists(ClassInstanceExpr func, Interface t, FunctionalInterface interface | creation.asExpr() = func and - func.getAnonymousClass().getAMethod() = c and + func.getAnonymousClass().getAMethod() = c.asCallable() and func.getConstructedType().extendsOrImplements+(t) and t.getSourceDeclaration() = interface and - c.(Method).overridesOrInstantiates+(pragma[only_bind_into](kind)) and + c.asCallable().(Method).overridesOrInstantiates+(pragma[only_bind_into](kind)) and pragma[only_bind_into](kind) = interface.getRunMethod().getSourceDeclaration() ) } @@ -369,3 +406,14 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { /** Extra data-flow steps needed for lambda flow analysis. */ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } + +/** + * Holds if flow is allowed to pass from parameter `p` and back to itself as a + * side-effect, resulting in a summary from `p` to itself. + * + * One example would be to allow flow like `p.foo = p.bar;`, which is disallowed + * by default as a heuristic. + */ +predicate allowParameterReturnInSelf(ParameterNode p) { + FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p) +} diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll index 462430b2b5a..1ae6749877d 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll @@ -101,6 +101,8 @@ predicate hasNonlocalValue(FieldRead fr) { predicate localFlowStep(Node node1, Node node2) { simpleLocalFlowStep(node1, node2) or + adjacentUseUse(node1.asExpr(), node2.asExpr()) + or // Simple flow through library code is included in the exposed local // step relation, even though flow is technically inter-procedural FlowSummaryImpl::Private::Steps::summaryThroughStep(node1, node2, true) @@ -131,7 +133,8 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { adjacentUseUse(node1.asExpr(), node2.asExpr()) and not exists(FieldRead fr | hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr() - ) + ) and + not FlowSummaryImpl::Private::Steps::summaryClearsContentArg(node1, _) or ThisFlow::adjacentThisRefs(node1, node2) or @@ -155,6 +158,10 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { ) or FlowSummaryImpl::Private::Steps::summaryLocalStep(node1, node2, true) + or + any(AdditionalValueStep a).step(node1, node2) and + pragma[only_bind_out](node1.getEnclosingCallable()) = + pragma[only_bind_out](node2.getEnclosingCallable()) } private newtype TContent = diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll index 83076558ec4..5955285bd6f 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll @@ -261,7 +261,10 @@ module Private { private newtype TSummaryNodeState = TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or - TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } + TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } or + TSummaryNodeClearsContentState(int i, boolean post) { + any(SummarizedCallable sc).clearsContent(i, _) and post in [false, true] + } /** * A state used to break up (complex) flow summaries into atomic flow steps. @@ -308,6 +311,12 @@ module Private { this = TSummaryNodeOutputState(s) and result = "to write: " + s ) + or + exists(int i, boolean post, string postStr | + this = TSummaryNodeClearsContentState(i, post) and + (if post = true then postStr = " (post)" else postStr = "") and + result = "clear: " + i + postStr + ) } } @@ -329,6 +338,11 @@ module Private { not parameterReadState(c, state, _) or state.isOutputState(c, _) + or + exists(int i | + c.clearsContent(i, _) and + state = TSummaryNodeClearsContentState(i, _) + ) } pragma[noinline] @@ -364,6 +378,8 @@ module Private { parameterReadState(c, _, i) or isParameterPostUpdate(_, c, i) + or + c.clearsContent(i, _) } private predicate callbackOutput( @@ -436,6 +452,12 @@ module Private { ) ) ) + or + exists(SummarizedCallable c, int i, ParamNode p | + n = summaryNode(c, TSummaryNodeClearsContentState(i, false)) and + p.isParameterOf(c, i) and + result = getNodeType(p) + ) } /** Holds if summary node `out` contains output of kind `rk` from call `c`. */ @@ -461,6 +483,9 @@ module Private { exists(SummarizedCallable c, int i | isParameterPostUpdate(post, c, i) and pre.(ParamNode).isParameterOf(c, i) + or + pre = summaryNode(c, TSummaryNodeClearsContentState(i, false)) and + post = summaryNode(c, TSummaryNodeClearsContentState(i, true)) ) or exists(SummarizedCallable callable, SummaryComponentStack s | @@ -478,6 +503,17 @@ module Private { ) } + /** + * Holds if flow is allowed to pass from parameter `p`, to a return + * node, and back out to `p`. + */ + predicate summaryAllowParameterReturnInSelf(ParamNode p) { + exists(SummarizedCallable c, int i | + c.clearsContent(i, _) and + p.isParameterOf(c, i) + ) + } + /** Provides a compilation of flow summaries to atomic data-flow steps. */ module Steps { /** @@ -504,11 +540,21 @@ module Private { // for `StringBuilder.append(x)` with a specified value flow from qualifier to // return value and taint flow from argument 0 to the qualifier, then this // allows us to infer taint flow from argument 0 to the return value. - succ instanceof ParamNode and summaryPostUpdateNode(pred, succ) and preservesValue = true + succ instanceof ParamNode and + summaryPostUpdateNode(pred, succ) and + preservesValue = true or // Similarly we would like to chain together summaries where values get passed // into callbacks along the way. - pred instanceof ArgNode and summaryPostUpdateNode(succ, pred) and preservesValue = true + pred instanceof ArgNode and + summaryPostUpdateNode(succ, pred) and + preservesValue = true + or + exists(SummarizedCallable c, int i | + pred.(ParamNode).isParameterOf(c, i) and + succ = summaryNode(c, TSummaryNodeClearsContentState(i, _)) and + preservesValue = true + ) } /** @@ -536,10 +582,39 @@ module Private { } /** - * Holds if values stored inside content `c` are cleared when passed as - * input of type `input` in `call`. + * Holds if values stored inside content `c` are cleared at `n`. `n` is a + * synthesized summary node, so in order for values to be cleared at calls + * to the relevant method, it is important that flow does not pass over + * the argument, either via use-use flow or def-use flow. + * + * Example: + * + * ``` + * a.b = taint; + * a.clearB(); // assume we have a flow summary for `clearB` that clears `b` on the qualifier + * sink(a.b); + * ``` + * + * In the above, flow should not pass from `a` on the first line (or the second + * line) to `a` on the third line. Instead, there will be synthesized flow from + * `a` on line 2 to the post-update node for `a` on that line (via an intermediate + * node where field `b` is cleared). */ - predicate summaryClearsContent(ArgNode arg, Content c) { + predicate summaryClearsContent(Node n, Content c) { + exists(SummarizedCallable sc, int i | + n = summaryNode(sc, TSummaryNodeClearsContentState(i, true)) and + sc.clearsContent(i, c) + ) + } + + /** + * Holds if values stored inside content `c` are cleared inside a + * callable to which `arg` is an argument. + * + * In such cases, it is important to prevent use-use flow out of + * `arg` (see comment for `summaryClearsContent`). + */ + predicate summaryClearsContentArg(ArgNode arg, Content c) { exists(DataFlowCall call, int i | viableCallable(call).(SummarizedCallable).clearsContent(i, c) and arg.argumentOf(call, i) @@ -599,25 +674,6 @@ module Private { ret.getKind() = rk ) } - - /** - * Holds if data is written into content `c` of argument `arg` using a flow summary. - * - * Depending on the type of `c`, this predicate may be relevant to include in the - * definition of `clearsContent()`. - */ - predicate summaryStoresIntoArg(Content c, Node arg) { - exists(ParamUpdateReturnKind rk, ReturnNodeExt ret, PostUpdateNode out | - exists(DataFlowCall call, SummarizedCallable callable | - getNodeEnclosingCallable(ret) = callable and - viableCallable(call) = callable and - summaryStoreStep(_, c, ret) and - ret.getKind() = pragma[only_bind_into](rk) and - out = rk.getAnOutNode(call) and - arg = out.getPreUpdateNode() - ) - ) - } } /** diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll index e4c3091f05e..a3d5d64a766 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll @@ -30,7 +30,7 @@ DataFlowType getContentType(Content c) { result = c.getType() } /** Gets the return type of kind `rk` for callable `c`. */ DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) { - result = getErasedRepr(c.getReturnType()) and + result = getErasedRepr(c.asCallable().getReturnType()) and exists(rk) } @@ -62,7 +62,7 @@ predicate summaryElement(DataFlowCallable c, string input, string output, string string namespace, string type, boolean subtypes, string name, string signature, string ext | summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and - c = interpretElement(namespace, type, subtypes, name, signature, ext) + c.asCallable() = interpretElement(namespace, type, subtypes, name, signature, ext) ) } @@ -119,7 +119,7 @@ class InterpretNode extends TInterpretNode { DataFlowCall asCall() { result.asCall() = this.asElement() } /** Gets the callable that this node corresponds to, if any. */ - DataFlowCallable asCallable() { result = this.asElement() } + DataFlowCallable asCallable() { result.asCallable() = this.asElement() } /** Gets the target of this call, if any. */ Callable getCallTarget() { result = this.asCall().asCall().getCallee().getSourceDeclaration() } diff --git a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index e92ad541a51..bab6025b4a6 100644 --- a/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/repo-tests/codeql/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -285,11 +285,11 @@ private predicate taintPreservingQualifierToMethod(Method m) { private class StringReplaceMethod extends TaintPreservingCallable { StringReplaceMethod() { - getDeclaringType() instanceof TypeString and + this.getDeclaringType() instanceof TypeString and ( - hasName("replace") or - hasName("replaceAll") or - hasName("replaceFirst") + this.hasName("replace") or + this.hasName("replaceAll") or + this.hasName("replaceFirst") ) } @@ -300,8 +300,8 @@ private predicate unsafeEscape(MethodAccess ma) { // Removing `", + "", "", "", "", + "", "", + "", "", "", + "", "", "", + "", "") and + regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression matches , but not " + or + not regexp.matches("") and + msg = "This regular expression matches , but not " + ) + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where the attribute uses single-quotes." + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where the attribute uses double-quotes." + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where tabs are used between attributes." + or + regexp.matches("") and + not RegExpFlags::isIgnoreCase(regexp) and + not regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression does not match upper case ") and + regexp.matches("") and + msg = "This regular expression does not match mixed case ") and + not regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression does not match script end tags like ." + or + not regexp.matches("") and + msg = "This regular expression does not match script end tags like ." + or + not regexp.matches("", + "", "", "", "", + "", "", + "", "", "", + "", "", "", + "", "") and + regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression matches , but not " + or + not regexp.matches("") and + msg = "This regular expression matches , but not " + ) + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where the attribute uses single-quotes." + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where the attribute uses double-quotes." + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where tabs are used between attributes." + or + regexp.matches("") and + not RegExpFlags::isIgnoreCase(regexp) and + not regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression does not match upper case ") and + regexp.matches("") and + msg = "This regular expression does not match mixed case ") and + not regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression does not match script end tags like ." + or + not regexp.matches("") and + msg = "This regular expression does not match script end tags like ." + or + not regexp.matches("", + "", "", "", "", + "", "", + "", "", "", + "", "", "", + "", "") and + regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression matches , but not " + or + not regexp.matches("") and + msg = "This regular expression matches , but not " + ) + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where the attribute uses single-quotes." + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where the attribute uses double-quotes." + or + regexp.matches("") and + regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + not regexp.matches("") and + msg = "This regular expression does not match script tags where tabs are used between attributes." + or + regexp.matches("") and + not RegExpFlags::isIgnoreCase(regexp) and + not regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression does not match upper case ") and + regexp.matches("") and + msg = "This regular expression does not match mixed case ") and + not regexp.matches("") and + not regexp.matches("") and + ( + not regexp.matches("") and + msg = "This regular expression does not match script end tags like ." + or + not regexp.matches("") and + msg = "This regular expression does not match script end tags like ." + or + not regexp.matches("