Merge branch 'main' into post-release-prep/codeql-cli-2.7.5

This commit is contained in:
Andrew Eisenberg
2022-01-14 08:23:43 -08:00
744 changed files with 39341 additions and 19067 deletions

View File

@@ -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
1 package sink source summary sink:code sink:html sink:remote sink:sql sink:xss source:local summary:taint summary:value
2 Dapper 55 55
3 Microsoft.ApplicationBlocks.Data 28 28
4 Microsoft.Extensions.Primitives 54 54
5 Microsoft.VisualBasic 4 4
6 MySql.Data.MySqlClient 48 48
7 Newtonsoft.Json 91 73 18

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
## 1.0.0

View File

@@ -0,0 +1 @@
## 1.0.0

View File

@@ -0,0 +1,4 @@
---
dependencies: {}
compiled: false
lockVersion: 1.0.0

View File

@@ -0,0 +1,2 @@
---
lastReleaseVersion: 1.0.1

View 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

View 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.

View File

@@ -0,0 +1 @@
## 1.0.0

View File

@@ -0,0 +1 @@
## 0.0.6

View File

@@ -0,0 +1 @@
## 1.0.0

View File

@@ -0,0 +1,2 @@
---
lastReleaseVersion: 1.0.1

View File

@@ -0,0 +1,4 @@
---
dependencies: {}
compiled: false
lockVersion: 1.0.0

View 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

View File

@@ -0,0 +1 @@
ModifiedFnvFunctionDetection.ql

View File

@@ -0,0 +1 @@
NumberOfKnownCommandsAboveThreshold.ql

View File

@@ -0,0 +1 @@
NumberOfKnownHashesAboveThreshold.ql

View File

@@ -0,0 +1 @@
NumberOfKnownLiteralsAboveThreshold.ql

View File

@@ -0,0 +1 @@
NumberOfKnownMethodNamesAboveThreshold.ql

View File

@@ -0,0 +1 @@
SwallowEverythingExceptionHandler.ql

View File

@@ -0,0 +1 @@
## 0.0.7

View File

@@ -0,0 +1,4 @@
---
dependencies: {}
compiled: false
lockVersion: 1.0.0

View 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: .

View 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())
}

View 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()
}

View File

@@ -0,0 +1,6 @@
import csharp
query predicate missingPrimaryQlClass(Element e) {
not exists(e.getAPrimaryQlClass()) and
e.fromSource()
}

View File

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

View File

@@ -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.

View File

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

View File

@@ -4,5 +4,4 @@ groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp
library: true
dependencies:
codeql/csharp-upgrades: ^0.0.3
upgrades: upgrades

View File

@@ -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), _)
)
}
}

View File

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

View File

@@ -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" }
}
/**

View File

@@ -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" }
}

View File

@@ -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" }
}
/**

View File

@@ -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" }
}
/**

View File

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

View File

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

View File

@@ -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), _)
)
}
}

View File

@@ -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."
)
}
}

View File

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

View File

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

View File

@@ -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

View File

@@ -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), _)
)
}
}

View File

@@ -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.

View File

@@ -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), _)
)
}
}

View File

@@ -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)
}
/**

View File

@@ -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)
}
/**

View File

@@ -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)
}
/**

View File

@@ -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)
}
/**

View File

@@ -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)
}
/**

View File

@@ -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" }
}
/**

View File

@@ -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. */

View File

@@ -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",
]
}
}

View File

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

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

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

View File

@@ -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. */

View File

@@ -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. */

View File

@@ -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