mirror of
https://github.com/github/codeql.git
synced 2026-04-18 13:34:02 +02:00
Merge branch 'main' into changedocs/2.19.0
This commit is contained in:
2
.github/workflows/go-tests.yml
vendored
2
.github/workflows/go-tests.yml
vendored
@@ -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
|
||||
|
||||
@@ -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
98
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -6,6 +6,8 @@ members = [
|
||||
"shared/tree-sitter-extractor",
|
||||
"ruby/extractor",
|
||||
"rust/extractor",
|
||||
"rust/extractor/macros",
|
||||
"rust/generate-schema",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.2.3
|
||||
version: 1.2.4-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -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
1
csharp/.gitignore
vendored
@@ -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
65
csharp/.vscode/launch.json
vendored
Normal 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
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add `cil` and `dotnet` related relations and types.
|
||||
compatibility: backwards
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
PopulateMetadataHandle(trapFile);
|
||||
PopulateAttributes();
|
||||
ContainingType!.PopulateGenerics();
|
||||
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
PopulateAttributes();
|
||||
PopulateModifiers(trapFile);
|
||||
BindComments();
|
||||
|
||||
|
||||
@@ -360,7 +360,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
PopulateParameters();
|
||||
PopulateMethodBody(trapFile);
|
||||
PopulateGenerics(trapFile);
|
||||
PopulateMetadataHandle(trapFile);
|
||||
PopulateNullability(trapFile, Symbol.GetAnnotatedReturnType());
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
PopulateMetadataHandle(trapFile);
|
||||
PopulateAttributes();
|
||||
PopulateModifiers(trapFile);
|
||||
BindComments();
|
||||
|
||||
@@ -77,7 +77,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
protected void PopulateType(TextWriter trapFile, bool constructUnderlyingTupleType = false)
|
||||
{
|
||||
PopulateMetadataHandle(trapFile);
|
||||
PopulateAttributes();
|
||||
|
||||
trapFile.Write("types(");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.25
|
||||
version: 1.7.26-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.25
|
||||
version: 1.7.26-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
4
csharp/ql/lib/change-notes/2024-09-16-accessor-mad.md
Normal file
4
csharp/ql/lib/change-notes/2024-09-16-accessor-mad.md
Normal 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`.
|
||||
4
csharp/ql/lib/change-notes/2024-09-16-delete-cil.md
Normal file
4
csharp/ql/lib/change-notes/2024-09-16-delete-cil.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* C#: Remove all CIL tables and related QL library functionality.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C#: Add extractor support for attributes on indexers.
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* The default QL library for modeling the Common Intermediate Language (CIL).
|
||||
*/
|
||||
|
||||
import semmle.code.cil.CIL as CIL
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 { }
|
||||
@@ -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(_) }
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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())
|
||||
)
|
||||
}
|
||||
@@ -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" }
|
||||
}
|
||||
@@ -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" }
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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 {...}" }
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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
@@ -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() }
|
||||
}
|
||||
@@ -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, _) }
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()) }
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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 { }
|
||||
@@ -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), ","
|
||||
)
|
||||
}
|
||||
@@ -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() = "" }
|
||||
}
|
||||
@@ -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(_) }
|
||||
}
|
||||
@@ -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" }
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 1.0.8
|
||||
version: 1.0.9-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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[] |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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] {...}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -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()
|
||||
@@ -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 { }
|
||||
}
|
||||
|
||||
@@ -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 { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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"]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user