mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge branch 'main' into redsun82/rust-perf-measures
This commit is contained in:
87
.vscode/tasks.json
vendored
87
.vscode/tasks.json
vendored
@@ -38,6 +38,93 @@
|
||||
"command": "${config:python.pythonPath}",
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Create query change note",
|
||||
"type": "process",
|
||||
"command": "python3",
|
||||
"args": [
|
||||
"misc/scripts/create-change-note.py",
|
||||
"${input:language}",
|
||||
"src",
|
||||
"${input:name}",
|
||||
"${input:categoryQuery}"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"close": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Create library change note",
|
||||
"type": "process",
|
||||
"command": "python3",
|
||||
"args": [
|
||||
"misc/scripts/create-change-note.py",
|
||||
"${input:language}",
|
||||
"lib",
|
||||
"${input:name}",
|
||||
"${input:categoryLibrary}"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"close": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"type": "pickString",
|
||||
"id": "language",
|
||||
"description": "Language",
|
||||
"options":
|
||||
[
|
||||
"go",
|
||||
"java",
|
||||
"javascript",
|
||||
"cpp",
|
||||
"csharp",
|
||||
"python",
|
||||
"ruby",
|
||||
"rust",
|
||||
"swift",
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "promptString",
|
||||
"id": "name",
|
||||
"description": "Short name (kebab-case)"
|
||||
},
|
||||
{
|
||||
"type": "pickString",
|
||||
"id": "categoryQuery",
|
||||
"description": "Category (query change)",
|
||||
"options":
|
||||
[
|
||||
"breaking",
|
||||
"deprecated",
|
||||
"newQuery",
|
||||
"queryMetadata",
|
||||
"majorAnalysis",
|
||||
"minorAnalysis",
|
||||
"fix",
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "pickString",
|
||||
"id": "categoryLibrary",
|
||||
"description": "Category (library change)",
|
||||
"options":
|
||||
[
|
||||
"breaking",
|
||||
"deprecated",
|
||||
"feature",
|
||||
"majorAnalysis",
|
||||
"minorAnalysis",
|
||||
"fix",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -793,28 +793,27 @@ private Element interpretElement0(
|
||||
) {
|
||||
(
|
||||
// Non-member functions
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
funcHasQualifiedName(result, namespace, name) and
|
||||
subtypes = false and
|
||||
type = "" and
|
||||
(
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
or
|
||||
signature = "" and
|
||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
||||
funcHasQualifiedName(result, namespace, name)
|
||||
elementSpec(namespace, type, subtypes, name, signature, _)
|
||||
)
|
||||
or
|
||||
// Member functions
|
||||
exists(Class namedClass, Class classWithMethod |
|
||||
hasClassAndName(classWithMethod, result, name) and
|
||||
classHasQualifiedName(namedClass, namespace, type)
|
||||
|
|
||||
(
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature) and
|
||||
hasClassAndName(classWithMethod, result, name)
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
or
|
||||
signature = "" and
|
||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
||||
hasClassAndName(classWithMethod, result, name)
|
||||
elementSpec(namespace, type, subtypes, name, "", _)
|
||||
) and
|
||||
classHasQualifiedName(namedClass, namespace, type) and
|
||||
(
|
||||
// member declared in the named type or a subtype of it
|
||||
subtypes = true and
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
|
||||
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check the argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the <code>if</code> condition preceeding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
|
||||
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the condition preceding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<sample src = "GuardedFree.cpp" />
|
||||
|
||||
<p>In this example, the condition checking the value of <code>foo</code> can be deleted.</p>
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
The Open Group Base Specifications Issue 7, 2018 Edition:
|
||||
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>
|
||||
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
</qhelp>
|
||||
@@ -8,7 +8,6 @@
|
||||
* @id cpp/guarded-free
|
||||
* @tags maintainability
|
||||
* readability
|
||||
* experimental
|
||||
*/
|
||||
|
||||
import cpp
|
||||
4
cpp/ql/src/change-notes/2014-11-26-guarded-free.md
Normal file
4
cpp/ql/src/change-notes/2014-11-26-guarded-free.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new high-precision quality query, `cpp/guarded-free`, which detects useless NULL pointer checks before calls to `free`. A variation of this query was originally contributed as an [experimental query by @mario-campos](https://github.com/github/codeql/pull/16331).
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Best Practices/GuardedFree.ql
|
||||
@@ -164,4 +164,10 @@ void test_format() {
|
||||
|
||||
auto s2 = std::format(string::source());
|
||||
sink(s2); // $ ir MISSING: ast
|
||||
}
|
||||
|
||||
void test(std::format_string s) {
|
||||
int x = source();
|
||||
int y = std::same_signature_as_format_but_different_name(s, x);
|
||||
sink(y); // clean
|
||||
}
|
||||
@@ -451,6 +451,9 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future
|
||||
| format.cpp:162:24:162:27 | {} | format.cpp:162:24:162:27 | call to basic_format_string | TAINT |
|
||||
| format.cpp:165:13:165:23 | call to format | format.cpp:166:8:166:9 | s2 | |
|
||||
| format.cpp:165:25:165:38 | call to source | format.cpp:165:25:165:40 | call to basic_format_string | TAINT |
|
||||
| format.cpp:169:30:169:30 | s | format.cpp:171:60:171:60 | s | |
|
||||
| format.cpp:170:11:170:16 | call to source | format.cpp:171:63:171:63 | x | |
|
||||
| format.cpp:171:11:171:58 | call to same_signature_as_format_but_different_name | format.cpp:172:8:172:8 | y | |
|
||||
| map.cpp:21:28:21:28 | call to pair | map.cpp:23:2:23:2 | a | |
|
||||
| map.cpp:21:28:21:28 | call to pair | map.cpp:24:7:24:7 | a | |
|
||||
| map.cpp:21:28:21:28 | call to pair | map.cpp:25:7:25:7 | a | |
|
||||
|
||||
@@ -676,4 +676,9 @@ namespace std {
|
||||
using format_string = basic_format_string<char>; // simplified from `char, std::type_identity_t<Args>...`
|
||||
|
||||
template<class... Args> string format( format_string fmt, Args&&... args );
|
||||
|
||||
// This function has the same signature as `format`, but a different name. It should NOT be able to use
|
||||
// the model for `format`.
|
||||
template <typename... Args>
|
||||
int same_signature_as_format_but_different_name(format_string, Args &&...args);
|
||||
}
|
||||
@@ -265,6 +265,8 @@ signatureMatches
|
||||
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 0 |
|
||||
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:678:33:678:38 | format | (format_string,Args &&) | | format<Args> | 1 |
|
||||
| stl.h:683:6:683:48 | same_signature_as_format_but_different_name | (format_string,Args &&) | | format<Args> | 0 |
|
||||
| stl.h:683:6:683:48 | same_signature_as_format_but_different_name | (format_string,Args &&) | | format<Args> | 1 |
|
||||
getSignatureParameterName
|
||||
| (InputIt,InputIt) | deque | assign<InputIt> | 0 | func:0 |
|
||||
| (InputIt,InputIt) | deque | assign<InputIt> | 1 | func:0 |
|
||||
@@ -729,6 +731,8 @@ getParameterTypeName
|
||||
| stl.h:678:33:678:38 | format | 0 | format_string |
|
||||
| stl.h:678:33:678:38 | format | 1 | func:0 && |
|
||||
| stl.h:678:33:678:38 | format | 1 | func:0 && |
|
||||
| stl.h:683:6:683:48 | same_signature_as_format_but_different_name | 0 | format_string |
|
||||
| stl.h:683:6:683:48 | same_signature_as_format_but_different_name | 1 | func:0 && |
|
||||
| stringstream.cpp:18:6:18:9 | sink | 0 | const basic_ostream> & |
|
||||
| stringstream.cpp:21:6:21:9 | sink | 0 | const basic_istream> & |
|
||||
| stringstream.cpp:24:6:24:9 | sink | 0 | const basic_iostream> & |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Best Practices/GuardedFree.ql
|
||||
@@ -32,6 +32,7 @@ Microsoft.Extensions.Logging,,,91,,,,,,,,,,,,,,,,,,,25,66
|
||||
Microsoft.Extensions.Options,,,68,,,,,,,,,,,,,,,,,,,44,24
|
||||
Microsoft.Extensions.Primitives,,,73,,,,,,,,,,,,,,,,,,,67,6
|
||||
Microsoft.Interop,,,159,,,,,,,,,,,,,,,,,,,75,84
|
||||
Microsoft.JSInterop,2,,,,,,,,,,2,,,,,,,,,,,,
|
||||
Microsoft.NET.Build.Tasks,,,5,,,,,,,,,,,,,,,,,,,3,2
|
||||
Microsoft.NET.Sdk.WebAssembly,,,2,,,,,,,,,,,,,,,,,,,1,1
|
||||
Microsoft.NET.WebAssembly.Webcil,,,6,,,,,,,,,,,,,,,,,,,6,
|
||||
|
||||
|
@@ -9,6 +9,6 @@ C# framework & library support
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",47,10818,54,5
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.Sdk.WebAssembly``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",57,2068,148,
|
||||
Totals,,104,12893,396,5
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.Sdk.WebAssembly``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",57,2068,150,2
|
||||
Totals,,104,12893,398,7
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added `js-interop` sinks for the `InvokeAsync` and `InvokeVoidAsync` methods of `Microsoft.JSInterop.IJSRuntime`, which can run arbitrary JavaScript.
|
||||
|
||||
7
csharp/ql/lib/ext/Microsoft.JSInterop.model.yml
Normal file
7
csharp/ql/lib/ext/Microsoft.JSInterop.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["Microsoft.JSInterop", "JSRuntimeExtensions", True, "InvokeAsync<TValue>", "", "", "Argument[1]", "js-injection", "manual"]
|
||||
- ["Microsoft.JSInterop", "JSRuntimeExtensions", True, "InvokeVoidAsync", "", "", "Argument[1]", "js-injection", "manual"]
|
||||
@@ -35,15 +35,61 @@ module ReportStats<StatsSig Stats> {
|
||||
module CallTargetStats implements StatsSig {
|
||||
int getNumberOfOk() { result = count(Call c | exists(c.getTarget())) }
|
||||
|
||||
int getNumberOfNotOk() {
|
||||
result =
|
||||
count(Call c |
|
||||
not exists(c.getTarget()) and
|
||||
not c instanceof DelegateCall and
|
||||
not c instanceof DynamicExpr
|
||||
private predicate isNoSetterPropertyCallInConstructor(PropertyCall c) {
|
||||
exists(Property p, Constructor ctor |
|
||||
p = c.getProperty() and
|
||||
not exists(Setter a | a = p.getAnAccessor()) and
|
||||
c.getEnclosingCallable() = ctor and
|
||||
(
|
||||
c.hasThisQualifier()
|
||||
or
|
||||
ctor instanceof StaticConstructor and p.getDeclaringType() = ctor.getDeclaringType()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isNoSetterPropertyInitialization(PropertyCall c) {
|
||||
exists(Property p, AssignExpr assign |
|
||||
p = c.getProperty() and
|
||||
not exists(Setter a | a = p.getAnAccessor()) and
|
||||
assign = c.getParent() and
|
||||
assign.getLValue() = c and
|
||||
assign.getParent() instanceof Property
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isAnonymousObjectMemberDeclaration(PropertyCall c) {
|
||||
exists(Property p, AssignExpr assign |
|
||||
p = c.getProperty() and
|
||||
assign = c.getParent() and
|
||||
assign.getLValue() = c and
|
||||
assign.getParent() instanceof ObjectInitializer and
|
||||
assign.getParent().getParent() instanceof AnonymousObjectCreation
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isInitializedWithCollectionInitializer(PropertyCall c) {
|
||||
exists(Property p, AssignExpr assign |
|
||||
p = c.getProperty() and
|
||||
assign = c.getParent() and
|
||||
assign.getLValue() = c and
|
||||
assign.getRValue() instanceof CollectionInitializer
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate isNotOkCall(Call c) {
|
||||
not exists(c.getTarget()) and
|
||||
not c instanceof DelegateCall and
|
||||
not c instanceof DynamicExpr and
|
||||
not isNoSetterPropertyCallInConstructor(c) and
|
||||
not isNoSetterPropertyInitialization(c) and
|
||||
not isAnonymousObjectMemberDeclaration(c) and
|
||||
not isInitializedWithCollectionInitializer(c) and
|
||||
not c.getParent+() instanceof NameOfExpr
|
||||
}
|
||||
|
||||
int getNumberOfNotOk() { result = count(Call c | isNotOkCall(c)) }
|
||||
|
||||
string getOkText() { result = "calls with call target" }
|
||||
|
||||
string getNotOkText() { result = "calls with missing call target" }
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* `csharp/diagnostic/database-quality` has been changed to exclude various property access expressions from database quality evaluation. The excluded property access expressions are expected to have no target callables even in manual or autobuilt databases.
|
||||
@@ -256,6 +256,12 @@ sink
|
||||
| Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;ExecuteSqlRawAsync;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Object[]);Argument[1];sql-injection;manual |
|
||||
| Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;ExecuteSqlRawAsync;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Threading.CancellationToken);Argument[1];sql-injection;manual |
|
||||
| Microsoft.EntityFrameworkCore;RelationalQueryableExtensions;FromSqlRaw<TEntity>;(Microsoft.EntityFrameworkCore.DbSet<TEntity>,System.String,System.Object[]);Argument[1];sql-injection;manual |
|
||||
| Microsoft.JSInterop;JSRuntimeExtensions;InvokeAsync<TValue>;(Microsoft.JSInterop.IJSRuntime,System.String,System.Object[]);Argument[1];js-injection;manual |
|
||||
| Microsoft.JSInterop;JSRuntimeExtensions;InvokeAsync<TValue>;(Microsoft.JSInterop.IJSRuntime,System.String,System.Threading.CancellationToken,System.Object[]);Argument[1];js-injection;manual |
|
||||
| Microsoft.JSInterop;JSRuntimeExtensions;InvokeAsync<TValue>;(Microsoft.JSInterop.IJSRuntime,System.String,System.TimeSpan,System.Object[]);Argument[1];js-injection;manual |
|
||||
| Microsoft.JSInterop;JSRuntimeExtensions;InvokeVoidAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.Object[]);Argument[1];js-injection;manual |
|
||||
| Microsoft.JSInterop;JSRuntimeExtensions;InvokeVoidAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.Threading.CancellationToken,System.Object[]);Argument[1];js-injection;manual |
|
||||
| Microsoft.JSInterop;JSRuntimeExtensions;InvokeVoidAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.TimeSpan,System.Object[]);Argument[1];js-injection;manual |
|
||||
| ServiceStack.Messaging;BackgroundMqClient;SendAllOneWay;(System.Collections.Generic.IEnumerable<System.Object>);Argument[1].Element;file-content-store;manual |
|
||||
| ServiceStack.Messaging;BackgroundMqClient;SendOneWay;(System.Object);Argument[0];file-content-store;manual |
|
||||
| ServiceStack.Messaging;BackgroundMqClient;SendOneWay;(System.String,System.Object);Argument[1];file-content-store;manual |
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @id test/missing-call-target
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import Telemetry.DatabaseQuality
|
||||
|
||||
from Call call
|
||||
where CallTargetStats::isNotOkCall(call)
|
||||
select call, "Call without target $@.", call, call.toString()
|
||||
@@ -0,0 +1,7 @@
|
||||
| Quality.cs:8:9:8:19 | access to property MyProperty5 | Call without target $@. | Quality.cs:8:9:8:19 | access to property MyProperty5 | access to property MyProperty5 |
|
||||
| Quality.cs:13:9:13:19 | access to property MyProperty1 | Call without target $@. | Quality.cs:13:9:13:19 | access to property MyProperty1 | access to property MyProperty1 |
|
||||
| Quality.cs:14:24:14:34 | access to property MyProperty3 | Call without target $@. | Quality.cs:14:24:14:34 | access to property MyProperty3 | access to property MyProperty3 |
|
||||
| Quality.cs:15:24:15:34 | access to property MyProperty3 | Call without target $@. | Quality.cs:15:24:15:34 | access to property MyProperty3 | access to property MyProperty3 |
|
||||
| Quality.cs:15:24:15:46 | access to property MyProperty2 | Call without target $@. | Quality.cs:15:24:15:46 | access to property MyProperty2 | access to property MyProperty2 |
|
||||
| Quality.cs:19:13:19:23 | access to property MyProperty4 | Call without target $@. | Quality.cs:19:13:19:23 | access to property MyProperty4 | access to property MyProperty4 |
|
||||
| Quality.cs:24:16:24:26 | access to property MyProperty2 | Call without target $@. | Quality.cs:24:16:24:26 | access to property MyProperty2 | access to property MyProperty2 |
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @id test/missing-call-target
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import Telemetry.DatabaseQuality
|
||||
|
||||
from Call call
|
||||
where not exists(call.getTarget())
|
||||
select call, "Call without target $@.", call, call.toString()
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class Test
|
||||
{
|
||||
static Test()
|
||||
{
|
||||
MyProperty5 = 42;
|
||||
}
|
||||
|
||||
public Test()
|
||||
{
|
||||
MyProperty1 = 42;
|
||||
var x = nameof(MyProperty3);
|
||||
var y = nameof(MyProperty3.MyProperty2);
|
||||
|
||||
new Test()
|
||||
{
|
||||
MyProperty4 = { 1, 2, 3 }
|
||||
};
|
||||
}
|
||||
|
||||
public int MyProperty1 { get; }
|
||||
public int MyProperty2 { get; } = 42;
|
||||
public Test MyProperty3 { get; set; }
|
||||
public List<int> MyProperty4 { get; }
|
||||
static int MyProperty5 { get; }
|
||||
}
|
||||
@@ -12,6 +12,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
codeql-library-for-go
|
||||
abstract-syntax-tree-classes-for-working-with-go-programs
|
||||
modeling-data-flow-in-go-libraries
|
||||
customizing-library-models-for-go
|
||||
|
||||
- :doc:`Basic query for Go code <basic-query-for-go-code>`: Learn to write and run a simple CodeQL query.
|
||||
|
||||
@@ -23,3 +24,5 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
|
||||
- :doc:`Modeling data flow in Go libraries <modeling-data-flow-in-go-libraries>`: When analyzing a Go program, CodeQL does not examine the source code for external packages.
|
||||
To track the flow of untrusted data through a library, you can create a model of the library.
|
||||
|
||||
- :doc:`Customizing library models for Go <customizing-library-models-for-go>`: You can model frameworks and libraries that your codebase depends on using data extensions and publish them as CodeQL model packs.
|
||||
|
||||
@@ -0,0 +1,427 @@
|
||||
.. _customizing-library-models-for-go:
|
||||
|
||||
Customizing library models for Go
|
||||
=================================
|
||||
|
||||
You can model the methods and functions that control data flow in any framework or library. This is especially useful for custom frameworks or niche libraries, that are not supported by the standard CodeQL libraries.
|
||||
|
||||
.. include:: ../reusables/beta-note-customizing-library-models.rst
|
||||
|
||||
About this article
|
||||
------------------
|
||||
|
||||
This article contains reference material about how to define custom models for sources, sinks, and flow summaries for Go dependencies in data extension files.
|
||||
|
||||
About data extensions
|
||||
---------------------
|
||||
|
||||
You can customize analysis by defining models (summaries, sinks, and sources) of your code's Go dependencies in data extension files. Each model defines the behavior of one or more elements of your library or framework, such as functions, methods, and fields. When you run dataflow analysis, these models expand the potential sources and sinks tracked by dataflow analysis and improve the precision of results.
|
||||
|
||||
Most of the security queries search for paths from a source of untrusted input to a sink that represents a vulnerability. This is known as taint tracking. Each source is a starting point for dataflow analysis to track tainted data and each sink is an end point.
|
||||
|
||||
Taint tracking queries also need to know how data can flow through elements that are not included in the source code. These are modeled as summaries. A summary model enables queries to synthesize the flow behavior through elements in dependency code that is not stored in your repository.
|
||||
|
||||
Syntax used to define an element in an extension file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Each model of an element is defined using a data extension where each tuple constitutes a model.
|
||||
A data extension file to extend the standard Go queries included with CodeQL is a YAML file with the form:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: <name of extensible predicate>
|
||||
data:
|
||||
- <tuple1>
|
||||
- <tuple2>
|
||||
- ...
|
||||
|
||||
Each YAML file may contain one or more top-level extensions.
|
||||
|
||||
- ``addsTo`` defines the CodeQL pack name and extensible predicate that the extension is injected into.
|
||||
- ``data`` defines one or more rows of tuples that are injected as values into the extensible predicate. The number of columns and their types must match the definition of the extensible predicate.
|
||||
|
||||
Data extensions use union semantics, which means that the tuples of all extensions for a single extensible predicate are combined, duplicates are removed, and all of the remaining tuples are queryable by referencing the extensible predicate.
|
||||
|
||||
Publish data extension files in a CodeQL model pack to share
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can group one or more data extension files into a CodeQL model pack and publish it to the GitHub Container Registry. This makes it easy for anyone to download the model pack and use it to extend their analysis. For more information, see `Creating a CodeQL model pack <https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack>`__ and `Publishing and using CodeQL packs <https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/publishing-and-using-codeql-packs/>`__ in the CodeQL CLI documentation.
|
||||
|
||||
Extensible predicates used to create custom models in Go
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The CodeQL library for Go analysis exposes the following extensible predicates:
|
||||
|
||||
- ``sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance)``. This is used to model sources of potentially tainted data. The ``kind`` of the sources defined using this predicate determine which threat model they are associated with. Different threat models can be used to customize the sources used in an analysis. For more information, see ":ref:`Threat models <threat-models-go>`."
|
||||
- ``sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)``. This is used to model sinks where tainted data may be used in a way that makes the code vulnerable.
|
||||
- ``summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance)``. This is used to model flow through elements.
|
||||
- ``neutralModel(package, type, name, signature, kind, provenance)``. This is similar to a summary model but used to model the flow of values that have only a minor impact on the dataflow analysis. Manual neutral models (those with a provenance such as ``manual`` or ``ai-manual``) can be used to override generated summary models (those with a provenance such as ``df-generated``), so that the summary model will be ignored. Other than that, neutral models have no effect.
|
||||
|
||||
The extensible predicates are populated using the models defined in data extension files.
|
||||
|
||||
Examples of custom model definitions
|
||||
------------------------------------
|
||||
|
||||
The examples in this section are taken from the standard CodeQL Go query pack published by GitHub. They demonstrate how to add tuples to extend extensible predicates that are used by the standard queries.
|
||||
|
||||
Example: Taint sink in the ``database/sql`` package
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This example shows how the Go query pack models the argument of the ``Prepare`` method as a SQL injection sink.
|
||||
This is the ``Prepare`` method of the ``DB`` type in the ``database/sql`` package which creates a prepared statement.
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func Tainted(db *sql.DB, name string) {
|
||||
stmt, err := db.Prepare("SELECT * FROM users WHERE name = " + name) // The argument to this method is a SQL injection sink.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add a tuple to the ``sinkModel``\(package, type, subtypes, name, signature, ext, input, kind, provenance) extensible predicate by updating a data extension file.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["database/sql", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
|
||||
|
||||
Since we want to add a new sink, we need to add a tuple to the ``sinkModel`` extensible predicate.
|
||||
The first five values identify the function (in this case a method) to be modeled as a sink.
|
||||
|
||||
- The first value ``database/sql`` is the package name.
|
||||
- The second value ``DB`` is the name of the type that the method is associated with.
|
||||
- The third value ``True`` is a flag that indicates whether or not the sink also applies to subtypes. This includes when the subtype embeds the given type, so that the method or field is promoted to be a method or field of the subtype. For interface methods it also includes types which implement the interface type.
|
||||
- The fourth value ``Prepare`` is the method name.
|
||||
- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the sink.
|
||||
|
||||
- The seventh value ``Argument[0]`` is the ``access path`` to the first argument passed to the method, which means that this is the location of the sink.
|
||||
- The eighth value ``sql-injection`` is the kind of the sink. The sink kind is used to define the queries where the sink is in scope. In this case - the SQL injection queries.
|
||||
- The ninth value ``manual`` is the provenance of the sink, which is used to identify the origin of the sink.
|
||||
|
||||
Example: Taint source from the ``net/http`` package
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
This example shows how the Go query pack models the return value from the ``FormValue`` method as a ``remote`` source.
|
||||
This is the ``FormValue`` method of the ``Request`` type which is located in the ``net/http`` package.
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func Tainted(r *http.Request) {
|
||||
name := r.FormValue("name") // The return value of this method is a source of tainted data.
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
We need to add a tuple to the ``sourceModel``\(package, type, subtypes, name, signature, ext, output, kind, provenance) extensible predicate by updating a data extension file.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["net/http", "Request", True, "FormValue", "", "", "ReturnValue", "remote", "manual"]
|
||||
|
||||
|
||||
Since we are adding a new source, we need to add a tuple to the ``sourceModel`` extensible predicate.
|
||||
The first five values identify the function to be modeled as a source.
|
||||
|
||||
- The first value ``net/http`` is the package name.
|
||||
- The second value ``Request`` is the type name, since the function is a method of the ``Request`` type.
|
||||
- The third value ``True`` is a flag that indicates whether or not the sink also applies to subtypes. This includes when the subtype embeds the given type, so that the method or field is promoted to be a method or field of the subtype. For interface methods it also includes types which implement the interface type.
|
||||
- The fourth value ``FormValue`` is the function name.
|
||||
- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the source.
|
||||
|
||||
- The seventh value ``ReturnValue`` is the access path to the return of the method, which means that it is the return value that should be considered a source of tainted input.
|
||||
- The eighth value ``remote`` is the kind of the source. The source kind is used to define the threat model where the source is in scope. ``remote`` applies to many of the security related queries as it means a remote source of untrusted data. As an example the SQL injection query uses ``remote`` sources. For more information, see ":ref:`Threat models <threat-models-go>`."
|
||||
- The ninth value ``manual`` is the provenance of the source, which is used to identify the origin of the source.
|
||||
|
||||
Example: Add flow through the ``Max`` function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This example shows how the Go query pack models flow through a function for a simple case.
|
||||
This pattern covers many of the cases where we need to summarize flow through a function that is stored in a library or framework outside the repository.
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func ValueFlow {
|
||||
a := []int{1, 2, 3}
|
||||
max := slices.Max(a) // There is value flow from the elements of `a` to `max`.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add a tuple to the ``summaryModel``\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["slices", "", False, "Max", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
|
||||
|
||||
Since we are adding flow through a method, we need to add tuples to the ``summaryModel`` extensible predicate.
|
||||
The first row defines flow from the first argument (``a`` in the example) to the return value (``max`` in the example).
|
||||
|
||||
The first five values identify the function to be modeled as a summary.
|
||||
|
||||
- The first value ``slices`` is the package name.
|
||||
- The second value ``""`` is left blank, since the function is not a method of a type.
|
||||
- The third value ``False`` is a flag that indicates whether or not the sink also applies to subtypes. This has no effect for non-method functions.
|
||||
- The fourth value ``Max`` is the function name.
|
||||
- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary.
|
||||
|
||||
- The seventh value is the access path to the input (where data flows from). ``Argument[0].ArrayElement`` is the access path to the array elements of the first argument (the elements of the slice in the example).
|
||||
- The eighth value ``ReturnValue`` is the access path to the output (where data flows to), in this case ``ReturnValue``, which means that the input flows to the return value.
|
||||
- The ninth value ``value`` is the kind of the flow. ``value`` flow indicates an entire value is moved, ``taint`` means that taint is propagated through the call.
|
||||
- The tenth value ``manual`` is the provenance of the summary, which is used to identify the origin of the summary.
|
||||
|
||||
Example: Add flow through the ``Concat`` function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This example shows how the Go query pack models flow through a function for a simple case.
|
||||
This pattern covers many of the cases where we need to summarize flow through a function that is stored in a library or framework outside the repository.
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func ValueFlow {
|
||||
a := []int{1, 2, 3}
|
||||
b := []int{4, 5, 6}
|
||||
c := slices.Concat(a, b) // There is taint flow from `a` and `b` to `c`.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add a tuple to the ``summaryModel``\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["slices", "", False, "Concat", "", "", "Argument[0].ArrayElement.ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
|
||||
Since we are adding flow through a method, we need to add tuples to the ``summaryModel`` extensible predicate.
|
||||
The first row defines flow from the arguments (``a`` and ``b`` in the example) to the return value (``c`` in the example).
|
||||
|
||||
The first five values identify the function to be modeled as a summary.
|
||||
|
||||
- The first value ``slices`` is the package name.
|
||||
- The second value ``""`` is left blank, since the function is not a method of a type.
|
||||
- The third value ``False`` is a flag that indicates whether or not the sink also applies to subtypes. This has no effect for non-method functions.
|
||||
- The fourth value ``Max`` is the function name.
|
||||
- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary.
|
||||
|
||||
- The seventh value is the access path to the input (where data flows from). ``Argument[0].ArrayElement.ArrayElement`` is the access path to the array elements of the array elements of the first argument. Note that a variadic parameter of type `...T` is treated as if it has type `[]T` and arguments corresponding to the variadic parameter are accessed as elements of this slice.
|
||||
- The eighth value ``ReturnValue.ArrayElement`` is the access path to the output (where data flows to), in this case ``ReturnValue.ArrayElement``, which means that the input flows to the array elements of the return value.
|
||||
- The ninth value ``value`` is the kind of the flow. ``value`` flow indicates an entire value is moved, ``taint`` means that taint is propagated through the call.
|
||||
- The tenth value ``manual`` is the provenance of the summary, which is used to identify the origin of the summary.
|
||||
|
||||
Example: Add flow through the ``Join`` function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
This example shows how the Go query pack models flow through a method for a simple case.
|
||||
This pattern covers many of the cases where we need to summarize flow through a function that is stored in a library or framework outside the repository.
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func TaintFlow() {
|
||||
elems := []string{"Hello", "World"}
|
||||
sep := " "
|
||||
t := strings.Join(elems, sep) // There is taint flow from elems and sep to t.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add tuples to the ``summaryModel``\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["strings", "", False, "Join", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["strings", "", False, "Join", "", "", "Argument[1]", "ReturnValue", "taint", "manual"]
|
||||
|
||||
Since we are adding flow through a method, we need to add tuples to the ``summaryModel`` extensible predicate.
|
||||
Each tuple defines flow from one argument to the return value.
|
||||
The first row defines flow from the first argument (``elems`` in the example) to the return value (``t`` in the example) and the second row defines flow from the second argument (``sep`` in the example) to the return value (``t`` in the example).
|
||||
|
||||
The first five values identify the function to be modeled as a summary.
|
||||
These are the same for both of the rows above as we are adding two summaries for the same method.
|
||||
|
||||
- The first value ``strings`` is the package name.
|
||||
- The second value ``""`` is left blank, since the function is not a method of a type.
|
||||
- The third value ``False`` is a flag that indicates whether or not the sink also applies to subtypes. This has no effect for non-method functions.
|
||||
- The fourth value ``Join`` is the function name.
|
||||
- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary.
|
||||
|
||||
- The seventh value is the access path to the input (where data flows from). ``Argument[0]`` is the access path to the first argument (``elems`` in the example) and ``Argument[1]`` is the access path to the second argument (``sep`` in the example).
|
||||
- The eighth value ``ReturnValue`` is the access path to the output (where data flows to), in this case ``ReturnValue``, which means that the input flows to the return value.
|
||||
- The ninth value ``taint`` is the kind of the flow. ``taint`` means that taint is propagated through the call.
|
||||
- The tenth value ``manual`` is the provenance of the summary, which is used to identify the origin of the summary.
|
||||
|
||||
It would also be possible to merge the two rows into one by using ".." to indicate a range in the seventh value. This would be useful if the method has many arguments and the flow is the same for all of them.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["strings", "", False, "Join", "", "", "Argument[0..1]", "ReturnValue", "taint", "manual"]
|
||||
|
||||
This row defines flow from both the first and the second argument to the return value. The seventh value ``Argument[0..1]`` is shorthand for specifying an access path to both ``Argument[0]`` and ``Argument[1]``.
|
||||
|
||||
Example: Add flow through the ``Hostname`` method
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
This example shows how the Go query pack models flow through a method for a simple case.
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func TaintFlow(u *url.URL) {
|
||||
host := u.Hostname() // There is taint flow from u to host.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add a tuple to the ``summaryModel``\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["net/url", "URL", True, "Hostname", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
|
||||
|
||||
Since we are adding flow through a method, we need to add tuples to the ``summaryModel`` extensible predicate.
|
||||
Each tuple defines flow from one argument to the return value.
|
||||
The first row defines flow from the qualifier of the method call (``u`` in the example) to the return value (``host`` in the example).
|
||||
|
||||
The first five values identify the function (in this case a method) to be modeled as a summary.
|
||||
|
||||
- The first value ``net/url`` is the package name.
|
||||
- The second value ``URL`` is the receiver type.
|
||||
- The third value ``True`` is a flag that indicates whether or not the sink also applies to subtypes. This includes when the subtype embeds the given type, so that the method or field is promoted to be a method or field of the subtype. For interface methods it also includes types which implement the interface type.
|
||||
- The fourth value ``Hostname`` is the method name.
|
||||
- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary.
|
||||
|
||||
- The seventh value is the access path to the input (where data flows from). ``Argument[receiver]`` is the access path to the receiver (``u`` in the example).
|
||||
- The eighth value ``ReturnValue`` is the access path to the output (where data flows to), in this case ``ReturnValue``, which means that the input flows to the return value. When there are multiple return values, use ``ReturnValue[i]`` to refer to the ``i`` th return value (starting from 0).
|
||||
- The ninth value ``taint`` is the kind of the flow. ``taint`` means that taint is propagated through the call.
|
||||
- The tenth value ``manual`` is the provenance of the summary, which is used to identify the origin of the summary.
|
||||
|
||||
Example: Accessing the ``Body`` field of an HTTP request
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
This example shows how we can model a field read as a source of tainted data.
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func TaintFlow(w http.ResponseWriter, r *http.Request) {
|
||||
body := r.Body // The Body field of an HTTP request is a source of tainted data.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add a tuple to the ``sourceModel``\(package, type, subtypes, name, signature, ext, output, kind, provenance) extensible predicate by updating a data extension file.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["net/http", "Request", True, "Body", "", "", "", "remote", "manual"]
|
||||
|
||||
Since we are adding a new source, we need to add a tuple to the ``sourceModel`` extensible predicate.
|
||||
The first five values identify the field to be modeled as a source.
|
||||
|
||||
- The first value ``net/http`` is the package name.
|
||||
- The second value ``Request`` is the name of the type that the field is associated with.
|
||||
- The third value ``True`` is a flag that indicates whether or not the sink also applies to subtypes. For fields this means when the field is accessed as a promoted field in another type.
|
||||
- The fourth value ``Body`` is the field name.
|
||||
- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the source.
|
||||
|
||||
- The seventh value ``""`` is left blank. Leaving the access path of a source model blank indicates that it is a field access.
|
||||
- The eighth value ``remote`` is the source kind. This indicates that the source is a remote source of untrusted data.
|
||||
- The ninth value ``manual`` is the provenance of the source, which is used to identify the origin of the source.
|
||||
|
||||
Package versions
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
When the major version number is greater than 1 it is included in the package import path. It usually looks like ``/v2`` after the module import path. This is called the major version suffix. We normally want our models to apply to all versions of a package. Rather than having to repeat models with the package column changed to include all available versions, we can just use the package name without the major version suffix and this will be matched to any version. So models with ``github.com/couchbase/gocb`` in the package column will match packages imported from ``github.com/couchbase/gocb`` and ``github.com/couchbase/gocb/v2`` (or any other version).
|
||||
|
||||
Note that packages hosted at ``gopkg.in`` use a slightly different syntax: the major version suffix looks like ``.v2``, and it is present even for version 1. This is also supported. So models with ``gopkg.in/yaml`` in the package column will match packages imported from ``gopkg.in/yaml.v1``, ``gopkg.in/yaml.v2`` and ``gopkg.in/yaml.v3``.
|
||||
|
||||
To write models that only apply to ``github.com/couchbase/gocb/v2``, it is sufficient to include the major version suffix (``/v2``) in the package column. To write models that only apply to ``github.com/couchbase/gocb``, you may prefix the package column with ``fixed-version:``. For example, here are two models for a method that has changed name from v1 to v2.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["fixed-version:github.com/couchbase/gocb", "Cluster", True, "ExecuteAnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"]
|
||||
- ["github.com/couchbase/gocb/v2", "Cluster", True, "AnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"]
|
||||
|
||||
Package grouping
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Since Go uses URLs for package identifiers, it is possible for packages to be imported with different paths. For example, the ``glog`` package can be imported using both the ``github.com/golang/glog`` and ``gopkg.in/glog`` paths.
|
||||
|
||||
To handle this, the CodeQL Go library uses a mapping from the package path to a group name for the package. This mapping can be specified using the ``packageGrouping`` extensible predicate, and then the models for the APIs in the package
|
||||
will use the the prefix ``group:`` followed by the group name in place of the package path.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go
|
||||
extensible: packageGrouping
|
||||
data:
|
||||
- ["glog", "github.com/golang/glog"]
|
||||
- ["glog", "gopkg.in/glog"]
|
||||
- addsTo:
|
||||
pack: codeql/go
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["group:glog", "", False, "Info", "", "", "Argument[0]", "log-injection", "manual"]
|
||||
|
||||
.. _threat-models-go:
|
||||
|
||||
Threat models
|
||||
-------------
|
||||
|
||||
.. include:: ../reusables/threat-model-description.rst
|
||||
@@ -130,6 +130,7 @@ os,29,11,6,3,,,,,26,,,,,,,,,,,7,3,,1,6,
|
||||
path,,,18,,,,,,,,,,,,,,,,,,,,,18,
|
||||
reflect,,,37,,,,,,,,,,,,,,,,,,,,,37,
|
||||
regexp,10,,20,,,,,,,3,3,4,,,,,,,,,,,,20,
|
||||
slices,,,17,,,,,,,,,,,,,,,,,,,,,,17
|
||||
sort,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
strconv,,,9,,,,,,,,,,,,,,,,,,,,,9,
|
||||
strings,,,34,,,,,,,,,,,,,,,,,,,,,34,
|
||||
|
||||
|
@@ -26,7 +26,7 @@ Go framework & library support
|
||||
`Macaron <https://gopkg.in/macaron.v1>`_,``gopkg.in/macaron*``,12,1,1
|
||||
`Revel <http://revel.github.io/>`_,"``github.com/revel/revel*``, ``github.com/robfig/revel*``",46,20,4
|
||||
`SendGrid <https://github.com/sendgrid/sendgrid-go>`_,``github.com/sendgrid/sendgrid-go*``,,1,
|
||||
`Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",33,587,104
|
||||
`Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",33,604,104
|
||||
`XPath <https://github.com/antchfx/xpath>`_,``github.com/antchfx/xpath*``,,,4
|
||||
`appleboy/gin-jwt <https://github.com/appleboy/gin-jwt>`_,``github.com/appleboy/gin-jwt*``,,,1
|
||||
`beego <https://beego.me/>`_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",63,63,213
|
||||
@@ -61,5 +61,5 @@ Go framework & library support
|
||||
`yaml <https://gopkg.in/yaml.v3>`_,``gopkg.in/yaml*``,,9,
|
||||
`zap <https://go.uber.org/zap>`_,``go.uber.org/zap*``,,11,33
|
||||
Others,"``github.com/Masterminds/squirrel``, ``github.com/caarlos0/env``, ``github.com/go-gorm/gorm``, ``github.com/go-xorm/xorm``, ``github.com/gobuffalo/envy``, ``github.com/gogf/gf/database/gdb``, ``github.com/hashicorp/go-envparse``, ``github.com/jinzhu/gorm``, ``github.com/jmoiron/sqlx``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``, ``github.com/lann/squirrel``, ``github.com/raindog308/gorqlite``, ``github.com/rqlite/gorqlite``, ``github.com/uptrace/bun``, ``go.mongodb.org/mongo-driver/mongo``, ``gopkg.in/Masterminds/squirrel``, ``gorm.io/gorm``, ``xorm.io/xorm``",23,2,391
|
||||
Totals,,307,911,1532
|
||||
Totals,,307,928,1532
|
||||
|
||||
|
||||
31
go/ql/lib/ext/slices.model.yml
Normal file
31
go/ql/lib/ext/slices.model.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
# All should be modeled when we have a way to model iterators
|
||||
# AppendSec should be modeled when we have a way to model iterators
|
||||
# Backward should be modeled when we have a way to model iterators
|
||||
# Chunk should be modeled when we have a way to model iterators
|
||||
- ["slices", "", False, "Clip", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Clone", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
# Collect should be modeled when we have a way to model iterators
|
||||
- ["slices", "", False, "Compact", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "CompactFunc", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Concat", "", "", "Argument[0].ArrayElement.ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Delete", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "DeleteFunc", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Grow", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Insert", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Insert", "", "", "Argument[2].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Max", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
|
||||
- ["slices", "", False, "MaxFunc", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
|
||||
- ["slices", "", False, "Min", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
|
||||
- ["slices", "", False, "MinFunc", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
|
||||
- ["slices", "", False, "Repeat", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Replace", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["slices", "", False, "Replace", "", "", "Argument[3].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
# Sorted should be modeled when we have a way to model iterators
|
||||
# SortedFunc should be modeled when we have a way to model iterators
|
||||
# SortedStableFunc should be modeled when we have a way to model iterators
|
||||
# Values should be modeled when we have a way to model iterators
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added value flow models for functions in the `slices` package which do not involve the `iter` package.
|
||||
@@ -0,0 +1,193 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TaintStepTest_SlicesClip(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Clip(fromStringSlice)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesClone(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Clone(fromStringSlice)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesCompact(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Compact(fromStringSlice)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesCompactFunc(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.CompactFunc(fromStringSlice, strings.EqualFold)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesConcat0(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Concat(fromStringSlice, []string{"a", "b", "c"})
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesConcat1(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Concat([]string{"a", "b", "c"}, fromStringSlice)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesDelete(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Delete(fromStringSlice, 0, 1)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesDeleteFunc(fromStringSlice []string) []string {
|
||||
deleteEmptyString := func(str string) bool {
|
||||
return str == ""
|
||||
}
|
||||
toStringSlice := slices.DeleteFunc(fromStringSlice, deleteEmptyString)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesGrow(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Grow(fromStringSlice, 1)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesInsert0(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Insert(fromStringSlice, 1, "a", "b")
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesInsert2(fromString string) []string {
|
||||
toStringSlice := slices.Insert([]string{}, 0, fromString, "b")
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesMax(fromStringSlice []string) string {
|
||||
toString := slices.Max(fromStringSlice)
|
||||
return toString
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesMaxFunc(fromStringSlice []string) string {
|
||||
toString := slices.MaxFunc(fromStringSlice, cmp.Compare)
|
||||
return toString
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesMin(fromStringSlice []string) string {
|
||||
toString := slices.Min(fromStringSlice)
|
||||
return toString
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesMinFunc(fromStringSlice []string) string {
|
||||
toString := slices.MinFunc(fromStringSlice, cmp.Compare)
|
||||
return toString
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesRepeat(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Repeat(fromStringSlice, 2)
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesReplace0(fromStringSlice []string) []string {
|
||||
toStringSlice := slices.Replace(fromStringSlice, 1, 2, "a")
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func TaintStepTest_SlicesReplace3(fromString string) []string {
|
||||
toStringSlice := slices.Replace([]string{}, 1, 3, fromString, "b")
|
||||
return toStringSlice
|
||||
}
|
||||
|
||||
func RunAllTaints_Slices() {
|
||||
{
|
||||
source := []string{newSource(0).(string)}
|
||||
out := TaintStepTest_SlicesClip(source)
|
||||
sink(0, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(1).(string)}
|
||||
out := TaintStepTest_SlicesClone(source)
|
||||
sink(1, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(2).(string)}
|
||||
out := TaintStepTest_SlicesCompact(source)
|
||||
sink(2, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(3).(string)}
|
||||
out := TaintStepTest_SlicesCompactFunc(source)
|
||||
sink(3, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(4).(string)}
|
||||
out := TaintStepTest_SlicesConcat0(source)
|
||||
sink(4, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(5).(string)}
|
||||
out := TaintStepTest_SlicesConcat1(source)
|
||||
sink(5, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(6).(string)}
|
||||
out := TaintStepTest_SlicesDelete(source)
|
||||
sink(6, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(7).(string)}
|
||||
out := TaintStepTest_SlicesDeleteFunc(source)
|
||||
sink(7, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(8).(string)}
|
||||
out := TaintStepTest_SlicesGrow(source)
|
||||
sink(8, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(9).(string)}
|
||||
out := TaintStepTest_SlicesInsert0(source)
|
||||
sink(9, out[0])
|
||||
}
|
||||
{
|
||||
source := newSource(10).(string)
|
||||
out := TaintStepTest_SlicesInsert2(source)
|
||||
sink(10, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(11).(string)}
|
||||
out := TaintStepTest_SlicesMax(source)
|
||||
sink(11, out)
|
||||
}
|
||||
{
|
||||
source := []string{newSource(12).(string)}
|
||||
out := TaintStepTest_SlicesMaxFunc(source)
|
||||
sink(12, out)
|
||||
}
|
||||
{
|
||||
source := []string{newSource(13).(string)}
|
||||
out := TaintStepTest_SlicesMin(source)
|
||||
sink(13, out)
|
||||
}
|
||||
{
|
||||
source := []string{newSource(14).(string)}
|
||||
out := TaintStepTest_SlicesMinFunc(source)
|
||||
sink(14, out)
|
||||
}
|
||||
{
|
||||
source := []string{newSource(15).(string)}
|
||||
out := TaintStepTest_SlicesRepeat(source)
|
||||
sink(15, out[0])
|
||||
}
|
||||
{
|
||||
source := []string{newSource(16).(string)}
|
||||
out := TaintStepTest_SlicesReplace0(source)
|
||||
sink(16, out[0])
|
||||
}
|
||||
{
|
||||
source := newSource(17).(string)
|
||||
out := TaintStepTest_SlicesReplace3(source)
|
||||
sink(17, out[0])
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
module example.com/m
|
||||
|
||||
go 1.20
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# golang.org/x/net v0.0.0-20201010224723-4f7140c49acb
|
||||
## explicit
|
||||
golang.org/x/net
|
||||
## explicit; go 1.11
|
||||
golang.org/x/net/context
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Calling `coll.contains(x)` is now a taint sanitizer (for any query) for the value `x`, where `coll` is a collection of constants.
|
||||
@@ -28,6 +28,7 @@ private module Frameworks {
|
||||
private import semmle.code.java.frameworks.ThreadLocal
|
||||
private import semmle.code.java.frameworks.ratpack.RatpackExec
|
||||
private import semmle.code.java.frameworks.stapler.Stapler
|
||||
private import semmle.code.java.security.ListOfConstantsSanitizer
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,3 +190,8 @@ private class NumberTaintPreservingCallable extends TaintPreservingCallable {
|
||||
* map-key and map-value content, so that e.g. a tainted `Map` is assumed to have tainted keys and values.
|
||||
*/
|
||||
abstract class TaintInheritingContent extends DataFlow::Content { }
|
||||
|
||||
/**
|
||||
* A sanitizer in all global taint flow configurations but not in local taint.
|
||||
*/
|
||||
abstract class DefaultTaintSanitizer extends DataFlow::Node { }
|
||||
|
||||
@@ -13,24 +13,27 @@ private import semmle.code.java.dispatch.VirtualDispatch
|
||||
private import semmle.code.java.dataflow.internal.BaseSSA
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import codeql.typeflow.TypeFlow
|
||||
private import codeql.typeflow.UniversalFlow as UniversalFlow
|
||||
|
||||
private module Input implements TypeFlowInput<Location> {
|
||||
private newtype TTypeFlowNode =
|
||||
/** Gets `t` if it is a `RefType` or the boxed type if `t` is a primitive type. */
|
||||
private RefType boxIfNeeded(J::Type t) {
|
||||
t.(PrimitiveType).getBoxedType() = result or
|
||||
result = t
|
||||
}
|
||||
|
||||
/** Provides the input types and predicates for instantiation of `UniversalFlow`. */
|
||||
module FlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
|
||||
private newtype TFlowNode =
|
||||
TField(Field f) { not f.getType() instanceof PrimitiveType } or
|
||||
TSsa(BaseSsaVariable ssa) { not ssa.getSourceVariable().getType() instanceof PrimitiveType } or
|
||||
TExpr(Expr e) or
|
||||
TMethod(Method m) { not m.getReturnType() instanceof PrimitiveType }
|
||||
|
||||
/** Gets `t` if it is a `RefType` or the boxed type if `t` is a primitive type. */
|
||||
private RefType boxIfNeeded(J::Type t) {
|
||||
t.(PrimitiveType).getBoxedType() = result or
|
||||
result = t
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Field`, `BaseSsaVariable`, `Expr`, or `Method`.
|
||||
*/
|
||||
class TypeFlowNode extends TTypeFlowNode {
|
||||
class FlowNode extends TFlowNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
result = this.asField().toString() or
|
||||
result = this.asSsa().toString() or
|
||||
@@ -38,6 +41,7 @@ private module Input implements TypeFlowInput<Location> {
|
||||
result = this.asMethod().toString()
|
||||
}
|
||||
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() {
|
||||
result = this.asField().getLocation() or
|
||||
result = this.asSsa().getLocation() or
|
||||
@@ -45,14 +49,19 @@ private module Input implements TypeFlowInput<Location> {
|
||||
result = this.asMethod().getLocation()
|
||||
}
|
||||
|
||||
/** Gets the field corresponding to this node, if any. */
|
||||
Field asField() { this = TField(result) }
|
||||
|
||||
/** Gets the SSA variable corresponding to this node, if any. */
|
||||
BaseSsaVariable asSsa() { this = TSsa(result) }
|
||||
|
||||
/** Gets the expression corresponding to this node, if any. */
|
||||
Expr asExpr() { this = TExpr(result) }
|
||||
|
||||
/** Gets the method corresponding to this node, if any. */
|
||||
Method asMethod() { this = TMethod(result) }
|
||||
|
||||
/** Gets the type of this node. */
|
||||
RefType getType() {
|
||||
result = this.asField().getType() or
|
||||
result = this.asSsa().getSourceVariable().getType() or
|
||||
@@ -61,8 +70,6 @@ private module Input implements TypeFlowInput<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
class Type = RefType;
|
||||
|
||||
private SrcCallable viableCallable_v1(Call c) {
|
||||
result = viableImpl_v1(c)
|
||||
or
|
||||
@@ -88,7 +95,7 @@ private module Input implements TypeFlowInput<Location> {
|
||||
*
|
||||
* For a given `n2`, this predicate must include all possible `n1` that can flow to `n2`.
|
||||
*/
|
||||
predicate step(TypeFlowNode n1, TypeFlowNode n2) {
|
||||
predicate step(FlowNode n1, FlowNode n2) {
|
||||
n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr()
|
||||
or
|
||||
exists(Field f, Expr e |
|
||||
@@ -134,7 +141,7 @@ private module Input implements TypeFlowInput<Location> {
|
||||
/**
|
||||
* Holds if `null` is the only value that flows to `n`.
|
||||
*/
|
||||
predicate isNullValue(TypeFlowNode n) {
|
||||
predicate isNullValue(FlowNode n) {
|
||||
n.asExpr() instanceof NullLiteral
|
||||
or
|
||||
exists(LocalVariableDeclExpr decl |
|
||||
@@ -144,11 +151,21 @@ private module Input implements TypeFlowInput<Location> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isExcludedFromNullAnalysis(TypeFlowNode n) {
|
||||
predicate isExcludedFromNullAnalysis(FlowNode n) {
|
||||
// Fields that are never assigned a non-null value are probably set by
|
||||
// reflection and are thus not always null.
|
||||
exists(n.asField())
|
||||
}
|
||||
}
|
||||
|
||||
private module Input implements TypeFlowInput<Location> {
|
||||
import FlowStepsInput
|
||||
|
||||
class TypeFlowNode = FlowNode;
|
||||
|
||||
predicate isExcludedFromNullAnalysis = FlowStepsInput::isExcludedFromNullAnalysis/1;
|
||||
|
||||
class Type = RefType;
|
||||
|
||||
predicate exactTypeBase(TypeFlowNode n, RefType t) {
|
||||
exists(ClassInstanceExpr e |
|
||||
|
||||
@@ -38,6 +38,7 @@ class BaseSsaSourceVariable extends TBaseSsaSourceVariable {
|
||||
/** Gets the `Callable` in which this `BaseSsaSourceVariable` is defined. */
|
||||
Callable getEnclosingCallable() { this = TLocalVar(result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
exists(LocalScopeVariable v, Callable c | this = TLocalVar(c, v) |
|
||||
if c = v.getCallable()
|
||||
@@ -46,6 +47,7 @@ class BaseSsaSourceVariable extends TBaseSsaSourceVariable {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() {
|
||||
exists(LocalScopeVariable v | this = TLocalVar(_, v) and result = v.getLocation())
|
||||
}
|
||||
@@ -482,8 +484,10 @@ class BaseSsaVariable extends TBaseSsaVariable {
|
||||
this = TSsaEntryDef(_, result)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() { result = this.getCfgNode().getLocation() }
|
||||
|
||||
/** Gets the `BasicBlock` in which this SSA variable is defined. */
|
||||
|
||||
@@ -161,6 +161,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) {
|
||||
node instanceof DefaultTaintSanitizer or
|
||||
// Ignore paths through test code.
|
||||
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass or
|
||||
node.asExpr() instanceof ValidatedVariableAccess
|
||||
|
||||
@@ -246,7 +246,7 @@ string getInsecureAlgorithmRegex() {
|
||||
string getASecureAlgorithmName() {
|
||||
result =
|
||||
[
|
||||
"RSA", "SHA-?256", "SHA-?512", "CCM", "GCM", "AES(?)",
|
||||
"RSA", "SHA-?(256|384|512)", "CCM", "GCM", "AES(?)",
|
||||
"Blowfish", "ECIES", "SHA3-(256|384|512)"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* Provides a default taint sanitizer identifying comparisons against lists of
|
||||
* compile-time constants.
|
||||
*/
|
||||
|
||||
import java
|
||||
private import codeql.typeflow.UniversalFlow as UniversalFlow
|
||||
private import semmle.code.java.Collections
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.internal.BaseSSA
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.TypeFlow
|
||||
private import semmle.code.java.dispatch.VirtualDispatch
|
||||
|
||||
private class FlowNode = FlowStepsInput::FlowNode;
|
||||
|
||||
/**
|
||||
* Holds if `n2` is an unmodifiable collection constructed from input `n1`,
|
||||
* which is either another collection or a number of elements.
|
||||
*/
|
||||
private predicate unmodifiableCollectionStep(FlowNode n1, FlowNode n2) {
|
||||
exists(Call c, Callable tgt |
|
||||
n2.asExpr() = c and
|
||||
n1.asExpr() = c.getAnArgument() and
|
||||
c.getCallee().getSourceDeclaration() = tgt
|
||||
|
|
||||
tgt.hasQualifiedName("java.util", "Collections",
|
||||
["unmodifiableCollection", "unmodifiableList", "unmodifiableSet"])
|
||||
or
|
||||
tgt.hasQualifiedName("java.util", ["List", "Set"], ["copyOf", "of"])
|
||||
or
|
||||
tgt.hasQualifiedName("com.google.common.collect", ["ImmutableList", "ImmutableSet"],
|
||||
["copyOf", "of"])
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a collection or array constructed from input `n1`, which is
|
||||
* either a collection, an array, or a number of elements.
|
||||
*/
|
||||
private predicate collectionStep(FlowNode n1, FlowNode n2) {
|
||||
n2.asExpr().(ArrayInit).getAnInit() = n1.asExpr()
|
||||
or
|
||||
n2.asExpr().(ArrayCreationExpr).getInit() = n1.asExpr()
|
||||
or
|
||||
unmodifiableCollectionStep(n1, n2)
|
||||
or
|
||||
exists(Call c, Callable tgt |
|
||||
n2.asExpr() = c and
|
||||
n1.asExpr() = c.getAnArgument() and
|
||||
c.getCallee().getSourceDeclaration() = tgt
|
||||
|
|
||||
tgt.hasQualifiedName("java.util", "Arrays", "asList")
|
||||
or
|
||||
tgt.isStatic() and
|
||||
tgt.hasName(["copyOf", "of"]) and
|
||||
tgt.getDeclaringType().getASourceSupertype+().hasQualifiedName("java.util", "Collection")
|
||||
or
|
||||
tgt instanceof Constructor and
|
||||
tgt.getNumberOfParameters() = 1 and
|
||||
tgt.getParameterType(0) instanceof CollectionType and
|
||||
tgt.getDeclaringType() instanceof CollectionType
|
||||
)
|
||||
}
|
||||
|
||||
private module BaseUniversalFlow = UniversalFlow::Make<Location, FlowStepsInput>;
|
||||
|
||||
private module UnmodifiableProp implements BaseUniversalFlow::NullaryPropertySig {
|
||||
predicate hasPropertyBase(FlowNode n) { unmodifiableCollectionStep(_, n) }
|
||||
}
|
||||
|
||||
/** Holds if the given node is an unmodifiable collection. */
|
||||
private predicate unmodifiableCollection =
|
||||
BaseUniversalFlow::FlowNullary<UnmodifiableProp>::hasProperty/1;
|
||||
|
||||
/**
|
||||
* Holds if `v` is a collection or array with an access, `coll`, at which the
|
||||
* element `e` gets added.
|
||||
*/
|
||||
private predicate collectionAddition(Variable v, VarAccess coll, Expr e) {
|
||||
exists(MethodCall mc, Method m, int arg |
|
||||
mc.getMethod().getSourceDeclaration().overridesOrInstantiates*(m) and
|
||||
mc.getQualifier() = coll and
|
||||
v.getAnAccess() = coll and
|
||||
mc.getArgument(arg) = e
|
||||
|
|
||||
m.hasQualifiedName("java.util", "Collection", ["add", "addAll"]) and
|
||||
m.getNumberOfParameters() = 1 and
|
||||
arg = 0
|
||||
or
|
||||
m.hasQualifiedName("java.util", "List", ["add", "addAll"]) and
|
||||
m.getNumberOfParameters() = 2 and
|
||||
arg = 1
|
||||
or
|
||||
m.hasQualifiedName("java.util", "SequencedCollection", ["addFirst", "addLast"]) and
|
||||
m.getNumberOfParameters() = 1 and
|
||||
arg = 0
|
||||
)
|
||||
or
|
||||
v.getAnAccess() = coll and
|
||||
exists(Assignment assign | assign.getSource() = e |
|
||||
coll = assign.getDest().(ArrayAccess).getArray()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` represents a definition of `v` and `v` is a collection or
|
||||
* array that has additions occurring as side-effects after its definition.
|
||||
*/
|
||||
private predicate nodeWithAddition(FlowNode n, Variable v) {
|
||||
collectionAddition(v, _, _) and
|
||||
(
|
||||
n.asField() = v
|
||||
or
|
||||
n.asSsa().getSourceVariable().getVariable() = v and
|
||||
(n.asSsa() instanceof BaseSsaUpdate or n.asSsa().(BaseSsaImplicitInit).isParameterDefinition(_))
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `c` does not add elements to the given collection. */
|
||||
private predicate safeCallable(Callable c) {
|
||||
c instanceof CollectionQueryMethod
|
||||
or
|
||||
c instanceof CollectionMethod and
|
||||
c.hasName(["clear", "remove", "removeAll", "stream", "iterator", "toArray"])
|
||||
or
|
||||
c.hasQualifiedName("org.apache.commons.lang3", "StringUtils", "join")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` might be mutated in ways that adds elements that are not
|
||||
* tracked by the `collectionAddition` predicate.
|
||||
*/
|
||||
private predicate collectionWithPossibleMutation(FlowNode n) {
|
||||
not unmodifiableCollection(n) and
|
||||
(
|
||||
exists(Expr e |
|
||||
n.asExpr() = e and
|
||||
(e.getType() instanceof CollectionType or e.getType() instanceof Array) and
|
||||
not collectionAddition(_, e, _) and
|
||||
not collectionStep(n, _)
|
||||
|
|
||||
exists(ArrayAccess aa | e = aa.getArray())
|
||||
or
|
||||
exists(Call c, Callable tgt | c.getAnArgument() = e or c.getQualifier() = e |
|
||||
tgt = c.getCallee().getSourceDeclaration() and
|
||||
not safeCallable(tgt)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(FlowNode mid |
|
||||
FlowStepsInput::step(n, mid) and
|
||||
collectionWithPossibleMutation(mid)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection constructor that constructs an empty mutable collection.
|
||||
*/
|
||||
private class EmptyCollectionConstructor extends Constructor {
|
||||
EmptyCollectionConstructor() {
|
||||
this.getDeclaringType() instanceof CollectionType and
|
||||
forall(Type t | t = this.getAParamType() | t instanceof PrimitiveType)
|
||||
}
|
||||
}
|
||||
|
||||
private module CollectionFlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
|
||||
import FlowStepsInput
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a collection/array/constant whose value(s) are
|
||||
* determined completely from the range of `n1` nodes.
|
||||
*/
|
||||
predicate step(FlowNode n1, FlowNode n2) {
|
||||
// Exclude the regular input constraints for those nodes that are covered
|
||||
// completely by `collectionStep`.
|
||||
FlowStepsInput::step(n1, n2) and
|
||||
not collectionStep(_, n2)
|
||||
or
|
||||
// For collections with side-effects in the form of additions, we add the
|
||||
// sources of those additions as additional input that need to originate
|
||||
// from constants.
|
||||
exists(Variable v |
|
||||
nodeWithAddition(n2, v) and
|
||||
collectionAddition(v, _, n1.asExpr())
|
||||
)
|
||||
or
|
||||
// Include various forms of collection transformation.
|
||||
collectionStep(n1, n2)
|
||||
}
|
||||
|
||||
predicate isExcludedFromNullAnalysis = FlowStepsInput::isExcludedFromNullAnalysis/1;
|
||||
}
|
||||
|
||||
private module CollectionUniversalFlow = UniversalFlow::Make<Location, CollectionFlowStepsInput>;
|
||||
|
||||
private module ConstantCollectionProp implements CollectionUniversalFlow::NullaryPropertySig {
|
||||
/**
|
||||
* Holds if `n` forms the base case for finding collections of constants.
|
||||
* These are individual constants and empty collections.
|
||||
*/
|
||||
predicate hasPropertyBase(FlowNode n) {
|
||||
n.asExpr().isCompileTimeConstant() or
|
||||
n.asExpr().(ConstructorCall).getConstructor() instanceof EmptyCollectionConstructor
|
||||
}
|
||||
|
||||
predicate barrier = collectionWithPossibleMutation/1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given node is either a constant or a collection/array of
|
||||
* constants.
|
||||
*/
|
||||
private predicate constantCollection =
|
||||
CollectionUniversalFlow::FlowNullary<ConstantCollectionProp>::hasProperty/1;
|
||||
|
||||
/** Gets the result of a case normalization call of `arg`. */
|
||||
private MethodCall normalizeCaseCall(Expr arg) {
|
||||
exists(Method changecase | result.getMethod() = changecase |
|
||||
changecase.hasName(["toUpperCase", "toLowerCase"]) and
|
||||
changecase.getDeclaringType() instanceof TypeString and
|
||||
arg = result.getQualifier()
|
||||
or
|
||||
changecase
|
||||
.hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "StringUtils",
|
||||
["lowerCase", "upperCase"]) and
|
||||
arg = result.getArgument(0)
|
||||
or
|
||||
changecase
|
||||
.hasQualifiedName("org.apache.hadoop.util", "StringUtils", ["toLowerCase", "toUpperCase"]) and
|
||||
arg = result.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the guard `g` ensures that the expression `e` is one of a set of
|
||||
* known constants upon evaluating to `branch`.
|
||||
*/
|
||||
private predicate constantCollectionContainsCheck(Guard g, Expr e, boolean branch) {
|
||||
exists(MethodCall mc, Method m, FlowNode n, Expr checked |
|
||||
g = mc and
|
||||
mc.getMethod().getSourceDeclaration().overridesOrInstantiates*(m) and
|
||||
m.hasQualifiedName("java.util", "Collection", "contains") and
|
||||
n.asExpr() = mc.getQualifier() and
|
||||
constantCollection(n) and
|
||||
checked = mc.getAnArgument() and
|
||||
branch = true
|
||||
|
|
||||
checked = e or
|
||||
checked = normalizeCaseCall(e)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison against a list of compile-time constants, sanitizing taint by
|
||||
* restricting to a set of known values.
|
||||
*/
|
||||
private class ListOfConstantsComparisonSanitizerGuard extends TaintTracking::DefaultTaintSanitizer {
|
||||
ListOfConstantsComparisonSanitizerGuard() {
|
||||
this = DataFlow::BarrierGuard<constantCollectionContainsCheck/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
4
java/ql/src/change-notes/2024-11-24-sha2.md
Normal file
4
java/ql/src/change-notes/2024-11-24-sha2.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added SHA-384 to the list of secure hashing algorithms. As a result the `java/potentially-weak-cryptographic-algorithm` query should no longer flag up uses of SHA-384.
|
||||
158
java/ql/test/library-tests/dataflow/range-analysis-inline/B.java
Normal file
158
java/ql/test/library-tests/dataflow/range-analysis-inline/B.java
Normal file
@@ -0,0 +1,158 @@
|
||||
public class B {
|
||||
|
||||
// Use this method to mark non-integer bounds
|
||||
// that should also be annotated.
|
||||
static void bound(int b) { }
|
||||
|
||||
public int forLoop() {
|
||||
int result = 0;
|
||||
for (int i = 0;
|
||||
i < 10; // $ bound="i in [0..10]"
|
||||
i++) { // $ bound="i in [0..9]"
|
||||
result = i; // $ bound="i in [0..9]"
|
||||
}
|
||||
return result; // $ bound="result in [0..9]"
|
||||
}
|
||||
|
||||
public int forLoopExit() {
|
||||
int result = 0;
|
||||
for (; result < 10;) { // $ bound="result in [0..10]"
|
||||
result += 1; // $ bound="result in [0..9]"
|
||||
}
|
||||
return result; // $ bound="result = 10"
|
||||
}
|
||||
|
||||
public int forLoopExitStep() {
|
||||
int result = 0;
|
||||
for (; result < 10;) { // $ bound="result in [0..12]"
|
||||
result += 3; // $ bound="result in [0..9]"
|
||||
}
|
||||
return result; // $ bound="result = 12"
|
||||
}
|
||||
|
||||
public int forLoopExitUpd() {
|
||||
int result = 0;
|
||||
for (; result < 10; // $ bound="result in [0..10]"
|
||||
result++) { // $ bound="result in [0..9]"
|
||||
}
|
||||
return result; // $ bound="result = 10"
|
||||
}
|
||||
|
||||
public int forLoopExitNested() {
|
||||
int result = 0;
|
||||
for (; result < 10;) {
|
||||
int i = 0;
|
||||
for (; i < 3;) { // $ bound="i in [0..3]"
|
||||
i += 1; // $ bound="i in [0..2]"
|
||||
}
|
||||
result += i; // $ bound="result in [0..9]" bound="i = 3"
|
||||
}
|
||||
return result; // $ MISSING:bound="result = 12"
|
||||
}
|
||||
|
||||
public int emptyForLoop() {
|
||||
int result = 0;
|
||||
for (int i = 0; i < 0; // $ bound="i = 0"
|
||||
i++) { // $ bound="i in [0..-1]"
|
||||
result = i; // $ bound="i in [0..-1]"
|
||||
}
|
||||
return result; // $ bound="result = 0"
|
||||
}
|
||||
|
||||
public int noLoop() {
|
||||
int result = 0;
|
||||
result += 1; // $ bound="result = 0"
|
||||
return result; // $ bound="result = 1"
|
||||
}
|
||||
|
||||
public int foreachLoop() {
|
||||
int result = 0;
|
||||
for (int i : new int[] {1, 2, 3, 4, 5}) {
|
||||
result = i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int emptyForeachLoop() {
|
||||
int result = 0;
|
||||
for (int i : new int[] {}) {
|
||||
result = i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int whileLoop() {
|
||||
int result = 100;
|
||||
while (result > 5) { // $ bound="result in [4..100]"
|
||||
result = result - 2; // $ bound="result in [6..100]"
|
||||
}
|
||||
return result; // $ bound="result = 4"
|
||||
}
|
||||
|
||||
public int oddWhileLoop() {
|
||||
int result = 101;
|
||||
while (result > 5) { // $ bound="result in [5..101]"
|
||||
result = result - 2; // $ bound="result in [7..101]"
|
||||
}
|
||||
return result; // $ bound="result = 5"
|
||||
}
|
||||
|
||||
static void arrayLength(int[] arr) {
|
||||
bound(arr.length);
|
||||
for (int i = 0;
|
||||
i < arr.length;
|
||||
i++) { // $ bound="i <= arr.length - 1"
|
||||
arr[i]++; // $ bound="i <= arr.length - 1"
|
||||
}
|
||||
}
|
||||
|
||||
static int varBound(int b) {
|
||||
bound(b);
|
||||
int result = 0;
|
||||
for (int i = 0;
|
||||
i < b;
|
||||
i++) { // $ bound="i <= b - 1"
|
||||
result = i; // $ bound="i <= b - 1"
|
||||
}
|
||||
return result; // We cannot conclude anything here, since we do not know that b > 0
|
||||
}
|
||||
|
||||
static int varBoundPositiveGuard(int b) {
|
||||
bound(b);
|
||||
if (b > 0) {
|
||||
int result = 0;
|
||||
for (int i = 0;
|
||||
i < b;
|
||||
i++) { // $ bound="i <= b - 1"
|
||||
result = i; // $ bound="i <= b - 1"
|
||||
}
|
||||
return result; // $ MISSING: bound="result <= b - 1"
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int varBoundPositiveGuardEarlyReturn(int b) {
|
||||
bound(b);
|
||||
if (b <= 0) return 0;
|
||||
int result = 0;
|
||||
for (int i = 0;
|
||||
i < b;
|
||||
i++) { // $ bound="i <= b - 1"
|
||||
result = i; // $ bound="i <= b - 1"
|
||||
}
|
||||
return result; // $ MISSING: bound="result <= b - 1"
|
||||
}
|
||||
|
||||
static int varBoundPositiveAssert(int b) {
|
||||
bound(b);
|
||||
assert b > 0;
|
||||
int result = 0;
|
||||
for (int i = 0;
|
||||
i < b;
|
||||
i++) { // $ bound="i <= b - 1"
|
||||
result = i; // $ bound="i <= b - 1"
|
||||
}
|
||||
return result; // $ MISSING: bound="result <= b - 1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Inline range analysis tests for Java.
|
||||
* See `shared/util/codeql/dataflow/test/InlineFlowTest.qll`
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.RangeAnalysis
|
||||
private import TestUtilities.InlineExpectationsTest as IET
|
||||
|
||||
module RangeTest implements IET::TestSig {
|
||||
string getARelevantTag() { result = "bound" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "bound" and
|
||||
(
|
||||
// simple integer bounds (`ZeroBound`s)
|
||||
exists(Expr e, int lower, int upper |
|
||||
constrained(e, lower, upper) and
|
||||
e instanceof VarRead and
|
||||
e.getCompilationUnit().fromSource()
|
||||
|
|
||||
location = e.getLocation() and
|
||||
element = e.toString() and
|
||||
if lower = upper
|
||||
then value = "\"" + e.toString() + " = " + lower.toString() + "\""
|
||||
else
|
||||
value = "\"" + e.toString() + " in [" + lower.toString() + ".." + upper.toString() + "]\""
|
||||
)
|
||||
or
|
||||
// advanced bounds
|
||||
exists(Expr e, int delta, string deltaStr, boolean upper, string cmp, Expr boundExpr |
|
||||
annotatedBound(e, _, boundExpr, delta, upper) and
|
||||
e instanceof VarRead and
|
||||
e.getCompilationUnit().fromSource() and
|
||||
(
|
||||
if delta = 0
|
||||
then deltaStr = ""
|
||||
else
|
||||
if delta > 0
|
||||
then deltaStr = " + " + delta.toString()
|
||||
else deltaStr = " - " + delta.abs().toString()
|
||||
) and
|
||||
if upper = true then cmp = "<=" else cmp = ">="
|
||||
|
|
||||
location = e.getLocation() and
|
||||
element = e.toString() and
|
||||
value = "\"" + e.toString() + " " + cmp + " " + boundExpr.toString() + deltaStr + "\""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate constrained(Expr e, int lower, int upper) {
|
||||
bounded(e, any(ZeroBound z), lower, false, _) and
|
||||
bounded(e, any(ZeroBound z), upper, true, _)
|
||||
}
|
||||
|
||||
private predicate annotatedBound(Expr e, Bound b, Expr boundExpr, int delta, boolean upper) {
|
||||
bounded(e, b, delta, upper, _) and
|
||||
// the expression for the bound is explicitly requested as being annotated
|
||||
// via a call such as
|
||||
// ```java
|
||||
// bound(expr);
|
||||
// ```
|
||||
boundExpr = b.getExpr() and
|
||||
exists(Call c | c.getCallee().getName() = "bound" and c.getArgument(0) = boundExpr) and
|
||||
// non-trivial bound
|
||||
not e = b.getExpr()
|
||||
}
|
||||
}
|
||||
|
||||
import IET::MakeTest<RangeTest>
|
||||
35
java/ql/test/library-tests/listofconstants/A.java
Normal file
35
java/ql/test/library-tests/listofconstants/A.java
Normal file
@@ -0,0 +1,35 @@
|
||||
import java.util.*;
|
||||
|
||||
public class A {
|
||||
private static final Set<String> SEPARATORS =
|
||||
Collections.unmodifiableSet(
|
||||
new HashSet<>(Arrays.asList("\t", "\n", ";")));
|
||||
|
||||
public static void sink(String s) { }
|
||||
|
||||
private void checkSeparator(String separator) {
|
||||
if (SEPARATORS.contains(separator)) {
|
||||
sink(separator);
|
||||
}
|
||||
}
|
||||
|
||||
public static final String URI1 = "yarn.io/gpu";
|
||||
public static final String URI2 = "yarn.io/fpga";
|
||||
|
||||
public static final Set<String> SCHEMAS = Set.of(URI1, URI2, "s3a", "wasb");
|
||||
|
||||
private void checkSchema(String schema) {
|
||||
if (SCHEMAS.contains(schema)) {
|
||||
sink(schema);
|
||||
}
|
||||
}
|
||||
|
||||
private void testAdd(String inp) {
|
||||
Set<String> s = new HashSet<>();
|
||||
s.add("AA");
|
||||
s.add("BB");
|
||||
if (s.contains(inp.toUpperCase())) {
|
||||
sink(inp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
| Type A uses out-of-scope type variable E. Note the Java extractor is known to sometimes do this; the Kotlin extractor should not. |
|
||||
3
java/ql/test/library-tests/listofconstants/test.expected
Normal file
3
java/ql/test/library-tests/listofconstants/test.expected
Normal file
@@ -0,0 +1,3 @@
|
||||
| A.java:12:12:12:20 | separator |
|
||||
| A.java:23:12:23:17 | schema |
|
||||
| A.java:32:12:32:14 | inp |
|
||||
5
java/ql/test/library-tests/listofconstants/test.ql
Normal file
5
java/ql/test/library-tests/listofconstants/test.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSteps
|
||||
|
||||
from DefaultTaintSanitizer e
|
||||
select e
|
||||
@@ -0,0 +1,306 @@
|
||||
// Test cases for CWE-089 (SQL injection and Java Persistence query injection)
|
||||
// http://cwe.mitre.org/data/definitions/89.html
|
||||
package test.cwe089.semmle.tests;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class AllowListSanitizerWithJavaUtilList {
|
||||
public static Connection connection;
|
||||
public static final List<String> goodAllowList1 = List.of("allowed1", "allowed2", "allowed3");
|
||||
public static final List<String> goodAllowList2 = Collections.unmodifiableList(Arrays.asList("allowed1"));
|
||||
public static final List<String> goodAllowList3;
|
||||
public static final List<String> goodAllowList4;
|
||||
public static final List<String> goodAllowList5;
|
||||
public static final List<String> badAllowList1 = List.of("allowed1", "allowed2", getNonConstantString());
|
||||
public static final List<String> badAllowList2 = Collections.unmodifiableList(Arrays.asList("allowed1", getNonConstantString()));
|
||||
public static final List<String> badAllowList3;
|
||||
public static final List<String> badAllowList4;
|
||||
public static List<String> badAllowList6 = List.of("allowed1", "allowed2", "allowed3");
|
||||
public final List<String> goodAllowList7 = List.of("allowed1", "allowed2", "allowed3");
|
||||
|
||||
static {
|
||||
goodAllowList3 = List.of("allowed1", "allowed2", "allowed3");
|
||||
goodAllowList4 = Collections.unmodifiableList(Arrays.asList("allowed1", "allowed2"));
|
||||
badAllowList3 = List.of(getNonConstantString(), "allowed2", "allowed3");
|
||||
badAllowList4 = Collections.unmodifiableList(Arrays.asList("allowed1", getNonConstantString()));
|
||||
goodAllowList5 = new ArrayList<String>();
|
||||
goodAllowList5.add("allowed1");
|
||||
goodAllowList5.add("allowed2");
|
||||
goodAllowList5.add("allowed3");
|
||||
}
|
||||
|
||||
public static String getNonConstantString() {
|
||||
return String.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException, SQLException {
|
||||
badAllowList6 = List.of("allowed1", getNonConstantString(), "allowed3");
|
||||
testStaticFields(args);
|
||||
testLocal(args);
|
||||
var x = new AllowListSanitizerWithJavaUtilList();
|
||||
x.testNonStaticFields(args);
|
||||
testMultipleSources(args);
|
||||
testEscape(args);
|
||||
}
|
||||
|
||||
private static void testStaticFields(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList1.contains(tainted.toLowerCase())){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList2.contains(tainted.toUpperCase())){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList3.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList4.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: an allowlist is used with constant strings
|
||||
if(badAllowList1.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: an allowlist is used with constant strings
|
||||
if(badAllowList2.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: an allowlist is used with constant strings
|
||||
if(badAllowList3.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: an allowlist is used with constant strings
|
||||
if(badAllowList4.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList5.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: the allowlist is in a non-final field
|
||||
if(badAllowList6.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
private void testNonStaticFields(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[0];
|
||||
// GOOD: the allowlist is in a non-static field
|
||||
if(goodAllowList7.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLocal(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
{
|
||||
List<String> allowlist = List.of("allowed1", "allowed2", "allowed3");
|
||||
if(allowlist.contains(tainted.toLowerCase())){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
List<String> allowlist = List.of("allowed1", "allowed2", args[2]);
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
{
|
||||
String[] allowedArray = {"allowed1", "allowed2", "allowed3"};
|
||||
List<String> allowlist = List.of(allowedArray);
|
||||
if(allowlist.contains(tainted.toUpperCase())){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
String[] allowedArray = {"allowed1", "allowed2", args[2]};
|
||||
List<String> allowlist = List.of(allowedArray);
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
{
|
||||
List<String> allowlist = Collections.unmodifiableList(Arrays.asList("allowed1"));
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
List<String> allowlist = Collections.unmodifiableList(Arrays.asList("allowed1", "allowed2", args[2]));
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
{
|
||||
String[] allowedArray = {"allowed1", "allowed2", "allowed3"};
|
||||
List<String> allowlist = Collections.unmodifiableList(Arrays.asList(allowedArray));
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
String[] allowedArray = {"allowed1", "allowed2", args[2]};
|
||||
List<String> allowlist = Collections.unmodifiableList(Arrays.asList(allowedArray));
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// GOOD: an allowlist is used with constant string
|
||||
{
|
||||
List<String> allowlist = new ArrayList<String>();
|
||||
allowlist.add("allowed1");
|
||||
allowlist.add("allowed2");
|
||||
allowlist.add("allowed3");
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
List<String> allowlist = new ArrayList<String>();
|
||||
allowlist.add("allowed1");
|
||||
allowlist.add(getNonConstantString());
|
||||
allowlist.add("allowed3");
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but it contains a non-compile-time constant element
|
||||
{
|
||||
List<String> allowlist = new ArrayList<String>();
|
||||
allowlist.add("allowed1");
|
||||
addNonConstantStringDirectly(allowlist);
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testMultipleSources(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
boolean b = args[2] == "True";
|
||||
{
|
||||
// BAD: an allowlist is used which might contain constant strings
|
||||
List<String> allowlist = new ArrayList<String>();
|
||||
allowlist.add("allowed1");
|
||||
if (b) {
|
||||
allowlist.add(getNonConstantString());
|
||||
}
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
{
|
||||
// BAD: an allowlist is used which might contain constant strings
|
||||
List<String> allowlist = b ? goodAllowList1 : badAllowList1;
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
{
|
||||
// BAD: an allowlist is used which might contain constant strings
|
||||
List<String> allowlist = b ? goodAllowList1 : List.of("allowed1", "allowed2", args[2]);;
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testEscape(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
boolean b = args[2] == "True";
|
||||
{
|
||||
// BAD: an allowlist is used which contains constant strings
|
||||
List<String> allowlist = new ArrayList<String>();
|
||||
addNonConstantStringViaLambda(e -> allowlist.add(e));
|
||||
if(allowlist.contains(tainted)){ // missing result
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addNonConstantStringDirectly(List<String> list) {
|
||||
list.add(getNonConstantString());
|
||||
}
|
||||
|
||||
private static void addNonConstantStringViaLambda(Consumer<String> adder) {
|
||||
adder.accept(getNonConstantString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
// Test cases for CWE-089 (SQL injection and Java Persistence query injection)
|
||||
// http://cwe.mitre.org/data/definitions/89.html
|
||||
package test.cwe089.semmle.tests;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class AllowListSanitizerWithJavaUtilSet {
|
||||
public static Connection connection;
|
||||
public static final Set<String> goodAllowList1 = Set.of("allowed1", "allowed2", "allowed3");
|
||||
public static final Set<String> goodAllowList2 = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("allowed1","allowed2")));
|
||||
public static final Set<String> goodAllowList3;
|
||||
public static final Set<String> goodAllowList4;
|
||||
public static final Set<String> goodAllowList5;
|
||||
public static final Set<String> badAllowList1 = Set.of("allowed1", "allowed2", getNonConstantString());
|
||||
public static final Set<String> badAllowList2 = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("allowed1", getNonConstantString())));
|
||||
public static final Set<String> badAllowList3;
|
||||
public static final Set<String> badAllowList4;
|
||||
public static Set<String> badAllowList6 = Set.of("allowed1", "allowed2", "allowed3");
|
||||
public final Set<String> goodAllowList7 = Set.of("allowed1", "allowed2", "allowed3");
|
||||
|
||||
static {
|
||||
goodAllowList3 = Set.of("allowed1", "allowed2", "allowed3");
|
||||
goodAllowList4 = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("allowed1", "allowed2")));
|
||||
badAllowList3 = Set.of(getNonConstantString(), "allowed2", "allowed3");
|
||||
badAllowList4 = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("allowed1", getNonConstantString())));
|
||||
goodAllowList5 = new HashSet<String>();
|
||||
goodAllowList5.add("allowed1");
|
||||
goodAllowList5.add("allowed2");
|
||||
goodAllowList5.add("allowed3");
|
||||
}
|
||||
|
||||
public static String getNonConstantString() {
|
||||
return String.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException, SQLException {
|
||||
badAllowList6 = Set.of("allowed1", getNonConstantString(), "allowed3");
|
||||
testStaticFields(args);
|
||||
testLocal(args);
|
||||
var x = new AllowListSanitizerWithJavaUtilSet();
|
||||
x.testNonStaticFields(args);
|
||||
testMultipleSources(args);
|
||||
testEscape(args);
|
||||
}
|
||||
|
||||
private static void testStaticFields(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList1.contains(tainted.toLowerCase())){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList2.contains(tainted.toUpperCase())){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList3.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList4.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: an allowlist is used with constant strings
|
||||
if(badAllowList1.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: an allowlist is used with constant strings
|
||||
if(badAllowList2.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: an allowlist is used with constant strings
|
||||
if(badAllowList3.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: an allowlist is used with constant strings
|
||||
if(badAllowList4.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
if(goodAllowList5.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
// BAD: the allowlist is in a non-final field
|
||||
if(badAllowList6.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
private void testNonStaticFields(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
// GOOD: the allowlist is in a non-static field
|
||||
if(goodAllowList7.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLocal(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
{
|
||||
Set<String> allowlist = Set.of("allowed1", "allowed2", "allowed3");
|
||||
if(allowlist.contains(tainted.toLowerCase())){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
Set<String> allowlist = Set.of("allowed1", "allowed2", args[2]);
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
{
|
||||
String[] allowedArray = {"allowed1", "allowed2", "allowed3"};
|
||||
Set<String> allowlist = Set.of(allowedArray);
|
||||
if(allowlist.contains(tainted.toUpperCase())){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
String[] allowedArray = {"allowed1", "allowed2", args[2]};
|
||||
Set<String> allowlist = Set.of(allowedArray);
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
{
|
||||
Set<String> allowlist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("allowed1")));
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
Set<String> allowlist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("allowed1", "allowed2", args[2])));
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// GOOD: an allowlist is used with constant strings
|
||||
{
|
||||
String[] allowedArray = {"allowed1", "allowed2", "allowed3"};
|
||||
Set<String> allowlist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(allowedArray)));
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
String[] allowedArray = {"allowed1", "allowed2", args[2]};
|
||||
Set<String> allowlist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(allowedArray)));
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// GOOD: an allowlist is used with constant string
|
||||
{
|
||||
Set<String> allowlist = new HashSet<String>();
|
||||
allowlist.add("allowed1");
|
||||
allowlist.add("allowed2");
|
||||
allowlist.add("allowed3");
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but one of the entries is not a compile-time constant
|
||||
{
|
||||
Set<String> allowlist = new HashSet<String>();
|
||||
allowlist.add("allowed1");
|
||||
allowlist.add(getNonConstantString());
|
||||
allowlist.add("allowed3");
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
// BAD: an allowlist is used but it contains a non-compile-time constant element
|
||||
{
|
||||
Set<String> allowlist = new HashSet<String>();
|
||||
allowlist.add("allowed1");
|
||||
addNonConstantStringDirectly(allowlist);
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testMultipleSources(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
boolean b = args[2] == "True";
|
||||
{
|
||||
// BAD: an allowlist is used which might contain constant strings
|
||||
Set<String> allowlist = new HashSet<String>();
|
||||
allowlist.add("allowed1");
|
||||
if (b) {
|
||||
allowlist.add(getNonConstantString());
|
||||
}
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
{
|
||||
// BAD: an allowlist is used which might contain constant strings
|
||||
Set<String> allowlist = b ? goodAllowList1 : badAllowList1;
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
{
|
||||
// BAD: an allowlist is used which might contain constant strings
|
||||
Set<String> allowlist = b ? goodAllowList1 : Set.of("allowed1", "allowed2", args[2]);;
|
||||
if(allowlist.contains(tainted)){
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testEscape(String[] args) throws IOException, SQLException {
|
||||
String tainted = args[1];
|
||||
boolean b = args[2] == "True";
|
||||
{
|
||||
// BAD: an allowlist is used which contains constant strings
|
||||
Set<String> allowlist = new HashSet<String>();
|
||||
addNonConstantStringViaLambda(e -> allowlist.add(e));
|
||||
if(allowlist.contains(tainted)){ // missing result
|
||||
String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ tainted + "' ORDER BY PRICE";
|
||||
ResultSet results = connection.createStatement().executeQuery(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addNonConstantStringDirectly(Set<String> set) {
|
||||
set.add(getNonConstantString());
|
||||
}
|
||||
|
||||
private static void addNonConstantStringViaLambda(Consumer<String> adder) {
|
||||
adder.accept(getNonConstantString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
| Type AllowListSanitizerWithJavaUtilSet uses out-of-scope type variable E. Note the Java extractor is known to sometimes do this; the Kotlin extractor should not. |
|
||||
@@ -1,3 +1,55 @@
|
||||
| AllowListSanitizerWithJavaUtilList.java:64:66:64:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:63:8:63:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:70:66:70:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:69:8:69:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:76:66:76:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:75:8:75:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:82:66:82:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:81:8:81:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:87:8:87:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:93:8:93:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:99:8:99:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:105:8:105:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:112:66:112:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:111:8:111:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:117:8:117:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:128:66:128:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:127:8:127:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:140:67:140:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:139:9:139:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:148:9:148:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:159:67:159:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:158:9:158:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:168:9:168:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:178:67:178:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:177:9:177:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:186:9:186:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:197:67:197:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:196:9:196:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:206:9:206:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:219:67:219:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:218:9:218:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:230:9:230:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:241:9:241:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:259:9:259:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:268:9:268:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:277:9:277:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:292:9:292:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:63:66:63:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:62:8:62:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:69:66:69:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:68:8:68:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:75:66:75:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:74:8:74:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:81:66:81:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:80:8:80:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:86:8:86:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:92:8:92:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:98:8:98:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:104:8:104:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:111:66:111:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:110:8:110:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:116:8:116:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:127:66:127:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:126:8:126:14 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:139:67:139:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:138:9:138:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:147:9:147:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:158:67:158:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:157:9:157:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:167:9:167:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:177:67:177:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:176:9:176:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:185:9:185:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:196:67:196:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:195:9:195:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:205:9:205:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:218:67:218:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:217:9:217:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:229:9:229:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:240:9:240:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:258:9:258:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:267:9:267:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:276:9:276:15 | tainted | this expression |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:291:9:291:15 | tainted | this expression |
|
||||
| Test.java:36:47:36:52 | query1 | Query built by concatenation with $@, which may be untrusted. | Test.java:35:8:35:15 | category | this expression |
|
||||
| Test.java:42:57:42:62 | query2 | Query built by concatenation with $@, which may be untrusted. | Test.java:41:51:41:52 | id | this expression |
|
||||
| Test.java:50:62:50:67 | query3 | Query built by concatenation with $@, which may be untrusted. | Test.java:49:8:49:15 | category | this expression |
|
||||
|
||||
@@ -1,4 +1,34 @@
|
||||
#select
|
||||
| AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value |
|
||||
| Mongo.java:17:45:17:67 | parse(...) | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:17:45:17:67 | parse(...) | This query depends on a $@. | Mongo.java:10:29:10:41 | args | user-provided value |
|
||||
| Mongo.java:21:49:21:52 | json | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:21:49:21:52 | json | This query depends on a $@. | Mongo.java:10:29:10:41 | args | user-provided value |
|
||||
| Test.java:36:47:36:52 | query1 | Test.java:227:26:227:38 | args : String[] | Test.java:36:47:36:52 | query1 | This query depends on a $@. | Test.java:227:26:227:38 | args | user-provided value |
|
||||
@@ -10,6 +40,52 @@
|
||||
| Test.java:209:47:209:68 | queryWithUserTableName | Test.java:227:26:227:38 | args : String[] | Test.java:209:47:209:68 | queryWithUserTableName | This query depends on a $@. | Test.java:227:26:227:38 | args | user-provided value |
|
||||
| Test.java:221:81:221:111 | ... + ... | Test.java:227:26:227:38 | args : String[] | Test.java:221:81:221:111 | ... + ... | This query depends on a $@. | Test.java:227:26:227:38 | args | user-provided value |
|
||||
edges
|
||||
| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:50:20:50:23 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:51:13:51:16 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:54:23:54:26 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:55:14:55:17 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilList.java:50:20:50:23 | args : String[] | AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilList.java:51:13:51:16 | args : String[] | AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilList.java:54:23:54:26 | args : String[] | AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilList.java:55:14:55:17 | args : String[] | AllowListSanitizerWithJavaUtilList.java:283:33:283:45 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilList.java:283:33:283:45 | args : String[] | AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:49:20:49:23 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:50:13:50:16 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:53:23:53:26 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:54:14:54:17 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:49:20:49:23 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:50:13:50:16 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:53:23:53:26 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:54:14:54:17 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:282:33:282:45 | args : String[] | provenance | |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | provenance | Sink:MaD:4 |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:282:33:282:45 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | provenance | Sink:MaD:4 |
|
||||
| Mongo.java:10:29:10:41 | args : String[] | Mongo.java:17:56:17:66 | stringQuery : String | provenance | |
|
||||
| Mongo.java:10:29:10:41 | args : String[] | Mongo.java:21:49:21:52 | json | provenance | |
|
||||
| Mongo.java:17:56:17:66 | stringQuery : String | Mongo.java:17:45:17:67 | parse(...) | provenance | Config |
|
||||
@@ -40,6 +116,54 @@ models
|
||||
| 6 | Summary: java.lang; AbstractStringBuilder; true; append; ; ; Argument[0]; Argument[this]; taint; manual |
|
||||
| 7 | Summary: java.lang; CharSequence; true; toString; ; ; Argument[this]; ReturnValue; taint; manual |
|
||||
nodes
|
||||
| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:50:20:50:23 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:51:13:51:16 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:54:23:54:26 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:55:14:55:17 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilList.java:283:33:283:45 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:49:20:49:23 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:50:13:50:16 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:53:23:53:26 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:54:14:54:17 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | semmle.label | query |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:282:33:282:45 | args : String[] | semmle.label | args : String[] |
|
||||
| AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | semmle.label | query |
|
||||
| Mongo.java:10:29:10:41 | args : String[] | semmle.label | args : String[] |
|
||||
| Mongo.java:17:45:17:67 | parse(...) | semmle.label | parse(...) |
|
||||
| Mongo.java:17:56:17:66 | stringQuery : String | semmle.label | stringQuery : String |
|
||||
|
||||
@@ -19,7 +19,7 @@ public class WeakHashing {
|
||||
|
||||
// BAD: Using a strong hashing algorithm but with a weak default
|
||||
MessageDigest bad3 = MessageDigest.getInstance(props.getProperty("hashAlg2", "MD5"));
|
||||
|
||||
|
||||
// GOOD: Using a strong hashing algorithm
|
||||
MessageDigest ok = MessageDigest.getInstance(props.getProperty("hashAlg2"));
|
||||
|
||||
@@ -28,5 +28,8 @@ public class WeakHashing {
|
||||
|
||||
// GOOD: Using a strong hashing algorithm
|
||||
MessageDigest ok3 = MessageDigest.getInstance("SHA3-512");
|
||||
|
||||
// GOOD: Using a strong hashing algorithm
|
||||
MessageDigest ok4 = MessageDigest.getInstance("SHA384");
|
||||
}
|
||||
}
|
||||
|
||||
55
misc/scripts/create-change-note.py
Normal file
55
misc/scripts/create-change-note.py
Normal file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Creates a change note and opens it in VSCode for editing.
|
||||
|
||||
# Expects to receive the following arguments:
|
||||
# - What language the change note is for
|
||||
# - Whether it's a query or library change (the string `src` or `lib`)
|
||||
# - The name of the change note (in kebab-case)
|
||||
# - The category of the change.
|
||||
|
||||
# The change note will be created in the `{language}/ql/{subdir}/change-notes` directory, where `subdir` is either `src` or `lib`.
|
||||
|
||||
# The format of the change note filename is `{current_date}-{change_note_name}.md` with the date in
|
||||
# the format `YYYY-MM-DD`.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Read the given arguments
|
||||
language = sys.argv[1]
|
||||
subdir = sys.argv[2]
|
||||
change_note_name = sys.argv[3]
|
||||
change_category = sys.argv[4]
|
||||
|
||||
# Find the root of the repository. The current script should be located in `misc/scripts`.
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
# Go to the repo root
|
||||
os.chdir(root)
|
||||
|
||||
output_dir = f"{language}/ql/{subdir}/change-notes"
|
||||
|
||||
# Abort if the output directory doesn't exist
|
||||
if not os.path.exists(output_dir):
|
||||
print(f"Output directory {output_dir} does not exist")
|
||||
sys.exit(1)
|
||||
|
||||
# Get the current date
|
||||
import datetime
|
||||
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
# Create the change note file
|
||||
change_note_file = f"{output_dir}/{current_date}-{change_note_name}.md"
|
||||
|
||||
change_note = f"""
|
||||
---
|
||||
category: {change_category}
|
||||
---
|
||||
* """.lstrip()
|
||||
|
||||
with open(change_note_file, "w") as f:
|
||||
f.write(change_note)
|
||||
|
||||
# Open the change note file in VSCode, reusing the existing window if possible
|
||||
os.system(f"code -r {change_note_file}")
|
||||
@@ -10,7 +10,7 @@ from io import BytesIO
|
||||
|
||||
#Semantic version of extractor.
|
||||
#Update this if any changes are made
|
||||
VERSION = "7.1.1"
|
||||
VERSION = "7.1.2"
|
||||
|
||||
PY_EXTENSIONS = ".py", ".pyw"
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
|
||||
- Fixed a problem with the control-flow graph construction, where writing `case True:` or `case False:` would cause parts of the graph to be pruned by mistake.
|
||||
@@ -28,8 +28,10 @@ fn class_name(type_name: &str) -> String {
|
||||
|
||||
fn property_name(type_name: &str, field_name: &str) -> String {
|
||||
let name = match (type_name, field_name) {
|
||||
("Path", "segment") => "part",
|
||||
("CallExpr", "expr") => "function",
|
||||
("LetExpr", "expr") => "scrutinee",
|
||||
("MatchExpr", "expr") => "scrutinee",
|
||||
("Path", "segment") => "part",
|
||||
(_, "then_branch") => "then",
|
||||
(_, "else_branch") => "else_",
|
||||
_ => field_name,
|
||||
|
||||
2
rust/extractor/src/generated/.generated.list
generated
2
rust/extractor/src/generated/.generated.list
generated
@@ -1,2 +1,2 @@
|
||||
mod.rs 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7
|
||||
top.rs abab6a736e75f9eabbe31deef4de782fc05f0c053798a01d410fffc859515278 abab6a736e75f9eabbe31deef4de782fc05f0c053798a01d410fffc859515278
|
||||
top.rs 272ecf2f56f35211d2449dbf55b1907d8414a8e4cceded03fd12f6f599852c73 272ecf2f56f35211d2449dbf55b1907d8414a8e4cceded03fd12f6f599852c73
|
||||
|
||||
369
rust/extractor/src/generated/top.rs
generated
369
rust/extractor/src/generated/top.rs
generated
@@ -200,6 +200,51 @@ impl From<trap::Label<Abi>> for trap::Label<Locatable> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Addressable {
|
||||
_unused: ()
|
||||
}
|
||||
|
||||
impl Addressable {
|
||||
pub fn emit_extended_canonical_path(id: trap::Label<Self>, value: String, out: &mut trap::Writer) {
|
||||
out.add_tuple("addressable_extended_canonical_paths", vec![id.into(), value.into()]);
|
||||
}
|
||||
pub fn emit_crate_origin(id: trap::Label<Self>, value: String, out: &mut trap::Writer) {
|
||||
out.add_tuple("addressable_crate_origins", vec![id.into(), value.into()]);
|
||||
}
|
||||
}
|
||||
|
||||
impl trap::TrapClass for Addressable {
|
||||
fn class_name() -> &'static str { "Addressable" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Addressable>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Addressable>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Addressable is a subclass of AstNode
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Addressable>> for trap::Label<Element> {
|
||||
fn from(value: trap::Label<Addressable>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Addressable is a subclass of Element
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Addressable>> for trap::Label<Locatable> {
|
||||
fn from(value: trap::Label<Addressable>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Addressable is a subclass of Locatable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArgList {
|
||||
pub id: trap::TrapId<ArgList>,
|
||||
@@ -2729,72 +2774,6 @@ impl From<trap::Label<UseTreeList>> for trap::Label<Locatable> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Variant {
|
||||
pub id: trap::TrapId<Variant>,
|
||||
pub attrs: Vec<trap::Label<Attr>>,
|
||||
pub expr: Option<trap::Label<Expr>>,
|
||||
pub field_list: Option<trap::Label<FieldList>>,
|
||||
pub name: Option<trap::Label<Name>>,
|
||||
pub visibility: Option<trap::Label<Visibility>>,
|
||||
}
|
||||
|
||||
impl trap::TrapEntry for Variant {
|
||||
fn extract_id(&mut self) -> trap::TrapId<Self> {
|
||||
std::mem::replace(&mut self.id, trap::TrapId::Star)
|
||||
}
|
||||
|
||||
fn emit(self, id: trap::Label<Self>, out: &mut trap::Writer) {
|
||||
out.add_tuple("variants", vec![id.into()]);
|
||||
for (i, v) in self.attrs.into_iter().enumerate() {
|
||||
out.add_tuple("variant_attrs", vec![id.into(), i.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.expr {
|
||||
out.add_tuple("variant_exprs", vec![id.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.field_list {
|
||||
out.add_tuple("variant_field_lists", vec![id.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.name {
|
||||
out.add_tuple("variant_names", vec![id.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.visibility {
|
||||
out.add_tuple("variant_visibilities", vec![id.into(), v.into()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl trap::TrapClass for Variant {
|
||||
fn class_name() -> &'static str { "Variant" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Variant>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Variant>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Variant is a subclass of AstNode
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Variant>> for trap::Label<Element> {
|
||||
fn from(value: trap::Label<Variant>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Variant is a subclass of Element
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Variant>> for trap::Label<Locatable> {
|
||||
fn from(value: trap::Label<Variant>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Variant is a subclass of Locatable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VariantList {
|
||||
pub id: trap::TrapId<VariantList>,
|
||||
@@ -4865,19 +4844,19 @@ pub struct Item {
|
||||
_unused: ()
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn emit_extended_canonical_path(id: trap::Label<Self>, value: String, out: &mut trap::Writer) {
|
||||
out.add_tuple("item_extended_canonical_paths", vec![id.into(), value.into()]);
|
||||
}
|
||||
pub fn emit_crate_origin(id: trap::Label<Self>, value: String, out: &mut trap::Writer) {
|
||||
out.add_tuple("item_crate_origins", vec![id.into(), value.into()]);
|
||||
}
|
||||
}
|
||||
|
||||
impl trap::TrapClass for Item {
|
||||
fn class_name() -> &'static str { "Item" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Item>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Item>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Item is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Item>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Item>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Item is a subclass of AstNode
|
||||
@@ -4963,7 +4942,7 @@ impl From<trap::Label<LabelableExpr>> for trap::Label<Locatable> {
|
||||
pub struct LetExpr {
|
||||
pub id: trap::TrapId<LetExpr>,
|
||||
pub attrs: Vec<trap::Label<Attr>>,
|
||||
pub expr: Option<trap::Label<Expr>>,
|
||||
pub scrutinee: Option<trap::Label<Expr>>,
|
||||
pub pat: Option<trap::Label<Pat>>,
|
||||
}
|
||||
|
||||
@@ -4977,8 +4956,8 @@ impl trap::TrapEntry for LetExpr {
|
||||
for (i, v) in self.attrs.into_iter().enumerate() {
|
||||
out.add_tuple("let_expr_attrs", vec![id.into(), i.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.expr {
|
||||
out.add_tuple("let_expr_exprs", vec![id.into(), v.into()]);
|
||||
if let Some(v) = self.scrutinee {
|
||||
out.add_tuple("let_expr_scrutinees", vec![id.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.pat {
|
||||
out.add_tuple("let_expr_pats", vec![id.into(), v.into()]);
|
||||
@@ -7780,6 +7759,81 @@ impl From<trap::Label<UnderscoreExpr>> for trap::Label<Locatable> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Variant {
|
||||
pub id: trap::TrapId<Variant>,
|
||||
pub attrs: Vec<trap::Label<Attr>>,
|
||||
pub expr: Option<trap::Label<Expr>>,
|
||||
pub field_list: Option<trap::Label<FieldList>>,
|
||||
pub name: Option<trap::Label<Name>>,
|
||||
pub visibility: Option<trap::Label<Visibility>>,
|
||||
}
|
||||
|
||||
impl trap::TrapEntry for Variant {
|
||||
fn extract_id(&mut self) -> trap::TrapId<Self> {
|
||||
std::mem::replace(&mut self.id, trap::TrapId::Star)
|
||||
}
|
||||
|
||||
fn emit(self, id: trap::Label<Self>, out: &mut trap::Writer) {
|
||||
out.add_tuple("variants", vec![id.into()]);
|
||||
for (i, v) in self.attrs.into_iter().enumerate() {
|
||||
out.add_tuple("variant_attrs", vec![id.into(), i.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.expr {
|
||||
out.add_tuple("variant_exprs", vec![id.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.field_list {
|
||||
out.add_tuple("variant_field_lists", vec![id.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.name {
|
||||
out.add_tuple("variant_names", vec![id.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.visibility {
|
||||
out.add_tuple("variant_visibilities", vec![id.into(), v.into()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl trap::TrapClass for Variant {
|
||||
fn class_name() -> &'static str { "Variant" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Variant>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Variant>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Variant is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Variant>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Variant>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Variant is a subclass of AstNode
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Variant>> for trap::Label<Element> {
|
||||
fn from(value: trap::Label<Variant>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Variant is a subclass of Element
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Variant>> for trap::Label<Locatable> {
|
||||
fn from(value: trap::Label<Variant>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Variant is a subclass of Locatable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WildcardPat {
|
||||
pub id: trap::TrapId<WildcardPat>,
|
||||
@@ -8066,7 +8120,7 @@ pub struct CallExpr {
|
||||
pub id: trap::TrapId<CallExpr>,
|
||||
pub arg_list: Option<trap::Label<ArgList>>,
|
||||
pub attrs: Vec<trap::Label<Attr>>,
|
||||
pub expr: Option<trap::Label<Expr>>,
|
||||
pub function: Option<trap::Label<Expr>>,
|
||||
}
|
||||
|
||||
impl trap::TrapEntry for CallExpr {
|
||||
@@ -8082,8 +8136,8 @@ impl trap::TrapEntry for CallExpr {
|
||||
for (i, v) in self.attrs.into_iter().enumerate() {
|
||||
out.add_tuple("call_expr_base_attrs", vec![id.into(), i.into(), v.into()]);
|
||||
}
|
||||
if let Some(v) = self.expr {
|
||||
out.add_tuple("call_expr_exprs", vec![id.into(), v.into()]);
|
||||
if let Some(v) = self.function {
|
||||
out.add_tuple("call_expr_functions", vec![id.into(), v.into()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8184,6 +8238,15 @@ impl trap::TrapClass for Const {
|
||||
fn class_name() -> &'static str { "Const" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Const>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Const>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Const is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Const>> for trap::Label<AssocItem> {
|
||||
fn from(value: trap::Label<Const>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Const is a subclass of AssocItem
|
||||
@@ -8281,6 +8344,15 @@ impl trap::TrapClass for Enum {
|
||||
fn class_name() -> &'static str { "Enum" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Enum>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Enum>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Enum is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Enum>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Enum>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Enum is a subclass of AstNode
|
||||
@@ -8361,6 +8433,15 @@ impl trap::TrapClass for ExternBlock {
|
||||
fn class_name() -> &'static str { "ExternBlock" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<ExternBlock>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<ExternBlock>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme ExternBlock is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<ExternBlock>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<ExternBlock>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme ExternBlock is a subclass of AstNode
|
||||
@@ -8441,6 +8522,15 @@ impl trap::TrapClass for ExternCrate {
|
||||
fn class_name() -> &'static str { "ExternCrate" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<ExternCrate>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<ExternCrate>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme ExternCrate is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<ExternCrate>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<ExternCrate>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme ExternCrate is a subclass of AstNode
|
||||
@@ -8561,6 +8651,15 @@ impl trap::TrapClass for Function {
|
||||
fn class_name() -> &'static str { "Function" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Function>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Function>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Function is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Function>> for trap::Label<AssocItem> {
|
||||
fn from(value: trap::Label<Function>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Function is a subclass of AssocItem
|
||||
@@ -8692,6 +8791,15 @@ impl trap::TrapClass for Impl {
|
||||
fn class_name() -> &'static str { "Impl" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Impl>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Impl>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Impl is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Impl>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Impl>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Impl is a subclass of AstNode
|
||||
@@ -8828,6 +8936,15 @@ impl trap::TrapClass for MacroCall {
|
||||
fn class_name() -> &'static str { "MacroCall" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroCall>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<MacroCall>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroCall is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroCall>> for trap::Label<AssocItem> {
|
||||
fn from(value: trap::Label<MacroCall>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroCall is a subclass of AssocItem
|
||||
@@ -8930,6 +9047,15 @@ impl trap::TrapClass for MacroDef {
|
||||
fn class_name() -> &'static str { "MacroDef" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroDef>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<MacroDef>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroDef is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroDef>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<MacroDef>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroDef is a subclass of AstNode
|
||||
@@ -9010,6 +9136,15 @@ impl trap::TrapClass for MacroRules {
|
||||
fn class_name() -> &'static str { "MacroRules" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroRules>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<MacroRules>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroRules is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<MacroRules>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<MacroRules>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme MacroRules is a subclass of AstNode
|
||||
@@ -9183,6 +9318,15 @@ impl trap::TrapClass for Module {
|
||||
fn class_name() -> &'static str { "Module" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Module>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Module>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Module is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Module>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Module>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Module is a subclass of AstNode
|
||||
@@ -9347,6 +9491,15 @@ impl trap::TrapClass for Static {
|
||||
fn class_name() -> &'static str { "Static" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Static>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Static>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Static is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Static>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Static>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Static is a subclass of AstNode
|
||||
@@ -9444,6 +9597,15 @@ impl trap::TrapClass for Struct {
|
||||
fn class_name() -> &'static str { "Struct" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Struct>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Struct>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Struct is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Struct>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Struct>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Struct is a subclass of AstNode
|
||||
@@ -9544,6 +9706,15 @@ impl trap::TrapClass for Trait {
|
||||
fn class_name() -> &'static str { "Trait" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Trait>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Trait>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Trait is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Trait>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Trait>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Trait is a subclass of AstNode
|
||||
@@ -9632,6 +9803,15 @@ impl trap::TrapClass for TraitAlias {
|
||||
fn class_name() -> &'static str { "TraitAlias" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<TraitAlias>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<TraitAlias>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme TraitAlias is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<TraitAlias>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<TraitAlias>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme TraitAlias is a subclass of AstNode
|
||||
@@ -9728,6 +9908,15 @@ impl trap::TrapClass for TypeAlias {
|
||||
fn class_name() -> &'static str { "TypeAlias" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<TypeAlias>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<TypeAlias>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme TypeAlias is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<TypeAlias>> for trap::Label<AssocItem> {
|
||||
fn from(value: trap::Label<TypeAlias>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme TypeAlias is a subclass of AssocItem
|
||||
@@ -9834,6 +10023,15 @@ impl trap::TrapClass for Union {
|
||||
fn class_name() -> &'static str { "Union" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Union>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Union>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Union is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Union>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Union>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Union is a subclass of AstNode
|
||||
@@ -9910,6 +10108,15 @@ impl trap::TrapClass for Use {
|
||||
fn class_name() -> &'static str { "Use" }
|
||||
}
|
||||
|
||||
impl From<trap::Label<Use>> for trap::Label<Addressable> {
|
||||
fn from(value: trap::Label<Use>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Use is a subclass of Addressable
|
||||
unsafe {
|
||||
Self::from_untyped(value.as_untyped())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trap::Label<Use>> for trap::Label<AstNode> {
|
||||
fn from(value: trap::Label<Use>) -> Self {
|
||||
// SAFETY: this is safe because in the dbscheme Use is a subclass of AstNode
|
||||
|
||||
@@ -10,7 +10,9 @@ use log::Level;
|
||||
use ra_ap_base_db::salsa::InternKey;
|
||||
use ra_ap_base_db::CrateOrigin;
|
||||
use ra_ap_hir::db::ExpandDatabase;
|
||||
use ra_ap_hir::{Adt, Crate, ItemContainer, Module, ModuleDef, PathResolution, Semantics, Type};
|
||||
use ra_ap_hir::{
|
||||
Adt, Crate, ItemContainer, Module, ModuleDef, PathResolution, Semantics, Type, Variant,
|
||||
};
|
||||
use ra_ap_hir_def::type_ref::Mutability;
|
||||
use ra_ap_hir_def::ModuleId;
|
||||
use ra_ap_hir_expand::ExpandTo;
|
||||
@@ -47,6 +49,9 @@ macro_rules! emit_detached {
|
||||
(Module, $self:ident, $node:ident, $label:ident) => {
|
||||
$self.extract_canonical_origin(&$node, $label.into());
|
||||
};
|
||||
(Variant, $self:ident, $node:ident, $label:ident) => {
|
||||
$self.extract_canonical_origin_of_enum_variant(&$node, $label);
|
||||
};
|
||||
// TODO canonical origin of other items
|
||||
(Path, $self:ident, $node:ident, $label:ident) => {
|
||||
$self.extract_canonical_destination(&$node, $label);
|
||||
@@ -396,16 +401,24 @@ impl<'a> Translator<'a> {
|
||||
ModuleDef::Adt(Adt::Struct(it)) => self.canonical_path_from_hir(it),
|
||||
ModuleDef::Adt(Adt::Union(it)) => self.canonical_path_from_hir(it),
|
||||
ModuleDef::Trait(it) => self.canonical_path_from_hir(it),
|
||||
ModuleDef::Variant(it) => self.canonical_path_from_enum_variant(it),
|
||||
ModuleDef::Static(_) => None,
|
||||
ModuleDef::TraitAlias(_) => None,
|
||||
ModuleDef::TypeAlias(_) => None,
|
||||
ModuleDef::BuiltinType(_) => None,
|
||||
ModuleDef::Macro(_) => None,
|
||||
ModuleDef::Variant(_) => None,
|
||||
ModuleDef::Const(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn canonical_path_from_enum_variant(&self, item: Variant) -> Option<String> {
|
||||
// if we have a Hir entity, it means we have semantics
|
||||
let sema = self.semantics.as_ref().unwrap();
|
||||
let prefix = self.canonical_path_from_hir(item.parent_enum(sema.db))?;
|
||||
let name = item.name(sema.db);
|
||||
Some(format!("{prefix}::{}", name.as_str()))
|
||||
}
|
||||
|
||||
fn origin_from_hir<T: AstNode>(&self, item: impl AddressableHir<T>) -> String {
|
||||
// if we have a Hir entity, it means we have semantics
|
||||
let sema = self.semantics.as_ref().unwrap();
|
||||
@@ -437,28 +450,58 @@ impl<'a> Translator<'a> {
|
||||
ModuleDef::Adt(Adt::Struct(it)) => Some(self.origin_from_hir(it)),
|
||||
ModuleDef::Adt(Adt::Union(it)) => Some(self.origin_from_hir(it)),
|
||||
ModuleDef::Trait(it) => Some(self.origin_from_hir(it)),
|
||||
ModuleDef::Variant(it) => Some(self.origin_from_enum_variant(it)),
|
||||
ModuleDef::Static(_) => None,
|
||||
ModuleDef::TraitAlias(_) => None,
|
||||
ModuleDef::TypeAlias(_) => None,
|
||||
ModuleDef::BuiltinType(_) => None,
|
||||
ModuleDef::Macro(_) => None,
|
||||
ModuleDef::Variant(_) => None,
|
||||
ModuleDef::Const(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn origin_from_enum_variant(&self, item: Variant) -> String {
|
||||
// if we have a Hir entity, it means we have semantics
|
||||
let sema = self.semantics.as_ref().unwrap();
|
||||
self.origin_from_hir(item.parent_enum(sema.db))
|
||||
}
|
||||
|
||||
pub(crate) fn extract_canonical_origin<T: AddressableAst + HasName>(
|
||||
&mut self,
|
||||
item: &T,
|
||||
label: Label<generated::Item>,
|
||||
label: Label<generated::Addressable>,
|
||||
) {
|
||||
(|| {
|
||||
let sema = self.semantics.as_ref()?;
|
||||
let def = T::Hir::try_from_source(item, sema)?;
|
||||
let path = self.canonical_path_from_hir(def)?;
|
||||
let origin = self.origin_from_hir(def);
|
||||
generated::Item::emit_crate_origin(label, origin, &mut self.trap.writer);
|
||||
generated::Item::emit_extended_canonical_path(label, path, &mut self.trap.writer);
|
||||
generated::Addressable::emit_crate_origin(label, origin, &mut self.trap.writer);
|
||||
generated::Addressable::emit_extended_canonical_path(
|
||||
label,
|
||||
path,
|
||||
&mut self.trap.writer,
|
||||
);
|
||||
Some(())
|
||||
})();
|
||||
}
|
||||
|
||||
pub(crate) fn extract_canonical_origin_of_enum_variant(
|
||||
&mut self,
|
||||
item: &ast::Variant,
|
||||
label: Label<generated::Variant>,
|
||||
) {
|
||||
(|| {
|
||||
let sema = self.semantics.as_ref()?;
|
||||
let def = sema.to_enum_variant_def(item)?;
|
||||
let path = self.canonical_path_from_enum_variant(def)?;
|
||||
let origin = self.origin_from_enum_variant(def);
|
||||
generated::Addressable::emit_crate_origin(label.into(), origin, &mut self.trap.writer);
|
||||
generated::Addressable::emit_extended_canonical_path(
|
||||
label.into(),
|
||||
path,
|
||||
&mut self.trap.writer,
|
||||
);
|
||||
Some(())
|
||||
})();
|
||||
}
|
||||
|
||||
8
rust/extractor/src/translate/generated.rs
generated
8
rust/extractor/src/translate/generated.rs
generated
@@ -397,12 +397,12 @@ impl Translator<'_> {
|
||||
pub(crate) fn emit_call_expr(&mut self, node: ast::CallExpr) -> Label<generated::CallExpr> {
|
||||
let arg_list = node.arg_list().map(|x| self.emit_arg_list(x));
|
||||
let attrs = node.attrs().map(|x| self.emit_attr(x)).collect();
|
||||
let expr = node.expr().map(|x| self.emit_expr(x));
|
||||
let function = node.expr().map(|x| self.emit_expr(x));
|
||||
let label = self.trap.emit(generated::CallExpr {
|
||||
id: TrapId::Star,
|
||||
arg_list,
|
||||
attrs,
|
||||
expr,
|
||||
function,
|
||||
});
|
||||
self.emit_location(label, &node);
|
||||
emit_detached!(CallExpr, self, node, label);
|
||||
@@ -958,12 +958,12 @@ impl Translator<'_> {
|
||||
|
||||
pub(crate) fn emit_let_expr(&mut self, node: ast::LetExpr) -> Label<generated::LetExpr> {
|
||||
let attrs = node.attrs().map(|x| self.emit_attr(x)).collect();
|
||||
let expr = node.expr().map(|x| self.emit_expr(x));
|
||||
let scrutinee = node.expr().map(|x| self.emit_expr(x));
|
||||
let pat = node.pat().map(|x| self.emit_pat(x));
|
||||
let label = self.trap.emit(generated::LetExpr {
|
||||
id: TrapId::Star,
|
||||
attrs,
|
||||
expr,
|
||||
scrutinee,
|
||||
pat,
|
||||
});
|
||||
self.emit_location(label, &node);
|
||||
|
||||
40
rust/ql/.generated.list
generated
40
rust/ql/.generated.list
generated
@@ -1,5 +1,6 @@
|
||||
lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll 5e6ce2581b312d74ac8ffde44941b77f643025a7ff2c47799b3834596a513fa4 24dc5d28eb4754f968cf850294ac32057a2a97cf5156a3e90e0924c28e50e810
|
||||
lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll a8e083c7d8c4dea6459c5e128e2123f5cf8fd14c076f2256ebda508c13d553cd 16fcc0d34097b0b37a0041281515ca028d2702eec6d9c1d03c39a1158883bdef
|
||||
lib/codeql/rust/elements/Abi.qll 4c973d28b6d628f5959d1f1cc793704572fd0acaae9a97dfce82ff9d73f73476 250f68350180af080f904cd34cb2af481c5c688dc93edf7365fd0ae99855e893
|
||||
lib/codeql/rust/elements/Addressable.qll 13011bfd2e1556694c3d440cc34af8527da4df49ad92b62f2939d3699ff2cea5 ddb25935f7553a1a384b1abe2e4b4fa90ab50b952dadec32fd867afcb054f4be
|
||||
lib/codeql/rust/elements/ArgList.qll 661f5100f5d3ef8351452d9058b663a2a5c720eea8cf11bedd628969741486a2 28e424aac01a90fb58cd6f9f83c7e4cf379eea39e636bc0ba07efc818be71c71
|
||||
lib/codeql/rust/elements/ArrayExpr.qll a3e6e122632f4011644ec31b37f88b32fe3f2b7e388e7e878a6883309937049f 12ccb5873d95c433da5606fd371d182ef2f71b78d0c53c2d6dec10fa45852bdc
|
||||
lib/codeql/rust/elements/ArrayType.qll affd43d308200d60d08e8924cdbb2a17a827ebaa62a296e07bb9ce97451e3c4c 80589a7f79bf2ac293a027faf2589b3027a6c4a286533f2ffccad259a306a8cb
|
||||
@@ -57,7 +58,7 @@ lib/codeql/rust/elements/Impl.qll 9593c47af4fa08afb19c52aab7d0bac6740fed7ec60201
|
||||
lib/codeql/rust/elements/ImplTraitType.qll f7241044f6666a509cfbc01bf6df3db5360e67dd0f9baba4a323566701359203 350636d0b1c7a77e006170cbfa9108c259dd5831b0f242da76c10be3ecc32870
|
||||
lib/codeql/rust/elements/IndexExpr.qll 0e2e9f018d06ae72be0fc4ddbc019a9aacd8a06f42b4c4431760bd149e7f2290 2bcfd557abd53a48e48de7915c4f2089107c62dfb3e732a904848248dfd3727b
|
||||
lib/codeql/rust/elements/InferType.qll c71184ae6aa181be94e299882503350e057493e17f1133a1e96162a0e5cbd1ef f0f19b611708df45a6ff811f8066c8042a8e1ac9b7bd94910514547ea430d3d5
|
||||
lib/codeql/rust/elements/Item.qll 5c9148ff0eaeb4404c2d8156e7df0ef5753fd44ead972da05a49659ddaa25480 78446f788617e40525d4d4b489848e75f2143a90e18d40974c3bff7b1e7c825c
|
||||
lib/codeql/rust/elements/Item.qll 59353bf99dea5b464f45ed0dc5cef2db8208e92985d81dcd0b5ea09b638d10e4 2b0b87a4b1a1d9b512a67279d1dec2089d22d1df121585f7a9ca9661d689f74f
|
||||
lib/codeql/rust/elements/ItemList.qll c33e46a9ee45ccb194a0fe5b30a6ad3bcecb0f51486c94e0191a943710a17a7d 5a69c4e7712b4529681c4406d23dc1b6b9e5b3c03552688c55addab271912ed5
|
||||
lib/codeql/rust/elements/Label.qll a31d41db351af7f99a55b26cdbbc7f13b4e96b660a74e2f1cc90c17ee8df8d73 689f87cb056c8a2aefe1a0bfc2486a32feb44eb3175803c61961a6aeee53d66e
|
||||
lib/codeql/rust/elements/LabelableExpr.qll 598be487cd051b004ab95cbbc3029100069dc9955851c492029d80f230e56f0d 92c49b3cfdaba07982f950e18a8d62dae4e96f5d9ae0d7d2f4292628361f0ddc
|
||||
@@ -159,7 +160,7 @@ lib/codeql/rust/elements/Union.qll 92ffb1abc03889b9b71dae9491d4595e443c80b472474
|
||||
lib/codeql/rust/elements/Use.qll e27d30ece0456a73732dfd867dfc5abdf48a50de56e7dafcab444b688610af72 7efe59c04dd2f10b4a25b8a17beb51362be0a93d73e5a9e1251cf133cf1227c3
|
||||
lib/codeql/rust/elements/UseTree.qll 16b6e42146dc4c2e9d8cc6bc143933d675d1a4c9a56b309f390f4bf5df99b25d 9f8dd7d621dd15f6f1ccec676b08da02773673cbb3a3570781c16167c6e08ef4
|
||||
lib/codeql/rust/elements/UseTreeList.qll 768c4ec25e8807bba65619f566b22fa5c0946c36e96c88cfdee04c2875b44554 6433c8d9acd4e346cadd5fef01d79dd35bb6245115bdceb5322c0511106030b0
|
||||
lib/codeql/rust/elements/Variant.qll b0770c3ce0a82dcb2e238024b1db4ee2b76271f5a3d94f03bdaee71a25218da1 af242bd8651b653d931bf4cd3c234bdb58c8516eb4576edc03a929232946c38e
|
||||
lib/codeql/rust/elements/Variant.qll 328323ef59faf01dcf71e7d728fd10a60465a1bd24e1d3578289cdf6554e5b63 ba49c635790395d9df4398c3c0fec700c3c7761fcc6581623a45d381d23ac34d
|
||||
lib/codeql/rust/elements/VariantList.qll 07adfe5750b2d5b50c8629f36feba24edd84f75698a80339d4cee20f4e95829d 7d322e60c84ea45f8c8b509226da7ae3c0125bcda42a98a94e3e6a9855cab79e
|
||||
lib/codeql/rust/elements/Visibility.qll d2cf0727efaf8df6b3808cb4a6b2e26d18e42db766d92e97ad3ef046d91cb9e5 8947a1e2d48b532c6455ddf143fa5b1dff28c40da1f1c6a72769fc9db7ecbaf6
|
||||
lib/codeql/rust/elements/WhereClause.qll da51212766700e40713fff968078a0172a4f73eebc5425d8e0d60b03c2fe59fa 0ec036aea729b8f4af0eb8118911dce715e2eb4640ae7b5e40a007a48da03899
|
||||
@@ -170,6 +171,7 @@ lib/codeql/rust/elements/YeetExpr.qll 4172bf70de31cab17639da6eed4a12a7afcefd7aa9
|
||||
lib/codeql/rust/elements/YieldExpr.qll de2dc096a077f6c57bba9d1c2b2dcdbecce501333753b866d77c3ffbe06aa516 1f3e8949689c09ed356ff4777394fe39f2ed2b1e6c381fd391790da4f5d5c76a
|
||||
lib/codeql/rust/elements/internal/AbiConstructor.qll 4484538db49d7c1d31c139f0f21879fceb48d00416e24499a1d4b1337b4141ac 460818e397f2a1a8f2e5466d9551698b0e569d4640fcb87de6c4268a519b3da1
|
||||
lib/codeql/rust/elements/internal/AbiImpl.qll 01439712ecadc9dc8da6f74d2e19cee13c77f8e1e25699055da675b2c88cb02d dcc9395ef8abd1af3805f3e7fcbc2d7ce30affbce654b6f5e559924768db403c
|
||||
lib/codeql/rust/elements/internal/AddressableImpl.qll e01a6104980960f5708d5a0ada774ba21db9a344e33deeaf3d3239c627268c77 b8bfc711b267df305ac9fe5f6a994f051ddeca7fc95dacd76d1bae2d4fa7adde
|
||||
lib/codeql/rust/elements/internal/ArgListConstructor.qll a73685c8792ae23a2d628e7357658efb3f6e34006ff6e9661863ef116ec0b015 0bee572a046e8dfc031b1216d729843991519d94ae66280f5e795d20aea07a22
|
||||
lib/codeql/rust/elements/internal/ArgListImpl.qll 19664651c06b46530f0ae5745ccb3233afc97b9152e053761d641de6e9c62d38 40af167e571f5c255f264b3be7cc7f5ff42ec109661ca03dcee94e92f8facfc6
|
||||
lib/codeql/rust/elements/internal/ArrayExprConstructor.qll f4ac4efefe5fe4fe1e666f35b1ee92d2243d977b3f3308151c89f61582203c09 4167ae58ec869f7dbd8467093c4a53afd7c1efcf1cc865efa62b4eb484bd7ff8
|
||||
@@ -191,7 +193,6 @@ lib/codeql/rust/elements/internal/BlockExprConstructor.qll 438337c807645e98a0144
|
||||
lib/codeql/rust/elements/internal/BlockExprImpl.qll 36ac09e4a6eeeec22919b62b1d004bdb5bb2527e67932c308aec383a770768d6 3b4b2a2014f6fe075c63a2d633b297566b548ef2e4343cadf067a9edbcadc876
|
||||
lib/codeql/rust/elements/internal/BoxPatConstructor.qll 153f110ba25fd6c889092bfd16f73bb610fa60d6e0c8965d5f44d2446fcd48a2 9324cf0d8aa29945551bf8ab64801d598f57aab8cd4e19bcd4e9ef8a4a4e06eb
|
||||
lib/codeql/rust/elements/internal/BreakExprConstructor.qll 356be043c28e0b34fdf925a119c945632ee883c6f5ebb9a27003c6a8d250afd9 bb77e66b04bb9489340e7506931559b94285c6904b6f9d2f83b214cba4f3cfd5
|
||||
lib/codeql/rust/elements/internal/CallExprBaseImpl.qll d2749cc1a9d7ee8bf7f34b6c3e0238a576a68e439a8c10a503c164ff45ffcbeb ffc7b0a8841945fe6736b0e1aed7d9ed69185db03dee2b16da121325b39397c7
|
||||
lib/codeql/rust/elements/internal/CallExprConstructor.qll 742b38e862e2cf82fd1ecc4d4fc5b4782a9c7c07f031452b2bae7aa59d5aa13a cad6e0a8be21d91b20ac2ec16cab9c30eae810b452c0f1992ed87d5c7f4144dc
|
||||
lib/codeql/rust/elements/internal/CallableImpl.qll 917a7d298583e15246428f32fba4cde6fc57a1790262731be27a96baddd8cf5e c5c0848024e0fe3fbb775e7750cf1a2c2dfa454a5aef0df55fec3d0a6fe99190
|
||||
lib/codeql/rust/elements/internal/CastExprConstructor.qll f3d6e10c4731f38a384675aeab3fba47d17b9e15648293787092bb3247ed808d d738a7751dbadb70aa1dcffcf8af7fa61d4cf8029798369a7e8620013afff4ed
|
||||
@@ -296,7 +297,6 @@ lib/codeql/rust/elements/internal/OrPatConstructor.qll 4ef583e07298487c0c4c6d7c7
|
||||
lib/codeql/rust/elements/internal/ParamBaseImpl.qll fe11999c728c443c46c992e9bed7a2b3e23afa16ae99592e70054bc57ae371b8 df86fdb23266bdfb9ed8a8f02558a760b67f173943b9d075b081229eb5844f66
|
||||
lib/codeql/rust/elements/internal/ParamConstructor.qll b98a2d8969f289fdcc8c0fb11cbd19a3b0c71be038c4a74f5988295a2bae52f0 77d81b31064167945b79b19d9697b57ca24462c3a7cc19e462c4693ce87db532
|
||||
lib/codeql/rust/elements/internal/ParamListConstructor.qll 3123142ab3cab46fb53d7f3eff6ba2d3ff7a45b78839a53dc1979a9c6a54920e 165f3d777ea257cfcf142cc4ba9a0ebcd1902eb99842b8a6657c87087f3df6fe
|
||||
lib/codeql/rust/elements/internal/ParamListImpl.qll 0ed6e9affe1dc0144641502292c2ddd51958fe3d503419caf15198176e3a4174 92d053cc5fdf40a2d98acb665083b5da15403d7da205779a97a4ee66fac0add4
|
||||
lib/codeql/rust/elements/internal/ParenExprConstructor.qll 104b67dc3fd53ab52e2a42ffde37f3a3a50647aa7bf35df9ba9528e9670da210 d1f5937756e87a477710c61698d141cdad0ccce8b07ecb51bab00330a1ca9835
|
||||
lib/codeql/rust/elements/internal/ParenPatConstructor.qll 9aea3c3b677755177d85c63e20234c234f530a16db20ab699de05ca3f1b59787 29f24aed0d880629a53b30550467ade09a0a778dbf88891769c1e11b0b239f98
|
||||
lib/codeql/rust/elements/internal/ParenTypeConstructor.qll d62e656a4a3c8ffd4eb87d49585a7a3bfb5dbe3826fbcbd11cb87b46f34c19ae febf6535965afa0f6eac4d2b08730f5a07bbb36a7434abe0a7663d7264961a3f
|
||||
@@ -332,7 +332,6 @@ lib/codeql/rust/elements/internal/RefTypeConstructor.qll e1952aa69586b440f878400
|
||||
lib/codeql/rust/elements/internal/RefTypeImpl.qll f72b760a8a26be21170435da2cb2981638513617fd82742f45f38bc437d9f2c4 f32df49f0b6df85ca5fc4393ccd341ac4304b4947a282ccea48468a26837ef3d
|
||||
lib/codeql/rust/elements/internal/RenameConstructor.qll 65fa2e938978d154701e6cac05b56320b176ee014ef5c20a7b66f3e94fd5c4a7 dfc0ff4606b8e1c14003cc93a0811f4d62ec993b07ff3c1aa0776746577ed103
|
||||
lib/codeql/rust/elements/internal/RenameImpl.qll 4f5943fbda4ec772203e651ed4b7dd1fb072219ddc0cb208c0a0951af5e72bd6 b9854cdcf02e70ee372330a4e0bfdb03012bc81af79dd12af2a567fd7fc4672b
|
||||
lib/codeql/rust/elements/internal/ResolvableImpl.qll 7599625454fe81c3490a122943363a2a2522a7877b78a80649e93155a418fedd 442072c3d70bdaababd7de8bc6c9382f4a50bab41d13759dcd1a5bee9ea32e49
|
||||
lib/codeql/rust/elements/internal/RestPatConstructor.qll 45430925ddf08fba70ede44c7f413ddb41b3113c149b7efc276e0c2bf72507b4 25c678898d72446e7a975bb8b7f2fde51e55b59dbd42f2cca997c833b1a995f1
|
||||
lib/codeql/rust/elements/internal/RetTypeConstructor.qll a96d803c6e4b40be49cfed0853a3e04ae917c47351e5c880fcab06eddf1af9cc d06a0a191cb14c270c0441ffc3d289263808170dcbe05e01847a35ac9d61dfb3
|
||||
lib/codeql/rust/elements/internal/RetTypeImpl.qll 0e96f1075ccade28ce5664ab0f5c2e98984ae1d0ed708bc02e40e882672d9e2f 350725d16bcb1e8911bfdd87d9dd21be73ec66d23c2a35827c8c8525c48dc885
|
||||
@@ -413,6 +412,7 @@ lib/codeql/rust/elements/internal/YeetExprImpl.qll e8924147c3ebe0c32d04c5b33edfd
|
||||
lib/codeql/rust/elements/internal/YieldExprConstructor.qll 8cbfa6405acb151ee31ccc7c89336948a597d783e8890e5c3e53853850871712 966f685eb6b9063bc359213323d3ff760b536158ecd17608e7618a3e9adf475f
|
||||
lib/codeql/rust/elements/internal/YieldExprImpl.qll af184649a348ddd0be16dee9daae307240bf123ace09243950342e9d71ededd9 17df90f67dd51623e8a5715b344ccd8740c8fc415af092469f801b99caacb70d
|
||||
lib/codeql/rust/elements/internal/generated/Abi.qll 87e1ea6b2a8ebf60e1c69176632740e4e27fc56c3f173939b098ba376562b5fa 94b2121e71c4ec94d53a79f972c05a8484ef0d80ed638f53031e7cf4dc5343d5
|
||||
lib/codeql/rust/elements/internal/generated/Addressable.qll 96a8b45166dd035b8d2c6d36b8b67019f2d4d0b4ccff6d492677c0c87197613e d8f1ce29feafc8ff7179399fc7eac5db031a7e1a8bc6b2cd75cfce1da3132e9b
|
||||
lib/codeql/rust/elements/internal/generated/ArgList.qll 1b75b2d7dcf524eb468a0268af6293e9d17832d6bedf3feec49a535824339b57 2bcaf464454bdfdda45fbd24d063f0f1df0eb69f684197b37105adc8f72cd1ea
|
||||
lib/codeql/rust/elements/internal/generated/ArrayExpr.qll 2ca97b602a707fe2c566002d8709792bb166ae52fdb7da28d7c4b8e0d66dd4bc 1cae1ef017171ec9a1ca28b4f2993b1ee26d22b51b3b04816d9b4e89fdff1fb3
|
||||
lib/codeql/rust/elements/internal/generated/ArrayType.qll 225ac477f67865d72b2a2e17420f5e52c25452a3c14f7ff367f873a859f97783 0030e3bf296dd5b69ea912fc85dc7120b060780033083127257cdca792dc3f4b
|
||||
@@ -428,7 +428,7 @@ lib/codeql/rust/elements/internal/generated/BinaryExpr.qll 64e9bd9c571edd6e5f3e7
|
||||
lib/codeql/rust/elements/internal/generated/BlockExpr.qll 5a5ddbe34bc478a7bd9b0d07d3b6f017c2d1f20581d859251a963314e6514d1f 9804c30b8b279038b864c52557535f854bd012bacdfe8e5840f1f777c74e52df
|
||||
lib/codeql/rust/elements/internal/generated/BoxPat.qll ec946a3e671ab7417e04b0207967adad004df512c570c4f0780ca5816d12d75f b0e64860855c4e85914042b1a51034899ff7cd1b2c6857188de89310a2726ea3
|
||||
lib/codeql/rust/elements/internal/generated/BreakExpr.qll 0f428a8b2f4209b134c2ffc3e1c93c30bc6b0e9c9172f140cefa88c1f77d8690 957b39f38ff6befe9061f55bc0b403c2f1c366dd0cf63b874bae6f8216576d76
|
||||
lib/codeql/rust/elements/internal/generated/CallExpr.qll 23ee64e3bf643cd5e6ff705181d2bb31e1aeaffecb5bdce73836172dbf15f12f 34b280139b1f8f70d78e1432392f03c971be392e8cb68d014eb325d0c101bddd
|
||||
lib/codeql/rust/elements/internal/generated/CallExpr.qll f1b8dae487077cc9d1dccf8c3cd61fd17afe860585f17ce8b860be4859be7ca4 6034fc03778e38802cdf3a6e460364b74e92912622581b31e6179951022bbbd6
|
||||
lib/codeql/rust/elements/internal/generated/CallExprBase.qll cce796e36847249f416629bacf3ea146313084de3374587412e66c10d2917b83 c219aa2174321c161a4a742ca0605521687ca9a5ca32db453a5c62db6f7784cc
|
||||
lib/codeql/rust/elements/internal/generated/Callable.qll b0502b5263b7bcd18e740f284f992c0e600e37d68556e3e0ba54a2ac42b94934 bda3e1eea11cacf5a9b932cd72efc2de6105103e8c575880fcd0cd89daadf068
|
||||
lib/codeql/rust/elements/internal/generated/CastExpr.qll d6fbf02e9e202254666082a9116634d0eb933177866ac4c0a57b5e9c4bb4b383 477f67773492e3b82695461d56327c9db05a7d1a67e8d192406265f2ce369670
|
||||
@@ -470,12 +470,12 @@ lib/codeql/rust/elements/internal/generated/Impl.qll e33ef5d3e49e64beca0ca9d5c0b
|
||||
lib/codeql/rust/elements/internal/generated/ImplTraitType.qll 3c29684f5ef386b883b79dc9758441d97f090e065be177ffc8240aaf0f3d1e7b 03ea42c2a95cf917ec73d88b7b4ca5e53e10d7b046074f59100c0ec6c2c1ed6d
|
||||
lib/codeql/rust/elements/internal/generated/IndexExpr.qll cf951fc40f6690e966b4dc78fa9a6221aa5c6cade44759dcb52254f799292d11 1572e71918cc4e0b7e028331b6d98c9db23100a3646cd3874d1915e06ab6211d
|
||||
lib/codeql/rust/elements/internal/generated/InferType.qll 23ee25135c59ea5578cdf7c34a41f606e217e7260c3c8f404d12836585d5cad4 400da322fa1be62c4e300ebdf481eb92d4226eb6c316c668da8cc5168065774f
|
||||
lib/codeql/rust/elements/internal/generated/Item.qll 25e645cb41222c21065798fb6cb0488bfef007aeb9b89717f58913f9b29d5559 3146941e55db2ff7c51ec030b4414e20d66d154cf6854b1a3fa42e74a09dfb77
|
||||
lib/codeql/rust/elements/internal/generated/Item.qll 97f204f27c12689a01fef502a4eec3b587e4eaccd278ec07a34c70a33ce6119d 139af2d44f794d0f91d9aabc3d50d895107c34bd9bcb72457a2e243c14622e51
|
||||
lib/codeql/rust/elements/internal/generated/ItemList.qll 73c8398a96d4caa47a2dc114d76c657bd3fcc59e4c63cb397ffac4a85b8cf8ab 540a13ca68d414e3727c3d53c6b1cc97687994d572bc74b3df99ecc8b7d8e791
|
||||
lib/codeql/rust/elements/internal/generated/Label.qll 6630fe16e9d2de6c759ff2684f5b9950bc8566a1525c835c131ebb26f3eea63e 671143775e811fd88ec90961837a6c0ee4db96e54f42efd80c5ae2571661f108
|
||||
lib/codeql/rust/elements/internal/generated/LabelableExpr.qll 896fd165b438b60d7169e8f30fa2a94946490c4d284e1bbadfec4253b909ee6c 5c6b029ea0b22cf096df2b15fe6f9384ad3e65b50b253cae7f19a2e5ffb04a58
|
||||
lib/codeql/rust/elements/internal/generated/LetElse.qll 7ca556118b5446bfc85abba8f0edd4970e029b30d414ea824a1b5f568310a76c a403540881336f9d0269cbcdb4b87107a17ab234a985247dc52a380f150a1641
|
||||
lib/codeql/rust/elements/internal/generated/LetExpr.qll 9af0f89b294c8a0a751317e7074fe370339563d36c1df4911d1ea082a4df77fd 68272593d1feb88990bfbd0b8c222776f085e49694894384fc6d96e9464ba734
|
||||
lib/codeql/rust/elements/internal/generated/LetExpr.qll 6f831be1d0f76258d5f74c847636e070a819dee5aa090be0c52a971f261eaff3 e85a48e7492862f738e184f5f1512c2d18d33a0cfb516e269334acf7448b508a
|
||||
lib/codeql/rust/elements/internal/generated/LetStmt.qll aa1852db86ec29f857a90677f0c6b4a07f0fd965fc193d4141be95ce15862fca 40f32a37c0cc161b099fe0b4c7d713da928781d3e2c3de90db991df1d9062647
|
||||
lib/codeql/rust/elements/internal/generated/Lifetime.qll 90d01c76188ce0c053122c62b41e47f27c4c7717ca5a4999a76797360043da0d 7b9feb202da5a06cd17f7770bb66742fd9e7cff0d410fefc7ffaafe710ac16d6
|
||||
lib/codeql/rust/elements/internal/generated/LifetimeArg.qll 7c1a44e3d480e75142b171eb51382c9492d393043833c0ab4a4036eba19043b8 7d8273b62794268dab6938ba1e3a3560a80a2c49cd9a9717345785dacd311059
|
||||
@@ -512,7 +512,7 @@ lib/codeql/rust/elements/internal/generated/ParamList.qll c808c9d84dd7800573832b
|
||||
lib/codeql/rust/elements/internal/generated/ParenExpr.qll bc0731505bfe88516205ec360582a4222d2681d11342c93e15258590ddee82f2 d4bd6e0c80cf1d63746c88d4bcb3a01d4c75732e5da09e3ebd9437ced227fb60
|
||||
lib/codeql/rust/elements/internal/generated/ParenPat.qll ce24b8f8ecbf0f204af200317405724063887257460c80cf250c39b2fdf37185 e7c87d37e1a0ca7ea03840017e1aa9ddb7f927f1f3b6396c0305b46aeee33db6
|
||||
lib/codeql/rust/elements/internal/generated/ParenType.qll 9cc954d73f8330dcac7b475f97748b63af5c8766dee9d2f2872c0a7e4c903537 c07534c8a9c683c4a9b11d490095647e420de0a0bfc23273eaf6f31b00244273
|
||||
lib/codeql/rust/elements/internal/generated/ParentChild.qll 78723cac5f2999f91317f39cf53267043fd2a56e98e838f013eae01b6b39929e 26dd29e5fd868f89982269db6b25aa799be942abdbe41ff1a8ffd4dae4385bdc
|
||||
lib/codeql/rust/elements/internal/generated/ParentChild.qll db7a782f11a14305acc666c865118475e2d324d2bf5d4110b157e1d488b62b75 3b5d31528d0baa0ceee139097e93461d18503797a1507288dc43428f378500e2
|
||||
lib/codeql/rust/elements/internal/generated/Pat.qll 3605ac062be2f294ee73336e9669027b8b655f4ad55660e1eab35266275154ee 7f9400db2884d336dd1d21df2a8093759c2a110be9bf6482ce8e80ae0fd74ed4
|
||||
lib/codeql/rust/elements/internal/generated/Path.qll 4c1c8e840ed57880e574142b081b11d7a7428a009f10e3aa8f4645e211f6b2e0 989668cf0f1bdee7557e2f97c01e41d2a56848227fed41477833f5fc1e1d35f6
|
||||
lib/codeql/rust/elements/internal/generated/PathExpr.qll 2096e3c1db22ee488a761690adabfc9cfdea501c99f7c5d96c0019cb113fc506 54245ce0449c4e263173213df01e079d5168a758503a5dbd61b25ad35a311140
|
||||
@@ -525,7 +525,7 @@ lib/codeql/rust/elements/internal/generated/PtrType.qll 40099c5a4041314b66932dfd
|
||||
lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll ea294a3ba33fd1bc632046c4fedbcb84dcb961a8e4599969d65893b19d90e590 ea294a3ba33fd1bc632046c4fedbcb84dcb961a8e4599969d65893b19d90e590
|
||||
lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9
|
||||
lib/codeql/rust/elements/internal/generated/RangePat.qll efd93730de217cf50dcba5875595263a5eadf9f7e4e1272401342a094d158614 229b251b3d118932e31e78ac4dfb75f48b766f240f20d436062785606d44467b
|
||||
lib/codeql/rust/elements/internal/generated/Raw.qll 9476dd5a6607f722de107b51713c1f529e95429416c7e0d102b78779cf826fe6 b3a4d58fb560c89344ac734cfda3df7f4dcb627c2db79dbe26babd6a67e69dce
|
||||
lib/codeql/rust/elements/internal/generated/Raw.qll 7de290d66bd594f4c5b5a296502792e803e9f1084bb2616d9774196e33b16c87 28150fdd3cff3bb49b407f0c2119602be13e78cbb1f8fd749edd31f5d9772f7a
|
||||
lib/codeql/rust/elements/internal/generated/RecordExpr.qll eb6cb662e463f9260efae1a6ce874fa781172063b916ef1963f861e9942d308d 1a21cbccc8f3799ff13281e822818ebfb21d81591720a427cac3625512cb9d40
|
||||
lib/codeql/rust/elements/internal/generated/RecordExprField.qll 7e9f8663d3b74ebbc9603b10c9912f082febba6bd73d344b100bbd3edf837802 fbe6b578e7fd5d5a6f21bbb8c388957ab7210a6a249ec71510a50fb35b319ea1
|
||||
lib/codeql/rust/elements/internal/generated/RecordExprFieldList.qll 179a97211fe7aa6265085d4d54115cdbc0e1cd7c9b2135591e8f36d6432f13d3 dd44bbbc1e83a1ed3a587afb729d7debf7aeb7b63245de181726af13090e50c0
|
||||
@@ -551,7 +551,7 @@ lib/codeql/rust/elements/internal/generated/Static.qll 5fbd6879858cf356d4bdaa6da
|
||||
lib/codeql/rust/elements/internal/generated/Stmt.qll 8473ff532dd5cc9d7decaddcd174b94d610f6ca0aec8e473cc051dad9f3db917 6ef7d2b5237c2dbdcacbf7d8b39109d4dc100229f2b28b5c9e3e4fbf673ba72b
|
||||
lib/codeql/rust/elements/internal/generated/StmtList.qll a667193e32341e17400867c6e359878c4e645ef9f5f4d97676afc0283a33a026 a320ed678ee359302e2fc1b70a9476705cd616fcfa44a499d32f0c7715627f73
|
||||
lib/codeql/rust/elements/internal/generated/Struct.qll 4d57f0db12dc7ad3e31e750a24172ef1505406b4dab16386af0674bd18bf8f4b 1a73c83df926b996f629316f74c61ea775be04532ab61b56af904223354f033e
|
||||
lib/codeql/rust/elements/internal/generated/Synth.qll db8ffbd55def03f0b0278cafa60274220eb571257da36e185f380e3c5b2caedf 19074971c3e96a43414738976c9625385c4bbac6b01c7eca2f46432034a279b7
|
||||
lib/codeql/rust/elements/internal/generated/Synth.qll 65873a7fa44e223edc5e76cc768591a036eb2550960a6b6882476f43a01aefba 3e08e2bdfba53ae26d8f48f2d240b92b44c603f03105518c37a963e0cbe63e3f
|
||||
lib/codeql/rust/elements/internal/generated/SynthConstructors.qll e929c49ea60810a2bbc19ad38110b8bbaf21db54dae90393b21a3459a54abf6f e929c49ea60810a2bbc19ad38110b8bbaf21db54dae90393b21a3459a54abf6f
|
||||
lib/codeql/rust/elements/internal/generated/Token.qll 77a91a25ca5669703cf3a4353b591cef4d72caa6b0b9db07bb9e005d69c848d1 2fdffc4882ed3a6ca9ac6d1fb5f1ac5a471ca703e2ffdc642885fa558d6e373b
|
||||
lib/codeql/rust/elements/internal/generated/TokenTree.qll 8577c2b097c1be2f0f7daa5acfcf146f78674a424d99563e08a84dd3e6d91b46 d2f30764e84dbfc0a6a5d3d8a5f935cd432413688cb32da9c94e420fbc10665c
|
||||
@@ -577,7 +577,7 @@ lib/codeql/rust/elements/internal/generated/Union.qll 06a602aa7c7097e72fff6ea33d
|
||||
lib/codeql/rust/elements/internal/generated/Use.qll d42ccf3516a9f79ae8766f93ad5f09d3cdcd7b96844d4c9de64189b56018a7b4 70a9553a8f71f6cbfdd0f59a4b42292d13177613ceb0542436436e0ac2e1f8ee
|
||||
lib/codeql/rust/elements/internal/generated/UseTree.qll b39cbc96e473802372726d580febbfa7d73668ba476095aa4a61fae914865913 40ce6515b7df068fa8c0a7e5ae8984f50b71f6f96d625d631b28d525e3e868b7
|
||||
lib/codeql/rust/elements/internal/generated/UseTreeList.qll 829441cf309f008a6a9d2e784aa414ab4c11880a658f8ee71aa4df385cd2b6a8 ced82df94fea7a191f414f7e6496d13791d2f535046844b6f712a390663ac3d0
|
||||
lib/codeql/rust/elements/internal/generated/Variant.qll 2e3d8e7a7a97f2f33d6cad458ec0ded498c17a14b697722a96fffecd50c83097 46149bb257c08d5cd9139198b6519d7ad3fd25cc9ea6bfe99deea66f5f1ef201
|
||||
lib/codeql/rust/elements/internal/generated/Variant.qll e40dbb23e07c5b70adc577efdf7a064e773207f216cad8fe8905882b1da9f4a9 13f7be36d043afcfc156d2c01bb828de882df69aa732f284aa76c5f00b063544
|
||||
lib/codeql/rust/elements/internal/generated/VariantList.qll 4eb923ca341033c256ca9b8a8a5b4e14c7eac9d015be187fd97eeb25dfb1e18e e7865e975c35db49cd72cb8f9864797d3cfed16c3a675b5032b867ced2bbb405
|
||||
lib/codeql/rust/elements/internal/generated/Visibility.qll aba81820f30bed0fd2cd06831f7256af15ae32525b2a437896420b4cc067ea38 d6aed90b27124b812daf2ddd14b4e181277cbe638b4ccaab74e27681ac30e4ab
|
||||
lib/codeql/rust/elements/internal/generated/WhereClause.qll d6c8f72bbec5d71c024f0d365c1c5e474f4d24ded0d34c56c1f66b1e4a384e9d ed14311d140eee00d3b26a4972f53e20d5af1bddf88fb5618e7e2d3ae1d816f3
|
||||
@@ -586,7 +586,7 @@ lib/codeql/rust/elements/internal/generated/WhileExpr.qll 7edf1f23fbf953a2baabcd
|
||||
lib/codeql/rust/elements/internal/generated/WildcardPat.qll d74b70b57a0a66bfae017a329352a5b27a6b9e73dd5521d627f680e810c6c59e 4b913b548ba27ff3c82fcd32cf996ff329cb57d176d3bebd0fcef394486ea499
|
||||
lib/codeql/rust/elements/internal/generated/YeetExpr.qll cac328200872a35337b4bcb15c851afb4743f82c080f9738d295571eb01d7392 94af734eea08129b587fed849b643e7572800e8330c0b57d727d41abda47930b
|
||||
lib/codeql/rust/elements/internal/generated/YieldExpr.qll 37e5f0c1e373a22bbc53d8b7f2c0e1f476e5be5080b8437c5e964f4e83fad79a 4a9a68643401637bf48e5c2b2f74a6bf0ddcb4ff76f6bffb61d436b685621e85
|
||||
lib/codeql/rust/elements.qll 83bda9f3bc481aaecc039db9cecb628495e15e469cc843336ca089f0d707f8d6 83bda9f3bc481aaecc039db9cecb628495e15e469cc843336ca089f0d707f8d6
|
||||
lib/codeql/rust/elements.qll ced76fbeebc6e2e972ecaed65ef97851f90a215cf330f28a0f31a253f1c03442 ced76fbeebc6e2e972ecaed65ef97851f90a215cf330f28a0f31a253f1c03442
|
||||
test/extractor-tests/generated/Abi/Abi.ql 7f6e7dc4af86eca3ebdc79b10373988cd0871bd78b51997d3cffd969105e5fdd 2f936b6ca005c6157c755121584410c03e4a3949c23bee302fbe05ee10ce118f
|
||||
test/extractor-tests/generated/Abi/Abi_getAbiString.ql a496762fcec5a0887b87023bbf93e9b650f02e20113e25c44d6e4281ae8f5335 14109c7ce11ba25e3cd6e7f1b3fcb4cb00622f2a4eac91bfe43145c5f366bc52
|
||||
test/extractor-tests/generated/ArgList/ArgList.ql e412927756e72165d0e7c5c9bd3fca89d08197bbf760db8fb7683c64bb2229bc 043dba8506946fbb87753e22c387987d7eded6ddb963aa067f9e60ef9024d684
|
||||
@@ -632,10 +632,10 @@ test/extractor-tests/generated/BreakExpr/BreakExpr.ql cdde2855d98f658187c60b9edc
|
||||
test/extractor-tests/generated/BreakExpr/BreakExpr_getAttr.ql c7690a9aab1923bf3c2fb06f0a1d441d480b3c91ee1df3a868bbbd96c4042053 c592dd077fb6e22b2d6ddcaec37da2c5a26ba92d84f5d1ae4c78a615b9013765
|
||||
test/extractor-tests/generated/BreakExpr/BreakExpr_getExpr.ql 0358f4fe6a66da56177703cf0e991042729c5e34ae8b6dccbb827f95fe936c72 1cb2dd778c50e19fe04c5fdf3a08a502635ea8303e71ff38d03aa7dc53213986
|
||||
test/extractor-tests/generated/BreakExpr/BreakExpr_getLifetime.ql ad83cc0db3c0f959fef6bb7ce0938d241a877e8cf84d15fb63879be2fe47238c 240b2fe2156b763d3a82fc64159615872db65b65ffb9ba2f3fd5d1ebd6c60f34
|
||||
test/extractor-tests/generated/CallExpr/CallExpr.ql 69d88b3c799f6e81fe53fe04724ed6c1cbfbfcc21023dd62aed3a3f852c6a2aa 0caa94802919d30bf2749d8a1c58545163e2b1cad5490f19158b5e5063806443
|
||||
test/extractor-tests/generated/CallExpr/CallExpr.ql ffb0cf1cb359a6dcbdf792a570c281e2d300779dca2dbc0f324990652adb972f 978a9e6c82758f9e8b334a682a02d6b893a6bf1db3cd85e9535839a9696b09b4
|
||||
test/extractor-tests/generated/CallExpr/CallExpr_getArgList.ql b022e7b6b6db9932e787e37b7760c6a09c91140a0368940374a2c919688e0488 c20849c96b53c96f6f717efff5e8b4c0e900c0ef5d715cfbaf7101c7056ad8f4
|
||||
test/extractor-tests/generated/CallExpr/CallExpr_getAttr.ql 1ace458070875b9ff2c671c2ee18392ea7bf6e51b68ee98d412c8606e8eb8d33 4c35da8255d2975cef4adee15623662441bb8f2e1d73582e4c193d1bc11cc1b5
|
||||
test/extractor-tests/generated/CallExpr/CallExpr_getExpr.ql f680f04423ece282c459d5908e5aa0bc43ca072ff0e605587dfa94210da1d06d f8a709015b8317b8e2dcf3b3ee9370e2c3a655ef7e3c6034b1b90f4d75ebdda2
|
||||
test/extractor-tests/generated/CallExpr/CallExpr_getFunction.ql 060a6c8b5b85c839b14fe96f9e50291a7a0e5662a945f4f337070f782ec76715 e9a1e44433936146d87be939aa160848b9a7d7333c36da601fb7d1a66d71eb59
|
||||
test/extractor-tests/generated/CastExpr/CastExpr.ql 2ffb22ebc6e47953a49162488b3605d36b9d89330b1e71187066e7bbc40a22ad 7621a39d49f573b9862b9a4e1021d53205670ee59b49e4d81128637926f76485
|
||||
test/extractor-tests/generated/CastExpr/CastExpr_getAttr.ql 5d5d98172e495cdb8b5cea9d6588c4c245107b441464e3ffd6c27668af11ab4e 5820bf083aaa4c3275004a2cd9eeecc4b45ab96916cbc0655a1b42611c540715
|
||||
test/extractor-tests/generated/CastExpr/CastExpr_getExpr.ql c37186b8f3e3dab8ae28c0da7263ff7272c40501beb16736ec0fb8990d285e22 59d50d7349234afcf84986b7570db9dcd342e16812f7c46199d4736cdfa5462d
|
||||
@@ -777,10 +777,10 @@ test/extractor-tests/generated/Label/Label.ql 6a92a27d615dd9c380cb9d889eecf827fc
|
||||
test/extractor-tests/generated/Label/Label_getLifetime.ql 3d6ddc3b44182e6432e938d5c1c95e0281575e320d517e431f6bad7748efb93e 56d07e485cb5e4263443eb5a0d62d7d4456bb0c2748331b371e519bfe14d3b81
|
||||
test/extractor-tests/generated/LetElse/LetElse.ql bdf2b17d5efe6b9cb5bb4fcfe854a5fcd72443d39ae1e7981d2a0459c481e394 a14a611d0783ae38d631600c2bde7409f4e739ba2f284314b90ec9a21c23ab3a
|
||||
test/extractor-tests/generated/LetElse/LetElse_getBlockExpr.ql 32c21ad843884944738a735f01e272032a347d1860fa6d27d17652c549f941b0 2bfd8a5e3d42eb1c73eb679ada847dd29f2f0657a0ad8ef15da126e54fff5ef5
|
||||
test/extractor-tests/generated/LetExpr/LetExpr.ql a25072a00cfe1242dc846b38199c000ed7217d33fdd50d2763237fdfda7b9449 8c9367af79d9fbc98ed2fe62450929fa876512f1c999615b5c1ecff082fdc7bc
|
||||
test/extractor-tests/generated/LetExpr/LetExpr.ql c76a0c4aaa73f4064207dacc8d2c649d3a5f8046c0f6e1aae985d2402a342e73 c5abe3845d4975d05c98ee6496732da384cdaca60ed49235776338e6dbe80b3d
|
||||
test/extractor-tests/generated/LetExpr/LetExpr_getAttr.ql 911b143afebaa0a487b13d533f089c5b0eaf336a44a4cab42147c284338484ba 625c91fb6d8c2e3a9f13e5679cc0cd29329c6c2b213d2e1191e23db2b65841dd
|
||||
test/extractor-tests/generated/LetExpr/LetExpr_getExpr.ql ccabfaa15cfc8685e86cb950cb62b7f2fec278f28906ab34deb97b308f160cc4 e0574537d47a77f1be85090970f3e1263858174479002fd4de3f85b777ee4336
|
||||
test/extractor-tests/generated/LetExpr/LetExpr_getPat.ql bc0363f77bc2ba583619ab7d309293ace0ed6a851bfb9b886f75729f96eb40a8 bc0cd9233b7904d8cc7f9021377120f5f4bcc5c7aa28b1b55f17bc738c434d78
|
||||
test/extractor-tests/generated/LetExpr/LetExpr_getScrutinee.ql ee33d3bbaf0ee7cdf9bd7b800e9684b5ac7ce8cf1939378cd460cb0c5ea11742 5d69e727b3e9d1ab4ce9eef702a7b1911515469625056bce87fac1d27ba863e6
|
||||
test/extractor-tests/generated/LetStmt/LetStmt.ql 02db64303bfe87a11a85663e4c79bdabd9ca13693f146c7923b47c4c92850fcc 9ec1326b8bc58b270b178a4c02621b1650d107de7c02a9408d97c59f0d8a6178
|
||||
test/extractor-tests/generated/LetStmt/LetStmt_getAttr.ql 68f69c4c054514140c0f0833a170e9f3facf950bd7af663ac9019f6c88ba0ea7 ca54d25cc052289458c7e34e40f0304bca2c412cecfb407f31279262bd74c15a
|
||||
test/extractor-tests/generated/LetStmt/LetStmt_getInitializer.ql 6a5f0eed3ce3e8cbc57be6ec2b4eed732f00e084108d21a61d9ab28b65e494ca a48b426b97a6c347ad04fe2e592cd25b5c66b2a6a299cbf8c0da03e14304fd70
|
||||
@@ -1097,9 +1097,11 @@ test/extractor-tests/generated/UseTree/UseTree_getRename.ql ec3917501f3c89ac4974
|
||||
test/extractor-tests/generated/UseTree/UseTree_getUseTreeList.ql c265a88347e813840969ae934dfd2904bc06f502de77709bc0b1c7255e46382a 52a239c8ea5fd8fbfbd606559d70ecadc769887437a9bcab6fb3e774208ad868
|
||||
test/extractor-tests/generated/UseTreeList/UseTreeList.ql cd943c15c86e66244caafeb95b960a5c3d351d5edbd506258744fb60a61af3b2 cfa584cd9d8aa08267fd1106745a66226b2c99fadd1da65059cc7ecf2f2e68cf
|
||||
test/extractor-tests/generated/UseTreeList/UseTreeList_getUseTree.ql dd72966b1cb7b04f0267503013809063fcfb145e2b2d7d5250d9f24d2e405f9a 75b953aa11c51ca0fe95e67d50d6238962d8df4a4b9054999a2c6338e5a5613d
|
||||
test/extractor-tests/generated/Variant/Variant.ql bf9b928ab3b1911e6c81fdc3fb9811e754ea28bfd0e4a21dca08b844aa42c3f1 bffd4bcc5019f721010722453985b39a4285240774e474e233ebe46f1cd5beb1
|
||||
test/extractor-tests/generated/Variant/Variant.ql c60dd31adac91e09f8b1e5523d6b859747e64ef072c077b5a3326763f9f461f7 55d6446a3a831ed1137264678c5df027eb94cb3570a88d364994851fe6236999
|
||||
test/extractor-tests/generated/Variant/Variant_getAttr.ql dd38e48e1eb05ce280b880652a90010eb63f7de3be7232411ba6265691249420 f8980680104de1e5fd40f264d8d62346aacaf6403a5e051f6fd680e234c82c1f
|
||||
test/extractor-tests/generated/Variant/Variant_getCrateOrigin.ql 99e79930f8ff87a25f256926e5c3ce1ee0847daf6fadc5445fb33c85328b4c61 2dd64a53813790654c83be25b5e175c9c5b388e758723c2138fff095353fdd7b
|
||||
test/extractor-tests/generated/Variant/Variant_getExpr.ql ce00af303d28f60c5fd1dc7df628c7974aced21884e223a2f656cb4f0d1a74d5 9de51a65510cf9a15801d4207b616915bd959c95ec7330fdb502c5dff5b650cc
|
||||
test/extractor-tests/generated/Variant/Variant_getExtendedCanonicalPath.ql fe6a4bfd1440e7629d47283910de84c5e8c2f5645512780e710f53540b5bc886 b1e31b765cb1a5fe063abb8c1b2115e881ae28aa3ccd39e088ff8f2af20d6cf4
|
||||
test/extractor-tests/generated/Variant/Variant_getFieldList.ql 083c8cf61989663de33d99b72dec231c308ccc8bb6739921465c473a07e8ea03 d03bff6945853c940acdc053b813d53b008ddab9a8bd4307826433828d4763ce
|
||||
test/extractor-tests/generated/Variant/Variant_getName.ql 0d7b47bec9f9031c67f7b684112a84a311ef9b2efeb260bd7cd6f424011ca0d8 73565e6f965dd7fd7bb9b3408c7d7b69120e1971b67ab307fed293eb663a59ae
|
||||
test/extractor-tests/generated/Variant/Variant_getVisibility.ql 2c8f365d28d96af55589f4d71ac3fee718b319b4cbc784560c0591d1f605a119 13160d9cf39fe169410eff6c338f5d063e1948109e8f18dd33ea0064f1dd9283
|
||||
|
||||
12
rust/ql/.gitattributes
generated
vendored
12
rust/ql/.gitattributes
generated
vendored
@@ -2,6 +2,7 @@
|
||||
/.gitattributes linguist-generated
|
||||
/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll linguist-generated
|
||||
/lib/codeql/rust/elements/Abi.qll linguist-generated
|
||||
/lib/codeql/rust/elements/Addressable.qll linguist-generated
|
||||
/lib/codeql/rust/elements/ArgList.qll linguist-generated
|
||||
/lib/codeql/rust/elements/ArrayExpr.qll linguist-generated
|
||||
/lib/codeql/rust/elements/ArrayType.qll linguist-generated
|
||||
@@ -172,6 +173,7 @@
|
||||
/lib/codeql/rust/elements/YieldExpr.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/AbiConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/AbiImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/AddressableImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ArgListConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ArgListImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ArrayExprConstructor.qll linguist-generated
|
||||
@@ -193,7 +195,6 @@
|
||||
/lib/codeql/rust/elements/internal/BlockExprImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/BoxPatConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/BreakExprConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/CallExprBaseImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/CallExprConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/CallableImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/CastExprConstructor.qll linguist-generated
|
||||
@@ -298,7 +299,6 @@
|
||||
/lib/codeql/rust/elements/internal/ParamBaseImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamListConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamListImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParenExprConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParenPatConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParenTypeConstructor.qll linguist-generated
|
||||
@@ -334,7 +334,6 @@
|
||||
/lib/codeql/rust/elements/internal/RefTypeImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/RenameConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/RenameImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ResolvableImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/RestPatConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/RetTypeConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/RetTypeImpl.qll linguist-generated
|
||||
@@ -415,6 +414,7 @@
|
||||
/lib/codeql/rust/elements/internal/YieldExprConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/YieldExprImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/Abi.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/Addressable.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/ArgList.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/ArrayExpr.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/generated/ArrayType.qll linguist-generated
|
||||
@@ -637,7 +637,7 @@
|
||||
/test/extractor-tests/generated/CallExpr/CallExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/CallExpr/CallExpr_getArgList.ql linguist-generated
|
||||
/test/extractor-tests/generated/CallExpr/CallExpr_getAttr.ql linguist-generated
|
||||
/test/extractor-tests/generated/CallExpr/CallExpr_getExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/CallExpr/CallExpr_getFunction.ql linguist-generated
|
||||
/test/extractor-tests/generated/CastExpr/CastExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/CastExpr/CastExpr_getAttr.ql linguist-generated
|
||||
/test/extractor-tests/generated/CastExpr/CastExpr_getExpr.ql linguist-generated
|
||||
@@ -781,8 +781,8 @@
|
||||
/test/extractor-tests/generated/LetElse/LetElse_getBlockExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/LetExpr/LetExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/LetExpr/LetExpr_getAttr.ql linguist-generated
|
||||
/test/extractor-tests/generated/LetExpr/LetExpr_getExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/LetExpr/LetExpr_getPat.ql linguist-generated
|
||||
/test/extractor-tests/generated/LetExpr/LetExpr_getScrutinee.ql linguist-generated
|
||||
/test/extractor-tests/generated/LetStmt/LetStmt.ql linguist-generated
|
||||
/test/extractor-tests/generated/LetStmt/LetStmt_getAttr.ql linguist-generated
|
||||
/test/extractor-tests/generated/LetStmt/LetStmt_getInitializer.ql linguist-generated
|
||||
@@ -1101,7 +1101,9 @@
|
||||
/test/extractor-tests/generated/UseTreeList/UseTreeList_getUseTree.ql linguist-generated
|
||||
/test/extractor-tests/generated/Variant/Variant.ql linguist-generated
|
||||
/test/extractor-tests/generated/Variant/Variant_getAttr.ql linguist-generated
|
||||
/test/extractor-tests/generated/Variant/Variant_getCrateOrigin.ql linguist-generated
|
||||
/test/extractor-tests/generated/Variant/Variant_getExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/Variant/Variant_getExtendedCanonicalPath.ql linguist-generated
|
||||
/test/extractor-tests/generated/Variant/Variant_getFieldList.ql linguist-generated
|
||||
/test/extractor-tests/generated/Variant/Variant_getName.ql linguist-generated
|
||||
/test/extractor-tests/generated/Variant/Variant_getVisibility.ql linguist-generated
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import pytest
|
||||
import shutil
|
||||
import json
|
||||
import commands
|
||||
import pathlib
|
||||
|
||||
class _Manifests:
|
||||
def __init__(self, cwd):
|
||||
self.dir = cwd / "manifests"
|
||||
|
||||
def select(self, name: str):
|
||||
(self.dir / name).rename(name)
|
||||
shutil.rmtree(self.dir)
|
||||
def cargo(cwd):
|
||||
assert (cwd / "Cargo.toml").exists()
|
||||
(cwd / "rust-project.json").unlink(missing_ok=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def manifests(cwd):
|
||||
return _Manifests(cwd)
|
||||
def rust_project(cwd):
|
||||
project_file = cwd / "rust-project.json"
|
||||
assert project_file.exists()
|
||||
rust_sysroot = pathlib.Path(commands.run("rustc --print sysroot", _capture=True))
|
||||
project = json.loads(project_file.read_text())
|
||||
project["sysroot_src"] = str(rust_sysroot.joinpath("lib", "rustlib", "src", "rust", "library"))
|
||||
project_file.write_text(json.dumps(project, indent=4))
|
||||
(cwd / "Cargo.toml").unlink(missing_ok=True)
|
||||
|
||||
@pytest.fixture
|
||||
def rust_check_diagnostics(check_diagnostics):
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
queries/diagnostics/ExtractionErrors.ql
|
||||
@@ -0,0 +1 @@
|
||||
| src/directory_module/not_loaded.rs:1:1:1:1 | semantic analyzer unavailable (not included as a module) | Extraction warning in src/directory_module/not_loaded.rs with message semantic analyzer unavailable (not included as a module) | 1 |
|
||||
@@ -0,0 +1 @@
|
||||
queries/diagnostics/ExtractionWarnings.ql
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"sysroot_src": "filled by the rust_project fixture",
|
||||
"crates": [{
|
||||
"root_module": "src/main.rs",
|
||||
"edition": "2021",
|
||||
17
rust/ql/integration-tests/hello-project/summary.expected
Normal file
17
rust/ql/integration-tests/hello-project/summary.expected
Normal file
@@ -0,0 +1,17 @@
|
||||
| Elements extracted | 50 |
|
||||
| Elements unextracted | 0 |
|
||||
| Extraction errors | 0 |
|
||||
| Extraction warnings | 1 |
|
||||
| Files extracted - total | 5 |
|
||||
| Files extracted - with errors | 1 |
|
||||
| Files extracted - without errors | 4 |
|
||||
| Inconsistencies - AST | 0 |
|
||||
| Inconsistencies - CFG | 0 |
|
||||
| Inconsistencies - data flow | 0 |
|
||||
| Lines of code extracted | 6 |
|
||||
| Lines of user code extracted | 6 |
|
||||
| Macro calls - resolved | 2 |
|
||||
| Macro calls - total | 2 |
|
||||
| Macro calls - unresolved | 0 |
|
||||
| Taint sources - active | 0 |
|
||||
| Taint sources - total | 0 |
|
||||
1
rust/ql/integration-tests/hello-project/summary.qlref
Normal file
1
rust/ql/integration-tests/hello-project/summary.qlref
Normal file
@@ -0,0 +1 @@
|
||||
queries/summary/SummaryStats.ql
|
||||
@@ -2,11 +2,9 @@ import pytest
|
||||
|
||||
|
||||
@pytest.mark.ql_test("steps.ql", expected=".cargo.expected")
|
||||
def test_cargo(codeql, rust, manifests, check_source_archive, rust_check_diagnostics):
|
||||
manifests.select("Cargo.toml")
|
||||
def test_cargo(codeql, rust, cargo, check_source_archive, rust_check_diagnostics):
|
||||
codeql.database.create()
|
||||
|
||||
@pytest.mark.ql_test("steps.ql", expected=".rust-project.expected")
|
||||
def test_rust_project(codeql, rust, manifests, check_source_archive, rust_check_diagnostics):
|
||||
manifests.select("rust-project.json")
|
||||
def test_rust_project(codeql, rust, rust_project, check_source_archive, rust_check_diagnostics):
|
||||
codeql.database.create()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
queries/diagnostics/ExtractionErrors.ql
|
||||
@@ -0,0 +1 @@
|
||||
queries/diagnostics/ExtractionWarnings.ql
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"sysroot_src": "filled by the rust_project fixture",
|
||||
"crates": [
|
||||
{
|
||||
"root_module": "exe/src/main.rs",
|
||||
17
rust/ql/integration-tests/hello-workspace/summary.expected
Normal file
17
rust/ql/integration-tests/hello-workspace/summary.expected
Normal file
@@ -0,0 +1,17 @@
|
||||
| Elements extracted | 72 |
|
||||
| Elements unextracted | 0 |
|
||||
| Extraction errors | 0 |
|
||||
| Extraction warnings | 0 |
|
||||
| Files extracted - total | 4 |
|
||||
| Files extracted - with errors | 0 |
|
||||
| Files extracted - without errors | 4 |
|
||||
| Inconsistencies - AST | 0 |
|
||||
| Inconsistencies - CFG | 0 |
|
||||
| Inconsistencies - data flow | 0 |
|
||||
| Lines of code extracted | 9 |
|
||||
| Lines of user code extracted | 9 |
|
||||
| Macro calls - resolved | 2 |
|
||||
| Macro calls - total | 2 |
|
||||
| Macro calls - unresolved | 0 |
|
||||
| Taint sources - active | 0 |
|
||||
| Taint sources - total | 0 |
|
||||
1
rust/ql/integration-tests/hello-workspace/summary.qlref
Normal file
1
rust/ql/integration-tests/hello-workspace/summary.qlref
Normal file
@@ -0,0 +1 @@
|
||||
queries/summary/SummaryStats.ql
|
||||
@@ -2,13 +2,11 @@ import pytest
|
||||
|
||||
|
||||
@pytest.mark.ql_test("steps.ql", expected=".cargo.expected")
|
||||
def test_cargo(codeql, rust, manifests, check_source_archive, rust_check_diagnostics):
|
||||
def test_cargo(codeql, rust, cargo, check_source_archive, rust_check_diagnostics):
|
||||
rust_check_diagnostics.expected_suffix = ".cargo.expected"
|
||||
manifests.select("Cargo.toml")
|
||||
codeql.database.create()
|
||||
|
||||
@pytest.mark.ql_test("steps.ql", expected=".rust-project.expected")
|
||||
def test_rust_project(codeql, rust, manifests, check_source_archive, rust_check_diagnostics):
|
||||
def test_rust_project(codeql, rust, rust_project, check_source_archive, rust_check_diagnostics):
|
||||
rust_check_diagnostics.expected_suffix = ".rust-project.expected"
|
||||
manifests.select("rust-project.json")
|
||||
codeql.database.create()
|
||||
|
||||
@@ -187,9 +187,37 @@ final class RecordExprCfgNode extends Nodes::RecordExprCfgNode {
|
||||
|
||||
RecordExprCfgNode() { node = this.getRecordExpr() }
|
||||
|
||||
/** Gets the `i`th record expression. */
|
||||
ExprCfgNode getExpr(int i) {
|
||||
any(ChildMapping mapping)
|
||||
.hasCfgChild(node, node.getRecordExprFieldList().getField(i).getExpr(), this, result)
|
||||
/** Gets the record expression for the field `field`. */
|
||||
pragma[nomagic]
|
||||
ExprCfgNode getFieldExpr(string field) {
|
||||
exists(RecordExprField ref |
|
||||
ref = node.getRecordExprFieldList().getAField() and
|
||||
any(ChildMapping mapping).hasCfgChild(node, ref.getExpr(), this, result) and
|
||||
field = ref.getNameRef().getText()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A record pattern. For example:
|
||||
* ```rust
|
||||
* match x {
|
||||
* Foo { a: 1, b: 2 } => "ok",
|
||||
* Foo { .. } => "fail",
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final class RecordPatCfgNode extends Nodes::RecordPatCfgNode {
|
||||
private RecordPatChildMapping node;
|
||||
|
||||
RecordPatCfgNode() { node = this.getRecordPat() }
|
||||
|
||||
/** Gets the record pattern for the field `field`. */
|
||||
PatCfgNode getFieldPat(string field) {
|
||||
exists(RecordPatField rpf |
|
||||
rpf = node.getRecordPatFieldList().getAField() and
|
||||
any(ChildMapping mapping).hasCfgChild(node, rpf.getPat(), this, result) and
|
||||
field = rpf.getNameRef().getText()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,12 @@ class RecordExprChildMapping extends ParentAstNode, RecordExpr {
|
||||
}
|
||||
}
|
||||
|
||||
class RecordPatChildMapping extends ParentAstNode, RecordPat {
|
||||
override predicate relevantChild(AstNode child) {
|
||||
child = this.getRecordPatFieldList().getAField().getPat()
|
||||
}
|
||||
}
|
||||
|
||||
class FormatArgsExprChildMapping extends ParentAstNode, CfgImpl::ExprTrees::FormatArgsExprTree {
|
||||
override predicate relevantChild(AstNode child) { child = this.getChildNode(_) }
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ module ExprTrees {
|
||||
|
||||
class CallExprTree extends StandardPostOrderTree instanceof CallExpr {
|
||||
override AstNode getChildNode(int i) {
|
||||
i = 0 and result = super.getExpr()
|
||||
i = 0 and result = super.getFunction()
|
||||
or
|
||||
result = super.getArgList().getArg(i - 1)
|
||||
}
|
||||
@@ -410,7 +410,7 @@ module ExprTrees {
|
||||
class LetExprTree extends StandardPreOrderTree, LetExpr {
|
||||
override AstNode getChildNode(int i) {
|
||||
i = 0 and
|
||||
result = this.getExpr()
|
||||
result = this.getScrutinee()
|
||||
or
|
||||
i = 1 and
|
||||
result = this.getPat()
|
||||
|
||||
@@ -570,7 +570,7 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
|
||||
override predicate relevantChild(AstNode child) {
|
||||
none()
|
||||
or
|
||||
child = this.getExpr()
|
||||
child = this.getFunction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,16 +592,16 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
|
||||
CallExpr getCallExpr() { result = node }
|
||||
|
||||
/**
|
||||
* Gets the expression of this call expression, if it exists.
|
||||
* Gets the function of this call expression, if it exists.
|
||||
*/
|
||||
ExprCfgNode getExpr() {
|
||||
any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result)
|
||||
ExprCfgNode getFunction() {
|
||||
any(ChildMapping mapping).hasCfgChild(node, node.getFunction(), this, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `getExpr()` exists.
|
||||
* Holds if `getFunction()` exists.
|
||||
*/
|
||||
predicate hasExpr() { exists(this.getExpr()) }
|
||||
predicate hasFunction() { exists(this.getFunction()) }
|
||||
}
|
||||
|
||||
final private class ParentCallExprBase extends ParentAstNode, CallExprBase {
|
||||
@@ -1245,7 +1245,7 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
|
||||
override predicate relevantChild(AstNode child) {
|
||||
none()
|
||||
or
|
||||
child = this.getExpr()
|
||||
child = this.getScrutinee()
|
||||
or
|
||||
child = this.getPat()
|
||||
}
|
||||
@@ -1283,16 +1283,16 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
|
||||
int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) }
|
||||
|
||||
/**
|
||||
* Gets the expression of this let expression, if it exists.
|
||||
* Gets the scrutinee of this let expression, if it exists.
|
||||
*/
|
||||
ExprCfgNode getExpr() {
|
||||
any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result)
|
||||
ExprCfgNode getScrutinee() {
|
||||
any(ChildMapping mapping).hasCfgChild(node, node.getScrutinee(), this, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `getExpr()` exists.
|
||||
* Holds if `getScrutinee()` exists.
|
||||
*/
|
||||
predicate hasExpr() { exists(this.getExpr()) }
|
||||
predicate hasScrutinee() { exists(this.getScrutinee()) }
|
||||
|
||||
/**
|
||||
* Gets the pat of this let expression, if it exists.
|
||||
@@ -3211,14 +3211,14 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
|
||||
cfgNode
|
||||
)
|
||||
or
|
||||
pred = "getExpr" and
|
||||
pred = "getFunction" and
|
||||
parent =
|
||||
any(Nodes::CallExprCfgNode cfgNode, CallExpr astNode |
|
||||
astNode = cfgNode.getCallExpr() and
|
||||
child = getDesugared(astNode.getExpr()) and
|
||||
child = getDesugared(astNode.getFunction()) and
|
||||
i = -1 and
|
||||
hasCfgNode(child) and
|
||||
not child = cfgNode.getExpr().getAstNode()
|
||||
not child = cfgNode.getFunction().getAstNode()
|
||||
|
|
||||
cfgNode
|
||||
)
|
||||
@@ -3355,14 +3355,14 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
|
||||
cfgNode
|
||||
)
|
||||
or
|
||||
pred = "getExpr" and
|
||||
pred = "getScrutinee" and
|
||||
parent =
|
||||
any(Nodes::LetExprCfgNode cfgNode, LetExpr astNode |
|
||||
astNode = cfgNode.getLetExpr() and
|
||||
child = getDesugared(astNode.getExpr()) and
|
||||
child = getDesugared(astNode.getScrutinee()) and
|
||||
i = -1 and
|
||||
hasCfgNode(child) and
|
||||
not child = cfgNode.getExpr().getAstNode()
|
||||
not child = cfgNode.getScrutinee().getAstNode()
|
||||
|
|
||||
cfgNode
|
||||
)
|
||||
|
||||
@@ -19,6 +19,12 @@ module DataFlow {
|
||||
|
||||
final class PostUpdateNode = Node::PostUpdateNode;
|
||||
|
||||
final class Content = DataFlowImpl::Content;
|
||||
|
||||
final class VariantContent = DataFlowImpl::VariantContent;
|
||||
|
||||
final class ContentSet = DataFlowImpl::ContentSet;
|
||||
|
||||
/**
|
||||
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step.
|
||||
|
||||
@@ -115,6 +115,11 @@ module Node {
|
||||
*/
|
||||
ExprCfgNode asExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets the pattern that corresponds to this node, if any.
|
||||
*/
|
||||
PatCfgNode asPat() { none() }
|
||||
|
||||
/** Gets the enclosing callable. */
|
||||
DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) }
|
||||
|
||||
@@ -177,8 +182,7 @@ module Node {
|
||||
|
||||
PatNode() { this = TPatNode(n) }
|
||||
|
||||
/** Gets the `PatCfgNode` in the CFG that this node corresponds to. */
|
||||
PatCfgNode getPat() { result = n }
|
||||
override PatCfgNode asPat() { result = n }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,8 +326,7 @@ module LocalFlow {
|
||||
nodeFrom.(Node::AstCfgFlowNode).getCfgNode() =
|
||||
nodeTo.(Node::SsaNode).getDefinitionExt().(Ssa::WriteDefinition).getControlFlowNode()
|
||||
or
|
||||
nodeFrom.(Node::ParameterNode).getParameter().(ParamCfgNode).getPat() =
|
||||
nodeTo.(Node::PatNode).getPat()
|
||||
nodeFrom.(Node::ParameterNode).getParameter().(ParamCfgNode).getPat() = nodeTo.asPat()
|
||||
or
|
||||
SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _)
|
||||
or
|
||||
@@ -331,18 +334,165 @@ module LocalFlow {
|
||||
a.getRhs() = nodeFrom.getCfgNode() and
|
||||
a.getLhs() = nodeTo.getCfgNode()
|
||||
)
|
||||
or
|
||||
exists(MatchExprCfgNode match |
|
||||
nodeFrom.asExpr() = match.getScrutinee() and
|
||||
nodeTo.asPat() = match.getArmPat(_)
|
||||
)
|
||||
or
|
||||
nodeFrom.asPat().(OrPatCfgNode).getAPat() = nodeTo.asPat()
|
||||
}
|
||||
}
|
||||
|
||||
private class DataFlowCallableAlias = DataFlowCallable;
|
||||
private import codeql.util.Option
|
||||
|
||||
private class ReturnKindAlias = ReturnKind;
|
||||
private class CrateOrigin extends string {
|
||||
CrateOrigin() {
|
||||
this = [any(Item i).getCrateOrigin(), any(Resolvable r).getResolvedCrateOrigin()]
|
||||
}
|
||||
}
|
||||
|
||||
private class DataFlowCallAlias = DataFlowCall;
|
||||
private class CrateOriginOption = Option<CrateOrigin>::Option;
|
||||
|
||||
private class ParameterPositionAlias = ParameterPosition;
|
||||
pragma[nomagic]
|
||||
private predicate hasExtendedCanonicalPath(Item i, CrateOriginOption crate, string path) {
|
||||
path = i.getExtendedCanonicalPath() and
|
||||
(
|
||||
crate.asSome() = i.getCrateOrigin()
|
||||
or
|
||||
crate.isNone() and
|
||||
not i.hasCrateOrigin()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate variantHasExtendedCanonicalPath(
|
||||
Enum e, Variant v, CrateOriginOption crate, string path, string name
|
||||
) {
|
||||
hasExtendedCanonicalPath(e, crate, path) and
|
||||
v = e.getVariantList().getAVariant() and
|
||||
name = v.getName().getText()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate resolveExtendedCanonicalPath(Resolvable r, CrateOriginOption crate, string path) {
|
||||
path = r.getResolvedPath() and
|
||||
(
|
||||
crate.asSome() = r.getResolvedCrateOrigin()
|
||||
or
|
||||
crate.isNone() and
|
||||
not r.hasResolvedCrateOrigin()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A path to a value contained in an object. For example a field name of a struct.
|
||||
*/
|
||||
abstract class Content extends TContent {
|
||||
/** Gets a textual representation of this content. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/** A canonical path pointing to an enum variant. */
|
||||
private class VariantCanonicalPath extends MkVariantCanonicalPath {
|
||||
CrateOriginOption crate;
|
||||
string path;
|
||||
string name;
|
||||
|
||||
VariantCanonicalPath() { this = MkVariantCanonicalPath(crate, path, name) }
|
||||
|
||||
/** Gets the underlying variant. */
|
||||
Variant getVariant() { variantHasExtendedCanonicalPath(_, result, crate, path, name) }
|
||||
|
||||
string toString() { result = name }
|
||||
|
||||
Location getLocation() { result = this.getVariant().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variant of an `enum`. In addition to the variant itself, this also includes the
|
||||
* position (for tuple variants) or the field name (for record variants).
|
||||
*/
|
||||
abstract class VariantContent extends Content { }
|
||||
|
||||
/** A tuple variant. */
|
||||
private class VariantPositionContent extends VariantContent, TVariantPositionContent {
|
||||
private VariantCanonicalPath v;
|
||||
private int pos_;
|
||||
|
||||
VariantPositionContent() { this = TVariantPositionContent(v, pos_) }
|
||||
|
||||
VariantCanonicalPath getVariantCanonicalPath(int pos) { result = v and pos = pos_ }
|
||||
|
||||
final override string toString() {
|
||||
// only print indices when the arity is > 1
|
||||
if exists(TVariantPositionContent(v, 1))
|
||||
then result = v.toString() + "(" + pos_ + ")"
|
||||
else result = v.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/** A record variant. */
|
||||
private class VariantFieldContent extends VariantContent, TVariantFieldContent {
|
||||
private VariantCanonicalPath v;
|
||||
private string field_;
|
||||
|
||||
VariantFieldContent() { this = TVariantFieldContent(v, field_) }
|
||||
|
||||
VariantCanonicalPath getVariantCanonicalPath(string field) { result = v and field = field_ }
|
||||
|
||||
final override string toString() {
|
||||
// only print field when the arity is > 1
|
||||
if strictcount(string f | exists(TVariantFieldContent(v, f))) > 1
|
||||
then result = v.toString() + "{" + field_ + "}"
|
||||
else result = v.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/** A value that represents a set of `Content`s. */
|
||||
abstract class ContentSet extends TContentSet {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
abstract Content getAStoreContent();
|
||||
|
||||
/** Gets a content that may be read from when reading from this set. */
|
||||
abstract Content getAReadContent();
|
||||
}
|
||||
|
||||
final private class SingletonContentSet extends ContentSet, TSingletonContentSet {
|
||||
private Content c;
|
||||
|
||||
SingletonContentSet() { this = TSingletonContentSet(c) }
|
||||
|
||||
Content getContent() { result = c }
|
||||
|
||||
override string toString() { result = c.toString() }
|
||||
|
||||
override Content getAStoreContent() { result = c }
|
||||
|
||||
override Content getAReadContent() { result = c }
|
||||
}
|
||||
|
||||
// Defines a set of aliases needed for the `RustDataFlow` module
|
||||
private module Aliases {
|
||||
class DataFlowCallableAlias = DataFlowCallable;
|
||||
|
||||
class ReturnKindAlias = ReturnKind;
|
||||
|
||||
class DataFlowCallAlias = DataFlowCall;
|
||||
|
||||
class ParameterPositionAlias = ParameterPosition;
|
||||
|
||||
class ContentAlias = Content;
|
||||
|
||||
class ContentSetAlias = ContentSet;
|
||||
}
|
||||
|
||||
module RustDataFlow implements InputSig<Location> {
|
||||
private import Aliases
|
||||
|
||||
/**
|
||||
* An element, viewed as a node in a data flow graph. Either an expression
|
||||
* (`ExprNode`) or a parameter (`ParameterNode`).
|
||||
@@ -388,56 +538,9 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
final class ReturnKind = ReturnKindAlias;
|
||||
|
||||
private import codeql.util.Option
|
||||
|
||||
private class CrateOrigin extends string {
|
||||
CrateOrigin() {
|
||||
this = [any(Item i).getCrateOrigin(), any(Resolvable r).getResolvedCrateOrigin()]
|
||||
}
|
||||
}
|
||||
|
||||
private class CrateOriginOption = Option<CrateOrigin>::Option;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasExtendedCanonicalPath(
|
||||
DataFlowCallable c, CrateOriginOption crate, string path
|
||||
) {
|
||||
exists(Item i |
|
||||
i = c.asCfgScope() and
|
||||
path = i.getExtendedCanonicalPath()
|
||||
|
|
||||
crate.asSome() = i.getCrateOrigin()
|
||||
or
|
||||
crate.isNone() and
|
||||
not i.hasCrateOrigin()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate resolvesExtendedCanonicalPath(
|
||||
DataFlowCall c, CrateOriginOption crate, string path
|
||||
) {
|
||||
exists(Resolvable r |
|
||||
path = r.getResolvedPath() and
|
||||
(
|
||||
r = c.asMethodCallExprCfgNode().getExpr()
|
||||
or
|
||||
r = c.asCallExprCfgNode().getExpr().(PathExprCfgNode).getPath()
|
||||
)
|
||||
|
|
||||
crate.asSome() = r.getResolvedCrateOrigin()
|
||||
or
|
||||
crate.isNone() and
|
||||
not r.hasResolvedCrateOrigin()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a viable implementation of the target of the given `Call`. */
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
exists(string path, CrateOriginOption crate |
|
||||
hasExtendedCanonicalPath(result, crate, path) and
|
||||
resolvesExtendedCanonicalPath(call, crate, path)
|
||||
)
|
||||
result.asCfgScope() = call.asCallBaseExprCfgNode().getCallExprBase().getStaticTarget()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -450,30 +553,23 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
// NOTE: For now we use the type `Unit` and do not benefit from type
|
||||
// information in the data flow analysis.
|
||||
final class DataFlowType = Unit;
|
||||
final class DataFlowType extends Unit {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() }
|
||||
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
||||
|
||||
final class Content = Void;
|
||||
class Content = ContentAlias;
|
||||
|
||||
class ContentSet = ContentSetAlias;
|
||||
|
||||
predicate forceHighPrecision(Content c) { none() }
|
||||
|
||||
class ContentSet extends TContentSet {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "ContentSet" }
|
||||
final class ContentApprox = Content; // TODO: Implement if needed
|
||||
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
Content getAStoreContent() { none() }
|
||||
|
||||
/** Gets a content that may be read from when reading from this set. */
|
||||
Content getAReadContent() { none() }
|
||||
}
|
||||
|
||||
final class ContentApprox = Void;
|
||||
|
||||
ContentApprox getContentApprox(Content c) { any() }
|
||||
ContentApprox getContentApprox(Content c) { result = c }
|
||||
|
||||
class ParameterPosition = ParameterPositionAlias;
|
||||
|
||||
@@ -501,19 +597,95 @@ module RustDataFlow implements InputSig<Location> {
|
||||
*/
|
||||
predicate jumpStep(Node node1, Node node2) { none() }
|
||||
|
||||
/** Holds if path `p` resolves to variant `v`. */
|
||||
private predicate pathResolveToVariantCanonicalPath(Path p, VariantCanonicalPath v) {
|
||||
exists(CrateOriginOption crate, string path |
|
||||
resolveExtendedCanonicalPath(p.getQualifier(), crate, path) and
|
||||
v = MkVariantCanonicalPath(crate, path, p.getPart().getNameRef().getText())
|
||||
)
|
||||
or
|
||||
// TODO: Remove once library types are extracted
|
||||
not p.hasQualifier() and
|
||||
v = MkVariantCanonicalPath(_, "crate::std::option::Option", p.getPart().getNameRef().getText())
|
||||
or
|
||||
// TODO: Remove once library types are extracted
|
||||
not p.hasQualifier() and
|
||||
v = MkVariantCanonicalPath(_, "crate::std::result::Result", p.getPart().getNameRef().getText())
|
||||
}
|
||||
|
||||
/** Holds if `p` destructs an enum variant `v`. */
|
||||
pragma[nomagic]
|
||||
private predicate tupleVariantDestruction(TupleStructPat p, VariantCanonicalPath v) {
|
||||
pathResolveToVariantCanonicalPath(p.getPath(), v)
|
||||
}
|
||||
|
||||
/** Holds if `p` destructs an enum variant `v`. */
|
||||
pragma[nomagic]
|
||||
private predicate recordVariantDestruction(RecordPat p, VariantCanonicalPath v) {
|
||||
pathResolveToVariantCanonicalPath(p.getPath(), v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
|
||||
* `node1` references an object with a content `c.getAReadContent()` whose
|
||||
* value ends up in `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) { none() }
|
||||
predicate readStep(Node node1, ContentSet cs, Node node2) {
|
||||
exists(Content c | c = cs.(SingletonContentSet).getContent() |
|
||||
exists(TupleStructPatCfgNode pat, int pos |
|
||||
pat = node1.asPat() and
|
||||
tupleVariantDestruction(pat.getPat(),
|
||||
c.(VariantPositionContent).getVariantCanonicalPath(pos)) and
|
||||
node2.asPat() = pat.getField(pos)
|
||||
)
|
||||
or
|
||||
exists(RecordPatCfgNode pat, string field |
|
||||
pat = node1.asPat() and
|
||||
recordVariantDestruction(pat.getPat(),
|
||||
c.(VariantFieldContent).getVariantCanonicalPath(field)) and
|
||||
node2.asPat() = pat.getFieldPat(field)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `ce` constructs an enum value of type `v`. */
|
||||
pragma[nomagic]
|
||||
private predicate tupleVariantConstruction(CallExpr ce, VariantCanonicalPath v) {
|
||||
pathResolveToVariantCanonicalPath(ce.getFunction().(PathExpr).getPath(), v)
|
||||
}
|
||||
|
||||
/** Holds if `re` constructs an enum value of type `v`. */
|
||||
pragma[nomagic]
|
||||
private predicate recordVariantConstruction(RecordExpr re, VariantCanonicalPath v) {
|
||||
pathResolveToVariantCanonicalPath(re.getPath(), v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a store into `c`. Thus,
|
||||
* `node2` references an object with a content `c.getAStoreContent()` that
|
||||
* contains the value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { none() }
|
||||
predicate storeStep(Node node1, ContentSet cs, Node node2) {
|
||||
exists(Content c | c = cs.(SingletonContentSet).getContent() |
|
||||
node2.asExpr() =
|
||||
any(CallExprCfgNode call, int pos |
|
||||
tupleVariantConstruction(call.getCallExpr(),
|
||||
c.(VariantPositionContent).getVariantCanonicalPath(pos)) and
|
||||
node1.asExpr() = call.getArgument(pos)
|
||||
|
|
||||
call
|
||||
)
|
||||
or
|
||||
node2.asExpr() =
|
||||
any(RecordExprCfgNode re, string field |
|
||||
recordVariantConstruction(re.getRecordExpr(),
|
||||
c.(VariantFieldContent).getVariantCanonicalPath(field)) and
|
||||
node1.asExpr() = re.getFieldExpr(field)
|
||||
|
|
||||
re
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`. For example,
|
||||
@@ -580,8 +752,6 @@ module RustDataFlow implements InputSig<Location> {
|
||||
class DataFlowSecondLevelScope = Void;
|
||||
}
|
||||
|
||||
final class ContentSet = RustDataFlow::ContentSet;
|
||||
|
||||
import MakeImpl<Location, RustDataFlow>
|
||||
|
||||
/** A collection of cached types and predicates to be evaluated in the same stage. */
|
||||
@@ -598,14 +768,6 @@ private module Cached {
|
||||
cached
|
||||
newtype TDataFlowCall = TCall(CallExprBaseCfgNode c)
|
||||
|
||||
cached
|
||||
newtype TOptionalContentSet =
|
||||
TAnyElementContent() or
|
||||
TAnyContent()
|
||||
|
||||
cached
|
||||
class TContentSet = TAnyElementContent or TAnyContent;
|
||||
|
||||
cached
|
||||
newtype TDataFlowCallable = TCfgScope(CfgScope scope)
|
||||
|
||||
@@ -621,6 +783,42 @@ private module Cached {
|
||||
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
|
||||
} or
|
||||
TSelfParameterPosition()
|
||||
|
||||
cached
|
||||
newtype TVariantCanonicalPath =
|
||||
MkVariantCanonicalPath(CrateOriginOption crate, string path, string name) {
|
||||
variantHasExtendedCanonicalPath(_, _, crate, path, name)
|
||||
or
|
||||
// TODO: Remove once library types are extracted
|
||||
crate.isNone() and
|
||||
path = "crate::std::option::Option" and
|
||||
name = "Some"
|
||||
or
|
||||
// TODO: Remove once library types are extracted
|
||||
crate.isNone() and
|
||||
path = "crate::std::result::Result" and
|
||||
name = ["Ok", "Err"]
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TContent =
|
||||
TVariantPositionContent(VariantCanonicalPath v, int pos) {
|
||||
pos in [0 .. v.getVariant().getFieldList().(TupleFieldList).getNumberOfFields() - 1]
|
||||
or
|
||||
// TODO: Remove once library types are extracted
|
||||
v = MkVariantCanonicalPath(_, "crate::std::option::Option", "Some") and
|
||||
pos = 0
|
||||
or
|
||||
// TODO: Remove once library types are extracted
|
||||
v = MkVariantCanonicalPath(_, "crate::std::result::Result", ["Ok", "Err"]) and
|
||||
pos = 0
|
||||
} or
|
||||
TVariantFieldContent(VariantCanonicalPath v, string field) {
|
||||
field = v.getVariant().getFieldList().(RecordFieldList).getAField().getName().getText()
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TContentSet = TSingletonContentSet(Content c)
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
@@ -24,6 +24,8 @@ predicate variableWrite(AstNode write, Variable v) {
|
||||
not isUnitializedLet(pat, v)
|
||||
)
|
||||
or
|
||||
exists(SelfParam self | self = write and self = v.getSelfParam())
|
||||
or
|
||||
exists(VariableAccess access |
|
||||
access = write and
|
||||
access.getVariable() = v
|
||||
@@ -477,7 +479,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
none() // handled in `DataFlowImpl.qll` instead
|
||||
}
|
||||
|
||||
class Parameter = CfgNodes::ParamCfgNode;
|
||||
class Parameter = CfgNodes::ParamBaseCfgNode;
|
||||
|
||||
/** Holds if SSA definition `def` initializes parameter `p` at function entry. */
|
||||
predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) {
|
||||
|
||||
1
rust/ql/lib/codeql/rust/elements.qll
generated
1
rust/ql/lib/codeql/rust/elements.qll
generated
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import codeql.rust.elements.Abi
|
||||
import codeql.rust.elements.Addressable
|
||||
import codeql.rust.elements.ArgList
|
||||
import codeql.rust.elements.ArrayExpr
|
||||
import codeql.rust.elements.ArrayType
|
||||
|
||||
14
rust/ql/lib/codeql/rust/elements/Addressable.qll
generated
Normal file
14
rust/ql/lib/codeql/rust/elements/Addressable.qll
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
// generated by codegen, do not edit
|
||||
/**
|
||||
* This module provides the public class `Addressable`.
|
||||
*/
|
||||
|
||||
private import internal.AddressableImpl
|
||||
import codeql.rust.elements.AstNode
|
||||
|
||||
/**
|
||||
* Something that can be addressed by a path.
|
||||
*
|
||||
* TODO: This does not yet include all possible cases.
|
||||
*/
|
||||
final class Addressable = Impl::Addressable;
|
||||
1
rust/ql/lib/codeql/rust/elements/Item.qll
generated
1
rust/ql/lib/codeql/rust/elements/Item.qll
generated
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
private import internal.ItemImpl
|
||||
import codeql.rust.elements.Addressable
|
||||
import codeql.rust.elements.Stmt
|
||||
|
||||
/**
|
||||
|
||||
2
rust/ql/lib/codeql/rust/elements/Variant.qll
generated
2
rust/ql/lib/codeql/rust/elements/Variant.qll
generated
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
private import internal.VariantImpl
|
||||
import codeql.rust.elements.AstNode
|
||||
import codeql.rust.elements.Addressable
|
||||
import codeql.rust.elements.Attr
|
||||
import codeql.rust.elements.Expr
|
||||
import codeql.rust.elements.FieldList
|
||||
|
||||
21
rust/ql/lib/codeql/rust/elements/internal/AddressableImpl.qll
generated
Normal file
21
rust/ql/lib/codeql/rust/elements/internal/AddressableImpl.qll
generated
Normal file
@@ -0,0 +1,21 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module provides a hand-modifiable wrapper around the generated class `Addressable`.
|
||||
*
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.Addressable
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the customizable definition of `Addressable` and should not
|
||||
* be referenced directly.
|
||||
*/
|
||||
module Impl {
|
||||
/**
|
||||
* Something that can be addressed by a path.
|
||||
*
|
||||
* TODO: This does not yet include all possible cases.
|
||||
*/
|
||||
class Addressable extends Generated::Addressable { }
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module provides a hand-modifiable wrapper around the generated class `CallExprBase`.
|
||||
*
|
||||
@@ -12,8 +11,27 @@ private import codeql.rust.elements.internal.generated.CallExprBase
|
||||
* be referenced directly.
|
||||
*/
|
||||
module Impl {
|
||||
private import codeql.rust.elements.internal.CallableImpl::Impl
|
||||
private import codeql.rust.elements.internal.MethodCallExprImpl::Impl
|
||||
private import codeql.rust.elements.internal.CallExprImpl::Impl
|
||||
private import codeql.rust.elements.internal.PathExprImpl::Impl
|
||||
|
||||
pragma[nomagic]
|
||||
private Resolvable getCallResolvable(CallExprBase call) {
|
||||
result = call.(MethodCallExpr)
|
||||
or
|
||||
result = call.(CallExpr).getFunction().(PathExpr).getPath()
|
||||
}
|
||||
|
||||
// the following QLdoc is generated: if you need to edit it, do it in the schema file
|
||||
/**
|
||||
* A function or method call expression. See `CallExpr` and `MethodCallExpr` for further details.
|
||||
*/
|
||||
class CallExprBase extends Generated::CallExprBase { }
|
||||
class CallExprBase extends Generated::CallExprBase {
|
||||
/**
|
||||
* Gets the target callable of this call, if a unique such target can
|
||||
* be statically resolved.
|
||||
*/
|
||||
Callable getStaticTarget() { getCallResolvable(this).resolvesAsItem(result) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@ module Impl {
|
||||
* ```
|
||||
*/
|
||||
class CallExpr extends Generated::CallExpr {
|
||||
override string toString() { result = this.getExpr().toAbbreviatedString() + "(...)" }
|
||||
override string toString() { result = this.getFunction().toAbbreviatedString() + "(...)" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ module Impl {
|
||||
or
|
||||
index = 1 and result = this.getPat().toAbbreviatedString()
|
||||
or
|
||||
index = 2 and result = "= " + this.getExpr().toAbbreviatedString()
|
||||
index = 2 and result = "= " + this.getScrutinee().toAbbreviatedString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user