mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
Merge branch 'main' into post-release-prep/codeql-cli-2.7.5
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package,sink,source,summary,sink:code,sink:html,sink:remote,sink:sql,sink:xss,source:local,summary:taint,summary:value
|
||||
Dapper,55,,,,,,55,,,,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,28,,,,
|
||||
Microsoft.Extensions.Primitives,,,54,,,,,,,54,
|
||||
Microsoft.VisualBasic,,,4,,,,,,,,4
|
||||
MySql.Data.MySqlClient,48,,,,,,48,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,73,18
|
||||
|
||||
|
@@ -9,6 +9,6 @@ C# framework & library support
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",3,2336,28,5
|
||||
Others,"``Dapper``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.VisualBasic``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``",,95,131,
|
||||
Totals,,3,2438,353,5
|
||||
Others,"``Dapper``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.Extensions.Primitives``, ``Microsoft.VisualBasic``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``",,149,131,
|
||||
Totals,,3,2492,353,5
|
||||
|
||||
|
||||
@@ -113,11 +113,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
trapFile.expr_call(init, target);
|
||||
|
||||
var child = 0;
|
||||
foreach (var arg in initializer.ArgumentList.Arguments)
|
||||
{
|
||||
Expression.Create(Context, arg.Expression, init, child++);
|
||||
}
|
||||
init.PopulateArguments(trapFile, initializer.ArgumentList, 0);
|
||||
}
|
||||
|
||||
private ConstructorDeclarationSyntax? Syntax
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.CSharp.Entities.Expressions;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
@@ -324,7 +325,12 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public void PopulateArguments(TextWriter trapFile, BaseArgumentListSyntax args, int child)
|
||||
{
|
||||
foreach (var arg in args.Arguments)
|
||||
PopulateArguments(trapFile, args.Arguments, child);
|
||||
}
|
||||
|
||||
public void PopulateArguments(TextWriter trapFile, IEnumerable<ArgumentSyntax> args, int child)
|
||||
{
|
||||
foreach (var arg in args)
|
||||
PopulateArgument(trapFile, arg, child++);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,12 +105,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
if (assignment.Left is ImplicitElementAccessSyntax iea)
|
||||
{
|
||||
// An array/indexer initializer of the form `[...] = ...`
|
||||
|
||||
var indexChild = 0;
|
||||
foreach (var arg in iea.ArgumentList.Arguments)
|
||||
{
|
||||
Expression.Create(Context, arg.Expression, access, indexChild++);
|
||||
}
|
||||
access.PopulateArguments(trapFile, iea.ArgumentList.Arguments, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -15,11 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
var child = 0;
|
||||
foreach (var argument in Syntax.Arguments.Select(a => a.Expression))
|
||||
{
|
||||
Expression.Create(Context, argument, this, child++);
|
||||
}
|
||||
PopulateArguments(trapFile, Syntax.Arguments, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class NamespaceDeclaration : CachedEntity<NamespaceDeclarationSyntax>
|
||||
internal class NamespaceDeclaration : CachedEntity<BaseNamespaceDeclarationSyntax>
|
||||
{
|
||||
private readonly NamespaceDeclaration parent;
|
||||
private readonly NamespaceDeclarationSyntax node;
|
||||
private readonly BaseNamespaceDeclarationSyntax node;
|
||||
|
||||
public NamespaceDeclaration(Context cx, NamespaceDeclarationSyntax node, NamespaceDeclaration parent)
|
||||
public NamespaceDeclaration(Context cx, BaseNamespaceDeclarationSyntax node, NamespaceDeclaration parent)
|
||||
: base(cx, node)
|
||||
{
|
||||
this.node = node;
|
||||
@@ -46,17 +46,17 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public static NamespaceDeclaration Create(Context cx, NamespaceDeclarationSyntax decl, NamespaceDeclaration parent)
|
||||
public static NamespaceDeclaration Create(Context cx, BaseNamespaceDeclarationSyntax decl, NamespaceDeclaration parent)
|
||||
{
|
||||
var init = (decl, parent);
|
||||
return NamespaceDeclarationFactory.Instance.CreateEntity(cx, decl, init);
|
||||
}
|
||||
|
||||
private class NamespaceDeclarationFactory : CachedEntityFactory<(NamespaceDeclarationSyntax decl, NamespaceDeclaration parent), NamespaceDeclaration>
|
||||
private class NamespaceDeclarationFactory : CachedEntityFactory<(BaseNamespaceDeclarationSyntax decl, NamespaceDeclaration parent), NamespaceDeclaration>
|
||||
{
|
||||
public static readonly NamespaceDeclarationFactory Instance = new NamespaceDeclarationFactory();
|
||||
|
||||
public override NamespaceDeclaration Create(Context cx, (NamespaceDeclarationSyntax decl, NamespaceDeclaration parent) init) =>
|
||||
public override NamespaceDeclaration Create(Context cx, (BaseNamespaceDeclarationSyntax decl, NamespaceDeclaration parent) init) =>
|
||||
new NamespaceDeclaration(cx, init.decl, init.parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,13 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
new UsingDirective(Cx, usingDirective, (NamespaceDeclaration)Parent);
|
||||
}
|
||||
|
||||
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
|
||||
{
|
||||
private void CreateNamespaceDeclaration(BaseNamespaceDeclarationSyntax node) =>
|
||||
NamespaceDeclaration.Create(Cx, node, (NamespaceDeclaration)Parent);
|
||||
}
|
||||
|
||||
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) =>
|
||||
CreateNamespaceDeclaration(node);
|
||||
|
||||
public override void VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node) =>
|
||||
CreateNamespaceDeclaration(node);
|
||||
}
|
||||
}
|
||||
|
||||
1
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
Normal file
1
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
Normal file
@@ -0,0 +1 @@
|
||||
## 1.0.0
|
||||
@@ -0,0 +1 @@
|
||||
## 1.0.0
|
||||
4
csharp/ql/campaigns/Solorigate/lib/codeql-pack.lock.yml
Normal file
4
csharp/ql/campaigns/Solorigate/lib/codeql-pack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.1
|
||||
8
csharp/ql/campaigns/Solorigate/lib/qlpack.yml
Normal file
8
csharp/ql/campaigns/Solorigate/lib/qlpack.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.0.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/csharp-all: ~0.0.3
|
||||
28
csharp/ql/campaigns/Solorigate/publish.sh
Executable file
28
csharp/ql/campaigns/Solorigate/publish.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
SOLORIGATE_ROOT="$(dirname $0)"
|
||||
WORKSPACE_ROOT="$SOLORIGATE_ROOT/../../../.."
|
||||
GRPS="solorigate,-test"
|
||||
|
||||
if [ -z "$CODEQL_DIST" ]; then
|
||||
echo "CODEQL_DIST not set"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
cd "$SOLORIGATE_ROOT"
|
||||
echo Testing solorigate queries
|
||||
"${CODEQL_DIST}/codeql" test run test
|
||||
|
||||
cd "$WORKSPACE_ROOT"
|
||||
|
||||
echo Preparing release
|
||||
"${CODEQL_DIST}/codeql" pack release --groups $GRPS
|
||||
|
||||
echo Publishing solorigate
|
||||
"${CODEQL_DIST}/codeql" pack publish --groups $GRPS
|
||||
|
||||
echo Bumping versions
|
||||
"${CODEQL_DIST}/codeql" pack post-release --groups $GRPS
|
||||
|
||||
echo Solorigate packs successfully published. Please commit and push the version changes.
|
||||
1
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
Normal file
1
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
Normal file
@@ -0,0 +1 @@
|
||||
## 1.0.0
|
||||
@@ -0,0 +1 @@
|
||||
## 0.0.6
|
||||
@@ -0,0 +1 @@
|
||||
## 1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.1
|
||||
4
csharp/ql/campaigns/Solorigate/src/qlpack.lock.yml
Normal file
4
csharp/ql/campaigns/Solorigate/src/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
9
csharp/ql/campaigns/Solorigate/src/qlpack.yml
Normal file
9
csharp/ql/campaigns/Solorigate/src/qlpack.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.0.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
defaultSuiteFile: codeql-suites/solorigate.qls
|
||||
dependencies:
|
||||
codeql/csharp-all: ~0.0.3
|
||||
codeql/csharp-solorigate-all: ^1.0
|
||||
@@ -0,0 +1 @@
|
||||
ModifiedFnvFunctionDetection.ql
|
||||
@@ -0,0 +1 @@
|
||||
NumberOfKnownCommandsAboveThreshold.ql
|
||||
@@ -0,0 +1 @@
|
||||
NumberOfKnownHashesAboveThreshold.ql
|
||||
@@ -0,0 +1 @@
|
||||
NumberOfKnownLiteralsAboveThreshold.ql
|
||||
@@ -0,0 +1 @@
|
||||
NumberOfKnownMethodNamesAboveThreshold.ql
|
||||
@@ -0,0 +1 @@
|
||||
SwallowEverythingExceptionHandler.ql
|
||||
@@ -0,0 +1 @@
|
||||
## 0.0.7
|
||||
4
csharp/ql/campaigns/Solorigate/test/qlpack.lock.yml
Normal file
4
csharp/ql/campaigns/Solorigate/test/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
12
csharp/ql/campaigns/Solorigate/test/qlpack.yml
Normal file
12
csharp/ql/campaigns/Solorigate/test/qlpack.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
name: csharp-solorigate-tests
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
- test
|
||||
dependencies:
|
||||
codeql/csharp-all: "*"
|
||||
codeql/csharp-queries: "*"
|
||||
codeql/charp-solorigate-all: "*"
|
||||
codeql/charp-solorigate-queries: "*"
|
||||
extractor: csharp
|
||||
tests: .
|
||||
19
csharp/ql/consistency-queries/AstConsistency.qll
Normal file
19
csharp/ql/consistency-queries/AstConsistency.qll
Normal file
@@ -0,0 +1,19 @@
|
||||
import csharp
|
||||
|
||||
query predicate missingLocation(Element e) {
|
||||
(
|
||||
e instanceof Declaration or
|
||||
e instanceof Expr or
|
||||
e instanceof Stmt
|
||||
) and
|
||||
not e instanceof ImplicitAccessorParameter and
|
||||
not e instanceof NullType and
|
||||
not e instanceof Parameter and // Bug in Roslyn - params occasionally lack locations
|
||||
not e.(Operator).getDeclaringType() instanceof IntType and // Roslyn quirk
|
||||
not e instanceof Constructor and
|
||||
not e instanceof ArrayType and
|
||||
not e instanceof UnknownType and
|
||||
not e instanceof ArglistType and
|
||||
not exists(TupleType t | e = t or e = t.getAField()) and
|
||||
not exists(e.getLocation())
|
||||
}
|
||||
9
csharp/ql/consistency-queries/GenericsConsistency.qll
Normal file
9
csharp/ql/consistency-queries/GenericsConsistency.qll
Normal file
@@ -0,0 +1,9 @@
|
||||
import csharp
|
||||
|
||||
query predicate missingUnbound(ConstructedGeneric g) { not exists(g.getUnboundGeneric()) }
|
||||
|
||||
query predicate missingArgs(ConstructedGeneric g) { g.getNumberOfTypeArguments() = 0 }
|
||||
|
||||
query predicate inconsistentArgCount(ConstructedGeneric g) {
|
||||
g.getUnboundGeneric().getNumberOfTypeParameters() != g.getNumberOfTypeArguments()
|
||||
}
|
||||
6
csharp/ql/consistency-queries/PrimaryQlClass.ql
Normal file
6
csharp/ql/consistency-queries/PrimaryQlClass.ql
Normal file
@@ -0,0 +1,6 @@
|
||||
import csharp
|
||||
|
||||
query predicate missingPrimaryQlClass(Element e) {
|
||||
not exists(e.getAPrimaryQlClass()) and
|
||||
e.fromSource()
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.SsaImplCommon::Consistency
|
||||
import Ssa
|
||||
|
||||
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
override predicate hasLocationInfo(
|
||||
@@ -8,3 +9,18 @@ class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) {
|
||||
// Local variables in C# must be initialized before every use, so uninitialized
|
||||
// local variables should not have an SSA definition, as that would imply that
|
||||
// the declaration is live (can reach a use without passing through a definition)
|
||||
exists(ExplicitDefinition def |
|
||||
d = def.getADefinition().(AssignableDefinitions::LocalVariableDefinition).getDeclaration()
|
||||
|
|
||||
not d = any(ForeachStmt fs).getVariableDeclExpr() and
|
||||
not d = any(SpecificCatchClause scc).getVariableDeclExpr() and
|
||||
not d.getVariable().getType() instanceof Struct and
|
||||
not d instanceof PatternExpr and
|
||||
not d.getVariable().isCaptured()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `codeql/csharp-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/charp-all` CodeQL pack.
|
||||
@@ -2,5 +2,40 @@
|
||||
* The default C# QL library.
|
||||
*/
|
||||
|
||||
// Do not add other imports here; add to `semmle.code.csharp.internal.csharp` instead
|
||||
import semmle.code.csharp.internal.csharp
|
||||
import Customizations
|
||||
import semmle.code.csharp.Attribute
|
||||
import semmle.code.csharp.Callable
|
||||
import semmle.code.csharp.Comments
|
||||
import semmle.code.csharp.Element
|
||||
import semmle.code.csharp.Event
|
||||
import semmle.code.csharp.File
|
||||
import semmle.code.csharp.Generics
|
||||
import semmle.code.csharp.Location
|
||||
import semmle.code.csharp.Member
|
||||
import semmle.code.csharp.Namespace
|
||||
import semmle.code.csharp.AnnotatedType
|
||||
import semmle.code.csharp.Property
|
||||
import semmle.code.csharp.Stmt
|
||||
import semmle.code.csharp.Type
|
||||
import semmle.code.csharp.Using
|
||||
import semmle.code.csharp.Variable
|
||||
import semmle.code.csharp.XML
|
||||
import semmle.code.csharp.Preprocessor
|
||||
import semmle.code.csharp.exprs.Access
|
||||
import semmle.code.csharp.exprs.ArithmeticOperation
|
||||
import semmle.code.csharp.exprs.Assignment
|
||||
import semmle.code.csharp.exprs.BitwiseOperation
|
||||
import semmle.code.csharp.exprs.Call
|
||||
import semmle.code.csharp.exprs.ComparisonOperation
|
||||
import semmle.code.csharp.exprs.Creation
|
||||
import semmle.code.csharp.exprs.Dynamic
|
||||
import semmle.code.csharp.exprs.Expr
|
||||
import semmle.code.csharp.exprs.Literal
|
||||
import semmle.code.csharp.exprs.LogicalOperation
|
||||
import semmle.code.csharp.controlflow.ControlFlowGraph
|
||||
import semmle.code.csharp.dataflow.DataFlow
|
||||
import semmle.code.csharp.dataflow.TaintTracking
|
||||
import semmle.code.csharp.dataflow.SSA
|
||||
|
||||
/** Whether the source was extracted without a build command. */
|
||||
predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) }
|
||||
|
||||
@@ -4,5 +4,4 @@ groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/csharp-upgrades: ^0.0.3
|
||||
upgrades: upgrades
|
||||
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* Provides classes representing filesystem files and folders.
|
||||
*/
|
||||
|
||||
private import Comments
|
||||
|
||||
/** A file or folder. */
|
||||
class Container extends @container {
|
||||
/**
|
||||
@@ -195,11 +197,18 @@ class File extends Container, @file {
|
||||
|
||||
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||
|
||||
/** Holds if this file is a QL test stub file. */
|
||||
pragma[noinline]
|
||||
private predicate isStub() { this.getAbsolutePath().matches("%resources/stubs/%") }
|
||||
|
||||
/** Holds if this file contains source code. */
|
||||
predicate fromSource() { this.getExtension() = "cs" }
|
||||
final predicate fromSource() {
|
||||
this.getExtension() = "cs" and
|
||||
not this.isStub()
|
||||
}
|
||||
|
||||
/** Holds if this file is a library. */
|
||||
predicate fromLibrary() {
|
||||
final predicate fromLibrary() {
|
||||
not this.getBaseName() = "" and
|
||||
not this.fromSource()
|
||||
}
|
||||
|
||||
@@ -277,6 +277,8 @@ class TypeParameterConstraints extends Element, @type_parameter_constraints {
|
||||
|
||||
/** Gets a textual representation of these constraints. */
|
||||
override string toString() { result = "where " + this.getTypeParameter().getName() + ": ..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeParameterConstraints" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,8 @@ class Modifier extends Element, @modifier {
|
||||
predicate hasName(string name) { name = this.getName() }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Modifier" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,4 +22,6 @@ class Modifier extends Element, @modifier {
|
||||
*/
|
||||
class AccessModifier extends Modifier {
|
||||
AccessModifier() { this.hasName(["public", "private", "internal", "protected"]) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AccessModifier" }
|
||||
}
|
||||
|
||||
@@ -413,6 +413,8 @@ class VoidType extends DotNet::ValueOrRefType, Type, @void_type {
|
||||
final override string getUndecoratedName() { result = "Void" }
|
||||
|
||||
override SystemNamespace getDeclaringNamespace() { any() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VoidType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,6 +456,8 @@ class BoolType extends SimpleType, @bool_type {
|
||||
override string toStringWithTypes() { result = "bool" }
|
||||
|
||||
override int getSize() { result = 1 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BoolType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -467,6 +471,8 @@ class CharType extends SimpleType, @char_type {
|
||||
override int minValue() { result = 0 }
|
||||
|
||||
override int maxValue() { result = 65535 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CharType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -506,6 +512,8 @@ class SByteType extends SignedIntegralType, @sbyte_type {
|
||||
override int minValue() { result = -128 }
|
||||
|
||||
override int maxValue() { result = 127 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SByteType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -519,6 +527,8 @@ class ShortType extends SignedIntegralType, @short_type {
|
||||
override int minValue() { result = -32768 }
|
||||
|
||||
override int maxValue() { result = 32767 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ShortType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -532,6 +542,8 @@ class IntType extends SignedIntegralType, @int_type {
|
||||
override int minValue() { result = -2147483647 - 1 }
|
||||
|
||||
override int maxValue() { result = 2147483647 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "IntType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -541,6 +553,8 @@ class LongType extends SignedIntegralType, @long_type {
|
||||
override string toStringWithTypes() { result = "long" }
|
||||
|
||||
override int getSize() { result = 8 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LongType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -552,6 +566,8 @@ class ByteType extends UnsignedIntegralType, @byte_type {
|
||||
override int getSize() { result = 1 }
|
||||
|
||||
override int maxValue() { result = 255 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ByteType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -563,6 +579,8 @@ class UShortType extends UnsignedIntegralType, @ushort_type {
|
||||
override int getSize() { result = 2 }
|
||||
|
||||
override int maxValue() { result = 65535 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UShortType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -572,6 +590,8 @@ class UIntType extends UnsignedIntegralType, @uint_type {
|
||||
override string toStringWithTypes() { result = "uint" }
|
||||
|
||||
override int getSize() { result = 4 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UIntType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -581,6 +601,8 @@ class ULongType extends UnsignedIntegralType, @ulong_type {
|
||||
override string toStringWithTypes() { result = "ulong" }
|
||||
|
||||
override int getSize() { result = 8 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ULongType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -597,6 +619,8 @@ class FloatType extends FloatingPointType, @float_type {
|
||||
override string toStringWithTypes() { result = "float" }
|
||||
|
||||
override int getSize() { result = 4 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FloatType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -606,6 +630,8 @@ class DoubleType extends FloatingPointType, @double_type {
|
||||
override string toStringWithTypes() { result = "double" }
|
||||
|
||||
override int getSize() { result = 8 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DoubleType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -615,6 +641,8 @@ class DecimalType extends SimpleType, @decimal_type {
|
||||
override string toStringWithTypes() { result = "decimal" }
|
||||
|
||||
override int getSize() { result = 16 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DecimalType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -775,6 +803,8 @@ class ObjectType extends Class {
|
||||
ObjectType() { this.hasQualifiedName("System.Object") }
|
||||
|
||||
override string toStringWithTypes() { result = "object" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ObjectType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -784,6 +814,8 @@ class StringType extends Class {
|
||||
StringType() { this.hasQualifiedName("System.String") }
|
||||
|
||||
override string toStringWithTypes() { result = "string" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StringType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -910,7 +942,9 @@ class FunctionPointerType extends Type, Parameterizable, @function_pointer_type
|
||||
/**
|
||||
* The `null` type. The type of the `null` literal.
|
||||
*/
|
||||
class NullType extends RefType, @null_type { }
|
||||
class NullType extends RefType, @null_type {
|
||||
override string getAPrimaryQlClass() { result = "NullType" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A nullable type, for example `int?`.
|
||||
@@ -1124,6 +1158,8 @@ class TupleType extends ValueType, @tuple_type {
|
||||
final override predicate hasQualifiedName(string qualifier, string name) {
|
||||
this.getUnderlyingType().hasQualifiedName(qualifier, name)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TupleType" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -338,6 +338,8 @@ class LocalVariable extends LocalScopeVariable, @local_variable {
|
||||
override Type getType() { localvars(this, _, _, _, getTypeRef(result), _) }
|
||||
|
||||
override Location getALocation() { localvar_location(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LocalVariable" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides functionality for validating that the database and library are in a
|
||||
* consistent state.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
private predicate missingLocation(Element e, string m) {
|
||||
(
|
||||
e instanceof Declaration or
|
||||
e instanceof Expr or
|
||||
e instanceof Stmt
|
||||
) and
|
||||
not e instanceof ImplicitAccessorParameter and
|
||||
not e instanceof NullType and
|
||||
not e instanceof Parameter and // Bug in Roslyn - params occasionally lack locations
|
||||
not e.(Operator).getDeclaringType() instanceof IntType and // Roslyn quirk
|
||||
not e instanceof Constructor and
|
||||
not e instanceof ArrayType and
|
||||
not e instanceof UnknownType and
|
||||
not e instanceof ArglistType and
|
||||
not exists(TupleType t | e = t or e = t.getAField()) and
|
||||
not exists(e.getLocation()) and
|
||||
m = "Element does not have a location"
|
||||
}
|
||||
|
||||
private predicate inconsistentGeneric(ConstructedGeneric g, string m) {
|
||||
not exists(g.getUnboundGeneric()) and
|
||||
m = "Constructed generic does not have an unbound generic"
|
||||
or
|
||||
g.getNumberOfTypeArguments() = 0 and
|
||||
m = "Constructed generic has no type arguments"
|
||||
or
|
||||
g.getUnboundGeneric().getNumberOfTypeParameters() != g.getNumberOfTypeArguments() and
|
||||
m = "Inconsistent number of type arguments/parameters"
|
||||
}
|
||||
|
||||
module SsaChecks {
|
||||
import Ssa
|
||||
|
||||
predicate nonUniqueSsaDef(AssignableRead read, string m) {
|
||||
exists(ControlFlow::Node cfn | strictcount(Definition def | def.getAReadAtNode(cfn) = read) > 1) and
|
||||
m = "Read is associated with multiple SSA definitions"
|
||||
}
|
||||
|
||||
predicate notDominatedByDef(AssignableRead read, string m) {
|
||||
exists(
|
||||
Definition def, ControlFlow::BasicBlock bb, ControlFlow::Node rnode, ControlFlow::Node dnode,
|
||||
int i
|
||||
|
|
||||
def.getAReadAtNode(rnode) = read
|
||||
|
|
||||
def.definesAt(_, bb, i) and
|
||||
dnode = bb.getNode(max(int j | j = i or j = 0)) and
|
||||
not dnode.dominates(rnode)
|
||||
) and
|
||||
m = "Read is not dominated by SSA definition"
|
||||
}
|
||||
|
||||
predicate localDeclWithSsaDef(LocalVariableDeclExpr d, string m) {
|
||||
// Local variables in C# must be initialized before every use, so uninitialized
|
||||
// local variables should not have an SSA definition, as that would imply that
|
||||
// the declaration is live (can reach a use without passing through a definition)
|
||||
exists(ExplicitDefinition def |
|
||||
d = def.getADefinition().(AssignableDefinitions::LocalVariableDefinition).getDeclaration()
|
||||
|
|
||||
not d = any(ForeachStmt fs).getVariableDeclExpr() and
|
||||
not d = any(SpecificCatchClause scc).getVariableDeclExpr() and
|
||||
not d.getVariable().getType() instanceof Struct and
|
||||
not d = any(BindingPatternExpr bpe).getVariableDeclExpr()
|
||||
) and
|
||||
m = "Local variable declaration has unexpected SSA definition"
|
||||
}
|
||||
|
||||
predicate ssaConsistencyFailure(Element e, string m) {
|
||||
nonUniqueSsaDef(e, m) or
|
||||
notDominatedByDef(e, m) or
|
||||
localDeclWithSsaDef(e, m)
|
||||
}
|
||||
}
|
||||
|
||||
module CfgChecks {
|
||||
predicate multipleSuccessors(ControlFlowElement cfe, string m) {
|
||||
exists(ControlFlow::Node cfn | cfn = cfe.getAControlFlowNode() |
|
||||
strictcount(cfn.getASuccessorByType(any(ControlFlow::SuccessorTypes::NormalSuccessor e))) > 1 and
|
||||
m = "Multiple (non-conditional/exceptional) successors"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if element `e` has a consistency failure, as described by
|
||||
* the message in `m`.
|
||||
*/
|
||||
predicate consistencyFailure(Element e, string m) {
|
||||
missingLocation(e, m) or
|
||||
inconsistentGeneric(e, m) or
|
||||
SsaChecks::ssaConsistencyFailure(e, m) or
|
||||
CfgChecks::multipleSuccessors(e, m)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ newtype CompilationExt =
|
||||
TBuildless() { extractionIsStandalone() }
|
||||
|
||||
/** Gets the compilation that source file `f` belongs to. */
|
||||
CompilationExt getCompilation(SourceFile f) {
|
||||
CompilationExt getCompilation(File f) {
|
||||
exists(Compilation c |
|
||||
f = c.getAFileCompiled() and
|
||||
result = TCompilation(c)
|
||||
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ private import internal.FlowSummaryImplSpecific
|
||||
private module Frameworks {
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
private import semmle.code.csharp.frameworks.JsonNET
|
||||
private import semmle.code.csharp.frameworks.microsoft.extensions.Primitives
|
||||
private import semmle.code.csharp.frameworks.microsoft.VisualBasic
|
||||
private import semmle.code.csharp.frameworks.ServiceStack
|
||||
private import semmle.code.csharp.frameworks.Sql
|
||||
@@ -348,6 +349,24 @@ module CsvValidation {
|
||||
msg = "Invalid boolean \"" + b + "\" in " + pred + " model."
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(string row, string kind | summaryModel(row) |
|
||||
kind = row.splitAt(";", 8) and
|
||||
not kind = ["taint", "value"] and
|
||||
msg = "Invalid kind \"" + kind + "\" in summary model."
|
||||
)
|
||||
or
|
||||
exists(string row, string kind | sinkModel(row) |
|
||||
kind = row.splitAt(";", 7) and
|
||||
not kind = ["code", "sql", "xss", "remote", "html"] and
|
||||
msg = "Invalid kind \"" + kind + "\" in sink model."
|
||||
)
|
||||
or
|
||||
exists(string row, string kind | sourceModel(row) |
|
||||
kind = row.splitAt(";", 7) and
|
||||
not kind = "local" and
|
||||
msg = "Invalid kind \"" + kind + "\" in source model."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ class ArgumentPosition = DataFlowDispatch::ArgumentPosition;
|
||||
|
||||
// import all instances below
|
||||
private module Summaries {
|
||||
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
}
|
||||
|
||||
@@ -111,6 +110,29 @@ module SummaryComponentStack {
|
||||
|
||||
class SummarizedCallable = Impl::Public::SummarizedCallable;
|
||||
|
||||
private predicate recordConstructorFlow(Constructor c, int i, Property p) {
|
||||
c = any(Record r).getAMember() and
|
||||
exists(string name |
|
||||
c.getParameter(i).getName() = name and
|
||||
c.getDeclaringType().getAMember(name) = p
|
||||
)
|
||||
}
|
||||
|
||||
private class RecordConstructorFlow extends SummarizedCallable {
|
||||
RecordConstructorFlow() { recordConstructorFlow(this, _, _) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
exists(int i, Property p |
|
||||
recordConstructorFlow(this, i, p) and
|
||||
input = SummaryComponentStack::argument(i) and
|
||||
output = SummaryComponentStack::propertyOf(p, SummaryComponentStack::return()) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableDefaultClearsContent extends Impl::Public::SummarizedCallable {
|
||||
SummarizedCallableDefaultClearsContent() {
|
||||
this instanceof Impl::Public::SummarizedCallable or none()
|
||||
@@ -129,3 +151,17 @@ private class SummarizedCallableDefaultClearsContent extends Impl::Public::Summa
|
||||
}
|
||||
|
||||
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
|
||||
|
||||
private class RecordConstructorFlowRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
private SummaryComponent head;
|
||||
|
||||
RecordConstructorFlowRequiredSummaryComponentStack() {
|
||||
exists(Property p |
|
||||
recordConstructorFlow(_, _, p) and
|
||||
head = SummaryComponent::property(p) and
|
||||
this = SummaryComponentStack::return()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate required(SummaryComponent c) { c = head }
|
||||
}
|
||||
|
||||
@@ -1,571 +0,0 @@
|
||||
/**
|
||||
* Provides classes and predicates for tracking data flow through library types.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.system.Collections
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
private import semmle.code.csharp.frameworks.system.Text
|
||||
private import semmle.code.csharp.frameworks.system.runtime.CompilerServices
|
||||
private import semmle.code.csharp.frameworks.system.threading.Tasks
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPublic
|
||||
private import semmle.code.csharp.dataflow.internal.DelegateDataFlow
|
||||
// import `LibraryTypeDataFlow` definitions from other files to avoid potential reevaluation
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
private import FlowSummary
|
||||
|
||||
private newtype TAccessPath =
|
||||
TNilAccessPath() or
|
||||
TConsAccessPath(Content head, AccessPath tail) {
|
||||
tail = TNilAccessPath()
|
||||
or
|
||||
exists(LibraryTypeDataFlow ltdf |
|
||||
ltdf.requiresAccessPath(head, tail) and
|
||||
tail.length() < accessPathLimit()
|
||||
)
|
||||
or
|
||||
tail = AccessPath::singleton(_) and
|
||||
head instanceof ElementContent
|
||||
or
|
||||
tail = AccessPath::element()
|
||||
}
|
||||
|
||||
/** An access path. */
|
||||
class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
Content getHead() { this = TConsAccessPath(result, _) }
|
||||
|
||||
/** Gets the tail of this access path, if any. */
|
||||
AccessPath getTail() { this = TConsAccessPath(_, result) }
|
||||
|
||||
/** Gets the length of this access path. */
|
||||
int length() {
|
||||
this = TNilAccessPath() and result = 0
|
||||
or
|
||||
result = 1 + this.getTail().length()
|
||||
}
|
||||
|
||||
/** Gets the access path obtained by dropping the first `i` elements, if any. */
|
||||
AccessPath drop(int i) {
|
||||
i = 0 and result = this
|
||||
or
|
||||
result = this.getTail().drop(i - 1)
|
||||
}
|
||||
|
||||
/** Holds if this access path contains content `c`. */
|
||||
predicate contains(Content c) { c = this.drop(_).getHead() }
|
||||
|
||||
/** Gets a textual representation of this access path. */
|
||||
string toString() {
|
||||
exists(Content head, AccessPath tail |
|
||||
head = this.getHead() and
|
||||
tail = this.getTail() and
|
||||
if tail.length() = 0 then result = head.toString() else result = head + ", " + tail
|
||||
)
|
||||
or
|
||||
this = TNilAccessPath() and
|
||||
result = "<empty>"
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides predicates for constructing access paths. */
|
||||
module AccessPath {
|
||||
/** Gets the empty access path. */
|
||||
AccessPath empty() { result = TNilAccessPath() }
|
||||
|
||||
/** Gets a singleton access path containing `c`. */
|
||||
AccessPath singleton(Content c) { result = TConsAccessPath(c, TNilAccessPath()) }
|
||||
|
||||
/** Gets the access path obtained by concatenating `head` onto `tail`. */
|
||||
AccessPath cons(Content head, AccessPath tail) { result = TConsAccessPath(head, tail) }
|
||||
|
||||
/** Gets the singleton "element content" access path. */
|
||||
AccessPath element() { result = singleton(any(ElementContent c)) }
|
||||
|
||||
/** Gets a singleton property access path. */
|
||||
AccessPath property(Property p) {
|
||||
result = singleton(any(PropertyContent c | c.getProperty() = p.getUnboundDeclaration()))
|
||||
}
|
||||
|
||||
/** Gets a singleton field access path. */
|
||||
AccessPath field(Field f) {
|
||||
result = singleton(any(FieldContent c | c.getField() = f.getUnboundDeclaration()))
|
||||
}
|
||||
|
||||
/** Gets a singleton synthetic field access path. */
|
||||
AccessPath synthetic(SyntheticField f) {
|
||||
result = singleton(any(SyntheticFieldContent c | c.getField() = f))
|
||||
}
|
||||
|
||||
/** Gets an access path representing a property inside a collection. */
|
||||
AccessPath properties(Property p) { result = TConsAccessPath(any(ElementContent c), property(p)) }
|
||||
}
|
||||
|
||||
/** An unbound callable. */
|
||||
class SourceDeclarationCallable extends Callable {
|
||||
SourceDeclarationCallable() { this.isUnboundDeclaration() }
|
||||
}
|
||||
|
||||
/** An unbound method. */
|
||||
class SourceDeclarationMethod extends SourceDeclarationCallable, Method { }
|
||||
|
||||
private newtype TCallableFlowSource =
|
||||
TCallableFlowSourceQualifier() or
|
||||
TCallableFlowSourceArg(int i) { i = any(Parameter p).getPosition() } or
|
||||
TCallableFlowSourceDelegateArg(int i) { hasDelegateArgumentPosition(_, i) }
|
||||
|
||||
private predicate hasDelegateArgumentPosition(SourceDeclarationCallable c, int i) {
|
||||
exists(DelegateType dt |
|
||||
dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType()
|
||||
|
|
||||
not dt.getReturnType() instanceof VoidType
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasDelegateArgumentPosition2(SourceDeclarationCallable c, int i, int j) {
|
||||
exists(DelegateType dt |
|
||||
dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType()
|
||||
|
|
||||
exists(dt.getParameter(j))
|
||||
)
|
||||
}
|
||||
|
||||
/** A flow source specification. */
|
||||
class CallableFlowSource extends TCallableFlowSource {
|
||||
/** Gets a textual representation of this flow source specification. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the source of flow for call `c`, if any. */
|
||||
Expr getSource(Call c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type of the source for call `c`. Unlike `getSource()`, this
|
||||
* is defined for all flow source specifications.
|
||||
*/
|
||||
Type getSourceType(Call c) { result = this.getSource(c).getType() }
|
||||
}
|
||||
|
||||
/** A flow source specification: (method call) qualifier. */
|
||||
class CallableFlowSourceQualifier extends CallableFlowSource, TCallableFlowSourceQualifier {
|
||||
override string toString() { result = "qualifier" }
|
||||
|
||||
override Expr getSource(Call c) { result = c.getChild(-1) }
|
||||
}
|
||||
|
||||
/** A flow source specification: (method call) argument. */
|
||||
class CallableFlowSourceArg extends CallableFlowSource, TCallableFlowSourceArg {
|
||||
private int i;
|
||||
|
||||
CallableFlowSourceArg() { this = TCallableFlowSourceArg(i) }
|
||||
|
||||
/** Gets the index of this argument. */
|
||||
int getArgumentIndex() { result = i }
|
||||
|
||||
override string toString() { result = "argument " + i }
|
||||
|
||||
override Expr getSource(Call c) { result = c.getArgument(i) }
|
||||
}
|
||||
|
||||
/** A flow source specification: output from delegate argument. */
|
||||
class CallableFlowSourceDelegateArg extends CallableFlowSource, TCallableFlowSourceDelegateArg {
|
||||
private int i;
|
||||
|
||||
CallableFlowSourceDelegateArg() { this = TCallableFlowSourceDelegateArg(i) }
|
||||
|
||||
/** Gets the index of this delegate argument. */
|
||||
int getArgumentIndex() { result = i }
|
||||
|
||||
override string toString() { result = "output from argument " + i }
|
||||
|
||||
override Expr getSource(Call c) { none() }
|
||||
|
||||
override Type getSourceType(Call c) { result = c.getArgument(i).getType() }
|
||||
}
|
||||
|
||||
private newtype TCallableFlowSink =
|
||||
TCallableFlowSinkQualifier() or
|
||||
TCallableFlowSinkReturn() or
|
||||
TCallableFlowSinkArg(int i) { exists(SourceDeclarationCallable c | exists(c.getParameter(i))) } or
|
||||
TCallableFlowSinkDelegateArg(int i, int j) { hasDelegateArgumentPosition2(_, i, j) }
|
||||
|
||||
/** A flow sink specification. */
|
||||
class CallableFlowSink extends TCallableFlowSink {
|
||||
/** Gets a textual representation of this flow sink specification. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the sink of flow for call `c`, if any. */
|
||||
Expr getSink(Call c) { none() }
|
||||
}
|
||||
|
||||
/** A flow sink specification: (method call) qualifier. */
|
||||
class CallableFlowSinkQualifier extends CallableFlowSink, TCallableFlowSinkQualifier {
|
||||
override string toString() { result = "qualifier" }
|
||||
|
||||
override Expr getSink(Call c) { result = c.getChild(-1) }
|
||||
}
|
||||
|
||||
/** A flow sink specification: return value. */
|
||||
class CallableFlowSinkReturn extends CallableFlowSink, TCallableFlowSinkReturn {
|
||||
override string toString() { result = "return" }
|
||||
|
||||
override Expr getSink(Call c) { result = c }
|
||||
}
|
||||
|
||||
/** A flow sink specification: (method call) argument. */
|
||||
class CallableFlowSinkArg extends CallableFlowSink, TCallableFlowSinkArg {
|
||||
private int i;
|
||||
|
||||
CallableFlowSinkArg() { this = TCallableFlowSinkArg(i) }
|
||||
|
||||
/** Gets the index of this `out`/`ref` argument. */
|
||||
int getArgumentIndex() { result = i }
|
||||
|
||||
/** Gets the `out`/`ref` argument of method call `mc` matching this specification. */
|
||||
Expr getArgument(MethodCall mc) {
|
||||
exists(Parameter p |
|
||||
p = mc.getTarget().getParameter(i) and
|
||||
p.isOutOrRef() and
|
||||
result = mc.getArgumentForParameter(p)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "argument " + i }
|
||||
|
||||
override Expr getSink(Call c) {
|
||||
// The uses of the `i`th argument are the actual sinks
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/** A flow sink specification: parameter of a delegate argument. */
|
||||
class CallableFlowSinkDelegateArg extends CallableFlowSink, TCallableFlowSinkDelegateArg {
|
||||
private int delegateIndex;
|
||||
private int parameterIndex;
|
||||
|
||||
CallableFlowSinkDelegateArg() {
|
||||
this = TCallableFlowSinkDelegateArg(delegateIndex, parameterIndex)
|
||||
}
|
||||
|
||||
/** Gets the index of the delegate argument. */
|
||||
int getDelegateIndex() { result = delegateIndex }
|
||||
|
||||
/** Gets the index of the delegate parameter. */
|
||||
int getDelegateParameterIndex() { result = parameterIndex }
|
||||
|
||||
override string toString() {
|
||||
result = "parameter " + parameterIndex + " of argument " + delegateIndex
|
||||
}
|
||||
|
||||
override Expr getSink(Call c) {
|
||||
// The uses of the `j`th parameter are the actual sinks
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/** A specification of data flow for a library (non-source code) type. */
|
||||
abstract class LibraryTypeDataFlow extends Type {
|
||||
LibraryTypeDataFlow() { this = this.getUnboundDeclaration() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` when calling callable `c`.
|
||||
*
|
||||
* `preservesValue` indicates whether the value from `source` is preserved
|
||||
* (possibly copied) to `sink`. For example, the value is preserved from `x`
|
||||
* to `x.ToString()` when `x` is a `string`, but not from `x` to `x.ToLower()`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate callableFlow(
|
||||
CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
|
||||
boolean preservesValue
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` when calling callable `c`.
|
||||
*
|
||||
* `sourceAp` describes the contents of `source` that flows to `sink`
|
||||
* (if any), and `sinkAp` describes the contents of `sink` that it
|
||||
* flows to (if any).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate callableFlow(
|
||||
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
|
||||
SourceDeclarationCallable c, boolean preservesValue
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the access path obtained by concatenating `head` onto `tail` is
|
||||
* needed for a summary specified by `callableFlow()`.
|
||||
*
|
||||
* This predicate is needed for QL technical reasons only (the IPA type used
|
||||
* to represent access paths needs to be bounded).
|
||||
*/
|
||||
predicate requiresAccessPath(Content head, AccessPath tail) { none() }
|
||||
|
||||
/**
|
||||
* Holds if values stored inside `content` are cleared on objects passed as
|
||||
* arguments of type `source` to calls that target `callable`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate clearsContent(
|
||||
CallableFlowSource source, Content content, SourceDeclarationCallable callable
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal module for translating old `LibraryTypeDataFlow`-style
|
||||
* flow summaries into the new style.
|
||||
*/
|
||||
private module FrameworkDataFlowAdaptor {
|
||||
private CallableFlowSource toCallableFlowSource(SummaryComponentStack input) {
|
||||
result = TCallableFlowSourceQualifier() and
|
||||
input = SummaryComponentStack::qualifier()
|
||||
or
|
||||
exists(int i |
|
||||
result = TCallableFlowSourceArg(i) and
|
||||
input = SummaryComponentStack::argument(i)
|
||||
)
|
||||
or
|
||||
exists(int i | result = TCallableFlowSourceDelegateArg(i) |
|
||||
input =
|
||||
SummaryComponentStack::push(SummaryComponent::return(), SummaryComponentStack::argument(i))
|
||||
)
|
||||
}
|
||||
|
||||
private CallableFlowSink toCallableFlowSink(SummaryComponentStack output) {
|
||||
result = TCallableFlowSinkQualifier() and
|
||||
output = SummaryComponentStack::qualifier()
|
||||
or
|
||||
result = TCallableFlowSinkReturn() and
|
||||
output = SummaryComponentStack::return()
|
||||
or
|
||||
exists(int i |
|
||||
result = TCallableFlowSinkArg(i) and
|
||||
output = SummaryComponentStack::argument(i)
|
||||
)
|
||||
or
|
||||
exists(int i, int j | result = TCallableFlowSinkDelegateArg(i, j) |
|
||||
output =
|
||||
SummaryComponentStack::push(SummaryComponent::parameter(j),
|
||||
SummaryComponentStack::argument(i))
|
||||
)
|
||||
}
|
||||
|
||||
private class FrameworkDataFlowAdaptor extends SummarizedCallable {
|
||||
private LibraryTypeDataFlow ltdf;
|
||||
|
||||
FrameworkDataFlowAdaptor() {
|
||||
ltdf.callableFlow(_, _, this, _) or
|
||||
ltdf.callableFlow(_, _, _, _, this, _) or
|
||||
ltdf.clearsContent(_, _, this)
|
||||
}
|
||||
|
||||
predicate input(
|
||||
CallableFlowSource source, AccessPath sourceAp, SummaryComponent head,
|
||||
SummaryComponentStack tail, int i
|
||||
) {
|
||||
ltdf.callableFlow(source, sourceAp, _, _, this, _) and
|
||||
source = toCallableFlowSource(tail) and
|
||||
head = SummaryComponent::content(sourceAp.getHead()) and
|
||||
i = 0
|
||||
or
|
||||
exists(SummaryComponent tailHead, SummaryComponentStack tailTail |
|
||||
this.input(source, sourceAp, tailHead, tailTail, i - 1) and
|
||||
head = SummaryComponent::content(sourceAp.drop(i).getHead()) and
|
||||
tail = SummaryComponentStack::push(tailHead, tailTail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate output(
|
||||
CallableFlowSink sink, AccessPath sinkAp, SummaryComponent head, SummaryComponentStack tail,
|
||||
int i
|
||||
) {
|
||||
ltdf.callableFlow(_, _, sink, sinkAp, this, _) and
|
||||
sink = toCallableFlowSink(tail) and
|
||||
head = SummaryComponent::content(sinkAp.getHead()) and
|
||||
i = 0
|
||||
or
|
||||
exists(SummaryComponent tailHead, SummaryComponentStack tailTail |
|
||||
this.output(sink, sinkAp, tailHead, tailTail, i - 1) and
|
||||
head = SummaryComponent::content(sinkAp.drop(i).getHead()) and
|
||||
tail = SummaryComponentStack::push(tailHead, tailTail)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
ltdf.callableFlow(toCallableFlowSource(input), toCallableFlowSink(output), this,
|
||||
preservesValue)
|
||||
or
|
||||
exists(
|
||||
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp
|
||||
|
|
||||
ltdf.callableFlow(source, sourceAp, sink, sinkAp, this, preservesValue) and
|
||||
(
|
||||
exists(SummaryComponent head, SummaryComponentStack tail |
|
||||
this.input(source, sourceAp, head, tail, sourceAp.length() - 1) and
|
||||
input = SummaryComponentStack::push(head, tail)
|
||||
)
|
||||
or
|
||||
sourceAp.length() = 0 and
|
||||
source = toCallableFlowSource(input)
|
||||
) and
|
||||
(
|
||||
exists(SummaryComponent head, SummaryComponentStack tail |
|
||||
this.output(sink, sinkAp, head, tail, sinkAp.length() - 1) and
|
||||
output = SummaryComponentStack::push(head, tail)
|
||||
)
|
||||
or
|
||||
sinkAp.length() = 0 and
|
||||
sink = toCallableFlowSink(output)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate clearsContent(ParameterPosition pos, Content content) {
|
||||
exists(SummaryComponentStack input |
|
||||
ltdf.clearsContent(toCallableFlowSource(input), content, this) and
|
||||
input = SummaryComponentStack::argument(pos.getPosition())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class AdaptorRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
private SummaryComponent head;
|
||||
|
||||
AdaptorRequiredSummaryComponentStack() {
|
||||
exists(int i |
|
||||
exists(TCallableFlowSourceDelegateArg(i)) and
|
||||
head = SummaryComponent::return() and
|
||||
this = SummaryComponentStack::singleton(SummaryComponent::argument(i))
|
||||
)
|
||||
or
|
||||
exists(int i, int j | exists(TCallableFlowSinkDelegateArg(i, j)) |
|
||||
head = SummaryComponent::parameter(j) and
|
||||
this = SummaryComponentStack::singleton(SummaryComponent::argument(i))
|
||||
)
|
||||
or
|
||||
exists(FrameworkDataFlowAdaptor adaptor |
|
||||
adaptor.input(_, _, head, this, _)
|
||||
or
|
||||
adaptor.output(_, _, head, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate required(SummaryComponent c) { c = head }
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Text.StringBuilder`. */
|
||||
class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringBuilderClass {
|
||||
override predicate clearsContent(
|
||||
CallableFlowSource source, Content content, SourceDeclarationCallable callable
|
||||
) {
|
||||
source = TCallableFlowSourceQualifier() and
|
||||
callable = this.getAMethod("Clear") and
|
||||
content instanceof ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Collections.IEnumerable` (and sub types). */
|
||||
class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
IEnumerableFlow() { this.getABaseType*() instanceof SystemCollectionsIEnumerableInterface }
|
||||
|
||||
override predicate clearsContent(
|
||||
CallableFlowSource source, Content content, SourceDeclarationCallable callable
|
||||
) {
|
||||
source = TCallableFlowSourceQualifier() and
|
||||
callable = this.getAMethod("Clear") and
|
||||
content instanceof ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class SyntheticTaskField extends SyntheticField {
|
||||
bindingset[this]
|
||||
SyntheticTaskField() { any() }
|
||||
|
||||
override Type getType() { result instanceof SystemThreadingTasksTaskTClass }
|
||||
}
|
||||
|
||||
private class SyntheticTaskAwaiterUnderlyingTaskField extends SyntheticTaskField {
|
||||
SyntheticTaskAwaiterUnderlyingTaskField() { this = "m_task_task_awaiter" }
|
||||
}
|
||||
|
||||
private class SyntheticConfiguredTaskAwaitableUnderlyingTaskField extends SyntheticTaskField {
|
||||
SyntheticConfiguredTaskAwaitableUnderlyingTaskField() {
|
||||
this = "m_task_configured_task_awaitable"
|
||||
}
|
||||
}
|
||||
|
||||
private class SyntheticConfiguredTaskAwaiterField extends SyntheticField {
|
||||
SyntheticConfiguredTaskAwaiterField() { this = "m_configuredTaskAwaiter" }
|
||||
|
||||
override Type getType() {
|
||||
result instanceof
|
||||
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom flow through `StringValues` library class.
|
||||
*/
|
||||
class StringValuesFlow extends LibraryTypeDataFlow, Struct {
|
||||
StringValuesFlow() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") }
|
||||
|
||||
override predicate callableFlow(
|
||||
CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
|
||||
boolean preservesValue
|
||||
) {
|
||||
c.getDeclaringType() = this and
|
||||
(
|
||||
source instanceof CallableFlowSourceArg or
|
||||
source instanceof CallableFlowSourceQualifier
|
||||
) and
|
||||
sink instanceof CallableFlowSinkReturn and
|
||||
preservesValue = false
|
||||
}
|
||||
}
|
||||
|
||||
private predicate recordConstructorFlow(Constructor c, int i, Property p) {
|
||||
c = any(Record r).getAMember() and
|
||||
exists(string name |
|
||||
c.getParameter(i).getName() = name and
|
||||
c.getDeclaringType().getAMember(name) = p
|
||||
)
|
||||
}
|
||||
|
||||
private class RecordConstructorFlowRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
private SummaryComponent head;
|
||||
|
||||
RecordConstructorFlowRequiredSummaryComponentStack() {
|
||||
exists(Property p |
|
||||
recordConstructorFlow(_, _, p) and
|
||||
head = SummaryComponent::property(p) and
|
||||
this = SummaryComponentStack::singleton(SummaryComponent::return())
|
||||
)
|
||||
}
|
||||
|
||||
override predicate required(SummaryComponent c) { c = head }
|
||||
}
|
||||
|
||||
private class RecordConstructorFlow extends SummarizedCallable {
|
||||
RecordConstructorFlow() { recordConstructorFlow(this, _, _) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
exists(int i, Property p |
|
||||
recordConstructorFlow(this, i, p) and
|
||||
input = SummaryComponentStack::argument(i) and
|
||||
output = SummaryComponentStack::propertyOf(p, SummaryComponentStack::return()) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,17 @@ private import DataFlowImplSpecific::Public
|
||||
import Cached
|
||||
|
||||
module DataFlowImplCommonPublic {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
}
|
||||
|
||||
private newtype TFlowFeature =
|
||||
TFeatureHasSourceCallContext() or
|
||||
TFeatureHasSinkCallContext() or
|
||||
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,12 @@ private import semmle.code.csharp.frameworks.WCF
|
||||
*/
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
|
||||
* but not in local taint.
|
||||
*/
|
||||
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if default `TaintTracking::Configuration`s should allow implicit reads
|
||||
* of `c` at sinks and inputs to additional taint steps.
|
||||
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSource(DataFlow::Node source);
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
@@ -69,7 +69,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSink(DataFlow::Node sink);
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
@@ -93,7 +93,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSource(DataFlow::Node source);
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
@@ -69,7 +69,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSink(DataFlow::Node sink);
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
@@ -93,7 +93,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSource(DataFlow::Node source);
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
@@ -69,7 +69,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSink(DataFlow::Node sink);
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
@@ -93,7 +93,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSource(DataFlow::Node source);
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
@@ -69,7 +69,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSink(DataFlow::Node sink);
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
@@ -93,7 +93,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSource(DataFlow::Node source);
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
@@ -69,7 +69,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
abstract override predicate isSink(DataFlow::Node sink);
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
@@ -93,7 +93,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -316,6 +316,12 @@ private predicate hasChildPattern(ControlFlowElement pm, Expr child) {
|
||||
child = mid.getChildExpr(0) or
|
||||
child = mid.getChildExpr(1)
|
||||
)
|
||||
or
|
||||
exists(Expr mid |
|
||||
hasChildPattern(pm, mid) and
|
||||
mid instanceof @tuple_expr and
|
||||
child = mid.getAChildExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,13 +426,10 @@ class TypeAccessPatternExpr extends TypePatternExpr, TypeAccess {
|
||||
override string getAPrimaryQlClass() { result = "TypeAccessPatternExpr" }
|
||||
}
|
||||
|
||||
/** A pattern that may bind a variable, for example `string s` in `x is string s`. */
|
||||
class BindingPatternExpr extends PatternExpr {
|
||||
BindingPatternExpr() {
|
||||
this instanceof LocalVariableDeclExpr or
|
||||
this instanceof @recursive_pattern_expr
|
||||
}
|
||||
private class TBindingPatternExpr = @local_var_decl_expr or @recursive_pattern_expr;
|
||||
|
||||
/** A pattern that may bind a variable, for example `string s` in `x is string s`. */
|
||||
class BindingPatternExpr extends PatternExpr, TBindingPatternExpr {
|
||||
/**
|
||||
* Gets the local variable declaration of this pattern, if any. For example,
|
||||
* `string s` in `string { Length: 5 } s`.
|
||||
@@ -1081,6 +1084,8 @@ class DiscardExpr extends Expr, @discard_expr {
|
||||
|
||||
private class UnknownExpr extends Expr, @unknown_expr {
|
||||
override string toString() { result = "Expression" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnknownExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -112,6 +112,8 @@ class SystemBooleanStruct extends BoolType {
|
||||
result.getParameter(1).getType() instanceof BoolType and
|
||||
result.getReturnType() instanceof BoolType
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SystemBooleanStruct" }
|
||||
}
|
||||
|
||||
/** Data flow for `System.Boolean`. */
|
||||
@@ -1092,6 +1094,8 @@ class SystemIntPtrType extends ValueType {
|
||||
this = any(SystemNamespace n).getATypeDeclaration() and
|
||||
this.hasName("IntPtr")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SystemIntPtrType" }
|
||||
}
|
||||
|
||||
/** The `System.IDisposable` interface. */
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/** Provides definitions related to the `Microsoft.Extensions.Primitives` namespace. */
|
||||
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** Data flow for `Microsoft.Extensions.Primitives.StringValues`. */
|
||||
private class MicrosoftExtensionsPrimitivesStringValuesFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Add;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Add;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Contains;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Contains;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;CopyTo;(System.String[],System.Int32);;Element of Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;CopyTo;(System.String[],System.Int32);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;CopyTo;(System.String[],System.Int32);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,System.String[]);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,System.String[]);;Element of Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.Object);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.Object);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String[]);;Element of Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String[]);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String[],Microsoft.Extensions.Primitives.StringValues);;Element of Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String[],Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;GetEnumerator;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;GetHashCode;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;IndexOf;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;IndexOf;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Insert;(System.Int32,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Insert;(System.Int32,System.String);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Insert;(System.Int32,System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;IsNullOrEmpty;(Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Remove;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Remove;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;RemoveAt;(System.Int32);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;RemoveAt;(System.Int32);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;StringValues;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;StringValues;(System.String[]);;Element of Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;ToArray;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;ToString;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;get_Count;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;get_IsReadOnly;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;get_Item;(System.Int32);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;get_Item;(System.Int32);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[-1];ReturnValue;taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
|
||||
/** The `System.Collections` namespace. */
|
||||
class SystemCollectionsNamespace extends Namespace {
|
||||
@@ -45,6 +46,20 @@ private class SystemCollectionIEnumerableFlowModelCsv extends SummaryModelCsv {
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear content for Clear methods in all subtypes of `System.Collections.IEnumerable`. */
|
||||
private class SystemCollectionsIEnumerableClearFlow extends SummarizedCallable {
|
||||
SystemCollectionsIEnumerableClearFlow() {
|
||||
this.getDeclaringType().(RefType).getABaseType*() instanceof
|
||||
SystemCollectionsIEnumerableInterface and
|
||||
this.hasName("Clear")
|
||||
}
|
||||
|
||||
override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
|
||||
pos.getPosition() = -1 and
|
||||
content instanceof DataFlow::ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
/** The `System.Collections.IEnumerator` interface. */
|
||||
class SystemCollectionsIEnumeratorInterface extends SystemCollectionsInterface {
|
||||
SystemCollectionsIEnumeratorInterface() { this.hasName("IEnumerator") }
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
|
||||
/** The `System.Text` namespace. */
|
||||
class SystemTextNamespace extends Namespace {
|
||||
@@ -25,6 +26,18 @@ class SystemTextStringBuilderClass extends SystemTextClass {
|
||||
Method getAppendFormatMethod() { result = this.getAMethod("AppendFormat") }
|
||||
}
|
||||
|
||||
/** Clear content for `System.Text.StringBuilder.Clear`. */
|
||||
private class SystemTextStringBuilderClearFlow extends SummarizedCallable {
|
||||
SystemTextStringBuilderClearFlow() {
|
||||
this = any(SystemTextStringBuilderClass s).getAMethod("Clear")
|
||||
}
|
||||
|
||||
override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
|
||||
pos.getPosition() = -1 and
|
||||
content instanceof DataFlow::ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Text.StringBuilder`. */
|
||||
private class SystemTextStringBuilderFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.system.Runtime
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** The `System.Runtime.CompilerServices` namespace. */
|
||||
@@ -53,6 +54,15 @@ class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct extends System
|
||||
}
|
||||
}
|
||||
|
||||
private class SyntheticConfiguredTaskAwaiterField extends SyntheticField {
|
||||
SyntheticConfiguredTaskAwaiterField() { this = "m_configuredTaskAwaiter" }
|
||||
|
||||
override Type getType() {
|
||||
result instanceof
|
||||
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>`. */
|
||||
private class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.system.Threading
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** The `System.Threading.Tasks` namespace. */
|
||||
@@ -91,6 +92,23 @@ class SystemThreadingTasksTaskTClass extends SystemThreadingTasksUnboundGenericC
|
||||
Method getConfigureAwaitMethod() { result = this.getAMethod("ConfigureAwait") }
|
||||
}
|
||||
|
||||
abstract private class SyntheticTaskField extends SyntheticField {
|
||||
bindingset[this]
|
||||
SyntheticTaskField() { any() }
|
||||
|
||||
override Type getType() { result instanceof SystemThreadingTasksTaskTClass }
|
||||
}
|
||||
|
||||
private class SyntheticTaskAwaiterUnderlyingTaskField extends SyntheticTaskField {
|
||||
SyntheticTaskAwaiterUnderlyingTaskField() { this = "m_task_task_awaiter" }
|
||||
}
|
||||
|
||||
private class SyntheticConfiguredTaskAwaitableUnderlyingTaskField extends SyntheticTaskField {
|
||||
SyntheticConfiguredTaskAwaitableUnderlyingTaskField() {
|
||||
this = "m_task_configured_task_awaitable"
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Threading.Tasks.Task<>`. */
|
||||
private class SystemThreadingTasksTaskTFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* The default C# QL library.
|
||||
*/
|
||||
|
||||
import Customizations
|
||||
import semmle.code.csharp.Attribute
|
||||
import semmle.code.csharp.Callable
|
||||
import semmle.code.csharp.Comments
|
||||
import semmle.code.csharp.Element
|
||||
import semmle.code.csharp.Event
|
||||
import semmle.code.csharp.File
|
||||
import semmle.code.csharp.Generics
|
||||
import semmle.code.csharp.Location
|
||||
import semmle.code.csharp.Member
|
||||
import semmle.code.csharp.Namespace
|
||||
import semmle.code.csharp.AnnotatedType
|
||||
import semmle.code.csharp.Property
|
||||
import semmle.code.csharp.Stmt
|
||||
import semmle.code.csharp.Type
|
||||
import semmle.code.csharp.Using
|
||||
import semmle.code.csharp.Variable
|
||||
import semmle.code.csharp.XML
|
||||
import semmle.code.csharp.Preprocessor
|
||||
import semmle.code.csharp.exprs.Access
|
||||
import semmle.code.csharp.exprs.ArithmeticOperation
|
||||
import semmle.code.csharp.exprs.Assignment
|
||||
import semmle.code.csharp.exprs.BitwiseOperation
|
||||
import semmle.code.csharp.exprs.Call
|
||||
import semmle.code.csharp.exprs.ComparisonOperation
|
||||
import semmle.code.csharp.exprs.Creation
|
||||
import semmle.code.csharp.exprs.Dynamic
|
||||
import semmle.code.csharp.exprs.Expr
|
||||
import semmle.code.csharp.exprs.Literal
|
||||
import semmle.code.csharp.exprs.LogicalOperation
|
||||
import semmle.code.csharp.controlflow.ControlFlowGraph
|
||||
import semmle.code.csharp.dataflow.DataFlow
|
||||
import semmle.code.csharp.dataflow.TaintTracking
|
||||
import semmle.code.csharp.dataflow.SSA
|
||||
|
||||
/** Whether the source was extracted without a build command. */
|
||||
predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) }
|
||||
@@ -43,8 +43,15 @@ class Element extends @dotnet_element {
|
||||
|
||||
/**
|
||||
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
|
||||
*
|
||||
* If no primary class can be determined, the result is `"???"`.
|
||||
*/
|
||||
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
|
||||
final string getPrimaryQlClasses() {
|
||||
result = strictconcat(this.getAPrimaryQlClass(), ",")
|
||||
or
|
||||
not exists(this.getAPrimaryQlClass()) and
|
||||
result = "???"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of a primary CodeQL class to which this element belongs.
|
||||
@@ -53,11 +60,12 @@ class Element extends @dotnet_element {
|
||||
* which they belong; for example, `AddExpr` is a primary class, but
|
||||
* `BinaryOperation` is not.
|
||||
*
|
||||
* This predicate always has a result. If no primary class can be
|
||||
* determined, the result is `"???"`. If multiple primary classes match,
|
||||
* this predicate can have multiple results.
|
||||
* If no primary classes match, this predicate has no result. If multiple
|
||||
* primary classes match, this predicate can have multiple results.
|
||||
*
|
||||
* See also `getPrimaryQlClasses`, which is better to use in most cases.
|
||||
*/
|
||||
string getAPrimaryQlClass() { result = "???" }
|
||||
string getAPrimaryQlClass() { none() }
|
||||
}
|
||||
|
||||
/** An element that has a name. */
|
||||
|
||||
@@ -39,6 +39,8 @@ class Namespace extends Declaration, @namespace {
|
||||
final override string getName() { namespaces(this, result) }
|
||||
|
||||
final override string getUndecoratedName() { namespaces(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Namespace" }
|
||||
}
|
||||
|
||||
/** The global namespace. */
|
||||
|
||||
@@ -89,4 +89,6 @@ class ArrayType extends ValueOrRefType, @dotnet_array_type {
|
||||
final override string getLabel() { result = this.getElementType().getLabel() + "[]" }
|
||||
|
||||
override string toStringWithTypes() { result = this.getElementType().toStringWithTypes() + "[]" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArrayType" }
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user