Merge branch 'main' into changedocs/2.19.0

This commit is contained in:
Florin Coada
2024-09-19 15:16:49 +01:00
committed by GitHub
2990 changed files with 84990 additions and 31867 deletions

View File

@@ -3,6 +3,7 @@ on:
push:
paths:
- "go/**"
- "shared/**"
- .github/workflows/go-tests.yml
- .github/actions/**
- codeql-workspace.yml
@@ -12,6 +13,7 @@ on:
pull_request:
paths:
- "go/**"
- "shared/**"
- .github/workflows/go-tests.yml
- .github/actions/**
- codeql-workspace.yml

View File

@@ -15,7 +15,7 @@ repos:
- id: clang-format
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v1.6.0
rev: v2.0.4
hooks:
- id: autopep8
files: ^misc/codegen/.*\.py

98
Cargo.lock generated
View File

@@ -96,6 +96,16 @@ version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8"
[[package]]
name = "argfile"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a1cc0ba69de57db40674c66f7cf2caee3981ddef084388482c95c0e2133e5e8"
dependencies = [
"fs-err",
"os_str_bytes",
]
[[package]]
name = "arrayvec"
version = "0.7.6"
@@ -255,7 +265,7 @@ dependencies = [
"chalk-ir",
"ena",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"petgraph",
"rustc-hash",
"tracing",
@@ -360,9 +370,11 @@ name = "codeql-rust"
version = "0.1.0"
dependencies = [
"anyhow",
"argfile",
"clap",
"codeql-extractor",
"figment",
"itertools 0.13.0",
"log",
"num-traits",
"ra_ap_base_db",
@@ -370,10 +382,12 @@ dependencies = [
"ra_ap_hir_def",
"ra_ap_ide_db",
"ra_ap_load-cargo",
"ra_ap_parser",
"ra_ap_paths",
"ra_ap_project_model",
"ra_ap_syntax",
"ra_ap_vfs",
"rust-extractor-macros",
"serde",
"serde_with",
"stderrlog",
@@ -643,6 +657,15 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "fs-err"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
dependencies = [
"autocfg",
]
[[package]]
name = "fsevent-sys"
version = "4.1.0"
@@ -658,6 +681,16 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
[[package]]
name = "generate-schema"
version = "0.1.0"
dependencies = [
"itertools 0.10.5",
"proc-macro2",
"quote",
"ungrammar",
]
[[package]]
name = "getrandom"
version = "0.2.15"
@@ -827,6 +860,15 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.12.1"
@@ -836,6 +878,15 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
@@ -1064,6 +1115,15 @@ version = "11.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
[[package]]
name = "os_str_bytes"
version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ac44c994af577c799b1b4bd80dc214701e349873ad894d6cdf96f4f7526e0b9"
dependencies = [
"memchr",
]
[[package]]
name = "overload"
version = "0.1.1"
@@ -1303,7 +1363,7 @@ checksum = "c7c38520eb4770af561c34b908431f4e548c3282093cf3daf3c6e566d99a2937"
dependencies = [
"arrayvec",
"either",
"itertools",
"itertools 0.12.1",
"ra_ap_base_db",
"ra_ap_cfg",
"ra_ap_hir_def",
@@ -1335,7 +1395,7 @@ dependencies = [
"fst",
"hashbrown 0.14.5",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"la-arena",
"ra-ap-rustc_abi",
"ra-ap-rustc_parse_format",
@@ -1365,7 +1425,7 @@ dependencies = [
"cov-mark",
"either",
"hashbrown 0.14.5",
"itertools",
"itertools 0.12.1",
"la-arena",
"ra_ap_base_db",
"ra_ap_cfg",
@@ -1400,7 +1460,7 @@ dependencies = [
"either",
"ena",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"la-arena",
"nohash-hasher",
"oorandom",
@@ -1437,7 +1497,7 @@ dependencies = [
"either",
"fst",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"line-index",
"memchr",
"nohash-hasher",
@@ -1483,7 +1543,7 @@ checksum = "82e6f24b61f1ef1f3a756493d1fb7e711b69b2e4d5f4746fcb959313dfd41471"
dependencies = [
"anyhow",
"crossbeam-channel",
"itertools",
"itertools 0.12.1",
"ra_ap_hir_expand",
"ra_ap_ide_db",
"ra_ap_intern",
@@ -1578,7 +1638,7 @@ checksum = "db83d1844c74b22c110c4b8e8f2519be2b1723964008527281a11c3398749756"
dependencies = [
"anyhow",
"cargo_metadata",
"itertools",
"itertools 0.12.1",
"la-arena",
"ra_ap_base_db",
"ra_ap_cfg",
@@ -1602,7 +1662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "370b302873eeafd07ccc6a714fc9395cae11e385955ccb78081093ee3b86f94e"
dependencies = [
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"lock_api",
"oorandom",
"parking_lot",
@@ -1649,7 +1709,7 @@ checksum = "bb63ff9d6b11b4553fc0835f16705975258905e3b1230fcf1ddbf24c46aff69d"
dependencies = [
"always-assert",
"crossbeam-channel",
"itertools",
"itertools 0.12.1",
"jod-thread",
"libc",
"miow",
@@ -1665,7 +1725,7 @@ dependencies = [
"cov-mark",
"either",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"ra-ap-rustc_lexer",
"ra_ap_parser",
"ra_ap_stdx",
@@ -1699,7 +1759,7 @@ version = "0.0.232"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cb72ee1901baec556f4f2ef77e287d749ac0e973f063990672d6207b076aeac"
dependencies = [
"itertools",
"itertools 0.12.1",
"text-size",
]
@@ -1875,6 +1935,14 @@ dependencies = [
"text-size",
]
[[package]]
name = "rust-extractor-macros"
version = "0.1.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
@@ -2287,6 +2355,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "ungrammar"
version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
[[package]]
name = "unicode-ident"
version = "1.0.13"

View File

@@ -6,6 +6,8 @@ members = [
"shared/tree-sitter-extractor",
"ruby/extractor",
"rust/extractor",
"rust/extractor/macros",
"rust/generate-schema",
]
[patch.crates-io]

View File

@@ -60,6 +60,8 @@ r.from_cargo(
"//:Cargo.toml",
"//ruby/extractor:Cargo.toml",
"//rust/extractor:Cargo.toml",
"//rust/extractor/macros:Cargo.toml",
"//rust/generate-schema:Cargo.toml",
"//shared/tree-sitter-extractor:Cargo.toml",
],
)

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 2.0.0
version: 2.0.1-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.2.3
version: 1.2.4-dev
groups:
- cpp
- queries

View File

@@ -3,20 +3,20 @@ failures
edges
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:10 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:2 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:2 Sink:MaD:6 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:2 Sink:MaD:6 |
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:10 |
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | MaD:644 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:7:10:7:18 | call to ymlSource | provenance | Src:MaD:642 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:643 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:643 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:13:18:13:18 | x | provenance | |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:13:10:13:16 | call to ymlStep | provenance | |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:643 |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:643 |
| test.cpp:13:18:13:18 | x | test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | provenance | |
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | MaD:644 |
nodes

1
csharp/.gitignore vendored
View File

@@ -11,7 +11,6 @@ csharp.log
*.tlog
.vs
*.user
.vscode/launch.json
extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
paket-files/

65
csharp/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,65 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "C#: Standalone Debug",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "dotnet: build",
"program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Standalone/bin/Debug/net8.0/Semmle.Extraction.CSharp.Standalone.dll",
"args": [],
// Set the path to the folder that should be extracted:
"cwd": "${workspaceFolder}/ql/test/library-tests/standalone/standalonemode",
"env": {
"CODEQL_THREADS": "1",
"CODEQL_EXTRACTOR_CSHARP_OPTION_LOGGING_VERBOSITY": "progress+++",
"CODEQL_EXTRACTOR_CSHARP_OPTION_TRAP_COMPRESSION": "NONE",
},
"stopAtEntry": true,
"console": "internalConsole",
"justMyCode": false,
"symbolOptions": {
"searchPaths": [],
"searchMicrosoftSymbolServer": true,
"searchNuGetOrgSymbolServer": true
},
"sourceLinkOptions": {
"*": {
"enabled": true
}
},
"suppressJITOptimizations": true
},
{
"name": "C#: Autobuild Debug",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "dotnet: build",
"program": "${workspaceFolder}/autobuilder/Semmle.Autobuild.CSharp/bin/Debug/net8.0/Semmle.Autobuild.CSharp.dll",
// Set the path to the folder that should be extracted:
"cwd": "${workspaceFolder}/ql/integration-tests/all-platforms/autobuild",
"stopAtEntry": true,
"args": [],
"env": {
// The below folders need to exist before debugging
"CODEQL_EXTRACTOR_CSHARP_TRAP_DIR": "${workspaceFolder}/ql/integration-tests/DB",
"CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR": "${workspaceFolder}/ql/integration-tests/DB",
"CODEQL_EXTRACTOR_CSHARP_DIAGNOSTIC_DIR": "${workspaceFolder}/ql/integration-tests/DB",
"CODEQL_EXTRACTOR_CSHARP_SCRATCH_DIR": "${workspaceFolder}/ql/integration-tests/DB",
}
},
{
"name": "C#: Binary Log Debug",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "dotnet: build",
"program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Driver/bin/Debug/net8.0/Semmle.Extraction.CSharp.Driver.dll",
"stopAtEntry": true,
"args": [
"--binlog",
"${workspaceFolder}/ql/integration-tests/all-platforms/binlog/test.binlog"
],
"env": {}
},
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add `cil` and `dotnet` related relations and types.
compatibility: backwards

View File

@@ -144,50 +144,5 @@ namespace Semmle.Extraction.CSharp.Entities
public override bool NeedsPopulation => Context.Defines(Symbol);
public Extraction.Entities.Location Location => Context.CreateLocation(ReportingLocation);
protected void PopulateMetadataHandle(TextWriter trapFile)
{
var handle = MetadataHandle;
if (handle.HasValue)
trapFile.metadata_handle(this, Location, MetadataTokens.GetToken(handle.Value));
}
private static System.Reflection.PropertyInfo? GetPropertyInfo(object o, string name)
{
return o.GetType().GetProperty(name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetProperty);
}
public Handle? MetadataHandle
{
get
{
var handleProp = GetPropertyInfo(Symbol, "Handle");
object handleObj = Symbol;
if (handleProp is null)
{
var underlyingSymbolProp = GetPropertyInfo(Symbol, "UnderlyingSymbol");
if (underlyingSymbolProp?.GetValue(Symbol) is object underlying)
{
handleProp = GetPropertyInfo(underlying, "Handle");
handleObj = underlying;
}
}
if (handleProp is not null)
{
switch (handleProp.GetValue(handleObj))
{
case MethodDefinitionHandle md: return md;
case TypeDefinitionHandle td: return td;
case PropertyDefinitionHandle pd: return pd;
case FieldDefinitionHandle fd: return fd;
}
}
return null;
}
}
}
}

View File

@@ -26,7 +26,6 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
PopulateMetadataHandle(trapFile);
PopulateAttributes();
ContainingType!.PopulateGenerics();
PopulateNullability(trapFile, Symbol.GetAnnotatedType());

View File

@@ -51,6 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
PopulateAttributes();
PopulateModifiers(trapFile);
BindComments();

View File

@@ -360,7 +360,6 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateParameters();
PopulateMethodBody(trapFile);
PopulateGenerics(trapFile);
PopulateMetadataHandle(trapFile);
PopulateNullability(trapFile, Symbol.GetAnnotatedReturnType());
}

View File

@@ -34,7 +34,6 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
PopulateMetadataHandle(trapFile);
PopulateAttributes();
PopulateModifiers(trapFile);
BindComments();

View File

@@ -77,7 +77,6 @@ namespace Semmle.Extraction.CSharp.Entities
protected void PopulateType(TextWriter trapFile, bool constructUnderlyingTupleType = false)
{
PopulateMetadataHandle(trapFile);
PopulateAttributes();
trapFile.Write("types(");

View File

@@ -233,9 +233,6 @@ namespace Semmle.Extraction.CSharp
internal static void localvars(this TextWriter trapFile, LocalVariable key, VariableKind kind, string name, int @var, Type type, Expression expr) =>
trapFile.WriteTuple("localvars", key, (int)kind, name, @var, type, expr);
public static void metadata_handle(this TextWriter trapFile, IEntity entity, Location assembly, int handleValue) =>
trapFile.WriteTuple("metadata_handle", entity, assembly, handleValue);
internal static void method_location(this TextWriter trapFile, Method method, Location location) =>
trapFile.WriteTuple("method_location", method, location);

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.7.25
version: 1.7.26-dev
groups:
- csharp
- solorigate

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.7.25
version: 1.7.26-dev
groups:
- csharp
- solorigate

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* C#: Remove all CIL tables and related QL library functionality.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* C#: Add extractor support for attributes on indexers.

View File

@@ -1,5 +0,0 @@
/**
* The default QL library for modeling the Common Intermediate Language (CIL).
*/
import semmle.code.cil.CIL as CIL

View File

@@ -1,5 +0,0 @@
/**
* The default QL library for modeling .NET definitions for both C# and CIL code.
*/
deprecated import semmle.code.dotnet.DotNet as DotNet

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 2.0.0
version: 2.0.1-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -1,98 +0,0 @@
/**
* Provides classes for accesses.
*
* An access is any read or write of a variable.
*/
private import CIL
/** An instruction that accesses a variable. */
deprecated class Access extends Instruction, @cil_access {
/** Gets the declaration referenced by this instruction. */
Variable getTarget() { cil_access(this, result) }
}
/**
* An instruction that accesses a variable.
* This class is provided for consistency with the C# data model.
*/
deprecated class VariableAccess extends Access, @cil_access { }
/** An instruction that reads a variable. */
deprecated class ReadAccess extends VariableAccess, Expr, @cil_read_access {
override Type getType() { result = this.getTarget().getType() }
}
/** An instruction yielding an address. */
deprecated class ReadRef extends Expr, @cil_read_ref { }
/** An instruction that reads the address of a variable. */
deprecated class ReadRefAccess extends ReadAccess, ReadRef { }
/** An instruction that writes a variable. */
deprecated class WriteAccess extends VariableAccess, @cil_write_access {
/** Gets the expression whose value is used in this variable write. */
Expr getExpr() { none() }
}
/** An instruction that accesses a parameter. */
deprecated class ParameterAccess extends StackVariableAccess, @cil_arg_access {
override MethodParameter getTarget() { result = StackVariableAccess.super.getTarget() }
}
/** An instruction that reads a parameter. */
deprecated class ParameterReadAccess extends ParameterAccess, ReadAccess {
override int getPopCount() { result = 0 }
}
/** An instruction that writes to a parameter. */
deprecated class ParameterWriteAccess extends ParameterAccess, WriteAccess {
override int getPopCount() { result = 1 }
override Expr getExpr() { result = this.getOperand(0) }
}
/** An access to the `this` parameter. */
deprecated class ThisAccess extends ParameterReadAccess {
ThisAccess() { this.getTarget() instanceof ThisParameter }
}
/** An instruction that accesses a stack variable. */
deprecated class StackVariableAccess extends VariableAccess, @cil_stack_access {
override StackVariable getTarget() { result = VariableAccess.super.getTarget() }
}
/** An instruction that accesses a local variable. */
deprecated class LocalVariableAccess extends StackVariableAccess, @cil_local_access {
override LocalVariable getTarget() { result = StackVariableAccess.super.getTarget() }
}
/** An instruction that writes to a local variable. */
deprecated class LocalVariableWriteAccess extends LocalVariableAccess, WriteAccess {
override int getPopCount() { result = 1 }
override Expr getExpr() { result = this.getOperand(0) }
override string getExtra() { result = "L" + this.getTarget().getIndex() }
}
/** An instruction that reads a local variable. */
deprecated class LocalVariableReadAccess extends LocalVariableAccess, ReadAccess {
override int getPopCount() { result = 0 }
}
/** An instruction that accesses a field. */
deprecated class FieldAccess extends VariableAccess, @cil_field_access {
override Field getTarget() { result = VariableAccess.super.getTarget() }
override string getExtra() { result = this.getTarget().getName() }
/** Gets the qualifier of the access, if any. */
abstract Expr getQualifier();
}
/** An instruction that reads a field. */
abstract deprecated class FieldReadAccess extends FieldAccess, ReadAccess { }
/** An instruction that writes a field. */
abstract deprecated class FieldWriteAccess extends FieldAccess, WriteAccess { }

View File

@@ -1,45 +0,0 @@
/** Provides the `Attribute` class. */
private import CIL
private import semmle.code.csharp.Location as CS
/** An attribute to a declaration, such as a method, field, type or parameter. */
deprecated class Attribute extends Element, @cil_attribute {
/** Gets the declaration this attribute is attached to. */
Declaration getDeclaration() { cil_attribute(this, result, _) }
/** Gets the constructor used to construct this attribute. */
Method getConstructor() { cil_attribute(this, _, result) }
/** Gets the type of this attribute. */
Type getType() { result = this.getConstructor().getDeclaringType() }
override string toString() { result = "[" + this.getType().getName() + "(...)]" }
/** Gets the value of the `i`th argument of this attribute. */
string getArgument(int i) { cil_attribute_positional_argument(this, i, result) }
/** Gets the value of the named argument `name`. */
string getNamedArgument(string name) { cil_attribute_named_argument(this, name, result) }
/** Gets an argument of this attribute, if any. */
string getAnArgument() { result = this.getArgument(_) or result = this.getNamedArgument(_) }
override CS::Location getLocation() { result = this.getDeclaration().getLocation() }
}
/** A generic attribute to a declaration. */
deprecated class GenericAttribute extends Attribute {
private ConstructedType type;
GenericAttribute() { type = this.getType() }
/** Gets the total number of type arguments. */
int getNumberOfTypeArguments() { result = count(int i | cil_type_argument(type, i, _)) }
/** Gets the `i`th type argument, if any. */
Type getTypeArgument(int i) { result = type.getTypeArgument(i) }
/** Get a type argument. */
Type getATypeArgument() { result = this.getTypeArgument(_) }
}

View File

@@ -1,401 +0,0 @@
/**
* Provides classes representing basic blocks.
*/
private import CIL
/**
* A basic block, that is, a maximal straight-line sequence of control flow nodes
* without branches or joins.
*/
deprecated class BasicBlock extends Cached::TBasicBlockStart {
/** Gets an immediate successor of this basic block, if any. */
BasicBlock getASuccessor() { result.getFirstNode() = this.getLastNode().getASuccessor() }
/** Gets an immediate predecessor of this basic block, if any. */
BasicBlock getAPredecessor() { result.getASuccessor() = this }
/**
* Gets an immediate `true` successor, if any.
*
* An immediate `true` successor is a successor that is reached when
* the condition that ends this basic block evaluates to `true`.
*
* Example:
*
* ```csharp
* if (x < 0)
* x = -x;
* ```
*
* The basic block on line 2 is an immediate `true` successor of the
* basic block on line 1.
*/
BasicBlock getATrueSuccessor() { result.getFirstNode() = this.getLastNode().getTrueSuccessor() }
/**
* Gets an immediate `false` successor, if any.
*
* An immediate `false` successor is a successor that is reached when
* the condition that ends this basic block evaluates to `false`.
*
* Example:
*
* ```csharp
* if (!(x >= 0))
* x = -x;
* ```
*
* The basic block on line 2 is an immediate `false` successor of the
* basic block on line 1.
*/
BasicBlock getAFalseSuccessor() { result.getFirstNode() = this.getLastNode().getFalseSuccessor() }
/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
ControlFlowNode getNode(int pos) { Cached::bbIndex(this.getFirstNode(), result, pos) }
/** Gets a control flow node in this basic block. */
ControlFlowNode getANode() { result = this.getNode(_) }
/** Gets the first control flow node in this basic block. */
ControlFlowNode getFirstNode() { this = Cached::TBasicBlockStart(result) }
/** Gets the last control flow node in this basic block. */
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
/** Gets the length of this basic block. */
int length() { result = strictcount(this.getANode()) }
/**
* Holds if this basic block strictly dominates basic block `bb`.
*
* That is, all paths reaching basic block `bb` from some entry point
* basic block must go through this basic block (which must be different
* from `bb`).
*
* Example:
*
* ```csharp
* int M(string s) {
* if (s == null)
* throw new ArgumentNullException(nameof(s));
* return s.Length;
* }
* ```
*
* The basic block starting on line 2 strictly dominates the
* basic block on line 4 (all paths from the entry point of `M`
* to `return s.Length;` must go through the null check).
*/
predicate strictlyDominates(BasicBlock bb) { bbIDominates+(this, bb) }
/**
* Holds if this basic block dominates basic block `bb`.
*
* That is, all paths reaching basic block `bb` from some entry point
* basic block must go through this basic block.
*
* Example:
*
* ```csharp
* int M(string s) {
* if (s == null)
* throw new ArgumentNullException(nameof(s));
* return s.Length;
* }
* ```
*
* The basic block starting on line 2 dominates the basic
* block on line 4 (all paths from the entry point of `M` to
* `return s.Length;` must go through the null check).
*
* This predicate is *reflexive*, so for example `if (s == null)` dominates
* itself.
*/
predicate dominates(BasicBlock bb) {
bb = this or
this.strictlyDominates(bb)
}
/**
* Holds if `df` is in the dominance frontier of this basic block.
* That is, this basic block dominates a predecessor of `df`, but
* does not dominate `df` itself.
*
* Example:
*
* ```csharp
* if (x < 0) {
* x = -x;
* if (x > 10)
* x--;
* }
* Console.Write(x);
* ```
*
* The basic block on line 6 is in the dominance frontier
* of the basic block starting on line 2 because that block
* dominates the basic block on line 4, which is a predecessor of
* `Console.Write(x);`. Also, the basic block starting on line 2
* does not dominate the basic block on line 6.
*/
predicate inDominanceFrontier(BasicBlock df) {
this.dominatesPredecessor(df) and
not this.strictlyDominates(df)
}
/**
* Holds if this basic block dominates a predecessor of `df`.
*/
private predicate dominatesPredecessor(BasicBlock df) { this.dominates(df.getAPredecessor()) }
/**
* Gets the basic block that immediately dominates this basic block, if any.
*
* That is, all paths reaching this basic block from some entry point
* basic block must go through the result, which is an immediate basic block
* predecessor of this basic block.
*
* Example:
*
* ```csharp
* int M(string s) {
* if (s == null)
* throw new ArgumentNullException(nameof(s));
* return s.Length;
* }
* ```
*
* The basic block starting on line 2 is an immediate dominator of
* the basic block online 4 (all paths from the entry point of `M`
* to `return s.Length;` must go through the null check, and the null check
* is an immediate predecessor of `return s.Length;`).
*/
BasicBlock getImmediateDominator() { bbIDominates(result, this) }
/**
* Holds if this basic block strictly post-dominates basic block `bb`.
*
* That is, all paths reaching an exit point basic block from basic
* block `bb` must go through this basic block (which must be different
* from `bb`).
*
* Example:
*
* ```csharp
* int M(string s) {
* try {
* return s.Length;
* }
* finally {
* Console.WriteLine("M");
* }
* }
* ```
*
* The basic block on line 6 strictly post-dominates the basic block on
* line 3 (all paths to the exit point of `M` from `return s.Length;`
* must go through the `WriteLine` call).
*/
predicate strictlyPostDominates(BasicBlock bb) { bbIPostDominates+(this, bb) }
/**
* Holds if this basic block post-dominates basic block `bb`.
*
* That is, all paths reaching an exit point basic block from basic
* block `bb` must go through this basic block.
*
* Example:
*
* ```csharp
* int M(string s) {
* try {
* return s.Length;
* }
* finally {
* Console.WriteLine("M");
* }
* }
* ```
*
* The basic block on line 6 post-dominates the basic block on line 3
* (all paths to the exit point of `M` from `return s.Length;` must go
* through the `WriteLine` call).
*
* This predicate is *reflexive*, so for example `Console.WriteLine("M");`
* post-dominates itself.
*/
predicate postDominates(BasicBlock bb) {
this.strictlyPostDominates(bb) or
this = bb
}
/**
* Holds if this basic block is in a loop in the control flow graph. This
* includes loops created by `goto` statements. This predicate may not hold
* even if this basic block is syntactically inside a `while` loop if the
* necessary back edges are unreachable.
*/
predicate inLoop() { this.getASuccessor+() = this }
/** Gets a textual representation of this basic block. */
string toString() { result = this.getFirstNode().toString() }
/** Gets the location of this basic block. */
Location getLocation() { result = this.getFirstNode().getLocation() }
}
/**
* Internal implementation details.
*/
cached
deprecated private module Cached {
/** Internal representation of basic blocks. */
cached
newtype TBasicBlock = TBasicBlockStart(ControlFlowNode cfn) { startsBB(cfn) }
/** Holds if `cfn` starts a new basic block. */
private predicate startsBB(ControlFlowNode cfn) {
not exists(cfn.getAPredecessor()) and exists(cfn.getASuccessor())
or
cfn.isJoin()
or
cfn.getAPredecessor().isBranch()
}
/**
* Holds if `succ` is a control flow successor of `pred` within
* the same basic block.
*/
private predicate intraBBSucc(ControlFlowNode pred, ControlFlowNode succ) {
succ = pred.getASuccessor() and
not startsBB(succ)
}
/**
* Holds if `cfn` is the `i`th node in basic block `bb`.
*
* In other words, `i` is the shortest distance from a node `bb`
* that starts a basic block to `cfn` along the `intraBBSucc` relation.
*/
cached
predicate bbIndex(ControlFlowNode bbStart, ControlFlowNode cfn, int i) =
shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfn, i)
}
/**
* Holds if the first node of basic block `succ` is a control flow
* successor of the last node of basic block `pred`.
*/
deprecated private predicate succBB(BasicBlock pred, BasicBlock succ) {
succ = pred.getASuccessor()
}
/** Holds if `dom` is an immediate dominator of `bb`. */
deprecated predicate bbIDominates(BasicBlock dom, BasicBlock bb) =
idominance(entryBB/1, succBB/2)(_, dom, bb)
/** Holds if `pred` is a basic block predecessor of `succ`. */
deprecated private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) }
/** Holds if `dom` is an immediate post-dominator of `bb`. */
deprecated predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
idominance(exitBB/1, predBB/2)(_, dom, bb)
/**
* An entry basic block, that is, a basic block whose first node is
* the entry node of a callable.
*/
deprecated class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
}
/** Holds if `bb` is an entry basic block. */
deprecated private predicate entryBB(BasicBlock bb) {
bb.getFirstNode() instanceof MethodImplementation
}
/**
* An exit basic block, that is, a basic block whose last node is
* an exit node.
*/
deprecated class ExitBasicBlock extends BasicBlock {
ExitBasicBlock() { exitBB(this) }
}
/** Holds if `bb` is an exit basic block. */
deprecated private predicate exitBB(BasicBlock bb) { not exists(bb.getLastNode().getASuccessor()) }
/**
* A basic block with more than one predecessor.
*/
deprecated class JoinBlock extends BasicBlock {
JoinBlock() { this.getFirstNode().isJoin() }
}
/** A basic block that terminates in a condition, splitting the subsequent control flow. */
deprecated class ConditionBlock extends BasicBlock {
ConditionBlock() {
exists(BasicBlock succ |
succ = this.getATrueSuccessor()
or
succ = this.getAFalseSuccessor()
)
}
/**
* Holds if basic block `controlled` is controlled by this basic block with
* Boolean value `testIsTrue`. That is, `controlled` can only be reached from
* the callable entry point by going via the true edge (`testIsTrue = true`)
* or false edge (`testIsTrue = false`) out of this basic block.
*/
predicate controls(BasicBlock controlled, boolean testIsTrue) {
/*
* For this block to control the block `controlled` with `testIsTrue` the following must be true:
* Execution must have passed through the test i.e. `this` must strictly dominate `controlled`.
* Execution must have passed through the `testIsTrue` edge leaving `this`.
*
* Although "passed through the true edge" implies that `this.getATrueSuccessor()` dominates `controlled`,
* the reverse is not true, as flow may have passed through another edge to get to `this.getATrueSuccessor()`
* so we need to assert that `this.getATrueSuccessor()` dominates `controlled` *and* that
* all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`.
*
* For example, in the following C# snippet:
* ```csharp
* if (x)
* controlled;
* false_successor;
* uncontrolled;
* ```
* `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`)
* or dominated by itself. Whereas in the following code:
* ```csharp
* if (x)
* while (controlled)
* also_controlled;
* false_successor;
* uncontrolled;
* ```
* the block `while controlled` is controlled because all of its predecessors are `this` (`if (x)`)
* or (in the case of `also_controlled`) dominated by itself.
*
* The additional constraint on the predecessors of the test successor implies
* that `this` strictly dominates `controlled` so that isn't necessary to check
* directly.
*/
exists(BasicBlock succ |
this.isCandidateSuccessor(succ, testIsTrue) and
succ.dominates(controlled)
)
}
private predicate isCandidateSuccessor(BasicBlock succ, boolean testIsTrue) {
(
testIsTrue = true and succ = this.getATrueSuccessor()
or
testIsTrue = false and succ = this.getAFalseSuccessor()
) and
forall(BasicBlock pred | pred = succ.getAPredecessor() and pred != this | succ.dominates(pred))
}
}

View File

@@ -1,23 +0,0 @@
/** Provides the core CIL data model. */
import semmle.code.csharp.Location
import Element
import Instruction
import Instructions
import Access
import Variable
import Declaration
import Generics
import Type
import Types
import Method
import InstructionGroups
import BasicBlock
import Handler
import ControlFlow
import DataFlow
import Attribute
import Stubs
import CustomModifierReceiver
import Parameterizable
import semmle.code.cil.Ssa

View File

@@ -1,74 +0,0 @@
/**
* Provides predicates for analysing the return values of callables.
*/
private import CIL
cached
private module Cached {
/** Holds if method `m` always returns null. */
cached
deprecated predicate alwaysNullMethod(Method m) {
forex(Expr e | m.canReturn(e) | alwaysNullExpr(e))
}
/** Holds if method `m` always returns non-null. */
cached
deprecated predicate alwaysNotNullMethod(Method m) {
forex(Expr e | m.canReturn(e) | alwaysNotNullExpr(e))
}
/** Holds if method `m` always throws an exception. */
cached
deprecated predicate alwaysThrowsMethod(Method m) {
m.hasBody() and
not exists(m.getImplementation().getAnInstruction().(Return))
}
/** Holds if method `m` always throws an exception of type `t`. */
cached
deprecated predicate alwaysThrowsException(Method m, Type t) {
alwaysThrowsMethod(m) and
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExceptionType())
}
}
import Cached
pragma[noinline]
deprecated private predicate alwaysNullVariableUpdate(VariableUpdate vu) {
forex(Expr src | src = vu.getSource() | alwaysNullExpr(src))
}
/** Holds if expression `expr` always evaluates to `null`. */
deprecated private predicate alwaysNullExpr(Expr expr) {
expr instanceof NullLiteral
or
alwaysNullMethod(expr.(StaticCall).getTarget())
or
forex(Ssa::Definition def |
expr = any(Ssa::Definition def0 | def = def0.getAnUltimateDefinition()).getARead()
|
alwaysNullVariableUpdate(def.getVariableUpdate())
)
}
pragma[noinline]
deprecated private predicate alwaysNotNullVariableUpdate(VariableUpdate vu) {
forex(Expr src | src = vu.getSource() | alwaysNotNullExpr(src))
}
/** Holds if expression `expr` always evaluates to non-null. */
deprecated private predicate alwaysNotNullExpr(Expr expr) {
expr instanceof Opcodes::NewObj
or
expr instanceof Literal and not expr instanceof NullLiteral
or
alwaysNotNullMethod(expr.(StaticCall).getTarget())
or
forex(Ssa::Definition def |
expr = any(Ssa::Definition def0 | def = def0.getAnUltimateDefinition()).getARead()
|
alwaysNotNullVariableUpdate(def.getVariableUpdate())
)
}

View File

@@ -1,787 +0,0 @@
/**
* Provides checks for the consistency of the data model and database.
*/
private import CIL
private import csharp as CS
private import semmle.code.csharp.commons.QualifiedName
private newtype ConsistencyCheck =
MissingEntityCheck() or
deprecated TypeCheck(Type t) or
deprecated CfgCheck(ControlFlowNode n) or
deprecated DeclarationCheck(Declaration d) or
MissingCSharpCheck(CS::Declaration d)
/**
* A consistency violation in the database or data model.
*/
abstract deprecated class ConsistencyViolation extends ConsistencyCheck {
abstract string toString();
abstract string getMessage();
}
/**
* A check that is deliberately disabled.
*/
abstract deprecated class DisabledCheck extends ConsistencyViolation {
DisabledCheck() { none() }
}
/**
* A consistency violation on a control flow node.
*/
abstract deprecated class CfgViolation extends ConsistencyViolation, CfgCheck {
ControlFlowNode node;
CfgViolation() { this = CfgCheck(node) }
override string toString() { result = node.toString() }
}
/**
* A consistency violation in a specific instruction.
*/
abstract deprecated class InstructionViolation extends CfgViolation, CfgCheck {
Instruction instruction;
InstructionViolation() { this = CfgCheck(instruction) }
private string getInstructionsUpTo() {
result =
concat(Instruction i |
i.getIndex() <= instruction.getIndex() and
i.getImplementation() = instruction.getImplementation()
|
i.toString() + " [push: " + i.getPushCount() + ", pop: " + i.getPopCount() + "]", "; "
order by
i.getIndex()
)
}
override string toString() {
result =
instruction.getImplementation().getMethod().toStringWithTypes() + ": " +
instruction.toString() + ", " + this.getInstructionsUpTo()
}
}
/**
* A literal that does not have exactly one `getValue()`.
*/
deprecated class MissingValue extends InstructionViolation {
MissingValue() { exists(Literal l | l = instruction | count(l.getValue()) != 1) }
override string getMessage() { result = "Literal has invalid getValue()" }
}
/**
* A call that does not have exactly one `getTarget()`.
*/
deprecated class MissingCallTarget extends InstructionViolation {
MissingCallTarget() {
exists(Call c | c = instruction |
count(c.getTarget()) != 1 and not c instanceof Opcodes::Calli
or
count(c.(Opcodes::Calli).getTargetType()) != 1 and c instanceof Opcodes::Calli
)
}
override string getMessage() { result = "Call has invalid target" }
}
/**
* An instruction that has not been assigned a specific QL class.
*/
deprecated class MissingOpCode extends InstructionViolation {
MissingOpCode() { not exists(instruction.getOpcodeName()) }
override string getMessage() {
result = "Opcode " + instruction.getOpcode() + " is missing a QL class"
}
override string toString() {
result = "Unknown instruction in " + instruction.getImplementation().getMethod().toString()
}
}
/**
* An instruction that is missing an operand. It means that there is no instruction which pushes
* a value onto the stack for this instruction to pop.
*
* If this fails, it means that the `getPopCount`/`getPushCount`/control flow graph has failed.
* It could also mean that the target of a call has failed and has not determined the
* correct number of arguments.
*/
deprecated class MissingOperand extends InstructionViolation {
MissingOperand() {
exists(int op | op in [0 .. instruction.getPopCount() - 1] |
not exists(instruction.getOperand(op)) and not instruction instanceof DeadInstruction
)
}
int getMissingOperand() {
result in [0 .. instruction.getPopCount() - 1] and
not exists(instruction.getOperand(result))
}
override string getMessage() {
result = "This instruction is missing operand " + this.getMissingOperand()
}
}
/**
* A dead instruction, not reachable from any entry point.
* These should not exist, however it turns out that the Mono compiler sometimes
* emits them.
*/
deprecated class DeadInstruction extends Instruction {
DeadInstruction() { not exists(EntryPoint e | e.getASuccessor+() = this) }
}
/**
* An instruction that is not reachable from any entry point.
*
* If this fails, it means that the calculation of the call graph is incorrect.
* Disabled, because Mono compiler sometimes emits dead instructions.
*/
deprecated class DeadInstructionViolation extends InstructionViolation, DisabledCheck {
DeadInstructionViolation() { instruction instanceof DeadInstruction }
override string getMessage() { result = "This instruction is not reachable" }
}
deprecated class YesNoBranch extends ConditionalBranch {
YesNoBranch() { not this instanceof Opcodes::Switch }
}
/**
* A branch instruction that does not have exactly 2 successors.
*/
deprecated class InvalidBranchSuccessors extends InstructionViolation {
InvalidBranchSuccessors() {
// Mono compiler sometimes generates branches to the next instruction, which is just wrong.
// However it is valid CIL.
exists(YesNoBranch i | i = instruction | not count(i.getASuccessor()) in [1 .. 2])
}
override string getMessage() {
result = "Conditional branch has " + count(instruction.getASuccessor()) + " successors"
}
}
/**
* An instruction that has a true/false successor but is not a branch.
*/
deprecated class OnlyYesNoBranchHasTrueFalseSuccessors extends InstructionViolation {
OnlyYesNoBranchHasTrueFalseSuccessors() {
(exists(instruction.getTrueSuccessor()) or exists(instruction.getFalseSuccessor())) and
not instruction instanceof YesNoBranch
}
override string getMessage() { result = "This instruction has getTrue/FalseSuccessor()" }
}
/**
* An unconditional branch instruction that has more than one successor.
*/
deprecated class UnconditionalBranchSuccessors extends InstructionViolation {
UnconditionalBranchSuccessors() {
exists(UnconditionalBranch i | i = instruction | count(i.getASuccessor()) != 1)
}
override string getMessage() {
result = "Unconditional branch has " + count(instruction.getASuccessor()) + " successors"
}
}
/**
* A branch instruction that does not have a true successor.
*/
deprecated class NoTrueSuccessor extends InstructionViolation {
NoTrueSuccessor() { exists(YesNoBranch i | i = instruction | not exists(i.getTrueSuccessor())) }
override string getMessage() { result = "Missing a true successor" }
}
/**
* A branch instruction that does not have a false successor.
*/
deprecated class NoFalseSuccessor extends InstructionViolation {
NoFalseSuccessor() { exists(YesNoBranch i | i = instruction | not exists(i.getFalseSuccessor())) }
override string getMessage() { result = "Missing a false successor" }
}
/**
* An instruction whose true successor is not a successor.
*/
deprecated class TrueSuccessorIsSuccessor extends InstructionViolation {
TrueSuccessorIsSuccessor() {
exists(instruction.getTrueSuccessor()) and
not instruction.getTrueSuccessor() = instruction.getASuccessor()
}
override string getMessage() { result = "True successor isn't a successor" }
}
/**
* An instruction whose false successor is not a successor.
*/
deprecated class FalseSuccessorIsSuccessor extends InstructionViolation {
FalseSuccessorIsSuccessor() {
exists(instruction.getFalseSuccessor()) and
not instruction.getFalseSuccessor() = instruction.getASuccessor()
}
override string getMessage() { result = "True successor isn't a successor" }
}
/**
* An access that does not have exactly one target.
*/
deprecated class AccessMissingTarget extends InstructionViolation {
AccessMissingTarget() { exists(Access i | i = instruction | count(i.getTarget()) != 1) }
override string getMessage() { result = "Access has invalid getTarget()" }
}
/**
* A catch handler that doesn't have a caught exception type.
*/
deprecated class CatchHandlerMissingType extends CfgViolation {
CatchHandlerMissingType() { exists(CatchHandler h | h = node | not exists(h.getCaughtType())) }
override string getMessage() { result = "Catch handler missing caught type" }
}
/**
* A CFG node that does not have a stack size.
*/
deprecated class MissingStackSize extends CfgViolation {
MissingStackSize() {
(
not exists(node.getStackSizeAfter()) or
not exists(node.getStackSizeBefore())
) and
not node instanceof DeadInstruction
}
override string getMessage() { result = "Inconsistent stack size" }
}
/**
* A CFG node that does not have exactly one stack size.
* Disabled because inconsistent stack sizes have been observed.
*/
deprecated class InvalidStackSize extends CfgViolation, DisabledCheck {
InvalidStackSize() {
(
count(node.getStackSizeAfter()) != 1 or
count(node.getStackSizeBefore()) != 1
) and
not node instanceof DeadInstruction
}
override string getMessage() {
result =
"Inconsistent stack sizes " + count(node.getStackSizeBefore()) + " before and " +
count(node.getStackSizeAfter()) + " after"
}
}
/**
* A CFG node that does not have exactly 1 `getPopCount()`.
*/
deprecated class InconsistentPopCount extends CfgViolation {
InconsistentPopCount() { count(node.getPopCount()) != 1 }
override string getMessage() {
result = "Cfg node has " + count(node.getPopCount()) + " pop counts"
}
}
/**
* A CFG node that does not have exactly one `getPushCount()`.
*/
deprecated class InconsistentPushCount extends CfgViolation {
InconsistentPushCount() { count(node.getPushCount()) != 1 }
override string getMessage() {
result = "Cfg node has " + count(node.getPushCount()) + " push counts"
}
}
/**
* A return instruction that does not have a stack size of 0 after it.
*/
deprecated class InvalidReturn extends InstructionViolation {
InvalidReturn() { instruction instanceof Return and instruction.getStackSizeAfter() != 0 }
override string getMessage() { result = "Return has invalid stack size" }
}
/**
* A throw instruction that does not have a stack size of 0 after it.
*/
deprecated class InvalidThrow extends InstructionViolation, DisabledCheck {
InvalidThrow() { instruction instanceof Throw and instruction.getStackSizeAfter() != 0 }
override string getMessage() {
result = "Throw has invalid stack size: " + instruction.getStackSizeAfter()
}
}
/**
* A field access where the field is "static" but the instruction is "instance".
*/
deprecated class StaticFieldTarget extends InstructionViolation {
StaticFieldTarget() {
exists(FieldAccess i | i = instruction |
(i instanceof Opcodes::Stfld or i instanceof Opcodes::Stfld) and
i.getTarget().isStatic()
)
}
override string getMessage() { result = "Inconsistent static field" }
}
/**
* A branch without a target.
*/
deprecated class BranchWithoutTarget extends InstructionViolation {
BranchWithoutTarget() {
instruction = any(Branch b | not exists(b.getTarget()) and not b instanceof Opcodes::Switch)
}
override string getMessage() { result = "Branch without target" }
}
/**
* A consistency violation in a type.
*/
deprecated class TypeViolation extends ConsistencyViolation, TypeCheck {
/** Gets the type containing the violation. */
Type getType() { this = TypeCheck(result) }
override string toString() { result = this.getType().toString() }
abstract override string getMessage();
}
/**
* A type that has both type arguments and type parameters.
*/
deprecated class TypeIsBothConstructedAndUnbound extends TypeViolation {
TypeIsBothConstructedAndUnbound() {
this.getType() instanceof ConstructedGeneric and this.getType() instanceof UnboundGeneric
}
override string getMessage() { result = "Type is both constructed and unbound" }
}
/**
* The location of a constructed generic type should be the same
* as the location of its unbound generic type.
*/
deprecated class InconsistentTypeLocation extends TypeViolation {
InconsistentTypeLocation() {
this.getType().getLocation() != this.getType().getUnboundDeclaration().getLocation()
}
override string getMessage() { result = "Inconsistent constructed type location" }
}
/**
* A constructed type that does not match its unbound generic type.
*/
deprecated class TypeParameterMismatch extends TypeViolation {
TypeParameterMismatch() {
this.getType().(ConstructedGeneric).getNumberOfTypeArguments() !=
this.getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters()
}
override string getMessage() {
result =
"Constructed type (" + this.getType().toStringWithTypes() + ") has " +
this.getType().(ConstructedGeneric).getNumberOfTypeArguments() +
" type arguments and unbound type (" + this.getType().getUnboundType().toStringWithTypes() +
") has " + this.getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() +
" type parameters"
}
}
/**
* A consistency violation in a method.
*/
deprecated class MethodViolation extends ConsistencyViolation, DeclarationCheck {
/** Gets the method containing the violation. */
Method getMethod() { this = DeclarationCheck(result) }
override string toString() { result = this.getMethod().toString() }
override string getMessage() { none() }
}
/**
* The location of a constructed method should be equal to the
* location of its unbound generic.
*/
deprecated class InconsistentMethodLocation extends MethodViolation {
InconsistentMethodLocation() {
this.getMethod().getLocation() != this.getMethod().getUnboundDeclaration().getLocation()
}
override string getMessage() { result = "Inconsistent constructed method location" }
}
/**
* A constructed method that does not match its unbound method.
*/
deprecated class ConstructedMethodTypeParams extends MethodViolation {
ConstructedMethodTypeParams() {
this.getMethod().(ConstructedGeneric).getNumberOfTypeArguments() !=
this.getMethod().getUnboundDeclaration().(UnboundGeneric).getNumberOfTypeParameters()
}
override string getMessage() {
result =
"The constructed method " + this.getMethod().toStringWithTypes() +
" does not match unbound method " +
this.getMethod().getUnboundDeclaration().toStringWithTypes()
}
}
/**
* A violation marking an entity that should be present but is not.
*/
abstract deprecated class MissingEntityViolation extends ConsistencyViolation, MissingEntityCheck {
override string toString() { result = "Missing entity" }
}
/**
* The type `object` is missing from the database.
*/
deprecated class MissingObjectViolation extends MissingEntityViolation {
MissingObjectViolation() {
exists(this) and
not exists(ObjectType o)
}
override string getMessage() { result = "Object missing" }
}
/**
* An override that is invalid because the overridden method is not in a base class.
*/
deprecated class InvalidOverride extends MethodViolation {
private Method base;
InvalidOverride() {
base = this.getMethod().getOverriddenMethod() and
not this.getMethod().getDeclaringType().getABaseType+() = base.getDeclaringType() and
base.getDeclaringType().isUnboundDeclaration() // Bases classes of constructed types aren't extracted properly.
}
override string getMessage() {
exists(string qualifier, string type |
base.getDeclaringType().hasFullyQualifiedName(qualifier, type)
|
result =
"Overridden method from " + getQualifiedName(qualifier, type) + " is not in a base type"
)
}
}
/**
* A pointer type that does not have a pointee type.
*/
deprecated class InvalidPointerType extends TypeViolation {
InvalidPointerType() {
exists(PointerType p | p = this.getType() | count(p.getReferentType()) != 1)
}
override string getMessage() { result = "Invalid Pointertype.getPointeeType()" }
}
/**
* An array with an invalid `getElementType`.
*/
deprecated class ArrayTypeMissingElement extends TypeViolation {
ArrayTypeMissingElement() {
exists(ArrayType t | t = this.getType() | count(t.getElementType()) != 1)
}
override string getMessage() { result = "Invalid ArrayType.getElementType()" }
}
/**
* An array with an invalid `getRank`.
*/
deprecated class ArrayTypeInvalidRank extends TypeViolation {
ArrayTypeInvalidRank() { exists(ArrayType t | t = this.getType() | not t.getRank() > 0) }
override string getMessage() { result = "Invalid ArrayType.getRank()" }
}
/**
* A type should have at most one kind, except for missing referenced types
* where the interface/class is unknown.
*/
deprecated class KindViolation extends TypeViolation {
KindViolation() {
count(typeKind(this.getType())) != 1 and
exists(this.getType().getLocation())
}
override string getMessage() {
result = "Invalid kinds on type: " + concat(typeKind(this.getType()), " ")
}
}
/**
* The type of a kind must be consistent between a constructed generic and its
* unbound generic.
*/
deprecated class InconsistentKind extends TypeViolation {
InconsistentKind() {
typeKind(this.getType()) != typeKind(this.getType().getUnboundDeclaration())
}
override string getMessage() { result = "Inconsistent type kind of source declaration" }
}
deprecated private string typeKind(Type t) {
t instanceof Interface and result = "interface"
or
t instanceof Class and result = "class"
or
t instanceof TypeParameter and result = "type parameter"
or
t instanceof ArrayType and result = "array"
or
t instanceof PointerType and result = "pointer"
}
/**
* A violation in a `Member`.
*/
abstract deprecated class DeclarationViolation extends ConsistencyViolation, DeclarationCheck {
abstract override string getMessage();
/** Gets the member containing the potential violation. */
Declaration getDeclaration() { this = DeclarationCheck(result) }
override string toString() { result = this.getDeclaration().toString() }
}
/**
* Properties that have no accessors.
*/
deprecated class PropertyWithNoAccessors extends DeclarationViolation {
PropertyWithNoAccessors() {
exists(Property p | p = this.getDeclaration() | not exists(p.getAnAccessor()))
}
override string getMessage() { result = "Property has no accessors" }
}
/**
* An expression that have an unexpected push count.
*/
deprecated class ExprPushCount extends InstructionViolation {
ExprPushCount() {
instruction instanceof Expr and
not instruction instanceof Opcodes::Dup and
if instruction instanceof Call
then not instruction.getPushCount() in [0 .. 1]
else instruction.(Expr).getPushCount() != 1
}
override string getMessage() {
result = "Instruction has unexpected push count " + instruction.getPushCount()
}
}
/**
* An expression that does not have exactly one type.
* Note that calls with no return have type `System.Void`.
*/
deprecated class ExprMissingType extends InstructionViolation {
ExprMissingType() {
// Don't have types for the following op codes:
not instruction instanceof Opcodes::Ldftn and
not instruction instanceof Opcodes::Localloc and
not instruction instanceof Opcodes::Ldvirtftn and
not instruction instanceof Opcodes::Arglist and
not instruction instanceof Opcodes::Refanytype and
instruction.getPushCount() >= 1 and
count(instruction.getType()) != 1 and
// OS specific (osx) specific inconsistency
not instruction
.getImplementation()
.getMethod()
.hasFullyQualifiedName("System.Runtime.InteropServices.RuntimeInformation",
"get_OSDescription")
}
override string getMessage() { result = "Expression is missing getType()" }
}
/**
* An instruction that has a push count of 0, yet is still used as an operand
*/
deprecated class InvalidExpressionViolation extends InstructionViolation {
InvalidExpressionViolation() {
instruction.getPushCount() = 0 and
exists(Instruction expr | instruction = expr.getAnOperand())
}
override string getMessage() {
result = "This instruction is used as an operand but pushes no values"
}
}
/**
* A type that has multiple entities with the same qualified name in `System`.
* .NET Core does sometimes duplicate types, so this check is disabled.
*/
deprecated class TypeMultiplyDefined extends TypeViolation, DisabledCheck {
TypeMultiplyDefined() {
this.getType().getParent().getName() = "System" and
not this.getType() instanceof ConstructedGeneric and
not this.getType() instanceof ArrayType and
this.getType().isPublic() and
count(Type t |
not t instanceof ConstructedGeneric and
t.toStringWithTypes() = this.getType().toStringWithTypes()
) != 1
}
override string getMessage() {
result =
"This type (" + this.getType().toStringWithTypes() + ") has " +
count(Type t |
not t instanceof ConstructedGeneric and
t.toStringWithTypes() = this.getType().toStringWithTypes()
) + " entities"
}
}
/**
* A C# declaration which is expected to have a corresponding CIL declaration, but for some reason does not.
*/
deprecated class MissingCilDeclaration extends ConsistencyViolation, MissingCSharpCheck {
MissingCilDeclaration() {
exists(CS::Declaration decl | this = MissingCSharpCheck(decl) |
expectedCilDeclaration(decl) and
not exists(Declaration d | decl = d.getCSharpDeclaration())
)
}
CS::Declaration getDeclaration() { this = MissingCSharpCheck(result) }
override string getMessage() {
result =
"Cannot locate CIL for " + this.getDeclaration().toStringWithTypes() + " of class " +
this.getDeclaration().getPrimaryQlClasses()
}
override string toString() { result = this.getDeclaration().toStringWithTypes() }
}
/**
* Holds if the C# declaration is expected to have a CIl declaration.
*/
deprecated private predicate expectedCilDeclaration(CS::Declaration decl) {
decl = decl.getUnboundDeclaration() and
not decl instanceof CS::ArrayType and
decl.getALocation() instanceof CS::Assembly and
not decl.(CS::Modifiable).isInternal() and
not decl.(CS::Constructor).getNumberOfParameters() = 0 and // These are sometimes implicit
not decl.(CS::Method).getReturnType() instanceof CS::UnknownType and
not exists(CS::Parameter p | p = decl.(CS::Parameterizable).getAParameter() |
not expectedCilDeclaration(p)
) and
not decl instanceof CS::AnonymousClass and
(decl instanceof CS::Parameter implies expectedCilDeclaration(decl.(CS::Parameter).getType())) and
(decl instanceof CS::Parameter implies expectedCilDeclaration(decl.getParent())) and
(decl instanceof CS::Member implies expectedCilDeclaration(decl.getParent())) and
(
decl instanceof CS::Field
or
decl instanceof CS::Property
or
decl instanceof CS::ValueOrRefType
or
decl instanceof CS::Event
or
decl instanceof CS::Constructor
or
decl instanceof CS::Destructor
or
decl instanceof CS::Operator
or
decl instanceof CS::Method
or
decl instanceof CS::Parameter
)
}
/** A member with an invalid name. */
deprecated class MemberWithInvalidName extends DeclarationViolation {
MemberWithInvalidName() {
exists(string name | name = this.getDeclaration().(Member).getName() |
exists(name.indexOf(".")) and
not name = ".ctor" and
not name = ".cctor"
)
}
override string getMessage() {
result = "Invalid name " + this.getDeclaration().(Member).getName()
}
}
deprecated class ConstructedSourceDeclarationMethod extends MethodViolation {
Method method;
ConstructedSourceDeclarationMethod() {
method = this.getMethod() and
method = method.getUnboundDeclaration() and
(
method instanceof ConstructedGeneric or
method.getDeclaringType() instanceof ConstructedGeneric
)
}
override string getMessage() {
result = "Source declaration " + method.toStringWithTypes() + " is constructed"
}
}
/** A declaration with multiple labels. */
deprecated class DeclarationWithMultipleLabels extends DeclarationViolation {
DeclarationWithMultipleLabels() {
exists(Declaration d | this = DeclarationCheck(d) | strictcount(d.getLabel()) > 1)
}
override string getMessage() {
result = "Multiple labels " + concat(this.getDeclaration().getLabel(), ", ")
}
}
/** A declaration without a label. */
deprecated class DeclarationWithoutLabel extends DeclarationViolation {
DeclarationWithoutLabel() {
exists(Declaration d | this = DeclarationCheck(d) |
d.isUnboundDeclaration() and
not d instanceof TypeParameter and
not exists(d.getLabel()) and
(d instanceof Callable or d instanceof Type)
)
}
override string getMessage() { result = "No label" }
}

View File

@@ -1,179 +0,0 @@
/**
* Provides classes for control flow.
*/
private import CIL
/** A node in the control flow graph. */
deprecated class ControlFlowNode extends @cil_controlflow_node {
/** Gets a textual representation of this control flow node. */
string toString() { none() }
/** Gets the location of this control flow node. */
Location getLocation() { none() }
/**
* Gets the number of items this node pushes onto the stack.
* This value is either 0 or 1, except for the instruction `dup`
* which pushes 2 values onto the stack.
*/
int getPushCount() { result = 0 }
/** Gets the number of items this node pops from the stack. */
int getPopCount() { result = 0 }
/** Gets a successor of this node, if any. */
final Instruction getASuccessor() { result = this.getASuccessorType(_) }
/** Gets a true successor of this node, if any. */
final Instruction getTrueSuccessor() { result = this.getASuccessorType(any(TrueFlow f)) }
/** Gets a false successor of this node, if any. */
final Instruction getFalseSuccessor() { result = this.getASuccessorType(any(FalseFlow f)) }
/** Gets a successor to this node, of type `type`, if any. */
cached
Instruction getASuccessorType(FlowType t) { none() }
/** Gets a predecessor of this node, if any. */
ControlFlowNode getAPredecessor() { result.getASuccessor() = this }
/**
* Gets an instruction that supplies the `i`th operand to this instruction.
* Note that this can be multi-valued.
*/
cached
ControlFlowNode getOperand(int i) {
// Immediate predecessor pushes the operand
i in [0 .. this.getPopCount() - 1] and
result = this.getAPredecessor() and
i < result.getPushCount()
or
// Transitive predecessor pushes the operand
exists(ControlFlowNode mid, int pushes | this.getOperandRec(mid, i, pushes) |
pushes - mid.getStackDelta() < result.getPushCount() and
result = mid.getAPredecessor()
)
}
/**
* Gets the type of the `i`th operand. Unlike `getOperand(i).getType()`, this
* predicate takes into account when there are multiple possible operands with
* different types.
*/
Type getOperandType(int i) {
strictcount(this.getOperand(i)) = 1 and
result = this.getOperand(i).getType()
or
strictcount(this.getOperand(i)) = 2 and
exists(ControlFlowNode op1, ControlFlowNode op2, Type t2 |
op1 = this.getOperand(i) and
op2 = this.getOperand(i) and
op1 != op2 and
result = op1.getType() and
t2 = op2.getType()
|
result = t2
or
result.(PrimitiveType).getUnderlyingType().getConversionIndex() >
t2.(PrimitiveType).getUnderlyingType().getConversionIndex()
or
op2 instanceof NullLiteral
)
}
/** Gets an operand of this instruction, if any. */
ControlFlowNode getAnOperand() { result = this.getOperand(_) }
/** Gets an expression that consumes the output of this instruction on the stack. */
Instruction getParentExpr() { this = result.getAnOperand() }
/**
* Holds if `pred` is a transitive predecessor of this instruction, this
* instruction pops operand `i`, `pushes` additional pushes are required
* for operand `i` at node `pred`, and no instruction between (and including)
* `pred` and this instruction is a push for operand `i`.
*/
private predicate getOperandRec(ControlFlowNode pred, int i, int pushes) {
// Invariant: no node is a push for operand `i`
pushes >= pred.getPushCount() and
(
i in [0 .. this.getPopCount() - 1] and
pred = this.getAPredecessor() and
pushes = i
or
exists(ControlFlowNode mid, int pushes0 | this.getOperandRec(mid, i, pushes0) |
pushes = pushes0 - mid.getStackDelta() and
// This is a guard to prevent ill formed programs
// and other logic errors going into an infinite loop.
pushes <= this.getImplementation().getStackSize() and
pred = mid.getAPredecessor()
)
)
}
private int getStackDelta() { result = this.getPushCount() - this.getPopCount() }
/** Gets the stack size before this instruction. */
int getStackSizeBefore() { result = this.getAPredecessor().getStackSizeAfter() }
/** Gets the stack size after this instruction. */
final int getStackSizeAfter() {
// This is a guard to prevent ill formed programs
// and other logic errors going into an infinite loop.
result in [0 .. this.getImplementation().getStackSize()] and
result = this.getStackSizeBefore() + this.getStackDelta()
}
/** Gets the method containing this control flow node. */
MethodImplementation getImplementation() { none() }
/**
* Gets the type of the item pushed onto the stack, if any.
*
* If called via `ControlFlowNode::getOperand(i).getType()`, consider using
* `ControlFlowNode::getOperandType(i)` instead.
*/
cached
Type getType() { none() }
/** Holds if this control flow node has more than one predecessor. */
predicate isJoin() { strictcount(this.getAPredecessor()) > 1 }
/** Holds if this control flow node has more than one successor. */
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
}
/**
* A control flow entry point. Either a method (`MethodImplementation`) or a handler (`Handler`).
*
* Handlers are control flow nodes because they push the handled exception onto the stack.
*/
deprecated class EntryPoint extends ControlFlowNode, @cil_entry_point {
override int getStackSizeBefore() { result = 0 }
}
deprecated private newtype TFlowType =
TNormalFlow() or
TTrueFlow() or
TFalseFlow()
/** A type of control flow. Either normal flow (`NormalFlow`), true flow (`TrueFlow`) or false flow (`FalseFlow`). */
abstract deprecated class FlowType extends TFlowType {
abstract string toString();
}
/** Normal control flow. */
deprecated class NormalFlow extends FlowType, TNormalFlow {
override string toString() { result = "" }
}
/** True control flow. */
deprecated class TrueFlow extends FlowType, TTrueFlow {
override string toString() { result = "true" }
}
/** False control flow. */
deprecated class FalseFlow extends FlowType, TFalseFlow {
override string toString() { result = "false" }
}

View File

@@ -1,21 +0,0 @@
/**
* Provides a class to represent `modopt` and `modreq` declarations.
*/
private import CIL
private import dotnet
/**
* A class to represent entities that can receive custom modifiers. Custom modifiers can be attached to
* - the type of a `Field`,
* - the return type of a `Method` or `Property`,
* - the type of parameters.
* A `CustomModifierReceiver` is therefore either a `Field`, `Property`, `Method`, or `Parameter`.
*/
deprecated class CustomModifierReceiver extends Declaration, @cil_custom_modifier_receiver {
/** Holds if this targeted type has `modifier` applied as `modreq`. */
predicate hasRequiredCustomModifier(Type modifier) { cil_custom_modifiers(this, modifier, 1) }
/** Holds if this targeted type has `modifier` applied as `modopt`. */
predicate hasOptionalCustomModifier(Type modifier) { cil_custom_modifiers(this, modifier, 0) }
}

View File

@@ -1,69 +0,0 @@
/**
* Provides a collection of building blocks and utilities for data flow.
*/
private import CIL
/**
* A node in the data flow graph.
*
* Either an instruction (`Instruction`), a method return (`Method`), or a variable (`Variable`).
*/
deprecated class DataFlowNode extends @cil_dataflow_node {
/** Gets a textual representation of this data flow node. */
abstract string toString();
/** Gets the type of this data flow node. */
Type getType() { none() }
/** Gets the method that contains this dataflow node. */
Method getMethod() { none() }
/** Gets the location of this dataflow node. */
Location getLocation() { none() }
}
/** A node that updates a variable. */
abstract deprecated class VariableUpdate extends DataFlowNode {
/** Gets the value assigned, if any. */
abstract DataFlowNode getSource();
/** Gets the variable that is updated. */
abstract Variable getVariable();
/** Holds if this variable update happens at index `i` in basic block `bb`. */
abstract predicate updatesAt(BasicBlock bb, int i);
}
deprecated private class MethodParameterDef extends VariableUpdate, MethodParameter {
override MethodParameter getSource() { result = this }
override MethodParameter getVariable() { result = this }
override predicate updatesAt(BasicBlock bb, int i) {
bb.(EntryBasicBlock).getANode().getImplementation().getMethod() = this.getMethod() and
i = -1
}
}
deprecated private class VariableWrite extends VariableUpdate, WriteAccess {
override Expr getSource() { result = this.getExpr() }
override Variable getVariable() { result = this.getTarget() }
override predicate updatesAt(BasicBlock bb, int i) { this = bb.getNode(i) }
}
deprecated private class MethodOutOrRefTarget extends VariableUpdate, Call {
int parameterIndex;
MethodOutOrRefTarget() { this.getTarget().getRawParameter(parameterIndex).hasOutFlag() }
override Variable getVariable() {
result = this.getRawArgument(parameterIndex).(ReadAccess).getTarget()
}
override Expr getSource() { none() }
override predicate updatesAt(BasicBlock bb, int i) { this = bb.getNode(i) }
}

View File

@@ -1,148 +0,0 @@
/**
* Provides classes for declarations and members.
*/
import CIL
private import dotnet
private import semmle.code.csharp.Member as CS
private import semmle.code.csharp.commons.QualifiedName
/**
* A declaration. Either a member (`Member`) or a variable (`Variable`).
*/
deprecated class Declaration extends DotNet::Declaration, Element, @cil_declaration {
/** Gets an attribute (for example `[Obsolete]`) of this declaration, if any. */
Attribute getAnAttribute() { result.getDeclaration() = this }
/**
* Gets the C# declaration corresponding to this CIL declaration, if any.
* Note that this is only for source/unconstructed declarations.
*/
CS::Declaration getCSharpDeclaration() {
result = toCSharpNonTypeParameter(this) or
result = toCSharpTypeParameter(this)
}
override Declaration getUnboundDeclaration() { result = this }
deprecated override predicate hasQualifiedName(string qualifier, string name) {
exists(string dqualifier, string dname |
this.getDeclaringType().hasQualifiedName(dqualifier, dname) and
qualifier = getQualifiedName(dqualifier, dname)
) and
name = this.getName()
}
override predicate hasFullyQualifiedName(string qualifier, string name) {
exists(string dqualifier, string dname |
this.getDeclaringType().hasFullyQualifiedName(dqualifier, dname) and
qualifier = getQualifiedName(dqualifier, dname)
) and
name = this.getName()
}
}
deprecated private CS::Declaration toCSharpNonTypeParameter(Declaration d) {
result.(DotNet::Declaration).matchesHandle(d)
}
deprecated private CS::TypeParameter toCSharpTypeParameter(TypeParameter tp) {
toCSharpTypeParameterJoin(tp, result.getIndex(), result.getGeneric())
}
pragma[nomagic]
deprecated private predicate toCSharpTypeParameterJoin(
TypeParameter tp, int i, CS::UnboundGeneric ug
) {
exists(TypeContainer tc |
tp.getIndex() = i and
tc = tp.getGeneric() and
ug = toCSharpNonTypeParameter(tc)
)
}
/**
* A member of a type. Either a type (`Type`), a method (`Method`), a property (`Property`), or an event (`Event`).
*/
deprecated class Member extends DotNet::Member, Declaration, @cil_member {
override predicate isPublic() { cil_public(this) }
override predicate isProtected() { cil_protected(this) }
override predicate isPrivate() { cil_private(this) }
override predicate isInternal() { cil_internal(this) }
override predicate isSealed() { cil_sealed(this) }
override predicate isAbstract() { cil_abstract(this) }
override predicate isStatic() { cil_static(this) }
/** Holds if this member has a security attribute. */
predicate hasSecurity() { cil_security(this) }
override Location getLocation() { result = this.getDeclaringType().getLocation() }
}
/** A property. */
deprecated class Property extends DotNet::Property, Member, CustomModifierReceiver, @cil_property {
override string getName() { cil_property(this, _, result, _) }
/** Gets the type of this property. */
override Type getType() { cil_property(this, _, _, result) }
override ValueOrRefType getDeclaringType() { cil_property(this, result, _, _) }
/** Gets the getter of this property, if any. */
override Getter getGetter() { this = result.getProperty() }
/** Gets the setter of this property, if any. */
override Setter getSetter() { this = result.getProperty() }
/** Gets an accessor of this property. */
Accessor getAnAccessor() { result = this.getGetter() or result = this.getSetter() }
override string toString() { result = "property " + this.getName() }
override string toStringWithTypes() {
result =
this.getType().toStringWithTypes() + " " + this.getDeclaringType().toStringWithTypes() + "." +
this.getName()
}
}
/** A property that is trivial (wraps a field). */
deprecated class TrivialProperty extends Property {
TrivialProperty() {
this.getGetter().(TrivialGetter).getField() = this.getSetter().(TrivialSetter).getField()
}
/** Gets the underlying field of this property. */
Field getField() { result = this.getGetter().(TrivialGetter).getField() }
}
/** An event. */
deprecated class Event extends DotNet::Event, Member, @cil_event {
override string getName() { cil_event(this, _, result, _) }
/** Gets the type of this event. */
Type getType() { cil_event(this, _, _, result) }
override ValueOrRefType getDeclaringType() { cil_event(this, result, _, _) }
/** Gets the add event accessor. */
Method getAddEventAccessor() { cil_adder(this, result) }
/** Gets the remove event accessor. */
Method getRemoveEventAccessor() { cil_remover(this, result) }
/** Gets the raiser. */
Method getRaiser() { cil_raiser(this, result) }
override string toString() { result = "event " + this.getName() }
override string toStringWithTypes() {
result = this.getDeclaringType().toStringWithTypes() + "." + this.getName()
}
}

View File

@@ -1,15 +0,0 @@
/** Provides the `Element` class, the base class of all CIL program elements. */
private import dotnet
import semmle.code.csharp.Location
/** An element. */
deprecated class Element extends DotNet::Element, @cil_element {
override Location getLocation() { result = bestLocation(this) }
}
cached
deprecated private Location bestLocation(Element e) {
result = e.getALocation() and
(e.getALocation().getFile().isPdbSourceFile() implies result.getFile().isPdbSourceFile())
}

View File

@@ -1,59 +0,0 @@
/** Provides classes for generic types and methods. */
private import CIL
private import dotnet
/**
* A generic declaration. Either an unbound generic (`UnboundGeneric`) or a
* constructed generic (`ConstructedGeneric`).
*/
deprecated class Generic extends DotNet::Generic, Declaration, TypeContainer {
Generic() {
cil_type_parameter(this, _, _) or
cil_type_argument(this, _, _)
}
}
/** An unbound generic type or method. */
deprecated class UnboundGeneric extends Generic, DotNet::UnboundGeneric {
UnboundGeneric() { cil_type_parameter(this, _, _) }
final override TypeParameter getTypeParameter(int n) { cil_type_parameter(this, n, result) }
}
/** A constructed generic type or method. */
deprecated class ConstructedGeneric extends Generic, DotNet::ConstructedGeneric {
ConstructedGeneric() { cil_type_argument(this, _, _) }
final override Type getTypeArgument(int n) { cil_type_argument(this, n, result) }
}
/** Gets the concatenation of the `getName()` of type arguments. */
language[monotonicAggregates]
deprecated private string getTypeArgumentsNames(ConstructedGeneric cg) {
result = strictconcat(Type t, int i | t = cg.getTypeArgument(i) | t.getName(), "," order by i)
}
/** An unbound generic type. */
deprecated class UnboundGenericType extends UnboundGeneric, Type { }
/** An unbound generic method. */
deprecated class UnboundGenericMethod extends UnboundGeneric, Method { }
/** A constructed generic type. */
deprecated class ConstructedType extends ConstructedGeneric, Type {
final override UnboundGenericType getUnboundGeneric() { result = this.getUnboundType() }
override predicate isInterface() { this.getUnboundType().isInterface() }
override predicate isClass() { this.getUnboundType().isClass() }
final override string getName() {
result = this.getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">"
}
}
/** A constructed generic method. */
deprecated class ConstructedMethod extends ConstructedGeneric, Method {
final override UnboundGenericMethod getUnboundGeneric() { result = this.getUnboundMethod() }
}

View File

@@ -1,83 +0,0 @@
/**
* Provides classes for different types of handler.
*/
private import CIL
/**
* A handler is a piece of code that can be executed out of sequence, for example
* when an instruction generates an exception or leaves a `finally` block.
*
* Each handler has a scope representing the block of instructions guarded by
* this handler (corresponding to a C# `try { ... }` block), and a block of instructions
* to execute when the handler is triggered (corresponding to a `catch` or `finally` block).
*
* Handlers are entry points (`EntryPoint`) so that they can
* provide values on the stack, for example the value of the current exception. This is why
* some handlers have a push count of 1.
*
* Either a finally handler (`FinallyHandler`), filter handler (`FilterHandler`),
* catch handler (`CatchHandler`), or a fault handler (`FaultHandler`).
*/
deprecated class Handler extends Element, EntryPoint, @cil_handler {
override MethodImplementation getImplementation() { cil_handler(this, result, _, _, _, _, _) }
/** Gets the 0-based index of this handler. Handlers are evaluated in this sequence. */
int getIndex() { cil_handler(this, _, result, _, _, _, _) }
/** Gets the first instruction in the `try` block of this handler. */
Instruction getTryStart() { cil_handler(this, _, _, _, result, _, _) }
/** Gets the last instruction in the `try` block of this handler. */
Instruction getTryEnd() { cil_handler(this, _, _, _, _, result, _) }
/** Gets the first instruction in the `catch`/`finally` block. */
Instruction getHandlerStart() { cil_handler(this, _, _, _, _, _, result) }
/**
* Holds if the instruction `i` is in the scope of this handler.
*/
predicate isInScope(Instruction i) {
i.getImplementation() = this.getImplementation() and
i.getIndex() in [this.getTryStart().getIndex() .. this.getTryEnd().getIndex()]
}
override string toString() { none() }
override Instruction getASuccessorType(FlowType t) {
result = this.getHandlerStart() and
t instanceof NormalFlow
}
/** Gets the type of the caught exception, if any. */
Type getCaughtType() { cil_handler_type(this, result) }
override Location getLocation() { result = this.getTryStart().getLocation() }
}
/** A handler corresponding to a `finally` block. */
deprecated class FinallyHandler extends Handler, @cil_finally_handler {
override string toString() { result = "finally {...}" }
}
/** A handler corresponding to a `where()` clause. */
deprecated class FilterHandler extends Handler, @cil_filter_handler {
override string toString() { result = "where (...)" }
/** Gets the filter clause - the start of a sequence of instructions to evaluate the filter function. */
Instruction getFilterClause() { cil_handler_filter(this, result) }
override int getPushCount() { result = 1 }
}
/** A handler corresponding to a `catch` clause. */
deprecated class CatchHandler extends Handler, @cil_catch_handler {
override string toString() { result = "catch(" + this.getCaughtType().getName() + ") {...}" }
override int getPushCount() { result = 1 }
}
/** A handler for memory faults. */
deprecated class FaultHandler extends Handler, @cil_fault_handler {
override string toString() { result = "fault {...}" }
}

View File

@@ -1,70 +0,0 @@
/** Provides the `Instruction` class. */
private import CIL
/** An instruction. */
deprecated class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instruction {
override string toString() { result = this.getOpcodeName() }
/** Gets a more verbose textual representation of this instruction. */
string toStringExtra() {
result = this.getIndex() + ": " + this.getOpcodeName() + this.getExtraStr()
}
/** Gets the method containing this instruction. */
override MethodImplementation getImplementation() { cil_instruction(this, _, _, result) }
override Method getMethod() { result = this.getImplementation().getMethod() }
/**
* Gets the index of this instruction.
* Instructions are sequenced from 0.
*/
int getIndex() { cil_instruction(this, _, result, _) }
/** Gets the opcode of this instruction. */
final int getOpcode() { cil_instruction(this, result, _, _) }
/** Gets the opcode name of this instruction, for example `ldnull`. */
string getOpcodeName() { none() }
/** Gets an extra field to display for this instruction, if any. */
string getExtra() { none() }
private string getExtraStr() {
if exists(this.getExtra()) then result = " " + this.getExtra() else result = ""
}
/** Gets the declaration accessed by this instruction, if any. */
Declaration getAccess() { cil_access(this, result) }
/** Gets a successor instruction to this instruction. */
override Instruction getASuccessorType(FlowType t) {
t instanceof NormalFlow and
this.canFlowNext() and
result = this.getImplementation().getInstruction(this.getIndex() + 1)
}
/** Holds if this instruction passes control flow into the next instruction. */
predicate canFlowNext() { any() }
/**
* Gets the `i`th handler that applies to this instruction.
* Indexed from 0.
*/
Handler getHandler(int i) {
result.isInScope(this) and
result.getIndex() =
rank[i + 1](int hi | exists(Handler h | h.isInScope(this) and hi = h.getIndex()))
}
override Type getType() { result = ControlFlowNode.super.getType() }
override Location getALocation() {
cil_instruction_location(this, result) // The source code, if available
or
result = this.getImplementation().getLocation() // The containing assembly
}
override Location getLocation() { result = Element.super.getLocation() }
}

View File

@@ -1,263 +0,0 @@
/**
* Provides classes representing various classes of expression
* and other instructions.
*/
private import CIL
private import dotnet
/**
* An instruction that pushes a value onto the stack.
*/
deprecated class Expr extends DotNet::Expr, Instruction, @cil_expr {
override int getPushCount() { result = 1 }
override Type getType() { result = Instruction.super.getType() }
override Method getEnclosingCallable() { result = this.getImplementation().getMethod() }
/**
* The "parent" of a CIL expression is taken to be the instruction
* that consumes the value pushed by this instruction.
*/
override Expr getParent() { this = result.getAnOperand() }
}
/** An instruction that changes control flow. */
deprecated class Branch extends Instruction, @cil_jump {
/** Gets the instruction that is jumped to. */
Instruction getTarget() { cil_jump(this, result) }
override string getExtra() { result = this.getTarget().getIndex() + ":" }
}
/** An instruction that unconditionally jumps to another instruction. */
deprecated class UnconditionalBranch extends Branch, @cil_unconditional_jump {
override Instruction getASuccessorType(FlowType t) {
t instanceof NormalFlow and result = this.getTarget()
}
override predicate canFlowNext() { none() }
}
/** An instruction that jumps to a target based on a condition. */
deprecated class ConditionalBranch extends Branch, @cil_conditional_jump {
override Instruction getASuccessorType(FlowType t) {
t instanceof TrueFlow and result = this.getTarget()
or
t instanceof FalseFlow and result = this.getImplementation().getInstruction(this.getIndex() + 1)
}
override int getPushCount() { result = 0 }
}
/** An expression with two operands. */
deprecated class BinaryExpr extends Expr, @cil_binary_expr {
override int getPopCount() { result = 2 }
}
/** An expression with one operand. */
deprecated class UnaryExpr extends Expr, @cil_unary_expr {
override int getPopCount() { result = 1 }
/** Gets the operand of this unary expression. */
Expr getOperand() { result = this.getOperand(0) }
}
/** A binary expression that compares two values. */
deprecated class ComparisonOperation extends BinaryExpr, @cil_comparison_operation {
override BoolType getType() { exists(result) }
}
/** A binary arithmetic expression. */
deprecated class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation {
override Type getType() {
exists(Type t0, Type t1 |
t0 = this.getOperandType(0).getUnderlyingType() and
t1 = this.getOperandType(1).getUnderlyingType()
|
t0 = t1 and result = t0
or
t0.getConversionIndex() < t1.getConversionIndex() and result = t1
or
t0.getConversionIndex() > t1.getConversionIndex() and result = t0
)
}
}
/** A binary bitwise expression. */
deprecated class BinaryBitwiseOperation extends BinaryExpr, @cil_binary_bitwise_operation {
// This is wrong but efficient - should depend on the types of the operands.
override IntType getType() { exists(result) }
}
/** A unary bitwise expression. */
deprecated class UnaryBitwiseOperation extends UnaryExpr, @cil_unary_bitwise_operation {
// This is wrong but efficient - should depend on the types of the operands.
override IntType getType() { exists(result) }
}
/** A unary expression that converts a value from one primitive type to another. */
deprecated class Conversion extends UnaryExpr, @cil_conversion_operation {
/** Gets the expression being converted. */
Expr getExpr() { result = this.getOperand(0) }
}
/** A branch that leaves the scope of a `Handler`. */
deprecated class Leave extends UnconditionalBranch, @cil_leave_any { }
/** An expression that pushes a literal value onto the stack. */
deprecated class Literal extends DotNet::Literal, Expr, @cil_literal {
/** Gets the pushed value. */
override string getValue() { cil_value(this, result) }
override string getExtra() { result = this.getValue() }
}
/** An integer literal. */
deprecated class IntLiteral extends Literal, @cil_ldc_i {
override string getExtra() { none() }
override IntType getType() { exists(result) }
}
/** An expression that pushes a `float`/`Single`. */
deprecated class FloatLiteral extends Literal, @cil_ldc_r { }
/** An expression that pushes a `null` value onto the stack. */
deprecated class NullLiteral extends Literal, @cil_ldnull { }
/** An expression that pushes a string onto the stack. */
deprecated class StringLiteral extends Literal, @cil_ldstr { }
/** A branch with one operand. */
deprecated class UnaryBranch extends ConditionalBranch, @cil_unary_jump {
override int getPopCount() { result = 1 }
override int getPushCount() { result = 0 }
}
/** A branch with two operands. */
deprecated class BinaryBranch extends ConditionalBranch, @cil_binary_jump {
override int getPopCount() { result = 2 }
override int getPushCount() { result = 0 }
}
/** A call. */
deprecated class Call extends Expr, DotNet::Call, @cil_call_any {
/** Gets the method that is called. */
override Method getTarget() { cil_access(this, result) }
override Method getARuntimeTarget() { result = this.getTarget().getAnOverrider*() }
override string getExtra() { result = this.getTarget().getFullyQualifiedName() }
/**
* Gets the return type of the call. Methods that do not return a value
* return the `void` type, `System.Void`, although the value of `getPushCount` is
* 0 in this case.
*/
override Type getType() { result = this.getTarget().getReturnType() }
// The number of items popped/pushed from the stack
// depends on the target of the call.
override int getPopCount() { result = this.getTarget().getCallPopCount() }
override int getPushCount() { result = this.getTarget().getCallPushCount() }
/**
* Holds if this is a "tail call", meaning that control does not return to the
* calling method.
*/
predicate isTailCall() {
this.getImplementation().getInstruction(this.getIndex() - 1) instanceof Opcodes::Tail
}
/** Holds if this call is virtual and could go to an overriding method. */
predicate isVirtual() { none() }
override Expr getRawArgument(int i) { result = this.getOperand(this.getPopCount() - i - 1) }
/** Gets the qualifier of this call, if any. */
Expr getQualifier() { result = this.getRawArgument(0) and not this.getTarget().isStatic() }
override Expr getArgument(int i) {
if this.getTarget().isStatic()
then result = this.getRawArgument(i)
else (
result = this.getRawArgument(i + 1) and i >= 0
)
}
override Expr getArgumentForParameter(DotNet::Parameter param) {
exists(int index |
result = this.getRawArgument(index) and param = this.getTarget().getRawParameter(index)
)
}
}
/** A tail call. */
deprecated class TailCall extends Call {
TailCall() { this.isTailCall() }
override predicate canFlowNext() { none() }
}
/** A call to a static target. */
deprecated class StaticCall extends Call {
StaticCall() { not this.isVirtual() }
}
/** A call to a virtual target. */
deprecated class VirtualCall extends Call {
VirtualCall() { this.isVirtual() }
}
/** A read of an array element. */
deprecated class ReadArrayElement extends BinaryExpr, @cil_read_array {
/** Gets the array being read. */
Expr getArray() { result = this.getOperand(1) }
/** Gets the index into the array. */
Expr getArrayIndex() { result = this.getOperand(0) }
}
/** A write of an array element. */
deprecated class WriteArrayElement extends Instruction, @cil_write_array {
override int getPushCount() { result = 0 }
override int getPopCount() { result = 3 }
}
/** A `return` statement. */
deprecated class Return extends Instruction, @cil_ret {
/** Gets the expression being returned, if any. */
Expr getExpr() { result = this.getOperand(0) }
override predicate canFlowNext() { none() }
}
/** A `throw` statement. */
deprecated class Throw extends Instruction, DotNet::Throw, @cil_throw_any {
override Expr getExpr() { result = this.getOperand(0) }
/** Gets the type of the exception being thrown. */
Type getExceptionType() { result = this.getOperandType(0) }
override predicate canFlowNext() { none() }
}
/** Stores a value at an address/location. */
deprecated class StoreIndirect extends Instruction, @cil_stind {
override int getPopCount() { result = 2 }
/** Gets the location to store the value at. */
Expr getAddress() { result = this.getOperand(1) }
/** Gets the value to store. */
Expr getExpr() { result = this.getOperand(0) }
}
/** Loads a value from an address/location. */
deprecated class LoadIndirect extends UnaryExpr, @cil_ldind { }

File diff suppressed because it is too large Load Diff

View File

@@ -1,296 +0,0 @@
/**
* Provides classes for methods.
*
* Methods and implementations are different because there can be several implementations for the same
* method in different assemblies. It is not really possible to guarantee which methods will be loaded
* at run-time.
*/
private import CIL
private import dotnet
/**
* An implementation of a method in an assembly.
*/
deprecated class MethodImplementation extends EntryPoint, @cil_method_implementation {
/** Gets the method of this implementation. */
Method getMethod() { cil_method_implementation(this, result, _) }
override MethodImplementation getImplementation() { result = this }
/** Gets the location of this implementation. */
override Assembly getLocation() { cil_method_implementation(this, _, result) }
/** Gets the instruction at index `index`. */
Instruction getInstruction(int index) { cil_instruction(result, _, index, this) }
/** Gets the `n`th local variable of this implementation. */
LocalVariable getLocalVariable(int n) { cil_local_variable(result, this, n, _) }
/** Gets a local variable of this implementation, if any. */
LocalVariable getALocalVariable() { result = this.getLocalVariable(_) }
/** Gets an instruction in this implementation, if any. */
Instruction getAnInstruction() { result = this.getInstruction(_) }
/** Gets the total number of instructions in this implementation. */
int getNumberOfInstructions() { result = count(this.getAnInstruction()) }
/** Gets the `i`th handler in this implementation. */
Handler getHandler(int i) { result.getImplementation() = this and result.getIndex() = i }
/** Gets a handler in this implementation, if any. */
Handler getAHandler() { result.getImplementation() = this }
override Instruction getASuccessorType(FlowType t) {
t instanceof NormalFlow and result.getImplementation() = this and result.getIndex() = 0
}
/** Gets the maximum stack size of this implementation. */
int getStackSize() { cil_method_stack_size(this, result) }
override string toString() { result = this.getMethod().toString() }
/** Gets a string representing the disassembly of this implementation. */
string getDisassembly() {
result =
concat(Instruction i |
i = this.getAnInstruction()
|
i.toStringExtra(), ", " order by i.getIndex()
)
}
}
/**
* A method, which corresponds to any callable in C#, including constructors,
* destructors, operators, accessors and so on.
*/
deprecated class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowNode,
CustomModifierReceiver, Parameterizable, @cil_method
{
/**
* Gets a method implementation, if any. Note that there can
* be several implementations in different assemblies.
*/
MethodImplementation getAnImplementation() { result.getMethod() = this }
/** Gets the "best" implementation of this method, if any. */
BestImplementation getImplementation() { result = this.getAnImplementation() }
override Method getMethod() { result = this }
override string getName() { cil_method(this, result, _, _) }
override string getUndecoratedName() { result = this.getName() }
override string toString() { result = this.getName() }
override Type getDeclaringType() { cil_method(this, _, result, _) }
override Location getLocation() { result = Element.super.getLocation() }
override Location getALocation() { cil_method_location(this.getUnboundMethod+(), result) }
override MethodParameter getParameter(int n) {
if this.isStatic()
then result = this.getRawParameter(n)
else (
result = this.getRawParameter(n + 1) and n >= 0
)
}
override Type getType() { result = this.getReturnType() }
/** Gets the return type of this method. */
override Type getReturnType() { cil_method(this, _, _, result) }
/** Holds if the return type is `void`. */
predicate returnsVoid() { this.getReturnType() instanceof VoidType }
/** Gets the number of stack items pushed in a call to this method. */
int getCallPushCount() { if this.returnsVoid() then result = 0 else result = 1 }
/** Gets the number of stack items popped in a call to this method. */
int getCallPopCount() { result = count(this.getRawParameter(_)) }
/** Gets a method called by this method. */
Method getACallee() { result = this.getImplementation().getAnInstruction().(Call).getTarget() }
/** Holds if this method is `virtual`. */
predicate isVirtual() { cil_virtual(this) }
/** Holds if the name of this method is special, for example an operator. */
predicate isSpecial() { cil_specialname(this) }
/** Holds of this method is marked as secure. */
predicate isSecureObject() { cil_requiresecobject(this) }
/** Holds if the method does not override an existing method. */
predicate isNew() { cil_newslot(this) }
override predicate isStatic() { cil_static(this) }
/** Gets the unbound declaration of this method, or the method itself. */
Method getUnboundMethod() { cil_method_source_declaration(this, result) }
override Method getUnboundDeclaration() { result = this.getUnboundMethod() }
/** Holds if this method is an instance constructor. */
predicate isInstanceConstructor() { this.isSpecial() and this.getName() = ".ctor" }
/** Holds if this method is a static class constructor. */
predicate isStaticConstructor() { this.isSpecial() and this.getName() = ".cctor" }
/** Holds if this method is a constructor (static or instance). */
predicate isConstructor() { this.isStaticConstructor() or this.isInstanceConstructor() }
/** Holds if this method is a destructor/finalizer. */
predicate isFinalizer() {
this.getOverriddenMethod*().hasFullyQualifiedName("System", "Object", "Finalize")
}
/** Holds if this method is an operator. */
predicate isOperator() { this.isSpecial() and this.getName().matches("op\\_%") }
/** Holds if this method is a getter. */
predicate isGetter() { this.isSpecial() and this.getName().matches("get\\_%") }
/** Holds if this method is a setter. */
predicate isSetter() { this.isSpecial() and this.getName().matches("set\\_%") }
/** Holds if this method is an adder/add event accessor. */
predicate isAdder() { this.isSpecial() and this.getName().matches("add\\_%") }
/** Holds if this method is a remover/remove event accessor. */
predicate isRemove() { this.isSpecial() and this.getName().matches("remove\\_%") }
/** Holds if this method is an implicit conversion operator. */
predicate isImplicitConversion() { this.isSpecial() and this.getName() = "op_Implicit" }
/** Holds if this method is an explicit conversion operator. */
predicate isExplicitConversion() { this.isSpecial() and this.getName() = "op_Explicit" }
/** Holds if this method is a conversion operator. */
predicate isConversion() { this.isImplicitConversion() or this.isExplicitConversion() }
/**
* Gets a method that is overridden, either in a base class
* or in an interface.
*/
Method getOverriddenMethod() { cil_implements(this, result) }
/** Gets a method that overrides this method, if any. */
final Method getAnOverrider() { result.getOverriddenMethod() = this }
override predicate hasBody() { exists(this.getImplementation()) }
override predicate canReturn(DotNet::Expr expr) {
exists(Return ret | ret.getImplementation() = this.getImplementation() and expr = ret.getExpr())
}
}
/** A destructor/finalizer. */
deprecated class Destructor extends Method, DotNet::Destructor {
Destructor() { this.isFinalizer() }
}
/** A constructor. */
deprecated class Constructor extends Method, DotNet::Constructor {
Constructor() { this.isConstructor() }
}
/** A static/class constructor. */
deprecated class StaticConstructor extends Constructor {
StaticConstructor() { this.isStaticConstructor() }
}
/** An instance constructor. */
deprecated class InstanceConstructor extends Constructor {
InstanceConstructor() { this.isInstanceConstructor() }
}
/** A method that always returns the `this` parameter. */
deprecated class ChainingMethod extends Method {
ChainingMethod() {
forex(Return ret | ret = this.getImplementation().getAnInstruction() |
ret.getExpr() instanceof ThisAccess
)
}
}
/** An accessor. */
abstract deprecated class Accessor extends Method {
/** Gets the property declaring this accessor. */
abstract Property getProperty();
}
/** A getter. */
deprecated class Getter extends Accessor {
Getter() { cil_getter(_, this) }
override Property getProperty() { cil_getter(result, this) }
}
/**
* A method that does nothing but retrieve a field.
* Note that this is not necessarily a property getter.
*/
deprecated class TrivialGetter extends Method {
TrivialGetter() {
exists(MethodImplementation impl | impl = this.getAnImplementation() |
impl.getInstruction(0) instanceof ThisAccess and
impl.getInstruction(1) instanceof FieldReadAccess and
impl.getInstruction(2) instanceof Return
)
}
/** Gets the underlying field of this getter. */
Field getField() {
this.getImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result
}
}
/** A setter. */
deprecated class Setter extends Accessor {
Setter() { cil_setter(_, this) }
override Property getProperty() { cil_setter(result, this) }
/** Holds if this setter is an `init` accessor. */
predicate isInitOnly() {
exists(Type t | t.hasFullyQualifiedName("System.Runtime.CompilerServices", "IsExternalInit") |
this.hasRequiredCustomModifier(t)
)
}
}
/**
* A method that does nothing but set a field.
* This is not necessarily a property setter.
*/
deprecated class TrivialSetter extends Method {
TrivialSetter() {
exists(MethodImplementation impl | impl = this.getAnImplementation() |
impl.getInstruction(0) instanceof ThisAccess and
impl.getInstruction(1).(ParameterReadAccess).getTarget().getIndex() = 1 and
impl.getInstruction(2) instanceof FieldWriteAccess
)
}
/** Gets the underlying field of this setter. */
Field getField() {
result = this.getImplementation().getAnInstruction().(FieldWriteAccess).getTarget()
}
}
/** An alias for `Method` for compatibility with the C# data model. */
deprecated class Callable = Method;
/** An operator. */
deprecated class Operator extends Method {
Operator() { this.isOperator() }
/** Gets the name of the implementing method (for compatibility with C# data model). */
string getFunctionName() { result = this.getName() }
}

View File

@@ -1,15 +0,0 @@
/**
* Provides `Parameterizable` class.
*/
private import CIL
private import dotnet
/**
* A parameterizable entity, such as `FunctionPointerType` or `Method`.
*/
deprecated class Parameterizable extends DotNet::Parameterizable, Element, @cil_parameterizable {
override Parameter getRawParameter(int n) { cil_parameter(result, this, n, _) }
override Parameter getParameter(int n) { cil_parameter(result, this, n, _) }
}

View File

@@ -1,48 +0,0 @@
/**
* Provides the module `Ssa` for working with static single assignment (SSA) form.
*/
private import CIL
/**
* Provides classes for working with static single assignment (SSA) form.
*/
deprecated module Ssa {
private import internal.SsaImpl as SsaImpl
/** An SSA definition. */
class Definition extends SsaImpl::Definition {
/** Gets a read of this SSA definition. */
final ReadAccess getARead() { result = SsaImpl::getARead(this) }
/** Gets the underlying variable update, if any. */
final VariableUpdate getVariableUpdate() {
exists(BasicBlock bb, int i |
result.updatesAt(bb, i) and
this.definesAt(result.getVariable(), bb, i)
)
}
private Definition getAPhiInput() { result = this.(PhiNode).getAnInput() }
/**
* Gets a definition that ultimately defines this SSA definition and is
* not itself a phi node.
*/
final Definition getAnUltimateDefinition() {
result = this.getAPhiInput*() and
not result instanceof PhiNode
}
/** Gets the location of this SSA definition. */
override Location getLocation() { result = this.getVariableUpdate().getLocation() }
}
/** A phi node. */
class PhiNode extends SsaImpl::PhiNode, Definition {
final override Location getLocation() { result = this.getBasicBlock().getLocation() }
/** Gets an input to this phi node. */
final Definition getAnInput() { result = SsaImpl::getAPhiInput(this) }
}
}

View File

@@ -1,57 +0,0 @@
/**
* Provides classes and predicates for identifying stub code.
*/
import CIL
/**
* The average number of instructions per method,
* below which an assembly is probably a stub.
*/
deprecated private float stubInstructionThreshold() { result = 5.1 }
cached
private module Cached {
/**
* A simple heuristic for determining whether an assembly is a
* reference assembly where the method bodies have dummy implementations.
* Look at the average number of instructions per method.
*/
cached
deprecated predicate assemblyIsStubImpl(Assembly asm) {
exists(int totalInstructions, int totalImplementations |
totalInstructions = count(Instruction i | i.getImplementation().getLocation() = asm) and
totalImplementations =
count(MethodImplementation i | i.getImplementation().getLocation() = asm) and
totalInstructions.(float) / totalImplementations.(float) < stubInstructionThreshold()
)
}
cached
deprecated predicate bestImplementation(MethodImplementation mi) {
exists(Assembly asm |
asm = mi.getLocation() and
(assemblyIsStubImpl(asm) implies asm.getFile().extractedQlTest()) and
mi =
max(MethodImplementation impl |
mi.getMethod() = impl.getMethod()
|
impl order by impl.getNumberOfInstructions(), impl.getLocation().getFile().toString() desc
) and
exists(mi.getAnInstruction())
)
}
}
private import Cached
deprecated predicate assemblyIsStub = assemblyIsStubImpl/1;
/**
* A method implementation that is the "best" one for a particular method,
* if there are several potential implementations to choose between, and
* excludes implementations that are probably from stub/reference assemblies.
*/
deprecated class BestImplementation extends MethodImplementation {
BestImplementation() { bestImplementation(this) }
}

View File

@@ -1,125 +0,0 @@
/**
* Provides classes for types and associated classes.
*/
import CIL
private import dotnet
private import semmle.code.csharp.commons.QualifiedName
/**
* Something that contains other types.
*
* Either a type (`Type`), a method(`Method`), or a namespace (`Namespace`).
*/
deprecated class TypeContainer extends DotNet::NamedElement, @cil_type_container {
/** Gets the parent of this type container, if any. */
TypeContainer getParent() { none() }
override string toStringWithTypes() { result = this.getLabel() }
}
/** A namespace. */
deprecated class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
override string toString() { result = this.getFullName() }
override Namespace getParent() { result = this.getParentNamespace() }
override Namespace getParentNamespace() { parent_namespace(this, result) }
override Location getLocation() { none() }
}
/**
* A type.
*/
deprecated class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type {
override TypeContainer getParent() { cil_type(this, _, _, result, _) }
override string getName() { cil_type(this, result, _, _, _) }
override string toString() { result = this.getName() }
/** Gets the containing type of this type, if any. */
override Type getDeclaringType() { result = this.getParent() }
/** Gets a member of this type, if any. */
Member getAMember() { result.getDeclaringType() = this }
/**
* Gets the unbound generic type of this type, or `this` if the type
* is already unbound.
*/
Type getUnboundType() { cil_type(this, _, _, _, result) }
deprecated override predicate hasQualifiedName(string qualifier, string name) {
name = this.getName() and
exists(string pqualifier, string pname | this.getParent().hasQualifiedName(pqualifier, pname) |
qualifier = getQualifiedName(pqualifier, pname)
)
}
override predicate hasFullyQualifiedName(string qualifier, string name) {
name = this.getName() and
exists(string pqualifier, string pname |
this.getParent().hasFullyQualifiedName(pqualifier, pname)
|
qualifier = getQualifiedName(pqualifier, pname)
)
}
override Location getALocation() { cil_type_location(this.getUnboundDeclaration(), result) }
/** Holds if this type is a class. */
predicate isClass() { cil_class(this) }
/** Holds if this type is an interface. */
predicate isInterface() { cil_interface(this) }
/**
* Holds if this type is a member of the `System` namespace and has the name
* `name`.
*/
predicate isSystemType(string name) {
exists(Namespace system | this.getParent() = system |
system.getName() = "System" and
system.getParentNamespace().getName() = "" and
name = this.getName()
)
}
/** Holds if this type is an `enum`. */
predicate isEnum() { this.getBaseClass().isSystemType("Enum") }
/** Holds if this type is public. */
predicate isPublic() { cil_public(this) }
/** Holds if this type is private. */
predicate isPrivate() { cil_private(this) }
/** Gets the machine type used to store this type. */
Type getUnderlyingType() { result = this }
// Class hierarchy
/** Gets the immediate base class of this class, if any. */
Type getBaseClass() { cil_base_class(this, result) }
/** Gets an immediate base interface of this class, if any. */
Type getABaseInterface() { cil_base_interface(this, result) }
/** Gets an immediate base type of this type, if any. */
Type getABaseType() { result = this.getBaseClass() or result = this.getABaseInterface() }
/** Gets an immediate subtype of this type, if any. */
Type getASubtype() { result.getABaseType() = this }
/** Gets the namespace directly containing this type, if any. */
Namespace getNamespace() { result = this.getParent() }
/**
* Gets an index for implicit conversions. A type can be converted to another numeric type
* of a higher index.
*/
int getConversionIndex() { result = 0 }
override Type getUnboundDeclaration() { cil_type(this, _, _, _, result) }
}

View File

@@ -1,318 +0,0 @@
/**
* Provides classes representing various types.
*/
private import CIL
private import dotnet
/** A type parameter. */
deprecated class TypeParameter extends DotNet::TypeParameter, Type, @cil_typeparameter {
override int getIndex() { cil_type_parameter(_, result, this) }
/** Gets the generic type/method declaring this type parameter. */
TypeContainer getGeneric() { cil_type_parameter(result, _, this) }
override Location getLocation() { result = this.getParent().getLocation() }
/** Holds if this type parameter has the `new` constraint. */
predicate isDefaultConstructible() { cil_typeparam_new(this) }
/** Holds if this type parameter has the `struct` constraint. */
predicate isStruct() { cil_typeparam_struct(this) }
override predicate isClass() { cil_typeparam_class(this) }
/** Holds if this type parameter is covariant/is `in`. */
predicate isCovariant() { cil_typeparam_covariant(this) }
/** Holds if this type parameter is contravariant/is `out`. */
predicate isContravariant() { cil_typeparam_contravariant(this) }
/** Gets a type constraint on this type parameter, if any. */
Type getATypeConstraint() { cil_typeparam_constraint(this, result) }
}
/** A value or reference type. */
deprecated class ValueOrRefType extends DotNet::ValueOrRefType, Type, @cil_valueorreftype {
override ValueOrRefType getDeclaringType() { result = this.getParent() }
override string getUndecoratedName() { cil_type(this, result, _, _, _) }
override Namespace getDeclaringNamespace() { result = this.getNamespace() }
override ValueOrRefType getABaseType() { result = Type.super.getABaseType() }
}
/** An `enum`. */
deprecated class Enum extends ValueOrRefType {
Enum() { this.isEnum() }
override IntegralType getUnderlyingType() {
cil_enum_underlying_type(this, result)
or
not cil_enum_underlying_type(this, _) and
result instanceof IntType
}
}
/** A `class`. */
deprecated class Class extends ValueOrRefType {
Class() { this.isClass() }
}
/** An `interface`. */
deprecated class Interface extends ValueOrRefType {
Interface() { this.isInterface() }
}
/** An array. */
deprecated class ArrayType extends DotNet::ArrayType, Type, @cil_array_type {
override Type getElementType() { cil_array_type(this, result, _) }
/** Gets the rank of this array. */
int getRank() { cil_array_type(this, _, result) }
override string toStringWithTypes() { result = DotNet::ArrayType.super.toStringWithTypes() }
override Location getLocation() { result = this.getElementType().getLocation() }
override ValueOrRefType getABaseType() { result = Type.super.getABaseType() }
}
/** A pointer type. */
deprecated class PointerType extends DotNet::PointerType, PrimitiveType, @cil_pointer_type {
override Type getReferentType() { cil_pointer_type(this, result) }
override IntType getUnderlyingType() { any() }
override string getName() { result = DotNet::PointerType.super.getName() }
override Location getLocation() { result = this.getReferentType().getLocation() }
override string toString() { result = DotNet::PointerType.super.toString() }
override string toStringWithTypes() { result = DotNet::PointerType.super.toStringWithTypes() }
}
/** A primitive type, built into the runtime. */
abstract deprecated class PrimitiveType extends Type { }
/**
* A primitive numeric type.
* Either an integral type (`IntegralType`) or a floating point type (`FloatingPointType`).
*/
abstract deprecated class NumericType extends PrimitiveType, ValueOrRefType { }
/** A floating point type. Either single precision (`FloatType`) or double precision (`DoubleType`). */
abstract deprecated class FloatingPointType extends NumericType { }
/**
* An integral numeric type. Either a signed integral type (`SignedIntegralType`)
* or an unsigned integral type (`UnsignedIntegralType`).
*/
abstract deprecated class IntegralType extends NumericType { }
/** A signed integral type. */
abstract deprecated class SignedIntegralType extends IntegralType { }
/** An unsigned integral type. */
abstract deprecated class UnsignedIntegralType extends IntegralType { }
/** The `void` type, `System.Void`. */
deprecated class VoidType extends PrimitiveType {
VoidType() { this.isSystemType("Void") }
override string toString() { result = "void" }
override string toStringWithTypes() { result = "void" }
}
/** The type `System.Int32`. */
deprecated class IntType extends SignedIntegralType {
IntType() { this.isSystemType("Int32") }
override string toStringWithTypes() { result = "int" }
override int getConversionIndex() { result = 8 }
override IntType getUnderlyingType() { result = this }
}
/** The type `System.IntPtr`. */
deprecated class IntPtrType extends PrimitiveType {
IntPtrType() { this.isSystemType("IntPtr") }
override IntType getUnderlyingType() { any() }
}
/** The type `System.UIntPtr`. */
deprecated class UIntPtrType extends PrimitiveType {
UIntPtrType() { this.isSystemType("UIntPtr") }
override IntType getUnderlyingType() { any() }
}
/** The type `System.UInt32`. */
deprecated class UIntType extends UnsignedIntegralType {
UIntType() { this.isSystemType("UInt32") }
override string toStringWithTypes() { result = "uint" }
override int getConversionIndex() { result = 7 }
override IntType getUnderlyingType() { any() }
}
/** The type `System.SByte`. */
deprecated class SByteType extends SignedIntegralType {
SByteType() { this.isSystemType("SByte") }
override string toStringWithTypes() { result = "sbyte" }
override int getConversionIndex() { result = 2 }
}
/** The type `System.Byte`. */
deprecated class ByteType extends UnsignedIntegralType {
ByteType() { this.isSystemType("Byte") }
override string toStringWithTypes() { result = "byte" }
override int getConversionIndex() { result = 1 }
override SByteType getUnderlyingType() { any() }
}
/** The type `System.Int16`. */
deprecated class ShortType extends SignedIntegralType {
ShortType() { this.isSystemType("Int16") }
override string toStringWithTypes() { result = "short" }
override int getConversionIndex() { result = 4 }
}
/** The type `System.UInt16`. */
deprecated class UShortType extends UnsignedIntegralType {
UShortType() { this.isSystemType("UInt16") }
override string toStringWithTypes() { result = "ushort" }
override int getConversionIndex() { result = 3 }
override ShortType getUnderlyingType() { any() }
}
/** The type `System.Int64`. */
deprecated class LongType extends SignedIntegralType {
LongType() { this.isSystemType("Int64") }
override string toStringWithTypes() { result = "long" }
override int getConversionIndex() { result = 10 }
}
/** The type `System.UInt64`. */
deprecated class ULongType extends UnsignedIntegralType {
ULongType() { this.isSystemType("UInt64") }
override string toStringWithTypes() { result = "ulong" }
override int getConversionIndex() { result = 9 }
override LongType getUnderlyingType() { any() }
}
/** The type `System.Decimal`. */
deprecated class DecimalType extends SignedIntegralType {
DecimalType() { this.isSystemType("Decimal") }
override string toStringWithTypes() { result = "decimal" }
override int getConversionIndex() { result = 13 }
}
/** The type `System.String`. */
deprecated class StringType extends PrimitiveType, ValueOrRefType {
StringType() { this.isSystemType("String") }
override string toStringWithTypes() { result = "string" }
}
/** The type `System.Object`. */
deprecated class ObjectType extends ValueOrRefType {
ObjectType() { this.isSystemType("Object") }
override string toStringWithTypes() { result = "object" }
}
/** The type `System.Boolean`. */
deprecated class BoolType extends PrimitiveType, ValueOrRefType {
BoolType() { this.isSystemType("Boolean") }
override string toStringWithTypes() { result = "bool" }
override IntType getUnderlyingType() { any() }
}
/** The type `System.Double`. */
deprecated class DoubleType extends FloatingPointType {
DoubleType() { this.isSystemType("Double") }
override string toStringWithTypes() { result = "double" }
override int getConversionIndex() { result = 12 }
}
/** The type `System.Single`. */
deprecated class FloatType extends FloatingPointType {
FloatType() { this.isSystemType("Single") }
override string toStringWithTypes() { result = "float" }
override int getConversionIndex() { result = 4 }
}
/** The type `System.Char`. */
deprecated class CharType extends IntegralType {
CharType() { this.isSystemType("Char") }
override string toStringWithTypes() { result = "char" }
override int getConversionIndex() { result = 6 }
override IntType getUnderlyingType() { any() }
}
/** The type `System.Type`. */
deprecated class SystemType extends ValueOrRefType {
SystemType() { this.isSystemType("Type") }
}
/**
* A function pointer type, for example
*
* ```csharp
* delegate*<int, void>
* ```
*/
deprecated class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable,
@cil_function_pointer_type
{
/** Gets the return type of this function pointer. */
Type getReturnType() { cil_function_pointer_return_type(this, result) }
/** Gets the calling convention. */
int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) }
/** Holds if the return type is `void`. */
predicate returnsVoid() { this.getReturnType() instanceof VoidType }
/** Gets the number of stack items pushed in a call to this method. */
int getCallPushCount() { if this.returnsVoid() then result = 0 else result = 1 }
/** Gets the number of stack items popped in a call to this method. */
int getCallPopCount() { result = count(this.getRawParameter(_)) }
override string getLabel() { result = this.getName() }
}

View File

@@ -1,160 +0,0 @@
/**
* Provides classes for variables.
*/
private import CIL
private import dotnet
/** A variable. Either a stack variable (`StackVariable`) or a field (`Field`). */
deprecated class Variable extends DotNet::Variable, Declaration, DataFlowNode, @cil_variable {
/** Gets the type of this variable. */
override Type getType() { none() }
/** Gets a textual representation of this variable including type information. */
override string toStringWithTypes() { none() }
/** Gets an access to this variable, if any. */
VariableAccess getAnAccess() { result.getTarget() = this }
/** Gets a read access to this variable, if any. */
ReadAccess getARead() { result = this.getAnAccess() }
/** Gets a write access to this variable, if any. */
WriteAccess getAWrite() { result = this.getAnAccess() }
override string toString() { result = Declaration.super.toString() }
override Location getLocation() { result = Declaration.super.getLocation() }
}
/** A stack variable. Either a local variable (`LocalVariable`) or a parameter (`Parameter`). */
deprecated class StackVariable extends Variable, @cil_stack_variable {
deprecated override predicate hasQualifiedName(string qualifier, string name) { none() }
override predicate hasFullyQualifiedName(string qualifier, string name) { none() }
}
/**
* A local variable.
*
* Each method in CIL has a number of typed local variables, in addition to the evaluation stack.
*/
deprecated class LocalVariable extends StackVariable, @cil_local_variable {
override string toString() {
result =
"Local variable " + this.getIndex() + " of method " +
this.getImplementation().getMethod().getName()
}
/** Gets the method implementation defining this local variable. */
MethodImplementation getImplementation() { this = result.getALocalVariable() }
/** Gets the index number of this local variable. This is not usually significant. */
int getIndex() { this = this.getImplementation().getLocalVariable(result) }
override Type getType() { cil_local_variable(this, _, _, result) }
override Location getLocation() { result = this.getImplementation().getLocation() }
override Method getMethod() { result = this.getImplementation().getMethod() }
}
/** A parameter of a `Method` or `FunctionPointerType`. */
deprecated class Parameter extends DotNet::Parameter, CustomModifierReceiver, @cil_parameter {
override Parameterizable getDeclaringElement() { cil_parameter(this, result, _, _) }
/** Gets the index of this parameter. */
int getIndex() { cil_parameter(this, _, result, _) }
override string toString() {
result = "Parameter " + this.getIndex() + " of " + this.getDeclaringElement().getName()
}
override Type getType() { cil_parameter(this, _, _, result) }
/**
* Holds if this parameter has an "out" flag, meaning that it will
* be passed by reference and written to.
*/
predicate hasOutFlag() { cil_parameter_out(this) }
/**
* Holds if this parameter has an "in" flag, meaning that it will
* be passed by reference and may be read from and written to.
*/
predicate hasInFlag() { cil_parameter_in(this) }
/** Holds if this parameter has C# `out` semantics. */
override predicate isOut() { this.hasOutFlag() and not this.hasInFlag() }
/** Holds if this parameter has C# `ref` semantics. */
override predicate isRef() { this.hasOutFlag() and this.hasInFlag() }
override string toStringWithTypes() {
result = this.getPrefix() + this.getType().toStringWithTypes()
}
private string getPrefix() {
if this.isOut()
then result = "out "
else
if this.isRef()
then result = "ref "
else result = ""
}
override Location getLocation() { result = this.getDeclaringElement().getLocation() }
}
/** A method parameter. */
deprecated class MethodParameter extends Parameter, StackVariable {
/** Gets the method declaring this parameter. */
override Method getMethod() { this = result.getARawParameter() }
override ParameterAccess getAnAccess() { result.getTarget() = this }
/** Gets a parameter in an overridden method. */
MethodParameter getOverriddenParameter() {
result = this.getMethod().getOverriddenMethod().getRawParameter(this.getRawPosition())
}
override MethodParameter getUnboundDeclaration() {
result = this.getMethod().getUnboundDeclaration().getRawParameter(this.getRawPosition())
}
override string toString() { result = Parameter.super.toString() }
override string toStringWithTypes() { result = Parameter.super.toStringWithTypes() }
override Type getType() { result = Parameter.super.getType() }
override Location getLocation() { result = Parameter.super.getLocation() }
}
/** A parameter corresponding to `this`. */
deprecated class ThisParameter extends MethodParameter {
ThisParameter() {
not this.getMethod().isStatic() and
this.getIndex() = 0
}
}
/** A field. */
deprecated class Field extends DotNet::Field, Variable, Member, CustomModifierReceiver, @cil_field {
override string toString() { result = this.getName() }
override string toStringWithTypes() {
result = this.getDeclaringType().toStringWithTypes() + "." + this.getName()
}
override string getName() { cil_field(this, _, result, _) }
override Type getType() { cil_field(this, _, _, result) }
override ValueOrRefType getDeclaringType() { cil_field(this, result, _, _) }
override Location getLocation() { result = this.getDeclaringType().getLocation() }
/** Holds if this declaration is `ref`. */
predicate isRef() { cil_type_annotation(this, 32) }
}

View File

@@ -1,87 +0,0 @@
private import cil
private import CIL
private import codeql.ssa.Ssa as SsaImplCommon
deprecated private module SsaInput implements SsaImplCommon::InputSig<CIL::Location> {
class BasicBlock = CIL::BasicBlock;
class ControlFlowNode = CIL::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock extends BasicBlock, CIL::ExitBasicBlock { }
class SourceVariable = CIL::StackVariable;
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
forceCachingInSameStage() and
exists(CIL::VariableUpdate vu |
vu.updatesAt(bb, i) and
v = vu.getVariable() and
certain = true
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(CIL::ReadAccess ra | bb.getNode(i) = ra |
ra.getTarget() = v and
certain = true
)
}
}
deprecated import SsaImplCommon::Make<CIL::Location, SsaInput>
cached
private module Cached {
private import CIL
cached
deprecated predicate forceCachingInSameStage() { any() }
cached
deprecated ReadAccess getARead(Definition def) {
exists(BasicBlock bb, int i |
ssaDefReachesRead(_, def, bb, i) and
result = bb.getNode(i)
)
}
cached
deprecated ReadAccess getAFirstReadExt(DefinitionExt def) {
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
def.definesAt(_, bb1, i1, _) and
adjacentDefReadExt(def, _, bb1, i1, bb2, i2) and
result = bb2.getNode(i2)
)
}
cached
deprecated predicate hasAdjacentReadsExt(DefinitionExt def, ReadAccess first, ReadAccess second) {
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
first = bb1.getNode(i1) and
adjacentDefReadExt(def, _, bb1, i1, bb2, i2) and
second = bb2.getNode(i2)
)
}
cached
deprecated Definition getAPhiInput(PhiNode phi) { phiHasInputFromBlock(phi, result, _) }
cached
deprecated predicate lastRefBeforeRedefExt(
DefinitionExt def, BasicBlock bb, int i, DefinitionExt next
) {
lastRefRedefExt(def, _, bb, i, next)
}
}
import Cached
private module Deprecated {
private import CIL
}
import Deprecated

View File

@@ -21,70 +21,6 @@ private import TypeRef
* (`LocalFunction`).
*/
class Callable extends Parameterizable, ExprOrStmtParent, @callable {
pragma[noinline]
deprecated private string getDeclaringTypeLabel() { result = this.getDeclaringType().getLabel() }
pragma[noinline]
deprecated private string getParameterTypeLabelNonGeneric(int p) {
not this instanceof Generic and
result = this.getParameter(p).getType().getLabel()
}
language[monotonicAggregates]
pragma[nomagic]
deprecated private string getMethodParamListNonGeneric() {
result =
concat(int p |
p in [0 .. this.getNumberOfParameters() - 1]
|
this.getParameterTypeLabelNonGeneric(p), "," order by p
)
}
pragma[noinline]
deprecated private string getParameterTypeLabelGeneric(int p) {
this instanceof Generic and
result = this.getParameter(p).getType().getLabel()
}
language[monotonicAggregates]
pragma[nomagic]
deprecated private string getMethodParamListGeneric() {
result =
concat(int p |
p in [0 .. this.getNumberOfParameters() - 1]
|
this.getParameterTypeLabelGeneric(p), "," order by p
)
}
pragma[noinline]
deprecated private string getLabelNonGeneric() {
not this instanceof Generic and
result =
this.getReturnTypeLabel() + " " + this.getDeclaringTypeLabel() + "." +
this.getUndecoratedName() + "(" + this.getMethodParamListNonGeneric() + ")"
}
pragma[noinline]
deprecated private string getLabelGeneric() {
result =
this.getReturnTypeLabel() + " " + this.getDeclaringTypeLabel() + "." +
this.getUndecoratedName() + getGenericsLabel(this) + "(" + this.getMethodParamListGeneric() +
")"
}
deprecated final override string getLabel() {
result = this.getLabelNonGeneric() or
result = this.getLabelGeneric()
}
deprecated private string getReturnTypeLabel() {
result = this.getReturnType().getLabel()
or
not exists(this.getReturnType()) and result = "System.Void"
}
/** Gets the return type of this callable. */
Type getReturnType() { none() }

View File

@@ -27,12 +27,6 @@ class Element extends @element {
/** Holds if this element is from an assembly. */
predicate fromLibrary() { this.getFile().fromLibrary() }
/**
* Gets the "language" of this program element, as defined by the extension of the filename.
* For example, C# has language "cs", and Visual Basic has language "vb".
*/
deprecated final string getLanguage() { result = this.getLocation().getFile().getExtension() }
/**
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
*
@@ -159,29 +153,5 @@ class NamedElement extends Element, @named_element {
qualifier = "" and name = this.getName()
}
/** Gets a unique string label for this element. */
cached
deprecated string getLabel() { none() }
/** Holds if `other` has the same metadata handle in the same assembly. */
deprecated predicate matchesHandle(NamedElement other) {
exists(Assembly asm, int handle |
metadata_handle(this, asm, handle) and
metadata_handle(other, asm, handle)
)
}
/**
* Holds if this element was compiled from source code that is also present in the
* database. That is, this element corresponds to another element from source.
*/
deprecated predicate compiledFromSource() {
not this.fromSource() and
exists(NamedElement other | other != this |
this.matchesHandle(other) and
other.fromSource()
)
}
override string toString() { result = this.getName() }
}

View File

@@ -103,33 +103,6 @@ class ConstructedGeneric extends Generic {
final int getNumberOfTypeArguments() { result = count(int i | exists(this.getTypeArgument(i))) }
}
/**
* INTERNAL: Do not use.
*
* Constructs the label suffix for a generic method or type.
*/
deprecated string getGenericsLabel(Generic g) {
result = "`" + g.(UnboundGeneric).getNumberOfTypeParameters()
or
result = "<" + typeArgs(g) + ">"
}
pragma[noinline]
deprecated private string getTypeArgumentLabel(ConstructedGeneric generic, int p) {
result = generic.getTypeArgument(p).getLabel()
}
language[monotonicAggregates]
pragma[nomagic]
deprecated private string typeArgs(ConstructedGeneric generic) {
result =
concat(int p |
p in [0 .. generic.getNumberOfTypeArguments() - 1]
|
getTypeArgumentLabel(generic, p), ","
)
}
/** Gets the type arguments as a comma-separated string. */
language[monotonicAggregates]
private string getTypeArgumentsToString(ConstructedGeneric cg) {
@@ -264,8 +237,6 @@ class TypeParameter extends Type, @type_parameter {
/** Gets the index of this type parameter. For example the index of `U` in `Func<T,U>` is 1. */
override int getIndex() { type_parameters(this, result, _, _) }
deprecated final override string getLabel() { result = "!" + this.getIndex() }
override string getUndecoratedName() { result = "!" + this.getIndex() }
/** Gets the generic that defines this type parameter. */

View File

@@ -76,30 +76,6 @@ class ValueOrRefType extends Type, Attributable, @value_or_ref_type {
/** Gets a nested child type, if any. */
NestedType getAChildType() { nested_types(result, this, _) }
deprecated private string getPrefixWithTypes() {
result = this.getDeclaringType().getLabel() + "."
or
if this.getDeclaringNamespace().isGlobalNamespace()
then result = ""
else result = this.getDeclaringNamespace().getFullName() + "."
}
pragma[noinline]
deprecated private string getLabelNonGeneric() {
not this instanceof Generic and
result = this.getPrefixWithTypes() + this.getUndecoratedName()
}
pragma[noinline]
deprecated private string getLabelGeneric() {
result = this.getPrefixWithTypes() + this.getUndecoratedName() + getGenericsLabel(this)
}
deprecated override string getLabel() {
result = this.getLabelNonGeneric() or
result = this.getLabelGeneric()
}
/**
* Gets the source namespace declaration in which this type is declared, if any.
* This only holds for non-nested types.
@@ -996,8 +972,6 @@ class FunctionPointerType extends Type, Parameterizable, @function_pointer_type
AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) }
override string getAPrimaryQlClass() { result = "FunctionPointerType" }
deprecated override string getLabel() { result = this.getName() }
}
/**
@@ -1116,8 +1090,6 @@ class ArrayType extends RefType, @array_type {
array_element_type(this, _, _, getTypeRef(result))
}
deprecated final override string getLabel() { result = this.getElementType().getLabel() + "[]" }
/** Holds if this array type has the same shape (dimension and rank) as `that` array type. */
predicate hasSameShapeAs(ArrayType that) {
this.getDimension() = that.getDimension() and
@@ -1180,8 +1152,6 @@ class PointerType extends Type, @pointer_type {
final override string getName() { types(this, _, result) }
deprecated final override string getLabel() { result = this.getReferentType().getLabel() + "*" }
final override string getUndecoratedName() {
result = this.getReferentType().getUndecoratedName()
}
@@ -1271,8 +1241,6 @@ class TupleType extends ValueType, @tuple_type {
")"
}
deprecated override string getLabel() { result = this.getUnderlyingType().getLabel() }
override Type getChild(int i) { result = this.getUnderlyingType().getChild(i) }
override string getAPrimaryQlClass() { result = "TupleType" }

View File

@@ -29,7 +29,7 @@ module BaseSsa {
) {
exists(ControlFlow::ControlFlow::BasicBlocks::EntryBlock entry |
c = entry.getCallable() and
// In case `c` has multiple bodies, we want each body to gets its own implicit
// In case `c` has multiple bodies, we want each body to get its own implicit
// entry definition. In case `c` doesn't have multiple bodies, the line below
// is simply the same as `bb = entry`, because `entry.getFirstNode().getASuccessor()`
// will be in the entry block.

View File

@@ -267,8 +267,9 @@ module VariableCapture {
private predicate closureFlowStep(ControlFlow::Nodes::ExprNode e1, ControlFlow::Nodes::ExprNode e2) {
e1 = LocalFlow::getALastEvalNode(e2)
or
exists(Ssa::Definition def |
LocalFlow::ssaDefAssigns(def.getAnUltimateDefinition(), e1) and
exists(Ssa::Definition def, AssignableDefinition adef |
LocalFlow::defAssigns(adef, _, e1) and
def.getAnUltimateDefinition().(Ssa::ExplicitDefinition).getADefinition() = adef and
exists(def.getAReadAtNode(e2))
)
}
@@ -492,6 +493,30 @@ module VariableCapture {
}
}
/** Provides logic related to SSA. */
module SsaFlow {
private module Impl = SsaImpl::DataFlowIntegration;
Impl::Node asNode(Node n) {
n = TSsaNode(result)
or
result.(Impl::ExprNode).getExpr() = n.(ExprNode).getControlFlowNode()
or
result.(Impl::ExprPostUpdateNode).getExpr() =
n.(PostUpdateNode).getPreUpdateNode().(ExprNode).getControlFlowNode()
or
result.(Impl::ParameterNode).getParameter() = n.(ExplicitParameterNode).getSsaDefinition()
}
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
}
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
}
}
/** Provides predicates related to local data flow. */
module LocalFlow {
class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -617,105 +642,6 @@ module LocalFlow {
any(LocalExprStepConfiguration x).hasDefPath(_, value, def, cfnDef)
}
predicate ssaDefAssigns(Ssa::ExplicitDefinition ssaDef, ControlFlow::Nodes::ExprNode value) {
exists(AssignableDefinition def, ControlFlow::Node cfnDef |
any(LocalExprStepConfiguration conf).hasDefPath(_, value, def, cfnDef) and
ssaDef.getADefinition() = def and
ssaDef.getControlFlowNode() = cfnDef
)
}
/**
* An uncertain SSA definition. Either an uncertain explicit definition or an
* uncertain qualifier definition.
*
* Restricts `Ssa::UncertainDefinition` by excluding implicit call definitions,
* as we---conservatively---consider such definitions to be certain.
*/
class UncertainExplicitSsaDefinition extends Ssa::UncertainDefinition {
UncertainExplicitSsaDefinition() {
this instanceof Ssa::ExplicitDefinition
or
this =
any(Ssa::ImplicitQualifierDefinition qdef |
qdef.getQualifierDefinition() instanceof UncertainExplicitSsaDefinition
)
}
}
/** An SSA definition into which another SSA definition may flow. */
private class SsaInputDefinitionExtNode extends SsaDefinitionExtNode {
SsaInputDefinitionExtNode() {
def instanceof Ssa::PhiNode
or
def instanceof SsaImpl::PhiReadNode
or
def instanceof LocalFlow::UncertainExplicitSsaDefinition
}
}
/**
* Holds if `nodeFrom` is a last node referencing SSA definition `def`, which
* can reach `next`.
*/
private predicate localFlowSsaInputFromDef(
Node nodeFrom, SsaImpl::DefinitionExt def, SsaInputDefinitionExtNode next
) {
exists(ControlFlow::BasicBlock bb, int i |
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
def.definesAt(_, bb, i, _) and
def = getSsaDefinitionExt(nodeFrom) and
nodeFrom != next
)
}
/**
* Holds if `read` is a last node reading SSA definition `def`, which
* can reach `next`.
*/
predicate localFlowSsaInputFromRead(
Node read, SsaImpl::DefinitionExt def, SsaInputDefinitionExtNode next
) {
exists(ControlFlow::BasicBlock bb, int i |
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
read.asExprAtNode(bb.getNode(i)) instanceof AssignableRead
)
}
private SsaImpl::DefinitionExt getSsaDefinitionExt(Node n) {
result = n.(SsaDefinitionExtNode).getDefinitionExt()
or
result = n.(ExplicitParameterNode).getSsaDefinition()
}
/**
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
* involving SSA definition `def`.
*/
predicate localSsaFlowStepUseUse(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo |
SsaImpl::adjacentReadPairSameVarExt(def, cfnFrom, cfnTo) and
nodeTo = TExprNode(cfnTo) and
nodeFrom = TExprNode(cfnFrom)
)
}
/**
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
* SSA definition `def`.
*/
predicate localSsaFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
// Flow from SSA definition/parameter to first read
def = getSsaDefinitionExt(nodeFrom) and
SsaImpl::firstReadSameVarExt(def, nodeTo.(ExprNode).getControlFlowNode())
or
// Flow from read to next read
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
or
// Flow into phi (read)/uncertain SSA definition node from def
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
}
/**
* Holds if the source variable of SSA definition `def` is an instance field.
*/
@@ -800,10 +726,7 @@ module LocalFlow {
node2.asExpr() instanceof AssignExpr
)
or
exists(SsaImpl::Definition def |
def = getSsaDefinitionExt(node1) and
exists(SsaImpl::getAReadAtNode(def, node2.(ExprNode).getControlFlowNode()))
)
SsaFlow::localMustFlowStep(_, node1, node2)
or
node2 = node1.(LocalFunctionCreationNode).getAnAccess(true)
or
@@ -827,23 +750,15 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
(
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
exists(SsaImpl::DefinitionExt def |
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
not LocalFlow::usesInstanceField(def) and
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo)
isUseStep = false
or
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _) and
nodeFrom != nodeTo
or
// Flow into phi (read)/uncertain SSA definition node from read
exists(Node read | LocalFlow::localFlowSsaInputFromRead(read, def, nodeTo) |
nodeFrom = read and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
or
nodeFrom.(PostUpdateNode).getPreUpdateNode() = read
)
isUseStep = true and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
)
or
nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode)
@@ -1099,11 +1014,7 @@ private module Cached {
cached
newtype TNode =
TExprNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getAstNode() instanceof Expr } or
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) {
// Handled by `TExplicitParameterNode` below
not def instanceof Ssa::ImplicitParameterDefinition and
def.getBasicBlock() = any(DataFlowCallable c).getAControlFlowNode().getBasicBlock()
} or
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
TAssignableDefinitionNode(AssignableDefinition def, ControlFlow::Node cfn) {
cfn = def.getExpr().getAControlFlowNode()
} or
@@ -1166,17 +1077,7 @@ private module Cached {
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) and
nodeFrom != nodeTo
or
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
or
// Flow into phi (read)/uncertain SSA definition node from read
exists(Node read | LocalFlow::localFlowSsaInputFromRead(read, _, nodeTo) |
nodeFrom = read
or
nodeFrom.(PostUpdateNode).getPreUpdateNode() = read
)
SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _)
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
@@ -1245,7 +1146,7 @@ import Cached
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) {
n instanceof SsaDefinitionExtNode
n instanceof SsaNode
or
exists(Parameter p | p = n.(ParameterNode).getParameter() | not p.fromSource())
or
@@ -1279,13 +1180,16 @@ predicate nodeIsHidden(Node n) {
n instanceof CaptureNode
}
/** An SSA definition, viewed as a node in a data flow graph. */
class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
/** An SSA node. */
abstract class SsaNode extends NodeImpl, TSsaNode {
SsaImpl::DataFlowIntegration::SsaNode node;
SsaImpl::DefinitionExt def;
SsaDefinitionExtNode() { this = TSsaDefinitionExtNode(def) }
SsaNode() {
this = TSsaNode(node) and
def = node.getDefinitionExt()
}
/** Gets the underlying SSA definition. */
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
override DataFlowCallable getEnclosingCallableImpl() {
@@ -1298,9 +1202,57 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
result = def.(Ssa::Definition).getControlFlowNode()
}
override Location getLocationImpl() { result = def.getLocation() }
override Location getLocationImpl() { result = node.getLocation() }
override string toStringImpl() { result = def.toString() }
override string toStringImpl() { result = node.toString() }
}
/** An (extended) SSA definition, viewed as a node in a data flow graph. */
class SsaDefinitionExtNode extends SsaNode {
override SsaImpl::DataFlowIntegration::SsaDefinitionExtNode node;
}
/**
* A node that represents an input to an SSA phi (read) definition.
*
* This allows for barrier guards to filter input to phi nodes. For example, in
*
* ```csharp
* var x = taint;
* if (x != "safe")
* {
* x = "safe";
* }
* sink(x);
* ```
*
* the `false` edge out of `x != "safe"` guards the input from `x = taint` into the
* `phi` node after the condition.
*
* It is also relevant to filter input into phi read nodes:
*
* ```csharp
* var x = taint;
* if (b)
* {
* if (x != "safe1")
* {
* return;
* }
* } else {
* if (x != "safe2")
* {
* return;
* }
* }
*
* sink(x);
* ```
*
* both inputs into the phi read node after the outer condition are guarded.
*/
class SsaInputNode extends SsaNode {
override SsaImpl::DataFlowIntegration::SsaInputNode node;
}
/** A definition, viewed as a node in a data flow graph. */
@@ -2946,7 +2898,7 @@ private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) {
exists(SsaImpl::DefinitionExt def |
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, _) and
preservesValue = true
|
LocalFlow::usesInstanceField(def)

View File

@@ -171,8 +171,14 @@ signature predicate guardChecksSig(Guard g, Expr e, AbstractValue v);
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
private import SsaImpl as SsaImpl
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
pragma[nomagic]
Node getABarrierNode() {
SsaFlow::asNode(result) =
SsaImpl::DataFlowIntegration::BarrierGuard<guardChecks/3>::getABarrierNode()
or
exists(Guard g, Expr e, AbstractValue v |
guardChecks(g, e, v) and
g.controlsNode(result.getControlFlowNode(), e, v)
@@ -293,9 +299,12 @@ class ContentSet extends TContentSet {
*/
predicate isProperty(Property p) { this = TPropertyContentSet(p) }
/** Holds if this content set represent the field `f`. */
/** Holds if this content set represents the field `f`. */
predicate isField(Field f) { this.isSingleton(TFieldContent(f)) }
/** Holds if this content set represents the synthetic field `s`. */
predicate isSyntheticField(string s) { this.isSingleton(TSyntheticFieldContent(s)) }
/** Holds if this content set represents an element in a collection. */
predicate isElement() { this.isSingleton(TElementContent()) }

View File

@@ -28,11 +28,14 @@
* types can be short names or fully qualified names (mixing these two options
* is not allowed within a single signature).
* 6. The `ext` column specifies additional API-graph-like edges. Currently
* there are only two valid values: "" and "Attribute". The empty string has no
* effect. "Attribute" applies if `name` and `signature` were left blank and
* acts by selecting an element that is attributed with the attribute type
* selected by the first 4 columns. This can be another member such as a field,
* property, method, or parameter.
* there are only a few valid values: "", "Attribute", "Attribute.Getter" and "Attribute.Setter".
* The empty string has no effect. "Attribute" applies if `name` and `signature` were left blank
* and acts by selecting an element (except for properties and indexers) that is attributed with
* the attribute type selected by the first 4 columns. This can be another member such as
* a field, method, or parameter. "Attribute.Getter" and "Attribute.Setter" work similar to
* "Attribute", except that they can only be applied to properties and indexers.
* "Attribute.Setter" selects the setter element of a property/indexer and "Attribute.Getter"
* selects the getter.
* 7. The `input` column specifies how data enters the element selected by the
* first 6 columns, and the `output` column specifies how data leaves the
* element selected by the first 6 columns. For sinks, an `input` can be either "",
@@ -96,6 +99,7 @@ private import FlowSummaryImpl::Private::External
private import semmle.code.csharp.commons.QualifiedName
private import semmle.code.csharp.dispatch.OverridableCallable
private import semmle.code.csharp.frameworks.System
private import codeql.dataflow.internal.AccessPathSyntax as AccessPathSyntax
private import codeql.mad.ModelValidation as SharedModelVal
/**
@@ -194,8 +198,6 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
/** Provides a query predicate to check the MaD models for validation errors. */
module ModelValidation {
private import codeql.dataflow.internal.AccessPathSyntax as AccessPathSyntax
private predicate getRelevantAccessPath(string path) {
summaryModel(_, _, _, _, _, _, path, _, _, _, _) or
summaryModel(_, _, _, _, _, _, _, path, _, _, _) or
@@ -289,7 +291,7 @@ module ModelValidation {
not signature.regexpMatch("|\\([a-zA-Z0-9_<>\\.\\+\\*,\\[\\]]*\\)") and
result = "Dubious signature \"" + signature + "\" in " + pred + " model."
or
not ext.regexpMatch("|Attribute") and
not ext = ["", "Attribute", "Attribute.Getter", "Attribute.Setter"] and
result = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
or
invalidProvenance(provenance) and
@@ -406,6 +408,30 @@ Declaration interpretBaseDeclaration(string namespace, string type, string name,
)
}
pragma[inline]
private Declaration interpretExt(Declaration d, ExtPath ext) {
ext = "" and result = d
or
ext.getToken(0) = "Attribute" and
(
not exists(ext.getToken(1)) and
result.(Attributable).getAnAttribute().getType() = d and
not result instanceof Property and
not result instanceof Indexer
or
exists(string accessor | accessor = ext.getToken(1) |
result.(Accessor).getDeclaration().getAnAttribute().getType() = d and
(
result instanceof Getter and
accessor = "Getter"
or
result instanceof Setter and
accessor = "Setter"
)
)
)
}
/** Gets the source/sink/summary/neutral element corresponding to the supplied parameters. */
pragma[nomagic]
Declaration interpretElement(
@@ -425,12 +451,18 @@ Declaration interpretElement(
)
)
|
ext = "" and result = d
or
ext = "Attribute" and result.(Attributable).getAnAttribute().getType() = d
result = interpretExt(d, ext)
)
}
private predicate relevantExt(string ext) {
summaryModel(_, _, _, _, _, ext, _, _, _, _, _) or
sourceModel(_, _, _, _, _, ext, _, _, _, _) or
sinkModel(_, _, _, _, _, ext, _, _, _, _)
}
private class ExtPath = AccessPathSyntax::AccessPath<relevantExt/1>::AccessPath;
private predicate parseSynthField(AccessPathToken c, string name) {
c.getName() = "SyntheticField" and name = c.getAnArgument()
}

View File

@@ -6,6 +6,7 @@ import csharp
private import codeql.ssa.Ssa as SsaImplCommon
private import AssignableDefinitions
private import semmle.code.csharp.controlflow.internal.PreSsa
private import semmle.code.csharp.controlflow.Guards as Guards
private module SsaInput implements SsaImplCommon::InputSig<Location> {
class BasicBlock = ControlFlow::BasicBlock;
@@ -49,7 +50,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
}
}
private import SsaImplCommon::Make<Location, SsaInput> as Impl
import SsaImplCommon::Make<Location, SsaInput> as Impl
class Definition = Impl::Definition;
@@ -761,24 +762,6 @@ private predicate adjacentDefReachesRead(
)
}
private predicate adjacentDefReachesReadExt(
DefinitionExt def, SsaInput::SourceVariable v, SsaInput::BasicBlock bb1, int i1,
SsaInput::BasicBlock bb2, int i2
) {
Impl::adjacentDefReadExt(def, v, bb1, i1, bb2, i2) and
(
def.definesAt(v, bb1, i1, _)
or
SsaInput::variableRead(bb1, i1, v, true)
)
or
exists(SsaInput::BasicBlock bb3, int i3 |
adjacentDefReachesReadExt(def, v, bb1, i1, bb3, i3) and
SsaInput::variableRead(bb3, i3, v, false) and
Impl::adjacentDefReadExt(def, v, bb3, i3, bb2, i2)
)
}
/** Same as `adjacentDefRead`, but skips uncertain reads. */
pragma[nomagic]
private predicate adjacentDefSkipUncertainReads(
@@ -790,17 +773,6 @@ private predicate adjacentDefSkipUncertainReads(
)
}
/** Same as `adjacentDefReadExt`, but skips uncertain reads. */
pragma[nomagic]
private predicate adjacentDefSkipUncertainReadsExt(
DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
) {
exists(SsaInput::SourceVariable v |
adjacentDefReachesReadExt(def, v, bb1, i1, bb2, i2) and
SsaInput::variableRead(bb2, i2, v, true)
)
}
private predicate adjacentDefReachesUncertainRead(
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
) {
@@ -810,16 +782,6 @@ private predicate adjacentDefReachesUncertainRead(
)
}
pragma[nomagic]
private predicate adjacentDefReachesUncertainReadExt(
DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
) {
exists(SsaInput::SourceVariable v |
adjacentDefReachesReadExt(def, v, bb1, i1, bb2, i2) and
SsaInput::variableRead(bb2, i2, v, false)
)
}
/** Same as `lastRefRedef`, but skips uncertain reads. */
pragma[nomagic]
private predicate lastRefSkipUncertainReads(Definition def, SsaInput::BasicBlock bb, int i) {
@@ -874,7 +836,7 @@ private module Cached {
predicate implicitEntryDefinition(ControlFlow::ControlFlow::BasicBlock bb, Ssa::SourceVariable v) {
exists(ControlFlow::ControlFlow::BasicBlocks::EntryBlock entry, Callable c |
c = entry.getCallable() and
// In case `c` has multiple bodies, we want each body to gets its own implicit
// In case `c` has multiple bodies, we want each body to get its own implicit
// entry definition. In case `c` doesn't have multiple bodies, the line below
// is simply the same as `bb = entry`, because `entry.getFirstNode().getASuccessor()`
// will be in the entry block.
@@ -969,19 +931,6 @@ private module Cached {
)
}
/**
* Holds if the value defined at SSA definition `def` can reach a read at `cfn`,
* without passing through any other read.
*/
cached
predicate firstReadSameVarExt(DefinitionExt def, ControlFlow::Node cfn) {
exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 |
def.definesAt(_, bb1, i1, _) and
adjacentDefSkipUncertainReadsExt(def, bb1, i1, bb2, i2) and
cfn = bb2.getNode(i2)
)
}
/**
* Holds if the read at `cfn2` is a read of the same SSA definition `def`
* as the read at `cfn1`, and `cfn2` can be reached from `cfn1` without
@@ -997,23 +946,6 @@ private module Cached {
)
}
/**
* Holds if the read at `cfn2` is a read of the same SSA definition `def`
* as the read at `cfn1`, and `cfn2` can be reached from `cfn1` without
* passing through another read.
*/
cached
predicate adjacentReadPairSameVarExt(
DefinitionExt def, ControlFlow::Node cfn1, ControlFlow::Node cfn2
) {
exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 |
cfn1 = bb1.getNode(i1) and
variableReadActual(bb1, i1, _) and
adjacentDefSkipUncertainReadsExt(def, bb1, i1, bb2, i2) and
cfn2 = bb2.getNode(i2)
)
}
cached
predicate lastRefBeforeRedef(Definition def, ControlFlow::BasicBlock bb, int i, Definition next) {
Impl::lastRefRedef(def, bb, i, next) and
@@ -1025,21 +957,6 @@ private module Cached {
)
}
cached
predicate lastRefBeforeRedefExt(
DefinitionExt def, ControlFlow::BasicBlock bb, int i, DefinitionExt next
) {
exists(SsaInput::SourceVariable v |
Impl::lastRefRedefExt(def, v, bb, i, next) and
not SsaInput::variableRead(bb, i, v, false)
)
or
exists(SsaInput::BasicBlock bb0, int i0 |
Impl::lastRefRedefExt(def, _, bb0, i0, next) and
adjacentDefReachesUncertainReadExt(def, bb, i, bb0, i0)
)
}
cached
predicate lastReadSameVar(Definition def, ControlFlow::Node cfn) {
exists(ControlFlow::BasicBlock bb, int i |
@@ -1065,6 +982,41 @@ private module Cached {
outRefExitRead(bb, i, v)
)
}
cached
module DataFlowIntegration {
import DataFlowIntegrationImpl
cached
predicate localFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
DataFlowIntegrationImpl::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
}
cached
predicate localMustFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo) {
DataFlowIntegrationImpl::localMustFlowStep(def, nodeFrom, nodeTo)
}
signature predicate guardChecksSig(Guards::Guard g, Expr e, Guards::AbstractValue v);
cached // nothing is actually cached
module BarrierGuard<guardChecksSig/3 guardChecks> {
private predicate guardChecksAdjTypes(
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e, boolean branch
) {
exists(Guards::AbstractValues::BooleanValue v |
guardChecks(g, e.getAstNode(), v) and
branch = v.getValue()
)
}
private Node getABarrierNodeImpl() {
result = DataFlowIntegrationImpl::BarrierGuard<guardChecksAdjTypes/3>::getABarrierNode()
}
predicate getABarrierNode = getABarrierNodeImpl/0;
}
}
}
import Cached
@@ -1122,3 +1074,64 @@ class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
result = this.getSourceVariable().getEnclosingCallable()
}
}
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
private import csharp as Cs
private import semmle.code.csharp.controlflow.BasicBlocks
class Expr extends ControlFlow::Node {
predicate hasCfgNode(ControlFlow::BasicBlock bb, int i) { this = bb.getNode(i) }
}
Expr getARead(Definition def) { exists(getAReadAtNode(def, result)) }
predicate ssaDefAssigns(WriteDefinition def, Expr value) {
// exclude flow directly from RHS to SSA definition, as we instead want to
// go from RHS to matching assingnable definition, and from there to SSA definition
none()
}
class Parameter = Ssa::ImplicitParameterDefinition;
predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) { def = p }
/**
* Allows for flow into uncertain defintions that are not call definitions,
* as we, conservatively, consider such definitions to be certain.
*/
predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) {
def instanceof Ssa::ExplicitDefinition
or
def =
any(Ssa::ImplicitQualifierDefinition qdef |
allowFlowIntoUncertainDef(qdef.getQualifierDefinition())
)
}
class Guard extends Guards::Guard {
predicate hasCfgNode(ControlFlow::BasicBlock bb, int i) {
this.getAControlFlowNode() = bb.getNode(i)
}
}
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
predicate guardControlsBlock(Guard guard, ControlFlow::BasicBlock bb, boolean branch) {
exists(ConditionBlock conditionBlock, ControlFlow::SuccessorTypes::ConditionalSuccessor s |
guard.getAControlFlowNode() = conditionBlock.getLastNode() and
s.getValue() = branch and
conditionBlock.controls(bb, s)
)
}
/** Gets an immediate conditional successor of basic block `bb`, if any. */
ControlFlow::BasicBlock getAConditionalBasicBlockSuccessor(
ControlFlow::BasicBlock bb, boolean branch
) {
exists(ControlFlow::SuccessorTypes::ConditionalSuccessor s |
result = bb.getASuccessorByType(s) and
s.getValue() = branch
)
}
}
private module DataFlowIntegrationImpl = Impl::DataFlowIntegration<DataFlowIntegrationInput>;

View File

@@ -1,122 +0,0 @@
/**
* Provides `Callable` classes, which are things that can be called
* such as methods and constructors.
*/
import Declaration
import Variable
import Expr
import Parameterizable
/** A .Net callable. */
deprecated class Callable extends Parameterizable, @dotnet_callable {
/** Holds if this callable has a body or an implementation. */
predicate hasBody() { none() }
/** Holds if this callable can return expression `e`. */
predicate canReturn(Expr e) { none() }
pragma[noinline]
private string getDeclaringTypeLabel() { result = this.getDeclaringType().getLabel() }
pragma[noinline]
private string getParameterTypeLabelNonGeneric(int p) {
not this instanceof Generic and
result = this.getParameter(p).getType().getLabel()
}
language[monotonicAggregates]
pragma[nomagic]
private string getMethodParamListNonGeneric() {
result =
concat(int p |
p in [0 .. this.getNumberOfParameters() - 1]
|
this.getParameterTypeLabelNonGeneric(p), "," order by p
)
}
pragma[noinline]
private string getParameterTypeLabelGeneric(int p) {
this instanceof Generic and
result = this.getParameter(p).getType().getLabel()
}
language[monotonicAggregates]
pragma[nomagic]
private string getMethodParamListGeneric() {
result =
concat(int p |
p in [0 .. this.getNumberOfParameters() - 1]
|
this.getParameterTypeLabelGeneric(p), "," order by p
)
}
pragma[noinline]
private string getLabelNonGeneric() {
not this instanceof Generic and
result =
this.getReturnTypeLabel() + " " + this.getDeclaringTypeLabel() + "." +
this.getUndecoratedName() + "(" + this.getMethodParamListNonGeneric() + ")"
}
pragma[noinline]
private string getLabelGeneric() {
result =
this.getReturnTypeLabel() + " " + this.getDeclaringTypeLabel() + "." +
this.getUndecoratedName() + getGenericsLabel(this) + "(" + this.getMethodParamListGeneric() +
")"
}
final override string getLabel() {
result = this.getLabelNonGeneric() or
result = this.getLabelGeneric()
}
private string getReturnTypeLabel() {
result = this.getReturnType().getLabel()
or
not exists(this.getReturnType()) and result = "System.Void"
}
/** Gets the return type of this callable. */
Type getReturnType() { none() }
}
/** A constructor. */
abstract deprecated class Constructor extends Callable { }
/** A destructor/finalizer. */
abstract deprecated class Destructor extends Callable { }
pragma[nomagic]
deprecated private ValueOrRefType getARecordBaseType(ValueOrRefType t) {
exists(Callable c |
c.hasName("<Clone>$") and
c.getNumberOfParameters() = 0 and
t = c.getDeclaringType() and
result = t
)
or
result = getARecordBaseType(t).getABaseType()
}
/** A clone method on a record. */
deprecated class RecordCloneCallable extends Callable {
RecordCloneCallable() {
this.getDeclaringType() instanceof ValueOrRefType and
this.hasName("<Clone>$") and
this.getNumberOfParameters() = 0 and
this.getReturnType() = getARecordBaseType(this.getDeclaringType()) and
this.(Member).isPublic() and
not this.(Member).isStatic()
}
/** Gets the constructor that this clone method calls. */
Constructor getConstructor() {
result.getDeclaringType() = this.getDeclaringType() and
result.getNumberOfParameters() = 1 and
result.getParameter(0).getType() = this.getDeclaringType()
}
}

View File

@@ -1,123 +0,0 @@
/**
* Provides classes for .Net declarations.
*/
import Element
import Type
private import semmle.code.csharp.commons.QualifiedName
/** A declaration. */
deprecated class Declaration extends NamedElement, @dotnet_declaration {
/** Gets the name of this declaration, without additional decoration such as `<...>`. */
string getUndecoratedName() { none() }
/** Holds if this element has undecorated name 'name'. */
final predicate hasUndecoratedName(string name) { name = this.getUndecoratedName() }
/** Gets the type containing this declaration, if any. */
Type getDeclaringType() { none() }
/**
* Gets the unbound version of this declaration, that is, the declaration where
* all type arguments have been removed. For example, in
*
* ```csharp
* class C<T>
* {
* class Nested
* {
* }
*
* void Method<S>() { }
* }
* ```
*
* we have the following
*
* | Declaration | Unbound declaration |
* |-------------------------|---------------------|
* | `C<int>` | ``C`1`` |
* | ``C`1.Nested`` | ``C`1.Nested`` |
* | `C<int>.Nested` | ``C`1.Nested`` |
* | ``C`1.Method`1`` | ``C`1.Method`1`` |
* | ``C<int>.Method`1`` | ``C`1.Method`1`` |
* | `C<int>.Method<string>` | ``C`1.Method`1`` |
*/
Declaration getUnboundDeclaration() { result = this }
/** Holds if this declaration is unbound. */
final predicate isUnboundDeclaration() { this.getUnboundDeclaration() = this }
}
/** A member of a type. */
deprecated class Member extends Declaration, @dotnet_member {
/** Holds if this member is declared `public`. */
predicate isPublic() { none() }
/** Holds if this member is declared `protected.` */
predicate isProtected() { none() }
/** Holds if this member is `private`. */
predicate isPrivate() { none() }
/** Holds if this member is `internal`. */
predicate isInternal() { none() }
/** Holds if this member is `sealed`. */
predicate isSealed() { none() }
/** Holds if this member is `abstract`. */
predicate isAbstract() { none() }
/** Holds if this member is `static`. */
predicate isStatic() { none() }
/** Holds if this member is declared `required`. */
predicate isRequired() { none() }
/** Holds if this member is declared `file` local. */
predicate isFile() { none() }
/**
* DEPRECATED: Use `hasFullyQualifiedName` instead.
*
* Holds if this member has name `name` and is defined in type `type`
* with namespace `namespace`.
*/
cached
deprecated predicate hasQualifiedName(string namespace, string type, string name) {
this.getDeclaringType().hasQualifiedName(namespace, type) and
name = this.getName()
}
/**
* Holds if this member has name `name` and is defined in type `type`
* with namespace `namespace`.
*/
cached
predicate hasFullyQualifiedName(string namespace, string type, string name) {
this.getDeclaringType().hasFullyQualifiedName(namespace, type) and
name = this.getName()
}
}
/** A property. */
deprecated class Property extends Member, @dotnet_property {
/** Gets the getter of this property, if any. */
Callable getGetter() { none() }
/** Gets the setter of this property, if any. */
Callable getSetter() { none() }
/** Gets the type of this property. */
Type getType() { none() }
}
/** An event. */
deprecated class Event extends Member, @dotnet_event {
/** Gets the adder of this event, if any. */
Callable getAdder() { none() }
/** Gets the remover of this event, if any. */
Callable getRemover() { none() }
}

View File

@@ -1,13 +0,0 @@
/**
* Provides a common model for all .Net languages, including C# and CIL.
*/
import Element
import Namespace
import Declaration
import Generics
import Type
import Variable
import Callable
import Expr
import Utils

View File

@@ -1,162 +0,0 @@
/**
* Provides the .Net `Element` class.
*/
private import DotNet
import semmle.code.csharp.Location
/**
* A .Net program element.
*/
deprecated class Element extends @dotnet_element {
/** Gets a textual representation of this element. */
cached
string toString() { none() }
/** Gets the location of this element. */
pragma[nomagic]
Location getLocation() { none() }
/**
* Gets a location of this element, which can include locations in
* both DLLs and source files.
*/
Location getALocation() { none() }
/** Gets the file containing this element. */
final File getFile() { result = this.getLocation().getFile() }
/** Holds if this element is from source code. */
predicate fromSource() { this.getFile().fromSource() }
/** Holds if this element is from an assembly. */
predicate fromLibrary() { this.getFile().fromLibrary() }
/**
* Gets the "language" of this program element, as defined by the extension of the filename.
* For example, C# has language "cs", and Visual Basic has language "vb".
*/
final string getLanguage() { result = this.getLocation().getFile().getExtension() }
/** Gets the full textual representation of this element, including type information. */
string toStringWithTypes() { result = this.toString() }
/**
* 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 = strictconcat(this.getAPrimaryQlClass(), ",")
or
not exists(this.getAPrimaryQlClass()) and
result = "???"
}
/**
* Gets the name of a primary CodeQL class to which this element belongs.
*
* For most elements, this is simply the most precise syntactic category to
* which they belong; for example, `AddExpr` is a primary class, but
* `BinaryOperation` is not.
*
* 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() { none() }
}
/** An element that has a name. */
deprecated class NamedElement extends Element, @dotnet_named_element {
/** Gets the name of this element. */
cached
string getName() { none() }
/** Holds if this element has name 'name'. */
final predicate hasName(string name) { name = this.getName() }
/**
* Gets the fully qualified name of this element, for example the
* fully qualified name of `M` on line 3 is `N.C.M` in
*
* ```csharp
* namespace N {
* class C {
* void M(int i, string s) { }
* }
* }
* ```
*/
cached
deprecated final string getQualifiedName() {
exists(string qualifier, string name | this.hasQualifiedName(qualifier, name) |
if qualifier = "" then result = name else result = qualifier + "." + name
)
}
/**
* Gets the fully qualified name of this element, for example the
* fully qualified name of `M` on line 3 is `N.C.M` in
*
* ```csharp
* namespace N {
* class C {
* void M(int i, string s) { }
* }
* }
* ```
*
* Unbound generic types, such as `IList<T>`, are represented as
* ``System.Collections.Generic.IList`1``.
*/
cached
final string getFullyQualifiedName() {
exists(string qualifier, string name | this.hasFullyQualifiedName(qualifier, name) |
if qualifier = "" then result = name else result = qualifier + "." + name
)
}
/**
* DEPRECATED: Use `hasFullyQualifiedName` instead.
*
* Holds if this element has the qualified name `qualifier`.`name`.
*/
cached
deprecated predicate hasQualifiedName(string qualifier, string name) {
qualifier = "" and name = this.getName()
}
/** Holds if this element has the fully qualified name `qualifier`.`name`. */
cached
predicate hasFullyQualifiedName(string qualifier, string name) {
qualifier = "" and name = this.getName()
}
/** Gets a unique string label for this element. */
cached
string getLabel() { none() }
/** Holds if `other` has the same metadata handle in the same assembly. */
predicate matchesHandle(NamedElement other) {
exists(Assembly asm, int handle |
metadata_handle(this, asm, handle) and
metadata_handle(other, asm, handle)
)
}
/**
* Holds if this element was compiled from source code that is also present in the
* database. That is, this element corresponds to another element from source.
*/
predicate compiledFromSource() {
not this.fromSource() and
exists(NamedElement other | other != this |
this.matchesHandle(other) and
other.fromSource()
)
}
override string toString() { result = this.getName() }
}

View File

@@ -1,64 +0,0 @@
/**
* Provides .Net expression classes.
*/
import Expr
import Type
import Callable
/** An expression. */
deprecated class Expr extends Element, @dotnet_expr {
/** Gets the callable containing this expression. */
Callable getEnclosingCallable() { none() }
/** Gets the type of this expression. */
Type getType() { none() }
/** Gets the constant value of this expression, if any. */
string getValue() { none() }
/** Holds if this expression has a value. */
final predicate hasValue() { exists(this.getValue()) }
/**
* Gets the parent of this expression. This is for example the element
* that uses the result of this expression.
*/
Element getParent() { none() }
}
/** A call. */
deprecated class Call extends Expr, @dotnet_call {
/** Gets the target of this call. */
Callable getTarget() { none() }
/** Gets any potential target of this call. */
Callable getARuntimeTarget() { none() }
/**
* Gets the `i`th "raw" argument to this call, if any.
* For instance methods, argument 0 is the qualifier.
*/
Expr getRawArgument(int i) { none() }
/** Gets the `i`th argument to this call, if any. */
Expr getArgument(int i) { none() }
/** Gets an argument to this call. */
Expr getAnArgument() { result = this.getArgument(_) }
/** Gets the expression that is supplied for parameter `p`. */
Expr getArgumentForParameter(Parameter p) { none() }
}
/** A literal expression. */
deprecated class Literal extends Expr, @dotnet_literal { }
/** A string literal expression. */
deprecated class StringLiteral extends Literal, @dotnet_string_literal { }
/** An integer literal expression. */
deprecated class IntLiteral extends Literal, @dotnet_int_literal { }
/** A `null` literal expression. */
deprecated class NullLiteral extends Literal, @dotnet_null_literal { }

View File

@@ -1,72 +0,0 @@
/** Provides classes for generic types and methods. */
import Declaration
/**
* A generic declaration. Either an unbound generic (`UnboundGeneric`) or a
* constructed generic (`ConstructedGeneric`).
*/
abstract deprecated class Generic extends Declaration, @dotnet_generic { }
/** An unbound generic. */
abstract deprecated class UnboundGeneric extends Generic {
/** Gets the `i`th type parameter, if any. */
abstract TypeParameter getTypeParameter(int i);
/** Gets a type parameter. */
TypeParameter getATypeParameter() { result = this.getTypeParameter(_) }
/**
* Gets one of the constructed versions of this declaration,
* which has been bound to a specific set of types.
*/
ConstructedGeneric getAConstructedGeneric() { result.getUnboundGeneric() = this }
/** Gets the total number of type parameters. */
int getNumberOfTypeParameters() { result = count(int i | exists(this.getTypeParameter(i))) }
}
/** A constructed generic. */
abstract deprecated class ConstructedGeneric extends Generic {
/** Gets the `i`th type argument, if any. */
abstract Type getTypeArgument(int i);
/** Gets a type argument. */
Type getATypeArgument() { result = this.getTypeArgument(_) }
/**
* Gets the unbound generic declaration from which this declaration was
* constructed.
*/
UnboundGeneric getUnboundGeneric() { none() }
/** Gets the total number of type arguments. */
final int getNumberOfTypeArguments() { result = count(int i | exists(this.getTypeArgument(i))) }
}
/**
* INTERNAL: Do not use.
*
* Constructs the label suffix for a generic method or type.
*/
deprecated string getGenericsLabel(Generic g) {
result = "`" + g.(UnboundGeneric).getNumberOfTypeParameters()
or
result = "<" + typeArgs(g) + ">"
}
pragma[noinline]
deprecated private string getTypeArgumentLabel(ConstructedGeneric generic, int p) {
result = generic.getTypeArgument(p).getLabel()
}
language[monotonicAggregates]
pragma[nomagic]
deprecated private string typeArgs(ConstructedGeneric generic) {
result =
concat(int p |
p in [0 .. generic.getNumberOfTypeArguments() - 1]
|
getTypeArgumentLabel(generic, p), ","
)
}

View File

@@ -1,69 +0,0 @@
/**
* Provides the `Namespace` class to represent .Net namespaces.
*/
private import Declaration
private import semmle.code.csharp.commons.QualifiedName
/** A namespace. */
deprecated class Namespace extends Declaration, @namespace {
/**
* Gets the parent namespace, if any. For example the parent namespace of `System.IO`
* is `System`. The parent namespace of `System` is the global namespace.
*/
Namespace getParentNamespace() { none() }
/**
* Gets a child namespace, if any. For example `System.IO` is a child in
* the namespace `System`.
*/
Namespace getAChildNamespace() { result.getParentNamespace() = this }
/**
* Holds if this namespace has the qualified name `qualifier`.`name`.
*
* For example if the qualified name is `System.Collections.Generic`, then
* `qualifier`=`System.Collections` and `name`=`Generic`.
*/
deprecated override predicate hasQualifiedName(string qualifier, string name) {
namespaceHasQualifiedName(this, qualifier, name)
}
/**
* Holds if this namespace has the qualified name `qualifier`.`name`.
*
* For example if the qualified name is `System.Collections.Generic`, then
* `qualifier`=`System.Collections` and `name`=`Generic`.
*/
override predicate hasFullyQualifiedName(string qualifier, string name) {
namespaceHasQualifiedName(this, qualifier, name)
}
/** Gets a textual representation of this namespace. */
override string toString() { result = this.getFullName() }
/** Holds if this is the global namespace. */
final predicate isGlobalNamespace() { this.getName() = "" }
/** Gets the simple name of this namespace, for example `IO` in `System.IO`. */
final override string getName() { namespaces(this, result) }
final override string getUndecoratedName() { namespaces(this, result) }
override string getAPrimaryQlClass() { result = "Namespace" }
/**
* Get the fully qualified name of this namespace.
*/
string getFullName() {
exists(string namespace, string name |
namespaceHasQualifiedName(this, namespace, name) and
result = getQualifiedName(namespace, name)
)
}
}
/** The global namespace. */
deprecated class GlobalNamespace extends Namespace {
GlobalNamespace() { this.getName() = "" }
}

View File

@@ -1,30 +0,0 @@
/**
* Provides a general parameterizable entity to represent constructs that might
* have parameters.
*/
import Declaration
/**
* A general parameterizable entity, such as a callable, delegate type, accessor,
* indexer, or function pointer type.
*/
deprecated class Parameterizable extends Declaration, @dotnet_parameterizable {
/** Gets raw parameter `i`, including the `this` parameter at index 0. */
Parameter getRawParameter(int i) { none() }
/** Gets the `i`th parameter, excluding the `this` parameter. */
Parameter getParameter(int i) { none() }
/** Gets the number of parameters of this callable. */
int getNumberOfParameters() { result = count(this.getAParameter()) }
/** Holds if this declaration has no parameters. */
predicate hasNoParameters() { not exists(this.getAParameter()) }
/** Gets a parameter, if any. */
Parameter getAParameter() { result = this.getParameter(_) }
/** Gets a raw parameter (including the qualifier), if any. */
final Parameter getARawParameter() { result = this.getRawParameter(_) }
}

View File

@@ -1,94 +0,0 @@
/**
* Provides classes for .Net types.
*/
import Declaration
import Namespace
import Callable
import Generics
/**
* A type. Either a value or reference type (`ValueOrRefType`), a type parameter (`TypeParameter`),
* a pointer type (`PointerType`), or an array type (`ArrayType`).
*/
deprecated class Type extends Declaration, @dotnet_type {
/** Gets the name of this type without additional syntax such as `[]` or `*`. */
override string getUndecoratedName() { none() }
}
/**
* A value or reference type.
*/
deprecated class ValueOrRefType extends Type, @dotnet_valueorreftype {
/** Gets the namespace declaring this type, if any. */
Namespace getDeclaringNamespace() { none() }
private string getPrefixWithTypes() {
result = this.getDeclaringType().getLabel() + "."
or
if this.getDeclaringNamespace().isGlobalNamespace()
then result = ""
else result = this.getDeclaringNamespace().getFullName() + "."
}
pragma[noinline]
private string getLabelNonGeneric() {
not this instanceof Generic and
result = this.getPrefixWithTypes() + this.getUndecoratedName()
}
pragma[noinline]
private string getLabelGeneric() {
result = this.getPrefixWithTypes() + this.getUndecoratedName() + getGenericsLabel(this)
}
override string getLabel() {
result = this.getLabelNonGeneric() or
result = this.getLabelGeneric()
}
/** Gets a base type of this type, if any. */
ValueOrRefType getABaseType() { none() }
/** Holds if this type is a `record`. */
predicate isRecord() { exists(RecordCloneCallable c | c.getDeclaringType() = this) }
}
/**
* A type parameter, for example `T` in `System.Nullable<T>`.
*/
deprecated class TypeParameter extends Type, @dotnet_type_parameter {
/** Gets the generic type or method declaring this type parameter. */
UnboundGeneric getDeclaringGeneric() { this = result.getATypeParameter() }
/** Gets the index of this type parameter. For example the index of `U` in `Func<T,U>` is 1. */
int getIndex() { none() }
final override string getLabel() { result = "!" + this.getIndex() }
override string getUndecoratedName() { result = "!" + this.getIndex() }
}
/** A pointer type. */
deprecated class PointerType extends Type, @dotnet_pointer_type {
/** Gets the type referred by this pointer type, for example `char` in `char*`. */
Type getReferentType() { none() }
override string getName() { result = this.getReferentType().getName() + "*" }
final override string getLabel() { result = this.getReferentType().getLabel() + "*" }
override string toStringWithTypes() { result = this.getReferentType().toStringWithTypes() + "*" }
}
/** An array type. */
deprecated class ArrayType extends ValueOrRefType, @dotnet_array_type {
/** Gets the type of the array element. */
Type getElementType() { none() }
final override string getLabel() { result = this.getElementType().getLabel() + "[]" }
override string toStringWithTypes() { result = this.getElementType().toStringWithTypes() + "[]" }
override string getAPrimaryQlClass() { result = "ArrayType" }
}

View File

@@ -1,12 +0,0 @@
/**
* Provides some useful .Net classes.
*/
import Element
import Expr
/** A throw element. */
deprecated class Throw extends Element, @dotnet_throw {
/** Gets the expression being thrown, if any. */
Expr getExpr() { none() }
}

View File

@@ -1,34 +0,0 @@
/** Provides classes for .Net variables, such as fields and parameters. */
import Declaration
import Callable
/** A .Net variable. */
deprecated class Variable extends Declaration, @dotnet_variable {
/** Gets the type of this variable. */
Type getType() { none() }
}
/** A .Net field. */
deprecated class Field extends Variable, Member, @dotnet_field { }
/** A parameter to a .Net callable, property or function pointer type. */
deprecated class Parameter extends Variable, @dotnet_parameter {
/** Gets the raw position of this parameter, including the `this` parameter at index 0. */
final int getRawPosition() { this = this.getDeclaringElement().getRawParameter(result) }
/** Gets the position of this parameter, excluding the `this` parameter. */
int getPosition() { this = this.getDeclaringElement().getParameter(result) }
/** Gets the callable defining this parameter, if any. */
Callable getCallable() { result = this.getDeclaringElement() }
/** Gets the declaring `Parameterizable`. */
Parameterizable getDeclaringElement() { none() }
/** Holds if this is an `out` parameter. */
predicate isOut() { none() }
/** Holds if this is a `ref` parameter. */
predicate isRef() { none() }
}

View File

@@ -1457,643 +1457,3 @@ asp_tag_name(
unique int tag: @asp_open_tag ref,
string name: string ref);
asp_tag_isempty(int tag: @asp_open_tag ref);
/* Common Intermediate Language - CIL */
case @cil_instruction.opcode of
0 = @cil_nop
| 1 = @cil_break
| 2 = @cil_ldarg_0
| 3 = @cil_ldarg_1
| 4 = @cil_ldarg_2
| 5 = @cil_ldarg_3
| 6 = @cil_ldloc_0
| 7 = @cil_ldloc_1
| 8 = @cil_ldloc_2
| 9 = @cil_ldloc_3
| 10 = @cil_stloc_0
| 11 = @cil_stloc_1
| 12 = @cil_stloc_2
| 13 = @cil_stloc_3
| 14 = @cil_ldarg_s
| 15 = @cil_ldarga_s
| 16 = @cil_starg_s
| 17 = @cil_ldloc_s
| 18 = @cil_ldloca_s
| 19 = @cil_stloc_s
| 20 = @cil_ldnull
| 21 = @cil_ldc_i4_m1
| 22 = @cil_ldc_i4_0
| 23 = @cil_ldc_i4_1
| 24 = @cil_ldc_i4_2
| 25 = @cil_ldc_i4_3
| 26 = @cil_ldc_i4_4
| 27 = @cil_ldc_i4_5
| 28 = @cil_ldc_i4_6
| 29 = @cil_ldc_i4_7
| 30 = @cil_ldc_i4_8
| 31 = @cil_ldc_i4_s
| 32 = @cil_ldc_i4
| 33 = @cil_ldc_i8
| 34 = @cil_ldc_r4
| 35 = @cil_ldc_r8
| 37 = @cil_dup
| 38 = @cil_pop
| 39 = @cil_jmp
| 40 = @cil_call
| 41 = @cil_calli
| 42 = @cil_ret
| 43 = @cil_br_s
| 44 = @cil_brfalse_s
| 45 = @cil_brtrue_s
| 46 = @cil_beq_s
| 47 = @cil_bge_s
| 48 = @cil_bgt_s
| 49 = @cil_ble_s
| 50 = @cil_blt_s
| 51 = @cil_bne_un_s
| 52 = @cil_bge_un_s
| 53 = @cil_bgt_un_s
| 54 = @cil_ble_un_s
| 55 = @cil_blt_un_s
| 56 = @cil_br
| 57 = @cil_brfalse
| 58 = @cil_brtrue
| 59 = @cil_beq
| 60 = @cil_bge
| 61 = @cil_bgt
| 62 = @cil_ble
| 63 = @cil_blt
| 64 = @cil_bne_un
| 65 = @cil_bge_un
| 66 = @cil_bgt_un
| 67 = @cil_ble_un
| 68 = @cil_blt_un
| 69 = @cil_switch
| 70 = @cil_ldind_i1
| 71 = @cil_ldind_u1
| 72 = @cil_ldind_i2
| 73 = @cil_ldind_u2
| 74 = @cil_ldind_i4
| 75 = @cil_ldind_u4
| 76 = @cil_ldind_i8
| 77 = @cil_ldind_i
| 78 = @cil_ldind_r4
| 79 = @cil_ldind_r8
| 80 = @cil_ldind_ref
| 81 = @cil_stind_ref
| 82 = @cil_stind_i1
| 83 = @cil_stind_i2
| 84 = @cil_stind_i4
| 85 = @cil_stind_i8
| 86 = @cil_stind_r4
| 87 = @cil_stind_r8
| 88 = @cil_add
| 89 = @cil_sub
| 90 = @cil_mul
| 91 = @cil_div
| 92 = @cil_div_un
| 93 = @cil_rem
| 94 = @cil_rem_un
| 95 = @cil_and
| 96 = @cil_or
| 97 = @cil_xor
| 98 = @cil_shl
| 99 = @cil_shr
| 100 = @cil_shr_un
| 101 = @cil_neg
| 102 = @cil_not
| 103 = @cil_conv_i1
| 104 = @cil_conv_i2
| 105 = @cil_conv_i4
| 106 = @cil_conv_i8
| 107 = @cil_conv_r4
| 108 = @cil_conv_r8
| 109 = @cil_conv_u4
| 110 = @cil_conv_u8
| 111 = @cil_callvirt
| 112 = @cil_cpobj
| 113 = @cil_ldobj
| 114 = @cil_ldstr
| 115 = @cil_newobj
| 116 = @cil_castclass
| 117 = @cil_isinst
| 118 = @cil_conv_r_un
| 121 = @cil_unbox
| 122 = @cil_throw
| 123 = @cil_ldfld
| 124 = @cil_ldflda
| 125 = @cil_stfld
| 126 = @cil_ldsfld
| 127 = @cil_ldsflda
| 128 = @cil_stsfld
| 129 = @cil_stobj
| 130 = @cil_conv_ovf_i1_un
| 131 = @cil_conv_ovf_i2_un
| 132 = @cil_conv_ovf_i4_un
| 133 = @cil_conv_ovf_i8_un
| 134 = @cil_conv_ovf_u1_un
| 135 = @cil_conv_ovf_u2_un
| 136 = @cil_conv_ovf_u4_un
| 137 = @cil_conv_ovf_u8_un
| 138 = @cil_conv_ovf_i_un
| 139 = @cil_conv_ovf_u_un
| 140 = @cil_box
| 141 = @cil_newarr
| 142 = @cil_ldlen
| 143 = @cil_ldelema
| 144 = @cil_ldelem_i1
| 145 = @cil_ldelem_u1
| 146 = @cil_ldelem_i2
| 147 = @cil_ldelem_u2
| 148 = @cil_ldelem_i4
| 149 = @cil_ldelem_u4
| 150 = @cil_ldelem_i8
| 151 = @cil_ldelem_i
| 152 = @cil_ldelem_r4
| 153 = @cil_ldelem_r8
| 154 = @cil_ldelem_ref
| 155 = @cil_stelem_i
| 156 = @cil_stelem_i1
| 157 = @cil_stelem_i2
| 158 = @cil_stelem_i4
| 159 = @cil_stelem_i8
| 160 = @cil_stelem_r4
| 161 = @cil_stelem_r8
| 162 = @cil_stelem_ref
| 163 = @cil_ldelem
| 164 = @cil_stelem
| 165 = @cil_unbox_any
| 179 = @cil_conv_ovf_i1
| 180 = @cil_conv_ovf_u1
| 181 = @cil_conv_ovf_i2
| 182 = @cil_conv_ovf_u2
| 183 = @cil_conv_ovf_i4
| 184 = @cil_conv_ovf_u4
| 185 = @cil_conv_ovf_i8
| 186 = @cil_conv_ovf_u8
| 194 = @cil_refanyval
| 195 = @cil_ckinfinite
| 198 = @cil_mkrefany
| 208 = @cil_ldtoken
| 209 = @cil_conv_u2
| 210 = @cil_conv_u1
| 211 = @cil_conv_i
| 212 = @cil_conv_ovf_i
| 213 = @cil_conv_ovf_u
| 214 = @cil_add_ovf
| 215 = @cil_add_ovf_un
| 216 = @cil_mul_ovf
| 217 = @cil_mul_ovf_un
| 218 = @cil_sub_ovf
| 219 = @cil_sub_ovf_un
| 220 = @cil_endfinally
| 221 = @cil_leave
| 222 = @cil_leave_s
| 223 = @cil_stind_i
| 224 = @cil_conv_u
| 65024 = @cil_arglist
| 65025 = @cil_ceq
| 65026 = @cil_cgt
| 65027 = @cil_cgt_un
| 65028 = @cil_clt
| 65029 = @cil_clt_un
| 65030 = @cil_ldftn
| 65031 = @cil_ldvirtftn
| 65033 = @cil_ldarg
| 65034 = @cil_ldarga
| 65035 = @cil_starg
| 65036 = @cil_ldloc
| 65037 = @cil_ldloca
| 65038 = @cil_stloc
| 65039 = @cil_localloc
| 65041 = @cil_endfilter
| 65042 = @cil_unaligned
| 65043 = @cil_volatile
| 65044 = @cil_tail
| 65045 = @cil_initobj
| 65046 = @cil_constrained
| 65047 = @cil_cpblk
| 65048 = @cil_initblk
| 65050 = @cil_rethrow
| 65052 = @cil_sizeof
| 65053 = @cil_refanytype
| 65054 = @cil_readonly
;
// CIL ignored instructions
@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned;
// CIL local/parameter/field access
@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga;
@cil_starg_any = @cil_starg | @cil_starg_s;
@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca;
@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc;
@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda;
@cil_stfld_any = @cil_stfld | @cil_stsfld;
@cil_local_access = @cil_stloc_any | @cil_ldloc_any;
@cil_arg_access = @cil_starg_any | @cil_ldarg_any;
@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any;
@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any;
@cil_stack_access = @cil_local_access | @cil_arg_access;
@cil_field_access = @cil_ldfld_any | @cil_stfld_any;
@cil_access = @cil_read_access | @cil_write_access;
// CIL constant/literal instructions
@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8;
@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 |
@cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4;
@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8;
@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr;
// Control flow
@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump;
@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s |
@cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s |
@cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt |
@cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un;
@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch;
@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any;
@cil_leave_any = @cil_leave | @cil_leave_s;
@cil_jump = @cil_unconditional_jump | @cil_conditional_jump;
// CIL call instructions
@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj;
// CIL expression instructions
@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access |
@cil_newarr | @cil_ldtoken | @cil_sizeof |
@cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup;
@cil_unary_expr =
@cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation|
@cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any |
@cil_ldind | @cil_unbox;
@cil_conversion_operation =
@cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 |
@cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 |
@cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un |
@cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un |
@cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un |
@cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
@cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un |
@cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
@cil_conv_i | @cil_conv_u | @cil_conv_r_un;
@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 |
@cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4;
@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 |
@cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref;
@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation;
@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl;
@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un |
@cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un |
@cil_sub_ovf | @cil_sub_ovf_un;
@cil_unary_bitwise_operation = @cil_not;
@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation;
@cil_unary_arithmetic_operation = @cil_neg;
@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un;
// Elements that retrieve an address of something
@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema;
// CIL array instructions
@cil_read_array =
@cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i |
@cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 |
@cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4;
@cil_write_array = @cil_stelem | @cil_stelem_ref |
@cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 |
@cil_stelem_r4 | @cil_stelem_r8;
@cil_throw_any = @cil_throw | @cil_rethrow;
#keyset[impl, index]
cil_instruction(
unique int id: @cil_instruction,
int opcode: int ref,
int index: int ref,
int impl: @cil_method_implementation ref);
cil_jump(
unique int instruction: @cil_jump ref,
int target: @cil_instruction ref);
cil_access(
unique int instruction: @cil_instruction ref,
int target: @cil_accessible ref);
cil_value(
unique int instruction: @cil_literal ref,
string value: string ref);
#keyset[instruction, index]
cil_switch(
int instruction: @cil_switch ref,
int index: int ref,
int target: @cil_instruction ref);
cil_instruction_location(
unique int id: @cil_instruction ref,
int loc: @location ref);
cil_type_location(
int id: @cil_type ref,
int loc: @location ref);
cil_method_location(
int id: @cil_method ref,
int loc: @location ref);
@cil_namespace = @namespace;
@cil_type_container = @cil_type | @cil_namespace | @cil_method;
case @cil_type.kind of
0 = @cil_valueorreftype
| 1 = @cil_typeparameter
| 2 = @cil_array_type
| 3 = @cil_pointer_type
| 4 = @cil_function_pointer_type
;
cil_type(
unique int id: @cil_type,
string name: string ref,
int kind: int ref,
int parent: @cil_type_container ref,
int sourceDecl: @cil_type ref);
cil_pointer_type(
unique int id: @cil_pointer_type ref,
int pointee: @cil_type ref);
cil_array_type(
unique int id: @cil_array_type ref,
int element_type: @cil_type ref,
int rank: int ref);
cil_function_pointer_return_type(
unique int id: @cil_function_pointer_type ref,
int return_type: @cil_type ref);
cil_method(
unique int id: @cil_method,
string name: string ref,
int parent: @cil_type ref,
int return_type: @cil_type ref);
cil_method_source_declaration(
unique int method: @cil_method ref,
int source: @cil_method ref);
cil_method_implementation(
unique int id: @cil_method_implementation,
int method: @cil_method ref,
int location: @assembly ref);
cil_implements(
int id: @cil_method ref,
int decl: @cil_method ref);
#keyset[parent, name]
cil_field(
unique int id: @cil_field,
int parent: @cil_type ref,
string name: string ref,
int field_type: @cil_type ref);
@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace;
@cil_named_element = @cil_declaration | @cil_namespace;
@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member;
@cil_accessible = @cil_declaration;
@cil_variable = @cil_field | @cil_stack_variable;
@cil_stack_variable = @cil_local_variable | @cil_parameter;
@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event;
@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type;
@cil_parameterizable = @cil_method | @cil_function_pointer_type;
@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_field | @cil_method | @cil_function_pointer_type;
#keyset[parameterizable, index]
cil_parameter(
unique int id: @cil_parameter,
int parameterizable: @cil_parameterizable ref,
int index: int ref,
int param_type: @cil_type ref);
cil_parameter_in(unique int id: @cil_parameter ref);
cil_parameter_out(unique int id: @cil_parameter ref);
cil_setter(unique int prop: @cil_property ref,
int method: @cil_method ref);
#keyset[id, modifier]
cil_custom_modifiers(
int id: @cil_custom_modifier_receiver ref,
int modifier: @cil_type ref,
int kind: int ref); // modreq: 1, modopt: 0
cil_type_annotation(
int id: @cil_has_type_annotation ref,
int annotation: int ref);
cil_getter(unique int prop: @cil_property ref,
int method: @cil_method ref);
cil_adder(unique int event: @cil_event ref,
int method: @cil_method ref);
cil_remover(unique int event: @cil_event ref, int method: @cil_method ref);
cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref);
cil_property(
unique int id: @cil_property,
int parent: @cil_type ref,
string name: string ref,
int property_type: @cil_type ref);
#keyset[parent, name]
cil_event(unique int id: @cil_event,
int parent: @cil_type ref,
string name: string ref,
int event_type: @cil_type ref);
#keyset[impl, index]
cil_local_variable(
unique int id: @cil_local_variable,
int impl: @cil_method_implementation ref,
int index: int ref,
int var_type: @cil_type ref);
cil_function_pointer_calling_conventions(
int id: @cil_function_pointer_type ref,
int kind: int ref);
// CIL handlers (exception handlers etc).
case @cil_handler.kind of
0 = @cil_catch_handler
| 1 = @cil_filter_handler
| 2 = @cil_finally_handler
| 4 = @cil_fault_handler
;
#keyset[impl, index]
cil_handler(
unique int id: @cil_handler,
int impl: @cil_method_implementation ref,
int index: int ref,
int kind: int ref,
int try_start: @cil_instruction ref,
int try_end: @cil_instruction ref,
int handler_start: @cil_instruction ref);
cil_handler_filter(
unique int id: @cil_handler ref,
int filter_start: @cil_instruction ref);
cil_handler_type(
unique int id: @cil_handler ref,
int catch_type: @cil_type ref);
@cil_controlflow_node = @cil_entry_point | @cil_instruction;
@cil_entry_point = @cil_method_implementation | @cil_handler;
@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method;
cil_method_stack_size(
unique int method: @cil_method_implementation ref,
int size: int ref);
// CIL modifiers
cil_public(int id: @cil_member ref);
cil_private(int id: @cil_member ref);
cil_protected(int id: @cil_member ref);
cil_internal(int id: @cil_member ref);
cil_static(int id: @cil_member ref);
cil_sealed(int id: @cil_member ref);
cil_virtual(int id: @cil_method ref);
cil_abstract(int id: @cil_member ref);
cil_class(int id: @cil_type ref);
cil_interface(int id: @cil_type ref);
cil_security(int id: @cil_member ref);
cil_requiresecobject(int id: @cil_method ref);
cil_specialname(int id: @cil_method ref);
cil_newslot(int id: @cil_method ref);
cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref);
cil_base_interface(int id: @cil_type ref, int base: @cil_type ref);
cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref);
#keyset[unbound, index]
cil_type_parameter(
int unbound: @cil_member ref,
int index: int ref,
int param: @cil_typeparameter ref);
#keyset[bound, index]
cil_type_argument(
int bound: @cil_member ref,
int index: int ref,
int t: @cil_type ref);
// CIL type parameter constraints
cil_typeparam_covariant(int tp: @cil_typeparameter ref);
cil_typeparam_contravariant(int tp: @cil_typeparameter ref);
cil_typeparam_class(int tp: @cil_typeparameter ref);
cil_typeparam_struct(int tp: @cil_typeparameter ref);
cil_typeparam_new(int tp: @cil_typeparameter ref);
cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref);
// CIL attributes
cil_attribute(
unique int attributeid: @cil_attribute,
int element: @cil_declaration ref,
int constructor: @cil_method ref);
#keyset[attribute_id, param]
cil_attribute_named_argument(
int attribute_id: @cil_attribute ref,
string param: string ref,
string value: string ref);
#keyset[attribute_id, index]
cil_attribute_positional_argument(
int attribute_id: @cil_attribute ref,
int index: int ref,
string value: string ref);
// Common .Net data model covering both C# and CIL
// Common elements
@dotnet_element = @element | @cil_element;
@dotnet_named_element = @named_element | @cil_named_element;
@dotnet_callable = @callable | @cil_method;
@dotnet_variable = @variable | @cil_variable;
@dotnet_field = @field | @cil_field;
@dotnet_parameter = @parameter | @cil_parameter;
@dotnet_declaration = @declaration | @cil_declaration;
@dotnet_member = @member | @cil_member;
@dotnet_event = @event | @cil_event;
@dotnet_property = @property | @cil_property | @indexer;
@dotnet_parameterizable = @parameterizable | @cil_parameterizable;
// Common types
@dotnet_type = @type | @cil_type;
@dotnet_call = @call | @cil_call_any;
@dotnet_throw = @throw_element | @cil_throw_any;
@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type;
@dotnet_typeparameter = @type_parameter | @cil_typeparameter;
@dotnet_array_type = @array_type | @cil_array_type;
@dotnet_pointer_type = @pointer_type | @cil_pointer_type;
@dotnet_type_parameter = @type_parameter | @cil_typeparameter;
@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable;
// Attributes
@dotnet_attribute = @attribute | @cil_attribute;
// Expressions
@dotnet_expr = @expr | @cil_expr;
// Literals
@dotnet_literal = @literal_expr | @cil_literal;
@dotnet_string_literal = @string_literal_expr | @cil_ldstr;
@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i;
@dotnet_float_literal = @float_literal_expr | @cil_ldc_r;
@dotnet_null_literal = @null_literal_expr | @cil_ldnull;
@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property |
@callable | @value_or_ref_type | @void_type;
metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
description: Delete all `cil` and `dotnet` related relations and types.
compatibility: breaking
cil_instruction.rel: delete
cil_jump.rel: delete
cil_access.rel: delete
cil_value.rel: delete
cil_switch.rel: delete
cil_instruction_location.rel: delete
cil_type_location.rel: delete
cil_method_location.rel: delete
cil_type.rel: delete
cil_pointer_type.rel: delete
cil_array_type.rel: delete
cil_function_pointer_return_type.rel: delete
cil_method.rel: delete
cil_method_source_declaration.rel: delete
cil_method_implementation.rel: delete
cil_implements.rel: delete
cil_field.rel: delete
cil_parameter.rel: delete
cil_parameter_in.rel: delete
cil_parameter_out.rel: delete
cil_setter.rel: delete
cil_custom_modifiers.rel: delete
cil_type_annotation.rel: delete
cil_getter.rel: delete
cil_adder.rel: delete
cil_remover.rel: delete
cil_raiser.rel: delete
cil_property.rel: delete
cil_event.rel: delete
cil_local_variable.rel: delete
cil_function_pointer_calling_conventions.rel: delete
cil_handler.rel: delete
cil_handler_filter.rel: delete
cil_handler_type.rel: delete
cil_method_stack_size.rel: delete
cil_public.rel: delete
cil_private.rel: delete
cil_protected.rel: delete
cil_internal.rel: delete
cil_static.rel: delete
cil_sealed.rel: delete
cil_virtual.rel: delete
cil_abstract.rel: delete
cil_class.rel: delete
cil_interface.rel: delete
cil_security.rel: delete
cil_requiresecobject.rel: delete
cil_specialname.rel: delete
cil_newslot.rel: delete
cil_base_class.rel: delete
cil_base_interface.rel: delete
cil_enum_underlying_type.rel: delete
cil_type_parameter.rel: delete
cil_type_argument.rel: delete
cil_typeparam_covariant.rel: delete
cil_typeparam_contravariant.rel: delete
cil_typeparam_class.rel: delete
cil_typeparam_struct.rel: delete
cil_typeparam_new.rel: delete
cil_typeparam_constraint.rel: delete
cil_attribute.rel: delete
cil_attribute_named_argument.rel: delete
cil_attribute_positional_argument.rel: delete
metadata_handle.rel: delete

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries
version: 1.0.8
version: 1.0.9-dev
groups:
- csharp
- queries

View File

@@ -0,0 +1,13 @@
/**
* @name Capture content based summary models.
* @description Finds applicable content based summary models to be used by other queries.
* @kind diagnostic
* @id cs/utils/modelgenerator/contentbased-summary-models
* @tags modelgenerator
*/
import internal.CaptureModels
from DataFlowSummaryTargetApi api, string flow
where flow = captureContentFlow(api)
select flow order by flow

View File

@@ -127,7 +127,7 @@ string captureQualifierFlow(DataFlowSummaryTargetApi api) {
api = returnNodeEnclosingCallable(ret) and
isOwnInstanceAccessNode(ret)
) and
result = Printing::asValueModel(api, qualifierString(), "ReturnValue")
result = Printing::asLiftedValueModel(api, qualifierString(), "ReturnValue")
}
private int accessPathLimit0() { result = 2 }
@@ -237,7 +237,7 @@ string captureThroughFlow0(
input = parameterNodeAsInput(p) and
output = getOutput(returnNodeExt) and
input != output and
result = Printing::asTaintModel(api, input, output)
result = Printing::asLiftedTaintModel(api, input, output)
)
}
@@ -291,26 +291,257 @@ private string getContent(PropagateContentFlow::AccessPath ap, int i) {
)
}
/**
* Gets the MaD string representation of a store step access path.
*/
private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i)
}
/**
* Gets the MaD string representation of a read step access path.
*/
private string printReadAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i desc)
}
string captureContentFlow(DataFlowSummaryTargetApi api) {
exists(
DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output,
PropagateContentFlow::AccessPath reads, PropagateContentFlow::AccessPath stores,
boolean preservesValue
/**
* Holds if the access path `ap` contains a field or synthetic field access.
*/
private predicate mentionsField(PropagateContentFlow::AccessPath ap) {
exists(ContentSet head, PropagateContentFlow::AccessPath tail |
head = ap.getHead() and
tail = ap.getTail()
|
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
returnNodeExt.getEnclosingCallable() = api and
mentionsField(tail) or isField(head)
)
}
private predicate apiFlow(
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads,
ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores, boolean preservesValue
) {
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
returnNodeExt.getEnclosingCallable() = api and
p.getEnclosingCallable() = api
}
/**
* A class of APIs relevant for modeling using content flow.
* The following heuristic is applied:
* Content flow is only relevant for an API, if
* #content flow <= 2 * #parameters + 3
* If an API produces more content flow, it is likely that
* 1. Types are not sufficiently constrained leading to a combinatorial
* explosion in dispatch and thus in the generated summaries.
* 2. It is a reasonable approximation to use the non-content based flow
* detection instead, as reads and stores would use a significant
* part of an objects internal state.
*/
private class ContentDataFlowSummaryTargetApi extends DataFlowSummaryTargetApi {
ContentDataFlowSummaryTargetApi() {
count(string input, string output |
exists(
DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads,
ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores
|
apiFlow(this, p, reads, returnNodeExt, stores, _) and
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores)
)
) <= 2 * this.getNumberOfParameters() + 3
}
}
pragma[nomagic]
private predicate apiContentFlow(
ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p,
PropagateContentFlow::AccessPath reads, ReturnNodeExt returnNodeExt,
PropagateContentFlow::AccessPath stores, boolean preservesValue
) {
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
returnNodeExt.getEnclosingCallable() = api and
p.getEnclosingCallable() = api
}
/**
* Holds if any of the content sets in `path` translates into a synthetic field.
*/
private predicate hasSyntheticContent(PropagateContentFlow::AccessPath path) {
exists(PropagateContentFlow::AccessPath tail, ContentSet head |
head = path.getHead() and
tail = path.getTail()
|
exists(getSyntheticName(head)) or
hasSyntheticContent(tail)
)
}
/**
* A module containing predicates for validating access paths containing content sets
* that translates into synthetic fields, when used for generated summary models.
*/
private module AccessPathSyntheticValidation {
/**
* Holds if there exists an API that has content flow from `read` (on type `t1`)
* to `store` (on type `t2`).
*/
private predicate step(
Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store
) {
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt |
p.getType() = t1 and
returnNodeExt.getType() = t2 and
apiContentFlow(_, p, read, returnNodeExt, store, _)
)
}
/**
* Holds if there exists an API that has content flow from `read` (on type `t1`)
* to `store` (on type `t2`), where `read` does not have synthetic content and `store` does.
*
* Step A -> Synth.
*/
private predicate synthPathEntry(
Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store
) {
not hasSyntheticContent(read) and
hasSyntheticContent(store) and
step(t1, read, t2, store)
}
/**
* Holds if there exists an API that has content flow from `read` (on type `t1`)
* to `store` (on type `t2`), where `read` has synthetic content
* and `store` does not.
*
* Step Synth -> A.
*/
private predicate synthPathExit(
Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store
) {
hasSyntheticContent(read) and
not hasSyntheticContent(store) and
step(t1, read, t2, store)
}
/**
* Holds if there exists a path of steps from `read` to an exit.
*
* read ->* Synth -> A
*/
private predicate reachesSynthExit(Type t, PropagateContentFlow::AccessPath read) {
synthPathExit(t, read, _, _)
or
hasSyntheticContent(read) and
exists(PropagateContentFlow::AccessPath mid, Type midType |
hasSyntheticContent(mid) and
step(t, read, midType, mid) and
reachesSynthExit(midType, mid.reverse())
)
}
/**
* Holds if there exists a path of steps from an entry to `store`.
*
* A -> Synth ->* store
*/
private predicate synthEntryReaches(Type t, PropagateContentFlow::AccessPath store) {
synthPathEntry(_, _, t, store)
or
hasSyntheticContent(store) and
exists(PropagateContentFlow::AccessPath mid, Type midType |
hasSyntheticContent(mid) and
step(midType, mid, t, store) and
synthEntryReaches(midType, mid.reverse())
)
}
/**
* Holds if at least one of the access paths `read` (on type `t1`) and `store` (on type `t2`)
* contain content that will be translated into a synthetic field, when being used in
* a MaD summary model, and if there is a range of APIs, such that
* when chaining their flow access paths, there exists access paths `A` and `B` where
* A ->* read -> store ->* B and where `A` and `B` do not contain content that will
* be translated into a synthetic field.
*
* This is needed because we don't want to include summaries that reads from or
* stores into a "dead" synthetic field.
*
* Example:
* Assume we have a type `t` (in this case `t1` = `t2`) with methods `getX` and
* `setX`, which gets and sets a private field `X` on `t`.
* This would lead to the following content flows
* getX : Argument[this].SyntheticField[t.X] -> ReturnValue.
* setX : Argument[0] -> Argument[this].SyntheticField[t.X]
* As the reads and stores are on synthetic fields we should only make summaries
* if both of these methods exist.
*/
pragma[nomagic]
predicate acceptReadStore(
Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store
) {
synthPathEntry(t1, read, t2, store) and reachesSynthExit(t2, store.reverse())
or
exists(PropagateContentFlow::AccessPath store0 | store0.reverse() = read |
synthEntryReaches(t1, store0) and synthPathExit(t1, read, t2, store)
or
synthEntryReaches(t1, store0) and
step(t1, read, t2, store) and
reachesSynthExit(t2, store.reverse())
)
}
}
/**
* Holds, if the API `api` has relevant flow from `read` on `p` to `store` on `returnNodeExt`.
* Flow is considered relevant,
* 1. If `read` or `store` do not contain a content set that translates into a synthetic field.
* 2. If `read` or `store` contain a content set that translates into a synthetic field, and if
* the synthetic content is "live" on the relevant declaring type.
*/
private predicate apiRelevantContentFlow(
ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p,
PropagateContentFlow::AccessPath read, ReturnNodeExt returnNodeExt,
PropagateContentFlow::AccessPath store, boolean preservesValue
) {
apiContentFlow(api, p, read, returnNodeExt, store, preservesValue) and
(
not hasSyntheticContent(read) and not hasSyntheticContent(store)
or
AccessPathSyntheticValidation::acceptReadStore(p.getType(), read, returnNodeExt.getType(), store)
)
}
pragma[nomagic]
private predicate captureContentFlow0(
ContentDataFlowSummaryTargetApi api, string input, string output, boolean preservesValue,
boolean lift
) {
exists(
DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath reads,
PropagateContentFlow::AccessPath stores
|
apiRelevantContentFlow(api, p, reads, returnNodeExt, stores, preservesValue) and
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and
input != output and
result = Printing::asModel(api, input, output, preservesValue)
(if mentionsField(reads) or mentionsField(stores) then lift = false else lift = true)
)
}
/**
* Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to
* the return value or a parameter).
*
* Models are lifted to the best type in case the read and store access paths do not
* contain a field or synthetic field access.
*/
string captureContentFlow(ContentDataFlowSummaryTargetApi api) {
exists(string input, string output, boolean lift, boolean preservesValue |
captureContentFlow0(api, input, output, _, lift) and
preservesValue = max(boolean p | captureContentFlow0(api, input, output, p, lift)) and
result = Printing::asModel(api, input, output, preservesValue, lift)
)
}

View File

@@ -390,23 +390,47 @@ private string getFullyQualifiedName(Declaration d) {
}
/**
* Gets the MaD string representation of the contentset `c`.
* Holds if the content set `c` is a field, property or synthetic field.
*/
predicate isField(ContentSet c) { c.isField(_) or c.isSyntheticField(_) or c.isProperty(_) }
/**
* Gets the MaD synthetic name string representation for the content set `c`, if any.
*/
string getSyntheticName(DataFlow::ContentSet c) {
exists(CS::Field f |
not f.isEffectivelyPublic() and
c.isField(f) and
result = getFullyQualifiedName(f)
)
or
exists(CS::Property p |
not p.isEffectivelyPublic() and
c.isProperty(p) and
result = getFullyQualifiedName(p)
)
or
c.isSyntheticField(result)
}
/**
* Gets the MaD string representation of the content set `c`.
*/
string printContent(DataFlow::ContentSet c) {
exists(CS::Field f, string name | name = getFullyQualifiedName(f) |
c.isField(f) and
if f.isEffectivelyPublic()
then result = "Field[" + name + "]"
else result = "SyntheticField[" + name + "]"
f.isEffectivelyPublic() and
result = "Field[" + name + "]"
)
or
exists(CS::Property p, string name | name = getFullyQualifiedName(p) |
c.isProperty(p) and
if p.isEffectivelyPublic()
then result = "Property[" + name + "]"
else result = "SyntheticField[" + name + "]"
p.isEffectivelyPublic() and
result = "Property[" + name + "]"
)
or
result = "SyntheticField[" + getSyntheticName(c) + "]"
or
c.isElement() and
result = "Element"
}

View File

@@ -223,7 +223,7 @@ class TypeBasedFlowTargetApi extends Specific::SummaryTargetApi {
output(this, tp, output) and
input != output
|
result = Printing::asValueModel(this, input, output)
result = Printing::asLiftedValueModel(this, input, output)
)
}
}

View File

@@ -82,32 +82,34 @@ arguments
| attributes.cs:102:8:102:19 | [My3(...)] | 0 | attributes.cs:102:21:102:21 | 4 |
| attributes.cs:107:6:107:17 | [My3(...)] | 0 | attributes.cs:107:19:107:19 | 5 |
| attributes.cs:108:14:108:25 | [return: My3(...)] | 0 | attributes.cs:108:27:108:27 | 6 |
| attributes.cs:113:10:113:21 | [My3(...)] | 0 | attributes.cs:113:23:113:23 | 7 |
| attributes.cs:114:18:114:29 | [return: My3(...)] | 0 | attributes.cs:114:31:114:31 | 8 |
| attributes.cs:117:18:117:29 | [My3(...)] | 0 | attributes.cs:117:31:117:31 | 9 |
| attributes.cs:118:17:118:28 | [My3(...)] | 0 | attributes.cs:118:30:118:31 | 10 |
| attributes.cs:125:18:125:29 | [My3(...)] | 0 | attributes.cs:125:31:125:32 | 11 |
| attributes.cs:126:18:126:29 | [return: My3(...)] | 0 | attributes.cs:126:31:126:32 | 12 |
| attributes.cs:129:10:129:21 | [My3(...)] | 0 | attributes.cs:129:23:129:24 | 13 |
| attributes.cs:130:17:130:28 | [My3(...)] | 0 | attributes.cs:130:30:130:31 | 14 |
| attributes.cs:142:6:142:11 | [Params(...)] | 0 | attributes.cs:142:13:142:15 | "a" |
| attributes.cs:142:6:142:11 | [Params(...)] | 1 | attributes.cs:142:18:142:20 | "b" |
| attributes.cs:142:6:142:11 | [Params(...)] | 2 | attributes.cs:142:23:142:23 | 1 |
| attributes.cs:142:6:142:11 | [Params(...)] | 3 | attributes.cs:142:26:142:26 | 2 |
| attributes.cs:142:6:142:11 | [Params(...)] | 4 | attributes.cs:142:29:142:29 | 3 |
| attributes.cs:145:6:145:11 | [Params(...)] | 0 | attributes.cs:145:17:145:19 | "a" |
| attributes.cs:145:6:145:11 | [Params(...)] | 1 | attributes.cs:145:26:145:28 | "b" |
| attributes.cs:145:6:145:11 | [Params(...)] | 2 | attributes.cs:145:31:145:31 | 1 |
| attributes.cs:145:6:145:11 | [Params(...)] | 3 | attributes.cs:145:34:145:34 | 2 |
| attributes.cs:145:6:145:11 | [Params(...)] | 4 | attributes.cs:145:37:145:37 | 3 |
| attributes.cs:148:6:148:11 | [Params(...)] | 0 | attributes.cs:148:35:148:37 | "a" |
| attributes.cs:148:6:148:11 | [Params(...)] | 1 | attributes.cs:148:26:148:28 | "b" |
| attributes.cs:148:6:148:11 | [Params(...)] | 2 | attributes.cs:148:19:148:19 | 1 |
| attributes.cs:151:6:151:11 | [Params(...)] | 0 | attributes.cs:151:45:151:47 | "a" |
| attributes.cs:151:6:151:11 | [Params(...)] | 1 | attributes.cs:151:36:151:38 | "b" |
| attributes.cs:151:6:151:11 | [Params(...)] | 2 | attributes.cs:151:19:151:29 | array creation of type Int32[] |
| attributes.cs:155:2:155:13 | [Experimental(...)] | 0 | attributes.cs:155:15:155:37 | "MyExperimentalClassId" |
| attributes.cs:158:6:158:17 | [Experimental(...)] | 0 | attributes.cs:158:19:158:42 | "MyExperimentalMethodId" |
| attributes.cs:111:6:111:17 | [My3(...)] | 0 | attributes.cs:111:19:111:20 | 15 |
| attributes.cs:114:10:114:21 | [My3(...)] | 0 | attributes.cs:114:23:114:23 | 7 |
| attributes.cs:115:18:115:29 | [return: My3(...)] | 0 | attributes.cs:115:31:115:31 | 8 |
| attributes.cs:118:18:118:29 | [My3(...)] | 0 | attributes.cs:118:31:118:31 | 9 |
| attributes.cs:119:17:119:28 | [My3(...)] | 0 | attributes.cs:119:30:119:31 | 10 |
| attributes.cs:124:6:124:17 | [My3(...)] | 0 | attributes.cs:124:19:124:20 | 16 |
| attributes.cs:127:18:127:29 | [My3(...)] | 0 | attributes.cs:127:31:127:32 | 11 |
| attributes.cs:128:18:128:29 | [return: My3(...)] | 0 | attributes.cs:128:31:128:32 | 12 |
| attributes.cs:131:10:131:21 | [My3(...)] | 0 | attributes.cs:131:23:131:24 | 13 |
| attributes.cs:132:17:132:28 | [My3(...)] | 0 | attributes.cs:132:30:132:31 | 14 |
| attributes.cs:144:6:144:11 | [Params(...)] | 0 | attributes.cs:144:13:144:15 | "a" |
| attributes.cs:144:6:144:11 | [Params(...)] | 1 | attributes.cs:144:18:144:20 | "b" |
| attributes.cs:144:6:144:11 | [Params(...)] | 2 | attributes.cs:144:23:144:23 | 1 |
| attributes.cs:144:6:144:11 | [Params(...)] | 3 | attributes.cs:144:26:144:26 | 2 |
| attributes.cs:144:6:144:11 | [Params(...)] | 4 | attributes.cs:144:29:144:29 | 3 |
| attributes.cs:147:6:147:11 | [Params(...)] | 0 | attributes.cs:147:17:147:19 | "a" |
| attributes.cs:147:6:147:11 | [Params(...)] | 1 | attributes.cs:147:26:147:28 | "b" |
| attributes.cs:147:6:147:11 | [Params(...)] | 2 | attributes.cs:147:31:147:31 | 1 |
| attributes.cs:147:6:147:11 | [Params(...)] | 3 | attributes.cs:147:34:147:34 | 2 |
| attributes.cs:147:6:147:11 | [Params(...)] | 4 | attributes.cs:147:37:147:37 | 3 |
| attributes.cs:150:6:150:11 | [Params(...)] | 0 | attributes.cs:150:35:150:37 | "a" |
| attributes.cs:150:6:150:11 | [Params(...)] | 1 | attributes.cs:150:26:150:28 | "b" |
| attributes.cs:150:6:150:11 | [Params(...)] | 2 | attributes.cs:150:19:150:19 | 1 |
| attributes.cs:153:6:153:11 | [Params(...)] | 0 | attributes.cs:153:45:153:47 | "a" |
| attributes.cs:153:6:153:11 | [Params(...)] | 1 | attributes.cs:153:36:153:38 | "b" |
| attributes.cs:153:6:153:11 | [Params(...)] | 2 | attributes.cs:153:19:153:29 | array creation of type Int32[] |
| attributes.cs:157:2:157:13 | [Experimental(...)] | 0 | attributes.cs:157:15:157:37 | "MyExperimentalClassId" |
| attributes.cs:160:6:160:17 | [Experimental(...)] | 0 | attributes.cs:160:19:160:42 | "MyExperimentalMethodId" |
constructorArguments
| Assembly1.dll:0:0:0:0 | [Custom(...)] | 0 | Assembly1.dll:0:0:0:0 | 1 |
| Assembly1.dll:0:0:0:0 | [Custom(...)] | 0 | Assembly1.dll:0:0:0:0 | 3 |
@@ -180,32 +182,34 @@ constructorArguments
| attributes.cs:102:8:102:19 | [My3(...)] | 0 | attributes.cs:102:21:102:21 | 4 |
| attributes.cs:107:6:107:17 | [My3(...)] | 0 | attributes.cs:107:19:107:19 | 5 |
| attributes.cs:108:14:108:25 | [return: My3(...)] | 0 | attributes.cs:108:27:108:27 | 6 |
| attributes.cs:113:10:113:21 | [My3(...)] | 0 | attributes.cs:113:23:113:23 | 7 |
| attributes.cs:114:18:114:29 | [return: My3(...)] | 0 | attributes.cs:114:31:114:31 | 8 |
| attributes.cs:117:18:117:29 | [My3(...)] | 0 | attributes.cs:117:31:117:31 | 9 |
| attributes.cs:118:17:118:28 | [My3(...)] | 0 | attributes.cs:118:30:118:31 | 10 |
| attributes.cs:125:18:125:29 | [My3(...)] | 0 | attributes.cs:125:31:125:32 | 11 |
| attributes.cs:126:18:126:29 | [return: My3(...)] | 0 | attributes.cs:126:31:126:32 | 12 |
| attributes.cs:129:10:129:21 | [My3(...)] | 0 | attributes.cs:129:23:129:24 | 13 |
| attributes.cs:130:17:130:28 | [My3(...)] | 0 | attributes.cs:130:30:130:31 | 14 |
| attributes.cs:142:6:142:11 | [Params(...)] | 0 | attributes.cs:142:13:142:15 | "a" |
| attributes.cs:142:6:142:11 | [Params(...)] | 1 | attributes.cs:142:18:142:20 | "b" |
| attributes.cs:142:6:142:11 | [Params(...)] | 2 | attributes.cs:142:23:142:23 | 1 |
| attributes.cs:142:6:142:11 | [Params(...)] | 3 | attributes.cs:142:26:142:26 | 2 |
| attributes.cs:142:6:142:11 | [Params(...)] | 4 | attributes.cs:142:29:142:29 | 3 |
| attributes.cs:145:6:145:11 | [Params(...)] | 0 | attributes.cs:145:17:145:19 | "a" |
| attributes.cs:145:6:145:11 | [Params(...)] | 1 | attributes.cs:145:26:145:28 | "b" |
| attributes.cs:145:6:145:11 | [Params(...)] | 2 | attributes.cs:145:31:145:31 | 1 |
| attributes.cs:145:6:145:11 | [Params(...)] | 3 | attributes.cs:145:34:145:34 | 2 |
| attributes.cs:145:6:145:11 | [Params(...)] | 4 | attributes.cs:145:37:145:37 | 3 |
| attributes.cs:148:6:148:11 | [Params(...)] | 0 | attributes.cs:148:35:148:37 | "a" |
| attributes.cs:148:6:148:11 | [Params(...)] | 1 | attributes.cs:148:26:148:28 | "b" |
| attributes.cs:148:6:148:11 | [Params(...)] | 2 | attributes.cs:148:19:148:19 | 1 |
| attributes.cs:151:6:151:11 | [Params(...)] | 0 | attributes.cs:151:45:151:47 | "a" |
| attributes.cs:151:6:151:11 | [Params(...)] | 1 | attributes.cs:151:36:151:38 | "b" |
| attributes.cs:151:6:151:11 | [Params(...)] | 2 | attributes.cs:151:19:151:29 | array creation of type Int32[] |
| attributes.cs:155:2:155:13 | [Experimental(...)] | 0 | attributes.cs:155:15:155:37 | "MyExperimentalClassId" |
| attributes.cs:158:6:158:17 | [Experimental(...)] | 0 | attributes.cs:158:19:158:42 | "MyExperimentalMethodId" |
| attributes.cs:111:6:111:17 | [My3(...)] | 0 | attributes.cs:111:19:111:20 | 15 |
| attributes.cs:114:10:114:21 | [My3(...)] | 0 | attributes.cs:114:23:114:23 | 7 |
| attributes.cs:115:18:115:29 | [return: My3(...)] | 0 | attributes.cs:115:31:115:31 | 8 |
| attributes.cs:118:18:118:29 | [My3(...)] | 0 | attributes.cs:118:31:118:31 | 9 |
| attributes.cs:119:17:119:28 | [My3(...)] | 0 | attributes.cs:119:30:119:31 | 10 |
| attributes.cs:124:6:124:17 | [My3(...)] | 0 | attributes.cs:124:19:124:20 | 16 |
| attributes.cs:127:18:127:29 | [My3(...)] | 0 | attributes.cs:127:31:127:32 | 11 |
| attributes.cs:128:18:128:29 | [return: My3(...)] | 0 | attributes.cs:128:31:128:32 | 12 |
| attributes.cs:131:10:131:21 | [My3(...)] | 0 | attributes.cs:131:23:131:24 | 13 |
| attributes.cs:132:17:132:28 | [My3(...)] | 0 | attributes.cs:132:30:132:31 | 14 |
| attributes.cs:144:6:144:11 | [Params(...)] | 0 | attributes.cs:144:13:144:15 | "a" |
| attributes.cs:144:6:144:11 | [Params(...)] | 1 | attributes.cs:144:18:144:20 | "b" |
| attributes.cs:144:6:144:11 | [Params(...)] | 2 | attributes.cs:144:23:144:23 | 1 |
| attributes.cs:144:6:144:11 | [Params(...)] | 3 | attributes.cs:144:26:144:26 | 2 |
| attributes.cs:144:6:144:11 | [Params(...)] | 4 | attributes.cs:144:29:144:29 | 3 |
| attributes.cs:147:6:147:11 | [Params(...)] | 0 | attributes.cs:147:17:147:19 | "a" |
| attributes.cs:147:6:147:11 | [Params(...)] | 1 | attributes.cs:147:26:147:28 | "b" |
| attributes.cs:147:6:147:11 | [Params(...)] | 2 | attributes.cs:147:31:147:31 | 1 |
| attributes.cs:147:6:147:11 | [Params(...)] | 3 | attributes.cs:147:34:147:34 | 2 |
| attributes.cs:147:6:147:11 | [Params(...)] | 4 | attributes.cs:147:37:147:37 | 3 |
| attributes.cs:150:6:150:11 | [Params(...)] | 0 | attributes.cs:150:35:150:37 | "a" |
| attributes.cs:150:6:150:11 | [Params(...)] | 1 | attributes.cs:150:26:150:28 | "b" |
| attributes.cs:150:6:150:11 | [Params(...)] | 2 | attributes.cs:150:19:150:19 | 1 |
| attributes.cs:153:6:153:11 | [Params(...)] | 0 | attributes.cs:153:45:153:47 | "a" |
| attributes.cs:153:6:153:11 | [Params(...)] | 1 | attributes.cs:153:36:153:38 | "b" |
| attributes.cs:153:6:153:11 | [Params(...)] | 2 | attributes.cs:153:19:153:29 | array creation of type Int32[] |
| attributes.cs:157:2:157:13 | [Experimental(...)] | 0 | attributes.cs:157:15:157:37 | "MyExperimentalClassId" |
| attributes.cs:160:6:160:17 | [Experimental(...)] | 0 | attributes.cs:160:19:160:42 | "MyExperimentalMethodId" |
namedArguments
| Assembly1.dll:0:0:0:0 | [Custom(...)] | Prop2 | Assembly1.dll:0:0:0:0 | array creation of type Object[] |
| Assembly1.dll:0:0:0:0 | [Custom(...)] | Prop2 | Assembly1.dll:0:0:0:0 | array creation of type Object[] |

View File

@@ -24,20 +24,22 @@
| attributes.cs:103:17:103:27 | My2Delegate | attributes.cs:102:8:102:19 | [My3(...)] | My3Attribute |
| attributes.cs:109:32:109:32 | + | attributes.cs:107:6:107:17 | [My3(...)] | My3Attribute |
| attributes.cs:109:32:109:32 | + | attributes.cs:108:14:108:25 | [return: My3(...)] | My3Attribute |
| attributes.cs:115:9:115:11 | get_Item | attributes.cs:113:10:113:21 | [My3(...)] | My3Attribute |
| attributes.cs:115:9:115:11 | get_Item | attributes.cs:114:18:114:29 | [return: My3(...)] | My3Attribute |
| attributes.cs:119:9:119:11 | set_Item | attributes.cs:117:18:117:29 | [My3(...)] | My3Attribute |
| attributes.cs:119:9:119:11 | value | attributes.cs:118:17:118:28 | [My3(...)] | My3Attribute |
| attributes.cs:127:9:127:11 | get_Prop1 | attributes.cs:125:18:125:29 | [My3(...)] | My3Attribute |
| attributes.cs:127:9:127:11 | get_Prop1 | attributes.cs:126:18:126:29 | [return: My3(...)] | My3Attribute |
| attributes.cs:131:9:131:11 | set_Prop1 | attributes.cs:129:10:129:21 | [My3(...)] | My3Attribute |
| attributes.cs:131:9:131:11 | value | attributes.cs:130:17:130:28 | [My3(...)] | My3Attribute |
| attributes.cs:143:17:143:18 | M1 | attributes.cs:142:6:142:11 | [Params(...)] | Class1+ParamsAttribute |
| attributes.cs:146:17:146:18 | M2 | attributes.cs:145:6:145:11 | [Params(...)] | Class1+ParamsAttribute |
| attributes.cs:149:17:149:18 | M3 | attributes.cs:148:6:148:11 | [Params(...)] | Class1+ParamsAttribute |
| attributes.cs:152:17:152:18 | M4 | attributes.cs:151:6:151:11 | [Params(...)] | Class1+ParamsAttribute |
| attributes.cs:156:14:156:32 | MyExperimentalClass | attributes.cs:155:2:155:13 | [Experimental(...)] | System.Diagnostics.CodeAnalysis.ExperimentalAttribute |
| attributes.cs:159:17:159:36 | MyExperimentalMethod | attributes.cs:158:6:158:17 | [Experimental(...)] | System.Diagnostics.CodeAnalysis.ExperimentalAttribute |
| attributes.cs:112:16:112:19 | Item | attributes.cs:111:6:111:17 | [My3(...)] | My3Attribute |
| attributes.cs:116:9:116:11 | get_Item | attributes.cs:114:10:114:21 | [My3(...)] | My3Attribute |
| attributes.cs:116:9:116:11 | get_Item | attributes.cs:115:18:115:29 | [return: My3(...)] | My3Attribute |
| attributes.cs:120:9:120:11 | set_Item | attributes.cs:118:18:118:29 | [My3(...)] | My3Attribute |
| attributes.cs:120:9:120:11 | value | attributes.cs:119:17:119:28 | [My3(...)] | My3Attribute |
| attributes.cs:125:16:125:20 | Prop1 | attributes.cs:124:6:124:17 | [My3(...)] | My3Attribute |
| attributes.cs:129:9:129:11 | get_Prop1 | attributes.cs:127:18:127:29 | [My3(...)] | My3Attribute |
| attributes.cs:129:9:129:11 | get_Prop1 | attributes.cs:128:18:128:29 | [return: My3(...)] | My3Attribute |
| attributes.cs:133:9:133:11 | set_Prop1 | attributes.cs:131:10:131:21 | [My3(...)] | My3Attribute |
| attributes.cs:133:9:133:11 | value | attributes.cs:132:17:132:28 | [My3(...)] | My3Attribute |
| attributes.cs:145:17:145:18 | M1 | attributes.cs:144:6:144:11 | [Params(...)] | Class1+ParamsAttribute |
| attributes.cs:148:17:148:18 | M2 | attributes.cs:147:6:147:11 | [Params(...)] | Class1+ParamsAttribute |
| attributes.cs:151:17:151:18 | M3 | attributes.cs:150:6:150:11 | [Params(...)] | Class1+ParamsAttribute |
| attributes.cs:154:17:154:18 | M4 | attributes.cs:153:6:153:11 | [Params(...)] | Class1+ParamsAttribute |
| attributes.cs:158:14:158:32 | MyExperimentalClass | attributes.cs:157:2:157:13 | [Experimental(...)] | System.Diagnostics.CodeAnalysis.ExperimentalAttribute |
| attributes.cs:161:17:161:36 | MyExperimentalMethod | attributes.cs:160:6:160:17 | [Experimental(...)] | System.Diagnostics.CodeAnalysis.ExperimentalAttribute |
| attributes.dll:0:0:0:0 | attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | attributes.cs:11:12:11:24 | [assembly: AssemblyTitle(...)] | System.Reflection.AssemblyTitleAttribute |
| attributes.dll:0:0:0:0 | attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | attributes.cs:12:12:12:30 | [assembly: AssemblyDescription(...)] | System.Reflection.AssemblyDescriptionAttribute |
| attributes.dll:0:0:0:0 | attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | attributes.cs:13:12:13:32 | [assembly: AssemblyConfiguration(...)] | System.Reflection.AssemblyConfigurationAttribute |

View File

@@ -1,2 +1,2 @@
| attributes.cs:156:14:156:32 | MyExperimentalClass | attributes.cs:155:2:155:13 | [Experimental(...)] | MyExperimentalClassId |
| attributes.cs:159:17:159:36 | MyExperimentalMethod | attributes.cs:158:6:158:17 | [Experimental(...)] | MyExperimentalMethodId |
| attributes.cs:158:14:158:32 | MyExperimentalClass | attributes.cs:157:2:157:13 | [Experimental(...)] | MyExperimentalClassId |
| attributes.cs:161:17:161:36 | MyExperimentalMethod | attributes.cs:160:6:160:17 | [Experimental(...)] | MyExperimentalMethodId |

View File

@@ -338,136 +338,144 @@ attributes.cs:
# 109| 1: [Parameter] b
# 109| -1: [TypeMention] MyAttributeUsage
# 109| 4: [IntLiteral] 0
# 111| 6: [Indexer] Item
# 111| -1: [TypeMention] int
# 112| 6: [Indexer] Item
# 112| -1: [TypeMention] int
#-----| 0: (Attributes)
# 111| 1: [DefaultAttribute] [My3(...)]
# 111| -1: [TypeMention] My3Attribute
# 111| 0: [IntLiteral] 15
#-----| 1: (Parameters)
# 111| 0: [Parameter] x
# 111| -1: [TypeMention] int
# 115| 3: [Getter] get_Item
# 112| 0: [Parameter] x
# 112| -1: [TypeMention] int
# 116| 3: [Getter] get_Item
#-----| 0: (Attributes)
# 113| 1: [DefaultAttribute] [My3(...)]
# 113| -1: [TypeMention] My3Attribute
# 113| 0: [IntLiteral] 7
# 114| 2: [ReturnAttribute] [return: My3(...)]
# 114| 1: [DefaultAttribute] [My3(...)]
# 114| -1: [TypeMention] My3Attribute
# 114| 0: [IntLiteral] 8
# 114| 0: [IntLiteral] 7
# 115| 2: [ReturnAttribute] [return: My3(...)]
# 115| -1: [TypeMention] My3Attribute
# 115| 0: [IntLiteral] 8
#-----| 2: (Parameters)
# 111| 0: [Parameter] x
# 115| 4: [BlockStmt] {...}
# 115| 0: [ReturnStmt] return ...;
# 115| 0: [AddExpr] ... + ...
# 115| 0: [ParameterAccess] access to parameter x
# 115| 1: [IntLiteral] 1
# 119| 4: [Setter] set_Item
# 112| 0: [Parameter] x
# 116| 4: [BlockStmt] {...}
# 116| 0: [ReturnStmt] return ...;
# 116| 0: [AddExpr] ... + ...
# 116| 0: [ParameterAccess] access to parameter x
# 116| 1: [IntLiteral] 1
# 120| 4: [Setter] set_Item
#-----| 0: (Attributes)
# 117| 1: [DefaultAttribute] [My3(...)]
# 117| -1: [TypeMention] My3Attribute
# 117| 0: [IntLiteral] 9
# 118| 1: [DefaultAttribute] [My3(...)]
# 118| -1: [TypeMention] My3Attribute
# 118| 0: [IntLiteral] 9
#-----| 2: (Parameters)
# 111| 0: [Parameter] x
# 119| 1: [Parameter] value
# 112| 0: [Parameter] x
# 120| 1: [Parameter] value
#-----| 0: (Attributes)
# 118| 1: [DefaultAttribute] [My3(...)]
# 118| -1: [TypeMention] My3Attribute
# 118| 0: [IntLiteral] 10
# 119| 4: [BlockStmt] {...}
# 119| 0: [ReturnStmt] return ...;
# 122| 7: [Field] p
# 122| -1: [TypeMention] int
# 123| 8: [Property] Prop1
# 119| 1: [DefaultAttribute] [My3(...)]
# 119| -1: [TypeMention] My3Attribute
# 119| 0: [IntLiteral] 10
# 120| 4: [BlockStmt] {...}
# 120| 0: [ReturnStmt] return ...;
# 123| 7: [Field] p
# 123| -1: [TypeMention] int
# 127| 3: [Getter] get_Prop1
# 125| 8: [Property] Prop1
# 125| -1: [TypeMention] int
#-----| 0: (Attributes)
# 124| 1: [DefaultAttribute] [My3(...)]
# 124| -1: [TypeMention] My3Attribute
# 124| 0: [IntLiteral] 16
# 129| 3: [Getter] get_Prop1
#-----| 0: (Attributes)
# 125| 1: [DefaultAttribute] [My3(...)]
# 125| -1: [TypeMention] My3Attribute
# 125| 0: [IntLiteral] 11
# 126| 2: [ReturnAttribute] [return: My3(...)]
# 126| -1: [TypeMention] My3Attribute
# 126| 0: [IntLiteral] 12
# 127| 4: [BlockStmt] {...}
# 127| 0: [ReturnStmt] return ...;
# 127| 0: [FieldAccess] access to field p
# 131| 4: [Setter] set_Prop1
# 127| 1: [DefaultAttribute] [My3(...)]
# 127| -1: [TypeMention] My3Attribute
# 127| 0: [IntLiteral] 11
# 128| 2: [ReturnAttribute] [return: My3(...)]
# 128| -1: [TypeMention] My3Attribute
# 128| 0: [IntLiteral] 12
# 129| 4: [BlockStmt] {...}
# 129| 0: [ReturnStmt] return ...;
# 129| 0: [FieldAccess] access to field p
# 133| 4: [Setter] set_Prop1
#-----| 0: (Attributes)
# 129| 1: [DefaultAttribute] [My3(...)]
# 129| -1: [TypeMention] My3Attribute
# 129| 0: [IntLiteral] 13
# 131| 1: [DefaultAttribute] [My3(...)]
# 131| -1: [TypeMention] My3Attribute
# 131| 0: [IntLiteral] 13
#-----| 2: (Parameters)
# 131| 0: [Parameter] value
# 133| 0: [Parameter] value
#-----| 0: (Attributes)
# 130| 1: [DefaultAttribute] [My3(...)]
# 130| -1: [TypeMention] My3Attribute
# 130| 0: [IntLiteral] 14
# 131| 4: [BlockStmt] {...}
# 131| 0: [ExprStmt] ...;
# 131| 0: [AssignExpr] ... = ...
# 131| 0: [FieldAccess] access to field p
# 131| 1: [ParameterAccess] access to parameter value
# 135| [Class] Class1
# 137| 5: [Class] ParamsAttribute
# 132| 1: [DefaultAttribute] [My3(...)]
# 132| -1: [TypeMention] My3Attribute
# 132| 0: [IntLiteral] 14
# 133| 4: [BlockStmt] {...}
# 133| 0: [ExprStmt] ...;
# 133| 0: [AssignExpr] ... = ...
# 133| 0: [FieldAccess] access to field p
# 133| 1: [ParameterAccess] access to parameter value
# 137| [Class] Class1
# 139| 5: [Class] ParamsAttribute
#-----| 3: (Base types)
# 137| 0: [TypeMention] Attribute
# 139| 4: [InstanceConstructor] ParamsAttribute
# 139| 0: [TypeMention] Attribute
# 141| 4: [InstanceConstructor] ParamsAttribute
#-----| 2: (Parameters)
# 139| 0: [Parameter] s1
# 139| -1: [TypeMention] string
# 139| 1: [Parameter] s2
# 139| -1: [TypeMention] string
# 139| 2: [Parameter] args
# 139| -1: [TypeMention] Int32[]
# 139| 1: [TypeMention] int
# 139| 4: [BlockStmt] {...}
# 143| 6: [Method] M1
# 143| -1: [TypeMention] Void
# 141| 0: [Parameter] s1
# 141| -1: [TypeMention] string
# 141| 1: [Parameter] s2
# 141| -1: [TypeMention] string
# 141| 2: [Parameter] args
# 141| -1: [TypeMention] Int32[]
# 141| 1: [TypeMention] int
# 141| 4: [BlockStmt] {...}
# 145| 6: [Method] M1
# 145| -1: [TypeMention] Void
#-----| 0: (Attributes)
# 142| 1: [DefaultAttribute] [Params(...)]
# 142| -1: [TypeMention] ParamsAttribute
# 142| 0: [StringLiteralUtf16] "a"
# 142| 1: [StringLiteralUtf16] "b"
# 142| 2: [IntLiteral] 1
# 142| 3: [IntLiteral] 2
# 142| 4: [IntLiteral] 3
# 143| 4: [BlockStmt] {...}
# 146| 7: [Method] M2
# 146| -1: [TypeMention] Void
# 144| 1: [DefaultAttribute] [Params(...)]
# 144| -1: [TypeMention] ParamsAttribute
# 144| 0: [StringLiteralUtf16] "a"
# 144| 1: [StringLiteralUtf16] "b"
# 144| 2: [IntLiteral] 1
# 144| 3: [IntLiteral] 2
# 144| 4: [IntLiteral] 3
# 145| 4: [BlockStmt] {...}
# 148| 7: [Method] M2
# 148| -1: [TypeMention] Void
#-----| 0: (Attributes)
# 145| 1: [DefaultAttribute] [Params(...)]
# 145| -1: [TypeMention] ParamsAttribute
# 145| 0: [StringLiteralUtf16] "a"
# 145| 1: [StringLiteralUtf16] "b"
# 145| 2: [IntLiteral] 1
# 145| 3: [IntLiteral] 2
# 145| 4: [IntLiteral] 3
# 146| 4: [BlockStmt] {...}
# 149| 8: [Method] M3
# 149| -1: [TypeMention] Void
# 147| 1: [DefaultAttribute] [Params(...)]
# 147| -1: [TypeMention] ParamsAttribute
# 147| 0: [StringLiteralUtf16] "a"
# 147| 1: [StringLiteralUtf16] "b"
# 147| 2: [IntLiteral] 1
# 147| 3: [IntLiteral] 2
# 147| 4: [IntLiteral] 3
# 148| 4: [BlockStmt] {...}
# 151| 8: [Method] M3
# 151| -1: [TypeMention] Void
#-----| 0: (Attributes)
# 148| 1: [DefaultAttribute] [Params(...)]
# 148| -1: [TypeMention] ParamsAttribute
# 148| 0: [StringLiteralUtf16] "a"
# 148| 1: [StringLiteralUtf16] "b"
# 148| 2: [IntLiteral] 1
# 149| 4: [BlockStmt] {...}
# 152| 9: [Method] M4
# 152| -1: [TypeMention] Void
# 150| 1: [DefaultAttribute] [Params(...)]
# 150| -1: [TypeMention] ParamsAttribute
# 150| 0: [StringLiteralUtf16] "a"
# 150| 1: [StringLiteralUtf16] "b"
# 150| 2: [IntLiteral] 1
# 151| 4: [BlockStmt] {...}
# 154| 9: [Method] M4
# 154| -1: [TypeMention] Void
#-----| 0: (Attributes)
# 151| 1: [DefaultAttribute] [Params(...)]
# 151| -1: [TypeMention] ParamsAttribute
# 151| 0: [StringLiteralUtf16] "a"
# 151| 1: [StringLiteralUtf16] "b"
# 151| 2: [ArrayCreation] array creation of type Int32[]
# 151| -1: [ArrayInitializer] { ..., ... }
# 151| 0: [IntLiteral] 1
# 152| 4: [BlockStmt] {...}
# 156| [Class] MyExperimentalClass
# 153| 1: [DefaultAttribute] [Params(...)]
# 153| -1: [TypeMention] ParamsAttribute
# 153| 0: [StringLiteralUtf16] "a"
# 153| 1: [StringLiteralUtf16] "b"
# 153| 2: [ArrayCreation] array creation of type Int32[]
# 153| -1: [ArrayInitializer] { ..., ... }
# 153| 0: [IntLiteral] 1
# 154| 4: [BlockStmt] {...}
# 158| [Class] MyExperimentalClass
#-----| 0: (Attributes)
# 155| 1: [DefaultAttribute] [Experimental(...)]
# 155| -1: [TypeMention] ExperimentalAttribute
# 155| 0: [StringLiteralUtf16] "MyExperimentalClassId"
# 159| 5: [Method] MyExperimentalMethod
# 159| -1: [TypeMention] Void
# 157| 1: [DefaultAttribute] [Experimental(...)]
# 157| -1: [TypeMention] ExperimentalAttribute
# 157| 0: [StringLiteralUtf16] "MyExperimentalClassId"
# 161| 5: [Method] MyExperimentalMethod
# 161| -1: [TypeMention] Void
#-----| 0: (Attributes)
# 158| 1: [DefaultAttribute] [Experimental(...)]
# 158| -1: [TypeMention] ExperimentalAttribute
# 158| 0: [StringLiteralUtf16] "MyExperimentalMethodId"
# 159| 4: [BlockStmt] {...}
# 160| 1: [DefaultAttribute] [Experimental(...)]
# 160| -1: [TypeMention] ExperimentalAttribute
# 160| 0: [StringLiteralUtf16] "MyExperimentalMethodId"
# 161| 4: [BlockStmt] {...}

View File

@@ -108,6 +108,7 @@ public class MyAttributeUsage
[return: My3Attribute(6)]
public static int operator +(MyAttributeUsage a, MyAttributeUsage b) => 0;
[My3Attribute(15)]
public int this[int x]
{
[My3Attribute(7)]
@@ -120,6 +121,7 @@ public class MyAttributeUsage
}
private int p;
[My3Attribute(16)]
public int Prop1
{
[method: My3Attribute(11)]

View File

@@ -12,18 +12,21 @@
| CSharp7.cs:15:9:15:11 | SSA entry def(this.field) | CSharp7.cs:15:18:15:22 | access to field field |
| CSharp7.cs:15:9:15:11 | this | CSharp7.cs:15:18:15:22 | this access |
| CSharp7.cs:19:9:19:11 | this | CSharp7.cs:19:16:19:20 | this access |
| CSharp7.cs:20:9:20:11 | SSA param(value) | CSharp7.cs:20:24:20:28 | access to parameter value |
| CSharp7.cs:20:9:20:11 | this | CSharp7.cs:20:16:20:20 | this access |
| CSharp7.cs:20:9:20:11 | value | CSharp7.cs:20:24:20:28 | access to parameter value |
| CSharp7.cs:20:9:20:11 | value | CSharp7.cs:20:9:20:11 | SSA param(value) |
| CSharp7.cs:20:24:20:28 | access to parameter value | CSharp7.cs:20:16:20:20 | access to field field |
| CSharp7.cs:23:5:23:27 | this | CSharp7.cs:14:9:14:13 | this access |
| CSharp7.cs:24:6:24:28 | this | CSharp7.cs:24:35:24:39 | this access |
| CSharp7.cs:29:19:29:19 | i | CSharp7.cs:31:16:31:16 | access to parameter i |
| CSharp7.cs:29:19:29:19 | SSA param(i) | CSharp7.cs:31:16:31:16 | access to parameter i |
| CSharp7.cs:29:19:29:19 | i | CSharp7.cs:29:19:29:19 | SSA param(i) |
| CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:16:31:20 | ... > ... |
| CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:24:31:24 | access to parameter i |
| CSharp7.cs:31:24:31:24 | access to parameter i | CSharp7.cs:31:16:31:59 | ... ? ... : ... |
| CSharp7.cs:39:9:39:9 | access to parameter x | CSharp7.cs:39:9:39:21 | SSA def(x) |
| CSharp7.cs:39:13:39:21 | "tainted" | CSharp7.cs:39:9:39:9 | access to parameter x |
| CSharp7.cs:42:19:42:19 | x | CSharp7.cs:44:13:44:13 | access to parameter x |
| CSharp7.cs:42:19:42:19 | SSA param(x) | CSharp7.cs:44:13:44:13 | access to parameter x |
| CSharp7.cs:42:19:42:19 | x | CSharp7.cs:42:19:42:19 | SSA param(x) |
| CSharp7.cs:44:9:44:9 | access to parameter y | CSharp7.cs:44:9:44:13 | SSA def(y) |
| CSharp7.cs:44:13:44:13 | access to parameter x | CSharp7.cs:44:9:44:9 | access to parameter y |
| CSharp7.cs:47:10:47:10 | this | CSharp7.cs:49:9:49:24 | this access |
@@ -86,7 +89,8 @@
| CSharp7.cs:77:22:77:28 | (..., ...) | CSharp7.cs:77:9:77:18 | (..., ...) |
| CSharp7.cs:77:23:77:24 | "" | CSharp7.cs:77:9:77:28 | ... = ... |
| CSharp7.cs:77:27:77:27 | access to local variable x | CSharp7.cs:77:9:77:28 | ... = ... |
| CSharp7.cs:80:21:80:21 | x | CSharp7.cs:82:20:82:20 | access to parameter x |
| CSharp7.cs:80:21:80:21 | SSA param(x) | CSharp7.cs:82:20:82:20 | access to parameter x |
| CSharp7.cs:80:21:80:21 | x | CSharp7.cs:80:21:80:21 | SSA param(x) |
| CSharp7.cs:85:10:85:18 | this | CSharp7.cs:90:18:90:28 | this access |
| CSharp7.cs:87:13:87:14 | access to local variable t1 | CSharp7.cs:87:13:87:34 | SSA def(t1) |
| CSharp7.cs:87:13:87:34 | SSA def(t1) | CSharp7.cs:88:28:88:29 | access to local variable t1 |
@@ -133,40 +137,51 @@
| CSharp7.cs:121:28:121:36 | "DefUse3" | CSharp7.cs:121:22:121:24 | access to local variable m12 |
| CSharp7.cs:121:28:121:36 | "DefUse3" | CSharp7.cs:121:22:121:36 | ... = ... |
| CSharp7.cs:127:9:127:12 | this | CSharp7.cs:133:24:133:25 | this access |
| CSharp7.cs:129:20:129:20 | x | CSharp7.cs:129:32:129:32 | access to parameter x |
| CSharp7.cs:129:20:129:20 | SSA param(x) | CSharp7.cs:129:32:129:32 | access to parameter x |
| CSharp7.cs:129:20:129:20 | x | CSharp7.cs:129:20:129:20 | SSA param(x) |
| CSharp7.cs:129:32:129:32 | access to parameter x | CSharp7.cs:129:32:129:36 | ... + ... |
| CSharp7.cs:129:36:129:36 | 1 | CSharp7.cs:129:32:129:36 | ... + ... |
| CSharp7.cs:131:22:131:22 | t | CSharp7.cs:131:39:131:39 | access to parameter t |
| CSharp7.cs:131:22:131:22 | SSA param(t) | CSharp7.cs:131:39:131:39 | access to parameter t |
| CSharp7.cs:131:22:131:22 | t | CSharp7.cs:131:22:131:22 | SSA param(t) |
| CSharp7.cs:133:24:133:25 | delegate creation of type Func<Int32> | CSharp7.cs:133:19:133:20 | access to local variable f4 |
| CSharp7.cs:133:24:133:25 | this access | CSharp7.cs:154:16:154:17 | this access |
| CSharp7.cs:137:29:137:29 | x | CSharp7.cs:137:34:137:34 | access to parameter x |
| CSharp7.cs:137:29:137:29 | SSA param(x) | CSharp7.cs:137:34:137:34 | access to parameter x |
| CSharp7.cs:137:29:137:29 | x | CSharp7.cs:137:29:137:29 | SSA param(x) |
| CSharp7.cs:137:29:137:38 | (...) => ... | CSharp7.cs:137:24:137:25 | access to local variable f5 |
| CSharp7.cs:137:34:137:34 | access to parameter x | CSharp7.cs:137:34:137:38 | ... + ... |
| CSharp7.cs:137:38:137:38 | 1 | CSharp7.cs:137:34:137:38 | ... + ... |
| CSharp7.cs:139:20:139:20 | x | CSharp7.cs:139:26:139:26 | access to parameter x |
| CSharp7.cs:139:20:139:20 | SSA param(x) | CSharp7.cs:139:26:139:26 | access to parameter x |
| CSharp7.cs:139:20:139:20 | x | CSharp7.cs:139:20:139:20 | SSA param(x) |
| CSharp7.cs:139:26:139:26 | access to parameter x | CSharp7.cs:139:26:139:30 | ... > ... |
| CSharp7.cs:139:26:139:26 | access to parameter x | CSharp7.cs:139:41:139:41 | access to parameter x |
| CSharp7.cs:139:34:139:34 | 1 | CSharp7.cs:139:34:139:46 | ... + ... |
| CSharp7.cs:139:34:139:46 | ... + ... | CSharp7.cs:139:26:139:50 | ... ? ... : ... |
| CSharp7.cs:139:38:139:46 | call to local function f7 | CSharp7.cs:139:34:139:46 | ... + ... |
| CSharp7.cs:139:50:139:50 | 0 | CSharp7.cs:139:26:139:50 | ... ? ... : ... |
| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:29:141:29 | access to parameter x |
| CSharp7.cs:145:24:145:24 | x | CSharp7.cs:145:33:145:33 | access to parameter x |
| CSharp7.cs:141:20:141:20 | SSA param(x) | CSharp7.cs:141:29:141:29 | access to parameter x |
| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:20:141:20 | SSA param(x) |
| CSharp7.cs:145:24:145:24 | SSA param(x) | CSharp7.cs:145:33:145:33 | access to parameter x |
| CSharp7.cs:145:24:145:24 | x | CSharp7.cs:145:24:145:24 | SSA param(x) |
| CSharp7.cs:149:20:152:9 | (...) => ... | CSharp7.cs:149:16:149:16 | access to local variable a |
| CSharp7.cs:157:10:157:17 | this | CSharp7.cs:169:9:169:9 | this access |
| CSharp7.cs:160:18:160:18 | t | CSharp7.cs:160:24:160:24 | access to parameter t |
| CSharp7.cs:162:26:162:26 | u | CSharp7.cs:166:22:166:22 | access to parameter u |
| CSharp7.cs:160:18:160:18 | SSA param(t) | CSharp7.cs:160:24:160:24 | access to parameter t |
| CSharp7.cs:160:18:160:18 | t | CSharp7.cs:160:18:160:18 | SSA param(t) |
| CSharp7.cs:162:26:162:26 | SSA param(u) | CSharp7.cs:166:22:166:22 | access to parameter u |
| CSharp7.cs:162:26:162:26 | u | CSharp7.cs:162:26:162:26 | SSA param(u) |
| CSharp7.cs:165:13:165:16 | this access | CSharp7.cs:166:20:166:20 | this access |
| CSharp7.cs:169:9:169:9 | this access | CSharp7.cs:170:9:170:9 | this access |
| CSharp7.cs:173:10:173:19 | this | CSharp7.cs:180:21:180:21 | this access |
| CSharp7.cs:175:16:175:18 | access to local variable src | CSharp7.cs:175:16:175:30 | SSA def(src) |
| CSharp7.cs:175:16:175:30 | SSA def(src) | CSharp7.cs:180:23:180:25 | access to local variable src |
| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:175:16:175:18 | access to local variable src |
| CSharp7.cs:176:25:176:25 | s | CSharp7.cs:176:33:176:33 | access to parameter s |
| CSharp7.cs:176:25:176:25 | SSA param(s) | CSharp7.cs:176:33:176:33 | access to parameter s |
| CSharp7.cs:176:25:176:25 | s | CSharp7.cs:176:25:176:25 | SSA param(s) |
| CSharp7.cs:176:31:176:34 | call to local function g | CSharp7.cs:176:31:176:39 | ... + ... |
| CSharp7.cs:176:38:176:39 | "" | CSharp7.cs:176:31:176:39 | ... + ... |
| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:31:177:31 | access to parameter s |
| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:37:178:37 | access to parameter s |
| CSharp7.cs:177:25:177:25 | SSA param(s) | CSharp7.cs:177:31:177:31 | access to parameter s |
| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:25:177:25 | SSA param(s) |
| CSharp7.cs:178:25:178:25 | SSA param(s) | CSharp7.cs:178:37:178:37 | access to parameter s |
| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:25:178:25 | SSA param(s) |
| CSharp7.cs:180:21:180:21 | this access | CSharp7.cs:181:21:181:21 | this access |
| CSharp7.cs:180:21:180:26 | call to local function f | CSharp7.cs:180:13:180:17 | access to local variable sink1 |
| CSharp7.cs:180:23:180:25 | [post] access to local variable src | CSharp7.cs:181:23:181:25 | access to local variable src |
@@ -205,8 +220,10 @@
| CSharp7.cs:198:26:198:35 | this access | CSharp7.cs:199:9:199:18 | this access |
| CSharp7.cs:198:33:198:34 | access to local variable r1 | CSharp7.cs:199:16:199:17 | access to local variable r1 |
| CSharp7.cs:199:22:199:22 | 3 | CSharp7.cs:199:9:199:22 | ... = ... |
| CSharp7.cs:202:24:202:24 | p | CSharp7.cs:205:20:205:20 | access to parameter p |
| CSharp7.cs:204:28:204:28 | q | CSharp7.cs:204:44:204:44 | access to parameter q |
| CSharp7.cs:202:24:202:24 | SSA param(p) | CSharp7.cs:205:20:205:20 | access to parameter p |
| CSharp7.cs:202:24:202:24 | p | CSharp7.cs:202:24:202:24 | SSA param(p) |
| CSharp7.cs:204:28:204:28 | SSA param(q) | CSharp7.cs:204:44:204:44 | access to parameter q |
| CSharp7.cs:204:28:204:28 | q | CSharp7.cs:204:28:204:28 | SSA param(q) |
| CSharp7.cs:215:9:215:9 | access to parameter x | CSharp7.cs:215:9:215:17 | SSA def(x) |
| CSharp7.cs:215:13:215:17 | false | CSharp7.cs:215:9:215:9 | access to parameter x |
| CSharp7.cs:219:10:219:13 | this | CSharp7.cs:221:13:221:20 | this access |
@@ -224,8 +241,8 @@
| CSharp7.cs:232:16:232:23 | SSA def(o) | CSharp7.cs:233:13:233:13 | access to local variable o |
| CSharp7.cs:232:20:232:23 | null | CSharp7.cs:232:16:232:16 | access to local variable o |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:233:18:233:23 | Int32 i1 |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:237:18:237:18 | access to local variable o |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
| CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
| CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... |
@@ -235,19 +252,25 @@
| CSharp7.cs:233:28:233:29 | access to local variable i1 | CSharp7.cs:235:38:235:39 | access to local variable i1 |
| CSharp7.cs:233:28:233:33 | ... > ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
| CSharp7.cs:233:28:233:33 | ... > ... | CSharp7.cs:233:13:233:33 | [true] ... && ... |
| CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:235:33:235:36 | "int " | CSharp7.cs:235:31:235:41 | $"..." |
| CSharp7.cs:235:38:235:39 | access to local variable i1 | CSharp7.cs:235:31:235:41 | $"..." |
| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:237:23:237:31 | String s1 |
| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) |
| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:241:18:241:18 | access to local variable o |
| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:237:23:237:31 | SSA def(s1) | CSharp7.cs:239:41:239:42 | access to local variable s1 |
| CSharp7.cs:237:23:237:31 | String s1 | CSharp7.cs:237:23:237:31 | SSA def(s1) |
| CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:239:33:239:39 | "string " | CSharp7.cs:239:31:239:44 | $"..." |
| CSharp7.cs:239:41:239:42 | access to local variable s1 | CSharp7.cs:239:31:239:44 | $"..." |
| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) |
| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:244:18:244:18 | access to local variable o |
| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:18:244:28 | [input] SSA phi read(o) |
| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:23:244:28 | Object v1 |
| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:245:9:246:9 | [input] SSA phi read(o) |
| CSharp7.cs:244:18:244:28 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:245:9:246:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:248:9:274:9 | SSA phi read(o) | CSharp7.cs:248:17:248:17 | access to local variable o |
| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:254:27:254:27 | access to local variable o |
| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:257:18:257:23 | Int32 i2 |
@@ -281,14 +304,16 @@
| CSharp7.cs:283:13:283:16 | access to local variable list | CSharp7.cs:283:13:283:62 | SSA def(list) |
| CSharp7.cs:283:13:283:62 | SSA def(list) | CSharp7.cs:285:39:285:42 | access to local variable list |
| CSharp7.cs:283:20:283:62 | call to method Select<KeyValuePair<Int32,String>,(Int32,String)> | CSharp7.cs:283:13:283:16 | access to local variable list |
| CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:41:283:44 | access to parameter item |
| CSharp7.cs:283:32:283:35 | SSA param(item) | CSharp7.cs:283:41:283:44 | access to parameter item |
| CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:32:283:35 | SSA param(item) |
| CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:41:283:48 | access to property Key |
| CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:51:283:54 | access to parameter item |
| CSharp7.cs:283:51:283:54 | access to parameter item | CSharp7.cs:283:51:283:60 | access to property Value |
| CSharp7.cs:285:39:285:42 | access to local variable list | CSharp7.cs:287:36:287:39 | access to local variable list |
| CSharp7.cs:287:36:287:39 | access to local variable list | CSharp7.cs:289:32:289:35 | access to local variable list |
| CSharp7.cs:297:18:297:18 | access to local variable x | CSharp7.cs:297:18:297:22 | SSA def(x) |
| CSharp7.cs:297:18:297:22 | SSA def(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
| CSharp7.cs:297:18:297:22 | SSA def(x) | CSharp7.cs:297:18:297:22 | [input] SSA phi(x) |
| CSharp7.cs:297:18:297:22 | [input] SSA phi(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
| CSharp7.cs:297:22:297:22 | 0 | CSharp7.cs:297:18:297:18 | access to local variable x |
| CSharp7.cs:297:25:297:25 | SSA phi(x) | CSharp7.cs:297:25:297:25 | access to local variable x |
| CSharp7.cs:297:25:297:25 | access to local variable x | CSharp7.cs:297:25:297:30 | ... < ... |
@@ -301,5 +326,6 @@
| CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... |
| CSharp7.cs:297:40:297:44 | Int32 y | CSharp7.cs:297:40:297:44 | SSA def(y) |
| CSharp7.cs:297:40:297:44 | SSA def(y) | CSharp7.cs:299:31:299:31 | access to local variable y |
| CSharp7.cs:297:47:297:49 | SSA def(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
| CSharp7.cs:297:47:297:49 | SSA def(x) | CSharp7.cs:297:47:297:49 | [input] SSA phi(x) |
| CSharp7.cs:297:47:297:49 | [input] SSA phi(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
| CSharp7.cs:297:49:297:49 | access to local variable x | CSharp7.cs:297:47:297:49 | SSA def(x) |

View File

@@ -0,0 +1,83 @@
class BarrierFlow
{
static object Source(object source) => throw null;
public static void Sink(object o) { }
void M1()
{
var x = Source(1);
Sink(x); // $ hasValueFlow=1
}
void M2()
{
var x = Source(2);
if (x != "safe")
{
Sink(x); // $ hasValueFlow=2
}
}
void M3()
{
var x = Source(3);
if (x == "safe")
{
Sink(x);
}
}
void M4()
{
var x = Source(4);
if (x != "safe")
{
x = "safe";
}
Sink(x);
}
void M5()
{
var x = Source(5);
if (x == "safe")
{
}
else
{
x = "safe";
}
Sink(x);
}
void M6(bool b)
{
var x = Source(6);
if (b)
{
if (x != "safe1")
{
return;
}
}
else
{
if (x != "safe2")
{
return;
}
}
Sink(x);
}
}

View File

@@ -0,0 +1,18 @@
models
edges
| BarrierFlow.cs:10:13:10:13 | access to local variable x : Object | BarrierFlow.cs:12:14:12:14 | access to local variable x | provenance | |
| BarrierFlow.cs:10:17:10:25 | call to method Source : Object | BarrierFlow.cs:10:13:10:13 | access to local variable x : Object | provenance | |
| BarrierFlow.cs:17:13:17:13 | access to local variable x : Object | BarrierFlow.cs:21:18:21:18 | access to local variable x | provenance | |
| BarrierFlow.cs:17:17:17:25 | call to method Source : Object | BarrierFlow.cs:17:13:17:13 | access to local variable x : Object | provenance | |
nodes
| BarrierFlow.cs:10:13:10:13 | access to local variable x : Object | semmle.label | access to local variable x : Object |
| BarrierFlow.cs:10:17:10:25 | call to method Source : Object | semmle.label | call to method Source : Object |
| BarrierFlow.cs:12:14:12:14 | access to local variable x | semmle.label | access to local variable x |
| BarrierFlow.cs:17:13:17:13 | access to local variable x : Object | semmle.label | access to local variable x : Object |
| BarrierFlow.cs:17:17:17:25 | call to method Source : Object | semmle.label | call to method Source : Object |
| BarrierFlow.cs:21:18:21:18 | access to local variable x | semmle.label | access to local variable x |
subpaths
testFailures
#select
| BarrierFlow.cs:12:14:12:14 | access to local variable x | BarrierFlow.cs:10:17:10:25 | call to method Source : Object | BarrierFlow.cs:12:14:12:14 | access to local variable x | $@ | BarrierFlow.cs:10:17:10:25 | call to method Source : Object | call to method Source : Object |
| BarrierFlow.cs:21:18:21:18 | access to local variable x | BarrierFlow.cs:17:17:17:25 | call to method Source : Object | BarrierFlow.cs:21:18:21:18 | access to local variable x | $@ | BarrierFlow.cs:17:17:17:25 | call to method Source : Object | call to method Source : Object |

View File

@@ -0,0 +1,35 @@
/**
* @kind path-problem
*/
import csharp
import semmle.code.csharp.controlflow.Guards
private predicate stringConstCompare(Guard guard, Expr testedNode, AbstractValue value) {
guard
.isEquality(any(StringLiteral lit), testedNode,
value.(AbstractValues::BooleanValue).getValue())
}
class StringConstCompareBarrier extends DataFlow::Node {
StringConstCompareBarrier() {
this = DataFlow::BarrierGuard<stringConstCompare/3>::getABarrierNode()
}
}
import TestUtilities.InlineFlowTest
import PathGraph
module FlowConfig implements DataFlow::ConfigSig {
predicate isSource = DefaultFlowConfig::isSource/1;
predicate isSink = DefaultFlowConfig::isSink/1;
predicate isBarrier(DataFlow::Node n) { n instanceof StringConstCompareBarrier }
}
import ValueFlowTest<FlowConfig>
from PathNode source, PathNode sink
where flowPath(source, sink)
select sink, source, sink, "$@", source, source.toString()

View File

@@ -12,6 +12,12 @@ namespace My.Qltest
object fieldWrite = new object();
TaggedField = fieldWrite;
object propertyWrite = new object();
TaggedPropertySetter = propertyWrite;
object indexerWrite = new object();
this[0] = indexerWrite;
}
object SinkMethod()
@@ -34,7 +40,21 @@ namespace My.Qltest
[SinkAttribute]
object TaggedField;
[SinkPropertyAttribute]
object TaggedPropertySetter { get; set; }
[SinkIndexerAttribute]
object this[int index]
{
get { return null; }
set { }
}
}
class SinkAttribute : System.Attribute { }
}
class SinkPropertyAttribute : System.Attribute { }
class SinkIndexerAttribute : System.Attribute { }
}

View File

@@ -18,14 +18,17 @@ namespace My.Qltest
x = TaggedSrcField;
x = SrcTwoArg("", "");
x = TaggedSrcPropertyGetter;
x = this[0];
}
[SourceAttribute()]
[SourceAttribute]
void Tagged1(object taggedMethodParam)
{
}
void Tagged2([SourceAttribute()] object taggedSrcParam)
void Tagged2([SourceAttribute] object taggedSrcParam)
{
}
@@ -49,14 +52,20 @@ namespace My.Qltest
void SrcArg(object src) { }
[SourceAttribute()]
[SourceAttribute]
object TaggedSrcMethod() { return null; }
[SourceAttribute()]
[SourceAttribute]
object TaggedSrcField;
object SrcTwoArg(string s1, string s2) { return null; }
[SourceAttribute]
object TaggedSrcPropertyGetter { get; }
[SourceAttribute]
object this[int i] => null;
}
class SourceAttribute : System.Attribute { }
}
}

View File

@@ -4,5 +4,7 @@ invalidModelRow
| Sinks.cs:11:13:11:41 | this access | file-content-store |
| Sinks.cs:11:30:11:40 | access to local variable argToTagged | file-content-store |
| Sinks.cs:14:27:14:36 | access to local variable fieldWrite | sql-injection |
| Sinks.cs:20:20:20:22 | access to local variable res | js-injection |
| Sinks.cs:27:20:27:25 | access to local variable resTag | html-injection |
| Sinks.cs:17:36:17:48 | access to local variable propertyWrite | sql-injection |
| Sinks.cs:20:23:20:34 | access to local variable indexerWrite | sql-injection |
| Sinks.cs:26:20:26:22 | access to local variable res | js-injection |
| Sinks.cs:33:20:33:25 | access to local variable resTag | html-injection |

View File

@@ -9,3 +9,5 @@ extensions:
- ["My.Qltest", "SinkAttribute", false, "", "", "Attribute", "ReturnValue", "html-injection", "manual"]
- ["My.Qltest", "SinkAttribute", false, "", "", "Attribute", "Argument", "file-content-store", "manual"]
- ["My.Qltest", "SinkAttribute", false, "", "", "Attribute", "", "sql-injection", "manual"]
- ["My.Qltest", "SinkPropertyAttribute", false, "", "", "Attribute.Setter", "Argument[0]", "sql-injection", "manual"]
- ["My.Qltest", "SinkIndexerAttribute", false, "", "", "Attribute.Setter", "Argument[1]", "sql-injection", "manual"]

View File

@@ -9,9 +9,11 @@ invalidModelRow
| Sources.cs:17:17:17:33 | call to method TaggedSrcMethod | local |
| Sources.cs:18:17:18:30 | access to field TaggedSrcField | local |
| Sources.cs:20:17:20:33 | call to method SrcTwoArg | local |
| Sources.cs:24:14:24:20 | this | local |
| Sources.cs:24:29:24:45 | taggedMethodParam | local |
| Sources.cs:28:49:28:62 | taggedSrcParam | local |
| Sources.cs:40:45:40:45 | p | local |
| Sources.cs:47:50:47:50 | p | local |
| Sources.cs:53:16:53:30 | this | local |
| Sources.cs:22:17:22:39 | access to property TaggedSrcPropertyGetter | local |
| Sources.cs:23:17:23:23 | access to indexer | local |
| Sources.cs:27:14:27:20 | this | local |
| Sources.cs:27:29:27:45 | taggedMethodParam | local |
| Sources.cs:31:47:31:60 | taggedSrcParam | local |
| Sources.cs:43:45:43:45 | p | local |
| Sources.cs:50:50:50:50 | p | local |
| Sources.cs:56:16:56:30 | this | local |

View File

@@ -17,4 +17,5 @@ extensions:
- ["My.Qltest", "SourceAttribute", false, "", "", "Attribute", "ReturnValue", "local", "manual"]
- ["My.Qltest", "SourceAttribute", false, "", "", "Attribute", "Parameter", "local", "manual"]
- ["My.Qltest", "SourceAttribute", false, "", "", "Attribute", "", "local", "manual"]
- ["My.Qltest", "A", false, "SrcTwoArg", "(System.String,System.String)", "", "ReturnValue", "local", "manual"]
- ["My.Qltest", "SourceAttribute", false, "", "", "Attribute.Getter", "ReturnValue", "local", "manual"]
- ["My.Qltest", "A", false, "SrcTwoArg", "(System.String,System.String)", "", "ReturnValue", "local", "manual"]

View File

@@ -10,7 +10,7 @@ edges
| Test.cs:23:42:23:59 | call to method GetStream : NetworkStream | Test.cs:23:33:23:38 | access to local variable stream : NetworkStream | provenance | Src:MaD:3 |
| Test.cs:25:29:25:34 | access to local variable stream : NetworkStream | Test.cs:25:41:25:46 | [post] access to local variable buffer : Byte[] [element] : Object | provenance | MaD:2 |
| Test.cs:25:41:25:46 | [post] access to local variable buffer : Byte[] [element] : Object | Test.cs:28:99:28:104 | access to local variable buffer : Byte[] [element] : Object | provenance | |
| Test.cs:28:85:28:105 | call to method BytesToString : String | Test.cs:28:42:28:111 | ... + ... | provenance | Sink:MaD:1 |
| Test.cs:28:85:28:105 | call to method BytesToString : String | Test.cs:28:42:28:111 | ... + ... | provenance | Sink:MaD:1 |
| Test.cs:28:99:28:104 | access to local variable buffer : Byte[] [element] : Object | Test.cs:12:45:12:49 | bytes : Byte[] [element] : Object | provenance | |
| Test.cs:28:99:28:104 | access to local variable buffer : Byte[] [element] : Object | Test.cs:28:85:28:105 | call to method BytesToString : String | provenance | MaD:4 |
nodes

View File

@@ -11,10 +11,10 @@ edges
| Test.cs:23:42:23:59 | call to method GetStream : NetworkStream | Test.cs:23:33:23:38 | access to local variable stream : NetworkStream | provenance | Src:MaD:3 |
| Test.cs:25:29:25:34 | access to local variable stream : NetworkStream | Test.cs:25:41:25:46 | [post] access to local variable buffer : Byte[] [element] : Object | provenance | MaD:2 |
| Test.cs:25:41:25:46 | [post] access to local variable buffer : Byte[] [element] : Object | Test.cs:28:99:28:104 | access to local variable buffer : Byte[] [element] : Object | provenance | |
| Test.cs:28:85:28:105 | call to method BytesToString : String | Test.cs:28:42:28:111 | ... + ... | provenance | Sink:MaD:1 |
| Test.cs:28:85:28:105 | call to method BytesToString : String | Test.cs:28:42:28:111 | ... + ... | provenance | Sink:MaD:1 |
| Test.cs:28:99:28:104 | access to local variable buffer : Byte[] [element] : Object | Test.cs:12:45:12:49 | bytes : Byte[] [element] : Object | provenance | |
| Test.cs:28:99:28:104 | access to local variable buffer : Byte[] [element] : Object | Test.cs:28:85:28:105 | call to method BytesToString : String | provenance | MaD:4 |
| Test.cs:34:20:34:25 | access to local variable result : String | Test.cs:37:42:37:96 | ... + ... | provenance | Sink:MaD:1 |
| Test.cs:34:20:34:25 | access to local variable result : String | Test.cs:37:42:37:96 | ... + ... | provenance | Sink:MaD:1 |
| Test.cs:34:29:34:69 | call to method ExecuteQuery : String | Test.cs:34:20:34:25 | access to local variable result : String | provenance | Src:MaD:5 |
nodes
| Test.cs:12:45:12:49 | bytes : Byte[] [element] : Object | semmle.label | bytes : Byte[] [element] : Object |

Some files were not shown because too many files have changed in this diff Show More