mirror of
https://github.com/github/codeql.git
synced 2026-05-25 08:37:20 +02:00
Compare commits
4 Commits
esbena/pr-
...
hmac/comma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9afdab917e | ||
|
|
1915fce2d1 | ||
|
|
7a5b72b8f1 | ||
|
|
02794d95d4 |
@@ -6,7 +6,7 @@
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 6.5
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/system-data-exposure
|
||||
* @tags security
|
||||
* external/cwe/cwe-497
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/system-data-exposure` query has been increased from `medium` to `high` precision, following a number of improvements to the query logic.
|
||||
@@ -51,7 +51,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut)
|
||||
{
|
||||
var pattern = string.IsNullOrEmpty(args) ? cmd : cmd + " " + args;
|
||||
var pattern = cmd + " " + args;
|
||||
RunProcessIn.Add(pattern);
|
||||
|
||||
if (!RunProcessOut.TryGetValue(pattern, out var str))
|
||||
@@ -62,7 +62,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
RunProcessWorkingDirectory.TryGetValue(pattern, out var wd);
|
||||
|
||||
if (wd != workingDirectory)
|
||||
throw new ArgumentException($"Unexpected RunProcessWorkingDirectory, got {wd ?? "null"} expected {workingDirectory ?? "null"} in {pattern}");
|
||||
throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern);
|
||||
|
||||
if (!RunProcess.TryGetValue(pattern, out var ret))
|
||||
throw new ArgumentException("Missing RunProcess " + pattern);
|
||||
@@ -72,12 +72,12 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env)
|
||||
{
|
||||
var pattern = string.IsNullOrEmpty(args) ? cmd : cmd + " " + args;
|
||||
var pattern = cmd + " " + args;
|
||||
RunProcessIn.Add(pattern);
|
||||
RunProcessWorkingDirectory.TryGetValue(pattern, out var wd);
|
||||
|
||||
if (wd != workingDirectory)
|
||||
throw new ArgumentException($"Unexpected RunProcessWorkingDirectory, got {wd ?? "null"} expected {workingDirectory ?? "null"} in {pattern}");
|
||||
throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern);
|
||||
|
||||
if (!RunProcess.TryGetValue(pattern, out var ret))
|
||||
throw new ArgumentException("Missing RunProcess " + pattern);
|
||||
@@ -255,7 +255,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
[Fact]
|
||||
public void TestAnd1()
|
||||
{
|
||||
var cmd = BuildScript.Create("abc", "def ghi", false, null, null) & BuildScript.Create("codeql", null, false, null, null);
|
||||
var cmd = BuildScript.Create("abc", "def ghi", false, null, null) & BuildScript.Create("odasa", null, false, null, null);
|
||||
|
||||
actions.RunProcess["abc def ghi"] = 1;
|
||||
cmd.Run(actions, StartCallback, EndCallback);
|
||||
@@ -269,14 +269,14 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
[Fact]
|
||||
public void TestAnd2()
|
||||
{
|
||||
var cmd = BuildScript.Create("codeql", null, false, null, null) & BuildScript.Create("abc", "def ghi", false, null, null);
|
||||
var cmd = BuildScript.Create("odasa", null, false, null, null) & BuildScript.Create("abc", "def ghi", false, null, null);
|
||||
|
||||
actions.RunProcess["abc def ghi"] = 1;
|
||||
actions.RunProcess["codeql"] = 0;
|
||||
actions.RunProcess["odasa "] = 0;
|
||||
cmd.Run(actions, StartCallback, EndCallback);
|
||||
|
||||
Assert.Equal("codeql", actions.RunProcessIn[0]);
|
||||
Assert.Equal("codeql", startCallbackIn[0]);
|
||||
Assert.Equal("odasa ", actions.RunProcessIn[0]);
|
||||
Assert.Equal("odasa ", startCallbackIn[0]);
|
||||
Assert.Equal("", endCallbackIn[0]);
|
||||
Assert.Equal(0, endCallbackReturn[0]);
|
||||
|
||||
@@ -289,14 +289,14 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
[Fact]
|
||||
public void TestOr1()
|
||||
{
|
||||
var cmd = BuildScript.Create("codeql", null, false, null, null) | BuildScript.Create("abc", "def ghi", false, null, null);
|
||||
var cmd = BuildScript.Create("odasa", null, false, null, null) | BuildScript.Create("abc", "def ghi", false, null, null);
|
||||
|
||||
actions.RunProcess["abc def ghi"] = 1;
|
||||
actions.RunProcess["codeql"] = 0;
|
||||
actions.RunProcess["odasa "] = 0;
|
||||
cmd.Run(actions, StartCallback, EndCallback);
|
||||
|
||||
Assert.Equal("codeql", actions.RunProcessIn[0]);
|
||||
Assert.Equal("codeql", startCallbackIn[0]);
|
||||
Assert.Equal("odasa ", actions.RunProcessIn[0]);
|
||||
Assert.Equal("odasa ", startCallbackIn[0]);
|
||||
Assert.Equal("", endCallbackIn[0]);
|
||||
Assert.Equal(0, endCallbackReturn[0]);
|
||||
Assert.Equal(1, endCallbackReturn.Count);
|
||||
@@ -305,10 +305,10 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
[Fact]
|
||||
public void TestOr2()
|
||||
{
|
||||
var cmd = BuildScript.Create("abc", "def ghi", false, null, null) | BuildScript.Create("codeql", null, false, null, null);
|
||||
var cmd = BuildScript.Create("abc", "def ghi", false, null, null) | BuildScript.Create("odasa", null, false, null, null);
|
||||
|
||||
actions.RunProcess["abc def ghi"] = 1;
|
||||
actions.RunProcess["codeql"] = 0;
|
||||
actions.RunProcess["odasa "] = 0;
|
||||
cmd.Run(actions, StartCallback, EndCallback);
|
||||
|
||||
Assert.Equal("abc def ghi", actions.RunProcessIn[0]);
|
||||
@@ -316,8 +316,8 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
Assert.Equal("", endCallbackIn[0]);
|
||||
Assert.Equal(1, endCallbackReturn[0]);
|
||||
|
||||
Assert.Equal("codeql", actions.RunProcessIn[1]);
|
||||
Assert.Equal("codeql", startCallbackIn[1]);
|
||||
Assert.Equal("odasa ", actions.RunProcessIn[1]);
|
||||
Assert.Equal("odasa ", startCallbackIn[1]);
|
||||
Assert.Equal("", endCallbackIn[1]);
|
||||
Assert.Equal(0, endCallbackReturn[1]);
|
||||
}
|
||||
@@ -385,6 +385,9 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
|
||||
actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
|
||||
actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = isWindows ? "win64" : "linux64";
|
||||
actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
|
||||
actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java";
|
||||
actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools";
|
||||
actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion;
|
||||
actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments;
|
||||
actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform;
|
||||
@@ -413,7 +416,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.RunProcess["cmd.exe /C dotnet --info"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C dotnet clean C:\Project\test.csproj"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C dotnet restore C:\Project\test.csproj"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project\test.csproj"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project\test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project\test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -440,7 +443,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.RunProcess["dotnet --info"] = 0;
|
||||
actions.RunProcess[@"dotnet clean C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"dotnet restore C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project/test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -598,7 +601,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
[Fact]
|
||||
public void TestLinuxBuildCommand()
|
||||
{
|
||||
actions.RunProcess["./build.sh --skip-tests"] = 0;
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto ""./build.sh --skip-tests"""] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = "";
|
||||
@@ -619,8 +622,8 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = "";
|
||||
actions.RunProcess[@"/bin/chmod u+x C:\Project/build/build.sh"] = 0;
|
||||
actions.RunProcess[@"C:\Project/build/build.sh"] = 0;
|
||||
actions.RunProcessWorkingDirectory[@"C:\Project/build/build.sh"] = @"C:\Project/build";
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/build/build.sh"] = 0;
|
||||
actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto C:\Project/build/build.sh"] = @"C:\Project/build";
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder(false);
|
||||
@@ -636,8 +639,8 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = "";
|
||||
|
||||
actions.RunProcess[@"/bin/chmod u+x C:\Project/build.sh"] = 0;
|
||||
actions.RunProcess[@"C:\Project/build.sh"] = 0;
|
||||
actions.RunProcessWorkingDirectory[@"C:\Project/build.sh"] = @"C:\Project";
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/build.sh"] = 0;
|
||||
actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto C:\Project/build.sh"] = @"C:\Project";
|
||||
actions.FileExists["csharp.log"] = false;
|
||||
|
||||
var autobuilder = CreateAutoBuilder(false);
|
||||
@@ -653,8 +656,8 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = "";
|
||||
|
||||
actions.RunProcess[@"/bin/chmod u+x C:\Project/build.sh"] = 0;
|
||||
actions.RunProcess[@"C:\Project/build.sh"] = 5;
|
||||
actions.RunProcessWorkingDirectory[@"C:\Project/build.sh"] = @"C:\Project";
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/build.sh"] = 5;
|
||||
actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto C:\Project/build.sh"] = @"C:\Project";
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder(false);
|
||||
@@ -668,8 +671,8 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = "";
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\build.bat"] = 0;
|
||||
actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\Project\build.bat"] = @"C:\Project";
|
||||
actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\build.bat"] = 0;
|
||||
actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\build.bat"] = @"C:\Project";
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder(true);
|
||||
@@ -683,10 +686,10 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = "";
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\build.bat"] = 1;
|
||||
actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\Project\build.bat"] = @"C:\Project";
|
||||
actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\build.bat"] = 1;
|
||||
actions.RunProcessWorkingDirectory[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\build.bat"] = @"C:\Project";
|
||||
actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\codeql\tools\codeql index --xml --extensions config"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
|
||||
var autobuilder = CreateAutoBuilder(true, ignoreErrors: "true");
|
||||
@@ -696,9 +699,9 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
[Fact]
|
||||
public void TestWindowsCmdIgnoreErrors()
|
||||
{
|
||||
actions.RunProcess["cmd.exe /C ^\"build.cmd --skip-tests^\""] = 3;
|
||||
actions.RunProcess["cmd.exe /C C:\\odasa\\tools\\odasa index --auto ^\"build.cmd --skip-tests^\""] = 3;
|
||||
actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\codeql\tools\codeql index --xml --extensions config"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
SkipVsWhere();
|
||||
|
||||
@@ -715,9 +718,9 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
public void TestWindowCSharpMsBuild()
|
||||
{
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test1.sln -DisableParallelProcessing"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test2.sln -DisableParallelProcessing"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false;
|
||||
@@ -746,9 +749,9 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
public void TestWindowCSharpMsBuildMultipleSolutions()
|
||||
{
|
||||
actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test1.csproj -DisableParallelProcessing"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test2.csproj -DisableParallelProcessing"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project\test1.csproj"] = true;
|
||||
actions.FileExists[@"C:\Project\test2.csproj"] = true;
|
||||
@@ -791,7 +794,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
public void TestWindowCSharpMsBuildFailed()
|
||||
{
|
||||
actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test1.sln -DisableParallelProcessing"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 1;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 1;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false;
|
||||
@@ -817,8 +820,8 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
[Fact]
|
||||
public void TestSkipNugetMsBuild()
|
||||
{
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false;
|
||||
actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false;
|
||||
@@ -862,7 +865,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.RunProcess["dotnet --info"] = 0;
|
||||
actions.RunProcess[@"dotnet clean C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"dotnet restore C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"dotnet build --no-incremental /p:UseSharedCompilation=false --no-restore C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false --no-restore C:\Project/test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project/test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -894,7 +897,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0;
|
||||
actions.RunProcess[@"C:\Project/.dotnet/dotnet clean C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"C:\Project/.dotnet/dotnet restore C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"C:\Project/.dotnet/dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/.dotnet/dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists["test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -929,7 +932,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0;
|
||||
actions.RunProcess[@"C:\Project/.dotnet/dotnet clean C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"C:\Project/.dotnet/dotnet restore C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"C:\Project/.dotnet/dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0;
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto C:\Project/.dotnet/dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project/test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists["test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -960,7 +963,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet --info"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet clean C:\Project\test.csproj"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet restore C:\Project\test.csproj"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project\test.csproj"] = 0;
|
||||
actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto C:\Project\.dotnet\dotnet build --no-incremental /p:UseSharedCompilation=false C:\Project\test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project\test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -1008,7 +1011,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
{
|
||||
actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\dirs.proj -DisableParallelProcessing"] = 1;
|
||||
actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\dirs.proj -DisableParallelProcessing"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && msbuild C:\\Project\\dirs.proj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\dirs.proj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project\a\test.csproj"] = true;
|
||||
actions.FileExists[@"C:\Project\dirs.proj"] = true;
|
||||
@@ -1052,7 +1055,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
{
|
||||
actions.RunProcess[@"nuget restore C:\Project/dirs.proj -DisableParallelProcessing"] = 1;
|
||||
actions.RunProcess[@"mono C:\Project/.nuget/nuget.exe restore C:\Project/dirs.proj -DisableParallelProcessing"] = 0;
|
||||
actions.RunProcess[@"msbuild C:\Project/dirs.proj /p:UseSharedCompilation=false /t:rebuild /p:MvcBuildViews=true"] = 0;
|
||||
actions.RunProcess[@"C:\odasa/tools/odasa index --auto msbuild C:\Project/dirs.proj /p:UseSharedCompilation=false /t:rebuild /p:MvcBuildViews=true"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project/a/test.csproj"] = true;
|
||||
actions.FileExists[@"C:\Project/dirs.proj"] = true;
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace Semmle.Autobuild.CSharp
|
||||
private static BuildScript GetBuildScript(Autobuilder builder, string? dotNetPath, IDictionary<string, string>? environment, string projOrSln)
|
||||
{
|
||||
var build = new CommandBuilder(builder.Actions, null, environment);
|
||||
var script = build.RunCommand(DotNetCommand(builder.Actions, dotNetPath)).
|
||||
var script = builder.MaybeIndex(build, DotNetCommand(builder.Actions, dotNetPath)).
|
||||
Argument("build").
|
||||
Argument("--no-incremental");
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ namespace Semmle.Autobuild.CSharp
|
||||
{
|
||||
standalone = builder.Actions.PathCombine(builder.CodeQLExtractorLangRoot, "tools", builder.CodeQlPlatform, "Semmle.Extraction.CSharp.Standalone");
|
||||
}
|
||||
else if (builder.SemmlePlatformTools is not null)
|
||||
{
|
||||
standalone = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "Semmle.Extraction.CSharp.Standalone");
|
||||
}
|
||||
else
|
||||
{
|
||||
return BuildScript.Failure;
|
||||
|
||||
@@ -190,15 +190,19 @@ namespace Semmle.Autobuild.Shared
|
||||
});
|
||||
|
||||
CodeQLExtractorLangRoot = Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_ROOT");
|
||||
SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS");
|
||||
|
||||
CodeQlPlatform = Actions.GetEnvironmentVariable("CODEQL_PLATFORM");
|
||||
|
||||
TrapDir =
|
||||
Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR") ??
|
||||
throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR has not been set.");
|
||||
Actions.GetEnvironmentVariable("TRAP_FOLDER") ??
|
||||
throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR or TRAP_FOLDER has not been set.");
|
||||
|
||||
SourceArchiveDir =
|
||||
Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR") ??
|
||||
throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR has not been set.");
|
||||
Actions.GetEnvironmentVariable("SOURCE_ARCHIVE") ??
|
||||
throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set.");
|
||||
}
|
||||
|
||||
protected string TrapDir { get; }
|
||||
@@ -260,9 +264,34 @@ namespace Semmle.Autobuild.Shared
|
||||
/// </summary>
|
||||
public string? CodeQLExtractorLangRoot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of SEMMLE_PLATFORM_TOOLS environment variable.
|
||||
/// </summary>
|
||||
public string? SemmlePlatformTools { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of CODEQL_PLATFORM environment variable.
|
||||
/// </summary>
|
||||
public string? CodeQlPlatform { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The absolute path of the odasa executable.
|
||||
/// null if we are running in CodeQL.
|
||||
/// </summary>
|
||||
public string? Odasa
|
||||
{
|
||||
get
|
||||
{
|
||||
var semmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST");
|
||||
return semmleDist is null ? null : Actions.PathCombine(semmleDist, "tools", "odasa");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a command that executed the given <paramref name="cmd"/> wrapped in
|
||||
/// an <code>odasa --index</code>, unless indexing has been disabled, in which case
|
||||
/// <paramref name="cmd"/> is run directly.
|
||||
/// </summary>
|
||||
public CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Odasa is null ? builder.RunCommand(cmd) : builder.IndexCommand(Odasa, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Semmle.Autobuild.Shared
|
||||
if (vsTools is not null)
|
||||
command.CallBatFile(vsTools.Path);
|
||||
|
||||
command.RunCommand(scriptPath);
|
||||
builder.MaybeIndex(command, scriptPath);
|
||||
return command.Script;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
var vsTools = MsBuildRule.GetVcVarsBatFile(builder);
|
||||
if (vsTools is not null)
|
||||
command.CallBatFile(vsTools.Path);
|
||||
command.RunCommand(builder.Options.BuildCommand);
|
||||
builder.MaybeIndex(command, builder.Options.BuildCommand);
|
||||
|
||||
return command.Script;
|
||||
});
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Semmle.Autobuild.Shared
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public override string ToString() => arguments.Length > 0 ? exe + " " + arguments : exe;
|
||||
public override string ToString() => exe + " " + arguments;
|
||||
|
||||
public override int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,11 @@ namespace Semmle.Autobuild.Shared
|
||||
this.silent = silent;
|
||||
}
|
||||
|
||||
private void OdasaIndex(string odasa)
|
||||
{
|
||||
RunCommand(odasa, "index --auto");
|
||||
}
|
||||
|
||||
public CommandBuilder CallBatFile(string batFile, string? argumentsOpt = null)
|
||||
{
|
||||
NextCommand();
|
||||
@@ -54,6 +59,21 @@ namespace Semmle.Autobuild.Shared
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform odasa index on a given command or BAT file.
|
||||
/// </summary>
|
||||
/// <param name="odasa">The odasa executable.</param>
|
||||
/// <param name="command">The command to run.</param>
|
||||
/// <param name="argumentsOpt">Additional arguments.</param>
|
||||
/// <returns>this for chaining calls.</returns>
|
||||
public CommandBuilder IndexCommand(string odasa, string command, string? argumentsOpt = null)
|
||||
{
|
||||
OdasaIndex(odasa);
|
||||
QuoteArgument(command);
|
||||
Argument(argumentsOpt);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static readonly char[] specialChars = { ' ', '\t', '\n', '\v', '\"' };
|
||||
private static readonly char[] cmdMetacharacter = { '(', ')', '%', '!', '^', '\"', '<', '>', '&', '|' };
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Semmle.Autobuild.Shared
|
||||
command.RunCommand("set Platform=&& type NUL", quoteExe: false);
|
||||
}
|
||||
|
||||
command.RunCommand(msBuild);
|
||||
builder.MaybeIndex(command, msBuild);
|
||||
command.QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
command.Argument("/p:UseSharedCompilation=false");
|
||||
|
||||
14
csharp/config/tracer/linux/csharp-compiler-settings
Normal file
14
csharp/config/tracer/linux/csharp-compiler-settings
Normal file
@@ -0,0 +1,14 @@
|
||||
**/mcs.exe:
|
||||
**/csc.exe:
|
||||
invoke ${env.SEMMLE_PLATFORM_TOOLS}/csharp/Semmle.Extraction.CSharp.Driver
|
||||
prepend --compiler
|
||||
prepend "${compiler}"
|
||||
prepend --cil
|
||||
**/mono*:
|
||||
**/dotnet:
|
||||
invoke ${odasa_tools}/extract-csharp.sh
|
||||
**/msbuild:
|
||||
**/xbuild:
|
||||
replace yes
|
||||
invoke ${compiler}
|
||||
append /p:UseSharedCompilation=false
|
||||
16
csharp/config/tracer/linux/extract-csharp.sh
Executable file
16
csharp/config/tracer/linux/extract-csharp.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
echo extract-csharp.sh: Called with arguments: "$@"
|
||||
|
||||
extractor=$SEMMLE_PLATFORM_TOOLS/csharp/Semmle.Extraction.CSharp.Driver
|
||||
|
||||
for i in "$@"
|
||||
do
|
||||
shift
|
||||
if [[ `basename -- "$i"` =~ csc.exe|mcs.exe|csc.dll ]]
|
||||
then
|
||||
echo extract-csharp.sh: exec $extractor --cil $@
|
||||
exec "$extractor" --compiler $i --cil $@
|
||||
fi
|
||||
done
|
||||
|
||||
echo extract-csharp.sh: Not a compiler invocation
|
||||
9
csharp/config/tracer/windows/csharp-compiler-settings
Normal file
9
csharp/config/tracer/windows/csharp-compiler-settings
Normal file
@@ -0,0 +1,9 @@
|
||||
**\fakes*.exe:
|
||||
**\moles*.exe:
|
||||
order compiler
|
||||
trace no
|
||||
**\csc*.exe:
|
||||
invoke ${env.SEMMLE_PLATFORM_TOOLS}\csharp\Semmle.Extraction.CSharp.Driver.exe
|
||||
prepend --compiler
|
||||
prepend "${compiler}"
|
||||
prepend --cil
|
||||
@@ -20,11 +20,11 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
Console.WriteLine(" path A directory/dll/exe to analyze");
|
||||
}
|
||||
|
||||
private static void ExtractAssembly(string assemblyPath, ILogger logger, CommonOptions options)
|
||||
private static void ExtractAssembly(Layout layout, string assemblyPath, ILogger logger, CommonOptions options)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
Analyser.ExtractCIL(assemblyPath, logger, options, out _, out _);
|
||||
Analyser.ExtractCIL(layout, assemblyPath, logger, options, out _, out _);
|
||||
sw.Stop();
|
||||
logger.Log(Severity.Info, " {0} ({1})", assemblyPath, sw.Elapsed);
|
||||
}
|
||||
@@ -38,11 +38,12 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
}
|
||||
|
||||
var options = new ExtractorOptions(args);
|
||||
var layout = new Layout();
|
||||
using var logger = new ConsoleLogger(options.Verbosity);
|
||||
|
||||
var actions = options.AssembliesToExtract
|
||||
.Select(asm => asm.Filename)
|
||||
.Select<string, Action>(filename => () => ExtractAssembly(filename, logger, options))
|
||||
.Select<string, Action>(filename => () => ExtractAssembly(layout, filename, logger, options))
|
||||
.ToArray();
|
||||
|
||||
foreach (var missingRef in options.MissingReferences)
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Semmle.Extraction.CIL
|
||||
/// <param name="extractPdbs">Whether to extract PDBs.</param>
|
||||
/// <param name="trapFile">The path of the trap file.</param>
|
||||
/// <param name="extracted">Whether the file was extracted (false=cached).</param>
|
||||
public static void ExtractCIL(string assemblyPath, ILogger logger, CommonOptions options, out string trapFile, out bool extracted)
|
||||
public static void ExtractCIL(Layout layout, string assemblyPath, ILogger logger, CommonOptions options, out string trapFile, out bool extracted)
|
||||
{
|
||||
trapFile = "";
|
||||
extracted = false;
|
||||
@@ -35,7 +35,8 @@ namespace Semmle.Extraction.CIL
|
||||
var pathTransformer = new PathTransformer(canonicalPathCache);
|
||||
var extractor = new TracingExtractor(assemblyPath, logger, pathTransformer, options);
|
||||
var transformedAssemblyPath = pathTransformer.Transform(assemblyPath);
|
||||
using var trapWriter = transformedAssemblyPath.WithSuffix(".cil").CreateTrapWriter(logger, options.TrapCompression, discardDuplicates: true);
|
||||
var project = layout.LookupProjectOrDefault(transformedAssemblyPath);
|
||||
using var trapWriter = project.CreateTrapWriter(logger, transformedAssemblyPath.WithSuffix(".cil"), options.TrapCompression, discardDuplicates: true);
|
||||
trapFile = trapWriter.TrapFile;
|
||||
if (!options.Cache || !System.IO.File.Exists(trapFile))
|
||||
{
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
foreach (var r in DesktopRuntimes)
|
||||
yield return r;
|
||||
|
||||
// A bad choice if it's the self-contained runtime distributed in codeql dist.
|
||||
// A bad choice if it's the self-contained runtime distributed in odasa dist.
|
||||
yield return ExecutingRuntime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Semmle.Extraction.CSharp
|
||||
public void Initialize(CSharpCompilation compilationIn, CommonOptions options)
|
||||
{
|
||||
compilation = compilationIn;
|
||||
layout = new Layout();
|
||||
extractor = new StandaloneExtractor(Logger, PathTransformer, options);
|
||||
this.options = options;
|
||||
LogExtractorInfo(Extraction.Extractor.Version);
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
protected Extraction.Extractor? extractor;
|
||||
protected CSharpCompilation? compilation;
|
||||
protected Layout? layout;
|
||||
protected CommonOptions? options;
|
||||
|
||||
private readonly object progressMutex = new object();
|
||||
@@ -124,7 +125,8 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
var assemblyPath = r.FilePath!;
|
||||
var transformedAssemblyPath = PathTransformer.Transform(assemblyPath);
|
||||
using var trapWriter = transformedAssemblyPath.CreateTrapWriter(Logger, options.TrapCompression, discardDuplicates: true);
|
||||
var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath);
|
||||
using var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, options.TrapCompression, discardDuplicates: true);
|
||||
|
||||
var skipExtraction = options.Cache && File.Exists(trapWriter.TrapFile);
|
||||
|
||||
@@ -176,7 +178,7 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
CIL.Analyser.ExtractCIL(r.FilePath!, Logger, options, out var trapFile, out var extracted);
|
||||
CIL.Analyser.ExtractCIL(layout, r.FilePath!, Logger, options, out var trapFile, out var extracted);
|
||||
stopwatch.Stop();
|
||||
ReportProgress(r.FilePath, trapFile, stopwatch.Elapsed, extracted ? AnalysisAction.Extracted : AnalysisAction.UpToDate);
|
||||
}
|
||||
@@ -190,35 +192,44 @@ namespace Semmle.Extraction.CSharp
|
||||
var sourcePath = tree.FilePath;
|
||||
var transformedSourcePath = PathTransformer.Transform(sourcePath);
|
||||
|
||||
var trapPath = transformedSourcePath.GetTrapPath(Logger, options.TrapCompression);
|
||||
var projectLayout = layout.LookupProjectOrNull(transformedSourcePath);
|
||||
var excluded = projectLayout is null;
|
||||
var trapPath = excluded ? "" : projectLayout!.GetTrapPath(Logger, transformedSourcePath, options.TrapCompression);
|
||||
var upToDate = false;
|
||||
|
||||
// compilation.Clone() is used to allow symbols to be garbage collected.
|
||||
using var trapWriter = transformedSourcePath.CreateTrapWriter(Logger, options.TrapCompression, discardDuplicates: false);
|
||||
|
||||
upToDate = options.Fast && FileIsUpToDate(sourcePath, trapWriter.TrapFile);
|
||||
|
||||
if (!upToDate)
|
||||
if (!excluded)
|
||||
{
|
||||
var cx = new Context(extractor, compilation.Clone(), trapWriter, new SourceScope(tree), addAssemblyTrapPrefix);
|
||||
// Ensure that the file itself is populated in case the source file is totally empty
|
||||
var root = tree.GetRoot();
|
||||
Entities.File.Create(cx, root.SyntaxTree.FilePath);
|
||||
// compilation.Clone() is used to allow symbols to be garbage collected.
|
||||
using var trapWriter = projectLayout!.CreateTrapWriter(Logger, transformedSourcePath, options.TrapCompression, discardDuplicates: false);
|
||||
|
||||
var csNode = (CSharpSyntaxNode)root;
|
||||
var directiveVisitor = new DirectiveVisitor(cx);
|
||||
csNode.Accept(directiveVisitor);
|
||||
foreach (var branch in directiveVisitor.BranchesTaken)
|
||||
upToDate = options.Fast && FileIsUpToDate(sourcePath, trapWriter.TrapFile);
|
||||
|
||||
if (!upToDate)
|
||||
{
|
||||
cx.TrapStackSuffix.Add(branch);
|
||||
var cx = new Context(extractor, compilation.Clone(), trapWriter, new SourceScope(tree), addAssemblyTrapPrefix);
|
||||
// Ensure that the file itself is populated in case the source file is totally empty
|
||||
var root = tree.GetRoot();
|
||||
Entities.File.Create(cx, root.SyntaxTree.FilePath);
|
||||
|
||||
var csNode = (CSharpSyntaxNode)root;
|
||||
var directiveVisitor = new DirectiveVisitor(cx);
|
||||
csNode.Accept(directiveVisitor);
|
||||
foreach (var branch in directiveVisitor.BranchesTaken)
|
||||
{
|
||||
cx.TrapStackSuffix.Add(branch);
|
||||
}
|
||||
csNode.Accept(new CompilationUnitVisitor(cx));
|
||||
cx.PopulateAll();
|
||||
CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator);
|
||||
cx.PopulateAll();
|
||||
}
|
||||
csNode.Accept(new CompilationUnitVisitor(cx));
|
||||
cx.PopulateAll();
|
||||
CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator);
|
||||
cx.PopulateAll();
|
||||
}
|
||||
|
||||
ReportProgress(sourcePath, trapPath, stopwatch.Elapsed, upToDate ? AnalysisAction.UpToDate : AnalysisAction.Extracted);
|
||||
ReportProgress(sourcePath, trapPath, stopwatch.Elapsed, excluded
|
||||
? AnalysisAction.Excluded
|
||||
: upToDate
|
||||
? AnalysisAction.UpToDate
|
||||
: AnalysisAction.Extracted);
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
|
||||
@@ -452,6 +452,19 @@ namespace Semmle.Extraction.CSharp
|
||||
if (!string.IsNullOrEmpty(codeQlLogDir))
|
||||
return codeQlLogDir;
|
||||
|
||||
var snapshot = Environment.GetEnvironmentVariable("ODASA_SNAPSHOT");
|
||||
if (!string.IsNullOrEmpty(snapshot))
|
||||
return Path.Combine(snapshot, "log");
|
||||
|
||||
var buildErrorDir = Environment.GetEnvironmentVariable("ODASA_BUILD_ERROR_DIR");
|
||||
if (!string.IsNullOrEmpty(buildErrorDir))
|
||||
// Used by `qltest`
|
||||
return buildErrorDir;
|
||||
|
||||
var traps = Environment.GetEnvironmentVariable("TRAP_FOLDER");
|
||||
if (!string.IsNullOrEmpty(traps))
|
||||
return traps;
|
||||
|
||||
return Directory.GetCurrentDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace Semmle.Extraction.CSharp
|
||||
public static Options CreateWithEnvironment(string[] arguments)
|
||||
{
|
||||
var options = new Options();
|
||||
var extractionOptions = Environment.GetEnvironmentVariable("LGTM_INDEX_EXTRACTOR");
|
||||
var extractionOptions = Environment.GetEnvironmentVariable("SEMMLE_EXTRACTOR_OPTIONS") ??
|
||||
Environment.GetEnvironmentVariable("LGTM_INDEX_EXTRACTOR");
|
||||
|
||||
var argsList = new List<string>(arguments);
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
if (!init)
|
||||
throw new InternalError("EndInitialize called without BeginInitialize returning true");
|
||||
this.layout = new Layout();
|
||||
this.options = options;
|
||||
this.compilation = compilation;
|
||||
this.extractor = new TracingExtractor(GetOutputName(compilation, commandLineArguments), Logger, PathTransformer, options);
|
||||
@@ -201,7 +202,8 @@ namespace Semmle.Extraction.CSharp
|
||||
var assemblyPath = ((TracingExtractor?)extractor).OutputPath;
|
||||
var transformedAssemblyPath = PathTransformer.Transform(assemblyPath);
|
||||
var assembly = compilation.Assembly;
|
||||
var trapWriter = transformedAssemblyPath.CreateTrapWriter(Logger, options.TrapCompression, discardDuplicates: false);
|
||||
var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath);
|
||||
var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, options.TrapCompression, discardDuplicates: false);
|
||||
compilationTrapFile = trapWriter; // Dispose later
|
||||
var cx = new Context(extractor, compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), addAssemblyTrapPrefix);
|
||||
|
||||
|
||||
231
csharp/extractor/Semmle.Extraction.Tests/Layout.cs
Normal file
231
csharp/extractor/Semmle.Extraction.Tests/Layout.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
using Semmle.Util.Logging;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Semmle.Extraction.Tests
|
||||
{
|
||||
internal struct TransformedPathStub : PathTransformer.ITransformedPath
|
||||
{
|
||||
private readonly string value;
|
||||
public TransformedPathStub(string value) => this.value = value;
|
||||
public string Value => value;
|
||||
|
||||
public string Extension => throw new System.NotImplementedException();
|
||||
|
||||
public string NameWithoutExtension => throw new System.NotImplementedException();
|
||||
|
||||
public PathTransformer.ITransformedPath ParentDirectory => throw new System.NotImplementedException();
|
||||
|
||||
public string DatabaseId => throw new System.NotImplementedException();
|
||||
|
||||
public PathTransformer.ITransformedPath WithSuffix(string suffix)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class Layout
|
||||
{
|
||||
private readonly ILogger logger = new LoggerMock();
|
||||
|
||||
[Fact]
|
||||
public void TestDefaultLayout()
|
||||
{
|
||||
var layout = new Semmle.Extraction.Layout(null, null, null);
|
||||
var project = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs"));
|
||||
|
||||
Assert.NotNull(project);
|
||||
|
||||
// All files are mapped when there's no layout file.
|
||||
Assert.True(layout.FileInLayout(new TransformedPathStub("foo.cs")));
|
||||
|
||||
// Test trap filename
|
||||
var tmpDir = Path.GetTempPath();
|
||||
Directory.SetCurrentDirectory(tmpDir);
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
// `Directory.SetCurrentDirectory()` seems to slightly change the path on macOS,
|
||||
// so adjusting it:
|
||||
Assert.NotEqual(Directory.GetCurrentDirectory(), tmpDir);
|
||||
tmpDir = "/private" + tmpDir;
|
||||
// Remove trailing slash:
|
||||
Assert.Equal('/', tmpDir[tmpDir.Length - 1]);
|
||||
tmpDir = tmpDir.Substring(0, tmpDir.Length - 1);
|
||||
Assert.Equal(Directory.GetCurrentDirectory(), tmpDir);
|
||||
}
|
||||
var f1 = project!.GetTrapPath(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip);
|
||||
var g1 = TrapWriter.NestPaths(logger, tmpDir, "foo.cs.trap.gz");
|
||||
Assert.Equal(f1, g1);
|
||||
|
||||
// Test trap file generation
|
||||
var trapwriterFilename = project.GetTrapPath(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip);
|
||||
using (var trapwriter = project.CreateTrapWriter(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip, discardDuplicates: false))
|
||||
{
|
||||
trapwriter.Emit("1=*");
|
||||
Assert.False(File.Exists(trapwriterFilename));
|
||||
}
|
||||
Assert.True(File.Exists(trapwriterFilename));
|
||||
File.Delete(trapwriterFilename);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLayoutFile()
|
||||
{
|
||||
File.WriteAllLines("layout.txt", new string[]
|
||||
{
|
||||
"# Section",
|
||||
"TRAP_FOLDER=" + Path.GetFullPath("snapshot\\trap"),
|
||||
"ODASA_DB=snapshot\\db-csharp",
|
||||
"SOURCE_ARCHIVE=" + Path.GetFullPath("snapshot\\archive"),
|
||||
"ODASA_BUILD_ERROR_DIR=snapshot\build-errors",
|
||||
"-foo.cs",
|
||||
"bar.cs",
|
||||
"-excluded",
|
||||
"excluded/foo.cs",
|
||||
"included"
|
||||
});
|
||||
|
||||
var layout = new Semmle.Extraction.Layout(null, null, "layout.txt");
|
||||
|
||||
// Test general pattern matching
|
||||
Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs")));
|
||||
Assert.False(layout.FileInLayout(new TransformedPathStub("foo.cs")));
|
||||
Assert.False(layout.FileInLayout(new TransformedPathStub("goo.cs")));
|
||||
Assert.False(layout.FileInLayout(new TransformedPathStub("excluded/bar.cs")));
|
||||
Assert.True(layout.FileInLayout(new TransformedPathStub("excluded/foo.cs")));
|
||||
Assert.True(layout.FileInLayout(new TransformedPathStub("included/foo.cs")));
|
||||
|
||||
// Test the trap file
|
||||
var project = layout.LookupProjectOrNull(new TransformedPathStub("bar.cs"));
|
||||
Assert.NotNull(project);
|
||||
var trapwriterFilename = project!.GetTrapPath(logger, new TransformedPathStub("bar.cs"), TrapWriter.CompressionMode.Gzip);
|
||||
Assert.Equal(TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap"), "bar.cs.trap.gz"),
|
||||
trapwriterFilename);
|
||||
|
||||
// Test the source archive
|
||||
var trapWriter = project.CreateTrapWriter(logger, new TransformedPathStub("bar.cs"), TrapWriter.CompressionMode.Gzip, discardDuplicates: false);
|
||||
trapWriter.Archive("layout.txt", new TransformedPathStub("layout.txt"), System.Text.Encoding.ASCII);
|
||||
var writtenFile = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\archive"), "layout.txt");
|
||||
Assert.True(File.Exists(writtenFile));
|
||||
File.Delete("layout.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestTrapOverridesLayout()
|
||||
{
|
||||
// When you specify both a trap file and a layout, use the trap file.
|
||||
var layout = new Semmle.Extraction.Layout(Path.GetFullPath("snapshot\\trap"), null, "something.txt");
|
||||
Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs")));
|
||||
var subProject = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs"));
|
||||
Assert.NotNull(subProject);
|
||||
var f1 = subProject!.GetTrapPath(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip);
|
||||
var g1 = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap"), "foo.cs.trap.gz");
|
||||
Assert.Equal(f1, g1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestMultipleSections()
|
||||
{
|
||||
File.WriteAllLines("layout.txt", new string[]
|
||||
{
|
||||
"# Section 1",
|
||||
"TRAP_FOLDER=" + Path.GetFullPath("snapshot\\trap1"),
|
||||
"ODASA_DB=snapshot\\db-csharp",
|
||||
"SOURCE_ARCHIVE=" + Path.GetFullPath("snapshot\\archive1"),
|
||||
"ODASA_BUILD_ERROR_DIR=snapshot\build-errors",
|
||||
"foo.cs",
|
||||
"# Section 2",
|
||||
"TRAP_FOLDER=" + Path.GetFullPath("snapshot\\trap2"),
|
||||
"ODASA_DB=snapshot\\db-csharp",
|
||||
"SOURCE_ARCHIVE=" + Path.GetFullPath("snapshot\\archive2"),
|
||||
"ODASA_BUILD_ERROR_DIR=snapshot\build-errors",
|
||||
"bar.cs",
|
||||
});
|
||||
|
||||
var layout = new Semmle.Extraction.Layout(null, null, "layout.txt");
|
||||
|
||||
// Use Section 2
|
||||
Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs")));
|
||||
var subProject = layout.LookupProjectOrNull(new TransformedPathStub("bar.cs"));
|
||||
Assert.NotNull(subProject);
|
||||
var f1 = subProject!.GetTrapPath(logger, new TransformedPathStub("bar.cs"), TrapWriter.CompressionMode.Gzip);
|
||||
var g1 = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap2"), "bar.cs.trap.gz");
|
||||
Assert.Equal(f1, g1);
|
||||
|
||||
// Use Section 1
|
||||
Assert.True(layout.FileInLayout(new TransformedPathStub("foo.cs")));
|
||||
subProject = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs"));
|
||||
Assert.NotNull(subProject);
|
||||
var f2 = subProject!.GetTrapPath(logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip);
|
||||
var g2 = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap1"), "foo.cs.trap.gz");
|
||||
Assert.Equal(f2, g2);
|
||||
|
||||
// boo.dll is not in the layout, so use layout from first section.
|
||||
Assert.False(layout.FileInLayout(new TransformedPathStub("boo.dll")));
|
||||
var f3 = layout.LookupProjectOrDefault(new TransformedPathStub("boo.dll")).GetTrapPath(logger, new TransformedPathStub("boo.dll"), TrapWriter.CompressionMode.Gzip);
|
||||
var g3 = TrapWriter.NestPaths(logger, Path.GetFullPath("snapshot\\trap1"), "boo.dll.trap.gz");
|
||||
Assert.Equal(f3, g3);
|
||||
|
||||
// boo.cs is not in the layout, so return null
|
||||
Assert.False(layout.FileInLayout(new TransformedPathStub("boo.cs")));
|
||||
Assert.Null(layout.LookupProjectOrNull(new TransformedPathStub("boo.cs")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MissingLayout()
|
||||
{
|
||||
Assert.Throws<Extraction.Layout.InvalidLayoutException>(() =>
|
||||
new Semmle.Extraction.Layout(null, null, "nosuchfile.txt"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyLayout()
|
||||
{
|
||||
File.Create("layout.txt").Close();
|
||||
Assert.Throws<Extraction.Layout.InvalidLayoutException>(() =>
|
||||
new Semmle.Extraction.Layout(null, null, "layout.txt"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidLayout()
|
||||
{
|
||||
File.WriteAllLines("layout.txt", new string[]
|
||||
{
|
||||
"# Section 1"
|
||||
});
|
||||
|
||||
Assert.Throws<Extraction.Layout.InvalidLayoutException>(() =>
|
||||
new Semmle.Extraction.Layout(null, null, "layout.txt"));
|
||||
}
|
||||
|
||||
private sealed class LoggerMock : ILogger
|
||||
{
|
||||
public void Dispose() { }
|
||||
|
||||
public void Log(Severity s, string text) { }
|
||||
}
|
||||
}
|
||||
|
||||
internal static class TrapWriterTestExtensions
|
||||
{
|
||||
public static void Emit(this TrapWriter trapFile, string s)
|
||||
{
|
||||
trapFile.Emit(new StringTrapEmitter(s));
|
||||
}
|
||||
|
||||
private class StringTrapEmitter : ITrapEmitter
|
||||
{
|
||||
private readonly string content;
|
||||
public StringTrapEmitter(string content)
|
||||
{
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public void EmitTrap(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
public OptionsTests()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SEMMLE_EXTRACTOR_OPTIONS", "");
|
||||
Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "");
|
||||
}
|
||||
|
||||
@@ -125,14 +126,14 @@ namespace Semmle.Extraction.Tests
|
||||
[Fact]
|
||||
public void EnvironmentVariables()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "--cil c");
|
||||
Environment.SetEnvironmentVariable("SEMMLE_EXTRACTOR_OPTIONS", "--cil c");
|
||||
options = CSharp.Options.CreateWithEnvironment(new string[] { "a", "b" });
|
||||
Assert.True(options.CIL);
|
||||
Assert.Equal("a", options.CompilerArguments[0]);
|
||||
Assert.Equal("b", options.CompilerArguments[1]);
|
||||
Assert.Equal("c", options.CompilerArguments[2]);
|
||||
|
||||
Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "");
|
||||
Environment.SetEnvironmentVariable("SEMMLE_EXTRACTOR_OPTIONS", "");
|
||||
Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "--nocil");
|
||||
options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil" });
|
||||
Assert.False(options.CIL);
|
||||
|
||||
204
csharp/extractor/Semmle.Extraction/Layout.cs
Normal file
204
csharp/extractor/Semmle.Extraction/Layout.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using Semmle.Util.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
/// <summary>
|
||||
/// An extractor layout file.
|
||||
/// Represents the layout of projects into trap folders and source archives.
|
||||
/// </summary>
|
||||
public sealed class Layout
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception thrown when the layout file is invalid.
|
||||
/// </summary>
|
||||
public class InvalidLayoutException : Exception
|
||||
{
|
||||
public InvalidLayoutException(string file, string message) :
|
||||
base("ODASA_CSHARP_LAYOUT " + file + " " + message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of blocks in the layout file.
|
||||
/// </summary>
|
||||
private readonly List<LayoutBlock> blocks;
|
||||
|
||||
/// <summary>
|
||||
/// A subproject in the layout file.
|
||||
/// </summary>
|
||||
public class SubProject
|
||||
{
|
||||
/// <summary>
|
||||
/// The trap folder, or null for current directory.
|
||||
/// </summary>
|
||||
public string? TRAP_FOLDER { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The source archive, or null to skip.
|
||||
/// </summary>
|
||||
public string? SOURCE_ARCHIVE { get; }
|
||||
|
||||
public SubProject(string? traps, string? archive)
|
||||
{
|
||||
TRAP_FOLDER = traps;
|
||||
SOURCE_ARCHIVE = archive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the trap file for a given source/assembly file.
|
||||
/// </summary>
|
||||
/// <param name="srcFile">The source file.</param>
|
||||
/// <returns>The full filepath of the trap file.</returns>
|
||||
public string GetTrapPath(ILogger logger, PathTransformer.ITransformedPath srcFile, TrapWriter.CompressionMode trapCompression) =>
|
||||
TrapWriter.TrapPath(logger, TRAP_FOLDER, srcFile, trapCompression);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a trap writer for a given source/assembly file.
|
||||
/// </summary>
|
||||
/// <param name="srcFile">The source file.</param>
|
||||
/// <returns>A newly created TrapWriter.</returns>
|
||||
public TrapWriter CreateTrapWriter(ILogger logger, PathTransformer.ITransformedPath srcFile, TrapWriter.CompressionMode trapCompression, bool discardDuplicates) =>
|
||||
new TrapWriter(logger, srcFile, TRAP_FOLDER, SOURCE_ARCHIVE, trapCompression, discardDuplicates);
|
||||
}
|
||||
|
||||
private readonly SubProject defaultProject;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the suitable directories for a given source file.
|
||||
/// Returns null if not included in the layout.
|
||||
/// </summary>
|
||||
/// <param name="sourceFile">The file to look up.</param>
|
||||
/// <returns>The relevant subproject, or null if not found.</returns>
|
||||
public SubProject? LookupProjectOrNull(PathTransformer.ITransformedPath sourceFile)
|
||||
{
|
||||
if (!useLayoutFile)
|
||||
return defaultProject;
|
||||
|
||||
return blocks
|
||||
.Where(block => block.Matches(sourceFile))
|
||||
.Select(block => block.Directories)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the suitable directories for a given source file.
|
||||
/// Returns the default project if not included in the layout.
|
||||
/// </summary>
|
||||
/// <param name="sourceFile">The file to look up.</param>
|
||||
/// <returns>The relevant subproject, or DefaultProject if not found.</returns>
|
||||
public SubProject LookupProjectOrDefault(PathTransformer.ITransformedPath sourceFile)
|
||||
{
|
||||
return LookupProjectOrNull(sourceFile) ?? defaultProject;
|
||||
}
|
||||
|
||||
private readonly bool useLayoutFile;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor reads parameters from the environment.
|
||||
/// </summary>
|
||||
public Layout() : this(
|
||||
Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR") ?? Environment.GetEnvironmentVariable("TRAP_FOLDER"),
|
||||
Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR") ?? Environment.GetEnvironmentVariable("SOURCE_ARCHIVE"),
|
||||
Environment.GetEnvironmentVariable("ODASA_CSHARP_LAYOUT"))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the project layout. Reads the layout file if specified.
|
||||
/// </summary>
|
||||
/// <param name="traps">Directory for trap files, or null to use layout/current directory.</param>
|
||||
/// <param name="archive">Directory for source archive, or null for layout/no archive.</param>
|
||||
/// <param name="layout">Path of layout file, or null for no layout.</param>
|
||||
/// <exception cref="InvalidLayoutException">Failed to read layout file.</exception>
|
||||
public Layout(string? traps, string? archive, string? layout)
|
||||
{
|
||||
useLayoutFile = string.IsNullOrEmpty(traps) && !string.IsNullOrEmpty(layout);
|
||||
blocks = new List<LayoutBlock>();
|
||||
|
||||
if (useLayoutFile)
|
||||
{
|
||||
ReadLayoutFile(layout!);
|
||||
defaultProject = blocks[0].Directories;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultProject = new SubProject(traps, archive);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the source file included in the layout?
|
||||
/// </summary>
|
||||
/// <param name="path">The absolute path of the file to query.</param>
|
||||
/// <returns>True iff there is no layout file or the layout file specifies the file.</returns>
|
||||
public bool FileInLayout(PathTransformer.ITransformedPath path) => LookupProjectOrNull(path) is not null;
|
||||
|
||||
private void ReadLayoutFile(string layout)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lines = File.ReadAllLines(layout);
|
||||
|
||||
var i = 0;
|
||||
while (!lines[i].StartsWith("#"))
|
||||
i++;
|
||||
while (i < lines.Length)
|
||||
{
|
||||
var block = new LayoutBlock(lines, ref i);
|
||||
blocks.Add(block);
|
||||
}
|
||||
|
||||
if (blocks.Count == 0)
|
||||
throw new InvalidLayoutException(layout, "contains no blocks");
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new InvalidLayoutException(layout, ex.Message);
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw new InvalidLayoutException(layout, "is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class LayoutBlock
|
||||
{
|
||||
private readonly List<FilePattern> filePatterns = new List<FilePattern>();
|
||||
|
||||
public Layout.SubProject Directories { get; }
|
||||
|
||||
private static string? ReadVariable(string name, string line)
|
||||
{
|
||||
var prefix = name + "=";
|
||||
if (!line.StartsWith(prefix))
|
||||
return null;
|
||||
return line.Substring(prefix.Length).Trim();
|
||||
}
|
||||
|
||||
public LayoutBlock(string[] lines, ref int i)
|
||||
{
|
||||
// first line: #name
|
||||
i++;
|
||||
var trapFolder = ReadVariable("TRAP_FOLDER", lines[i++]);
|
||||
// Don't care about ODASA_DB.
|
||||
ReadVariable("ODASA_DB", lines[i++]);
|
||||
var sourceArchive = ReadVariable("SOURCE_ARCHIVE", lines[i++]);
|
||||
|
||||
Directories = new Layout.SubProject(trapFolder, sourceArchive);
|
||||
// Don't care about ODASA_BUILD_ERROR_DIR.
|
||||
ReadVariable("ODASA_BUILD_ERROR_DIR", lines[i++]);
|
||||
while (i < lines.Length && !lines[i].StartsWith("#"))
|
||||
{
|
||||
filePatterns.Add(new FilePattern(lines[i++]));
|
||||
}
|
||||
}
|
||||
|
||||
public bool Matches(PathTransformer.ITransformedPath path) => FilePattern.Matches(filePatterns, path.Value, out var _);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
@@ -36,20 +35,6 @@ namespace Semmle.Extraction
|
||||
ITransformedPath WithSuffix(string suffix);
|
||||
|
||||
string DatabaseId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the trap file for this file.
|
||||
/// </summary>
|
||||
/// <returns>The full filepath of the trap file.</returns>
|
||||
public string GetTrapPath(ILogger logger, TrapWriter.CompressionMode trapCompression) =>
|
||||
TrapWriter.TrapPath(logger, Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"), this, trapCompression);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a trap writer for this file.
|
||||
/// </summary>
|
||||
/// <returns>A newly created TrapWriter.</returns>
|
||||
public TrapWriter CreateTrapWriter(ILogger logger, TrapWriter.CompressionMode trapCompression, bool discardDuplicates) =>
|
||||
new(logger, this, Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"), Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"), trapCompression, discardDuplicates);
|
||||
}
|
||||
|
||||
private struct TransformedPath : ITransformedPath
|
||||
|
||||
@@ -234,7 +234,9 @@ namespace Semmle.Util
|
||||
/// <returns>A new CanonicalPathCache.</returns>
|
||||
public static CanonicalPathCache Create(ILogger logger, int maxCapacity)
|
||||
{
|
||||
var preserveSymlinks = Environment.GetEnvironmentVariable("CODEQL_PRESERVE_SYMLINKS") == "true";
|
||||
var preserveSymlinks =
|
||||
Environment.GetEnvironmentVariable("CODEQL_PRESERVE_SYMLINKS") == "true" ||
|
||||
Environment.GetEnvironmentVariable("SEMMLE_PRESERVE_SYMLINKS") == "true";
|
||||
return Create(logger, maxCapacity, preserveSymlinks ? CanonicalPathCache.Symlinks.Preserve : CanonicalPathCache.Symlinks.Follow);
|
||||
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Semmle.Util.Logging
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
Console.Error.WriteLine("CodeQL: Couldn't initialise C# extractor output: " + ex.Message + "\n" + ex.StackTrace);
|
||||
Console.Error.WriteLine("SEMMLE: Couldn't initialise C# extractor output: " + ex.Message + "\n" + ex.StackTrace);
|
||||
Console.Error.Flush();
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* The C# extractor no longer supports the following legacy environment variables:
|
||||
```
|
||||
ODASA_BUILD_ERROR_DIR
|
||||
ODASA_CSHARP_LAYOUT
|
||||
ODASA_SNAPSHOT
|
||||
SEMMLE_DIST
|
||||
SEMMLE_EXTRACTOR_OPTIONS
|
||||
SEMMLE_PLATFORM_TOOLS
|
||||
SEMMLE_PRESERVE_SYMLINKS
|
||||
SOURCE_ARCHIVE
|
||||
TRAP_FOLDER
|
||||
```
|
||||
@@ -36,18 +36,12 @@ module ArrayTaintTracking {
|
||||
succ = call
|
||||
)
|
||||
or
|
||||
// `array.filter(x => x)` and `array.filter(x => !!x)` keeps the taint
|
||||
// `array.filter(x => x)` keeps the taint
|
||||
call.(DataFlow::MethodCallNode).getMethodName() = "filter" and
|
||||
pred = call.getReceiver() and
|
||||
succ = call and
|
||||
exists(DataFlow::FunctionNode callback, DataFlow::Node param, DataFlow::Node ret |
|
||||
callback = call.getArgument(0).getAFunctionValue() and
|
||||
param = callback.getParameter(0).getALocalUse() and
|
||||
ret = callback.getAReturn()
|
||||
|
|
||||
param = ret
|
||||
or
|
||||
param = DataFlow::exprNode(ret.asExpr().(LogNotExpr).getOperand().(LogNotExpr).getOperand())
|
||||
exists(DataFlow::FunctionNode callback | callback = call.getArgument(0).getAFunctionValue() |
|
||||
callback.getParameter(0).getALocalUse() = callback.getAReturn()
|
||||
)
|
||||
or
|
||||
// `array.reduce` with tainted value in callback
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:5:8:5:14 | obj.foo |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:11:10:11:15 | arr[i] |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:15:27:15:27 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:16:23:16:23 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:20:8:20:16 | arr.pop() |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:49:8:49:13 | arr[0] |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:52:10:52:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:56:10:56:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:60:10:60:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:66:10:66:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:71:10:71:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:74:8:74:29 | arr.fin ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:77:8:77:35 | arrayFi ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:81:10:81:10 | x |
|
||||
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
|
||||
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
|
||||
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:30:8:30:17 | arr4.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:33:8:33:17 | arr5.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:35:8:35:26 | arr5.slice(2).pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:41:8:41:17 | arr6.pop() |
|
||||
| arrays.js:44:4:44:11 | "source" | arrays.js:45:10:45:18 | ary.pop() |
|
||||
| arrays.js:44:4:44:11 | "source" | arrays.js:46:10:46:12 | ary |
|
||||
| arrays.js:84:9:84:16 | "source" | arrays.js:84:8:84:34 | ["sourc ... ) => x) |
|
||||
| arrays.js:85:9:85:16 | "source" | arrays.js:85:8:85:36 | ["sourc ... => !!x) |
|
||||
@@ -1,15 +0,0 @@
|
||||
import javascript
|
||||
|
||||
class ArrayTaintFlowConfig extends TaintTracking::Configuration {
|
||||
ArrayTaintFlowConfig() { this = "ArrayTaintFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.asExpr().getStringValue() = "source" }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
from ArrayTaintFlowConfig config, DataFlow::Node src, DataFlow::Node snk
|
||||
where config.hasFlow(src, snk)
|
||||
select src, snk
|
||||
@@ -80,7 +80,4 @@
|
||||
for (const x of uniq(arr)) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
sink(["source"].filter((x) => x))
|
||||
sink(["source"].filter((x) => !!x))
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
nodes
|
||||
| arrays.js:1:1:86:2 | [ParExpr] (functi ... !x)) }) | semmle.label | [ParExpr] (functi ... !x)) }) |
|
||||
| arrays.js:1:1:86:3 | [ExprStmt] (functi ... x)) }); | semmle.label | [ExprStmt] (functi ... x)) }); |
|
||||
| arrays.js:1:1:86:3 | [ExprStmt] (functi ... x)) }); | semmle.order | 1 |
|
||||
| arrays.js:1:2:86:1 | [FunctionExpr] functio ... !!x)) } | semmle.label | [FunctionExpr] functio ... !!x)) } |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | semmle.label | [BlockStmt] { let ... !!x)) } |
|
||||
| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.label | [ParExpr] (functi ... } }) |
|
||||
| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | semmle.label | [ExprStmt] (functi ... } }); |
|
||||
| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | semmle.order | 1 |
|
||||
| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.label | [FunctionExpr] functio ... K } } |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.label | [BlockStmt] { let ... K } } |
|
||||
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | [DeclStmt] let source = ... |
|
||||
| arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | [VarDecl] source |
|
||||
| arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | [VariableDeclarator] source = "source" |
|
||||
@@ -339,30 +339,6 @@ nodes
|
||||
| arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.label | [CallExpr] sink(x) |
|
||||
| arrays.js:81:5:81:12 | [ExprStmt] sink(x); | semmle.label | [ExprStmt] sink(x); |
|
||||
| arrays.js:81:10:81:10 | [VarRef] x | semmle.label | [VarRef] x |
|
||||
| arrays.js:84:3:84:6 | [VarRef] sink | semmle.label | [VarRef] sink |
|
||||
| arrays.js:84:3:84:35 | [CallExpr] sink([" ... => x)) | semmle.label | [CallExpr] sink([" ... => x)) |
|
||||
| arrays.js:84:3:84:35 | [ExprStmt] sink([" ... => x)) | semmle.label | [ExprStmt] sink([" ... => x)) |
|
||||
| arrays.js:84:8:84:17 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] |
|
||||
| arrays.js:84:8:84:24 | [DotExpr] ["source"].filter | semmle.label | [DotExpr] ["source"].filter |
|
||||
| arrays.js:84:8:84:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.label | [MethodCallExpr] ["sourc ... ) => x) |
|
||||
| arrays.js:84:9:84:16 | [Literal] "source" | semmle.label | [Literal] "source" |
|
||||
| arrays.js:84:19:84:24 | [Label] filter | semmle.label | [Label] filter |
|
||||
| arrays.js:84:26:84:33 | [ArrowFunctionExpr] (x) => x | semmle.label | [ArrowFunctionExpr] (x) => x |
|
||||
| arrays.js:84:27:84:27 | [SimpleParameter] x | semmle.label | [SimpleParameter] x |
|
||||
| arrays.js:84:33:84:33 | [VarRef] x | semmle.label | [VarRef] x |
|
||||
| arrays.js:85:3:85:6 | [VarRef] sink | semmle.label | [VarRef] sink |
|
||||
| arrays.js:85:3:85:37 | [CallExpr] sink([" ... > !!x)) | semmle.label | [CallExpr] sink([" ... > !!x)) |
|
||||
| arrays.js:85:3:85:37 | [ExprStmt] sink([" ... > !!x)) | semmle.label | [ExprStmt] sink([" ... > !!x)) |
|
||||
| arrays.js:85:8:85:17 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] |
|
||||
| arrays.js:85:8:85:24 | [DotExpr] ["source"].filter | semmle.label | [DotExpr] ["source"].filter |
|
||||
| arrays.js:85:8:85:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.label | [MethodCallExpr] ["sourc ... => !!x) |
|
||||
| arrays.js:85:9:85:16 | [Literal] "source" | semmle.label | [Literal] "source" |
|
||||
| arrays.js:85:19:85:24 | [Label] filter | semmle.label | [Label] filter |
|
||||
| arrays.js:85:26:85:35 | [ArrowFunctionExpr] (x) => !!x | semmle.label | [ArrowFunctionExpr] (x) => !!x |
|
||||
| arrays.js:85:27:85:27 | [SimpleParameter] x | semmle.label | [SimpleParameter] x |
|
||||
| arrays.js:85:33:85:35 | [UnaryExpr] !!x | semmle.label | [UnaryExpr] !!x |
|
||||
| arrays.js:85:34:85:35 | [UnaryExpr] !x | semmle.label | [UnaryExpr] !x |
|
||||
| arrays.js:85:35:85:35 | [VarRef] x | semmle.label | [VarRef] x |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
@@ -404,104 +380,94 @@ nodes
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
edges
|
||||
| arrays.js:1:1:86:2 | [ParExpr] (functi ... !x)) }) | arrays.js:1:2:86:1 | [FunctionExpr] functio ... !!x)) } | semmle.label | 1 |
|
||||
| arrays.js:1:1:86:2 | [ParExpr] (functi ... !x)) }) | arrays.js:1:2:86:1 | [FunctionExpr] functio ... !!x)) } | semmle.order | 1 |
|
||||
| arrays.js:1:1:86:3 | [ExprStmt] (functi ... x)) }); | arrays.js:1:1:86:2 | [ParExpr] (functi ... !x)) }) | semmle.label | 1 |
|
||||
| arrays.js:1:1:86:3 | [ExprStmt] (functi ... x)) }); | arrays.js:1:1:86:2 | [ParExpr] (functi ... !x)) }) | semmle.order | 1 |
|
||||
| arrays.js:1:2:86:1 | [FunctionExpr] functio ... !!x)) } | arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | semmle.label | 5 |
|
||||
| arrays.js:1:2:86:1 | [FunctionExpr] functio ... !!x)) } | arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | semmle.order | 5 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.label | 18 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.order | 18 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 19 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 19 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 20 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 20 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.label | 21 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.order | 21 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.label | 22 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.order | 22 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 23 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 23 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 24 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 24 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.label | 25 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.order | 25 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.label | 26 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.order | 26 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.label | 27 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.order | 27 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.label | 28 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.order | 28 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.label | 29 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.order | 29 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 30 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 30 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.label | 31 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.order | 31 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 32 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 32 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 34 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 34 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.label | 35 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.order | 35 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 36 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 36 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.label | 37 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.order | 37 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:84:3:84:35 | [ExprStmt] sink([" ... => x)) | semmle.label | 39 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:84:3:84:35 | [ExprStmt] sink([" ... => x)) | semmle.order | 39 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:85:3:85:37 | [ExprStmt] sink([" ... > !!x)) | semmle.label | 40 |
|
||||
| arrays.js:1:14:86:1 | [BlockStmt] { let ... !!x)) } | arrays.js:85:3:85:37 | [ExprStmt] sink([" ... > !!x)) | semmle.order | 40 |
|
||||
| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.label | 1 |
|
||||
| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.order | 1 |
|
||||
| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.label | 1 |
|
||||
| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.order | 1 |
|
||||
| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.label | 5 |
|
||||
| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.order | 5 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.label | 18 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.order | 18 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 19 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 19 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 20 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 20 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.label | 21 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.order | 21 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.label | 22 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.order | 22 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 23 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 23 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 24 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 24 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.label | 25 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.order | 25 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.label | 26 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.order | 26 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.label | 27 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.order | 27 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.label | 28 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.order | 28 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.label | 29 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.order | 29 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 30 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 30 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.label | 31 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.order | 31 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 32 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 32 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 34 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 34 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.label | 35 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.order | 35 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 36 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 36 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.label | 37 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.order | 37 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 |
|
||||
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | 1 |
|
||||
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.order | 1 |
|
||||
| arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | 1 |
|
||||
@@ -1086,50 +1052,6 @@ edges
|
||||
| arrays.js:81:5:81:11 | [CallExpr] sink(x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
|
||||
| arrays.js:81:5:81:12 | [ExprStmt] sink(x); | arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.label | 1 |
|
||||
| arrays.js:81:5:81:12 | [ExprStmt] sink(x); | arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.order | 1 |
|
||||
| arrays.js:84:3:84:35 | [CallExpr] sink([" ... => x)) | arrays.js:84:3:84:6 | [VarRef] sink | semmle.label | 0 |
|
||||
| arrays.js:84:3:84:35 | [CallExpr] sink([" ... => x)) | arrays.js:84:3:84:6 | [VarRef] sink | semmle.order | 0 |
|
||||
| arrays.js:84:3:84:35 | [CallExpr] sink([" ... => x)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
|
||||
| arrays.js:84:3:84:35 | [CallExpr] sink([" ... => x)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
|
||||
| arrays.js:84:3:84:35 | [ExprStmt] sink([" ... => x)) | arrays.js:84:3:84:35 | [CallExpr] sink([" ... => x)) | semmle.label | 1 |
|
||||
| arrays.js:84:3:84:35 | [ExprStmt] sink([" ... => x)) | arrays.js:84:3:84:35 | [CallExpr] sink([" ... => x)) | semmle.order | 1 |
|
||||
| arrays.js:84:8:84:17 | [ArrayExpr] ["source"] | arrays.js:84:9:84:16 | [Literal] "source" | semmle.label | 1 |
|
||||
| arrays.js:84:8:84:17 | [ArrayExpr] ["source"] | arrays.js:84:9:84:16 | [Literal] "source" | semmle.order | 1 |
|
||||
| arrays.js:84:8:84:24 | [DotExpr] ["source"].filter | arrays.js:84:8:84:17 | [ArrayExpr] ["source"] | semmle.label | 1 |
|
||||
| arrays.js:84:8:84:24 | [DotExpr] ["source"].filter | arrays.js:84:8:84:17 | [ArrayExpr] ["source"] | semmle.order | 1 |
|
||||
| arrays.js:84:8:84:24 | [DotExpr] ["source"].filter | arrays.js:84:19:84:24 | [Label] filter | semmle.label | 2 |
|
||||
| arrays.js:84:8:84:24 | [DotExpr] ["source"].filter | arrays.js:84:19:84:24 | [Label] filter | semmle.order | 2 |
|
||||
| arrays.js:84:8:84:34 | [MethodCallExpr] ["sourc ... ) => x) | arrays.js:84:8:84:24 | [DotExpr] ["source"].filter | semmle.label | 0 |
|
||||
| arrays.js:84:8:84:34 | [MethodCallExpr] ["sourc ... ) => x) | arrays.js:84:8:84:24 | [DotExpr] ["source"].filter | semmle.order | 0 |
|
||||
| arrays.js:84:8:84:34 | [MethodCallExpr] ["sourc ... ) => x) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
|
||||
| arrays.js:84:8:84:34 | [MethodCallExpr] ["sourc ... ) => x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
|
||||
| arrays.js:84:26:84:33 | [ArrowFunctionExpr] (x) => x | arrays.js:84:33:84:33 | [VarRef] x | semmle.label | 5 |
|
||||
| arrays.js:84:26:84:33 | [ArrowFunctionExpr] (x) => x | arrays.js:84:33:84:33 | [VarRef] x | semmle.order | 5 |
|
||||
| arrays.js:84:26:84:33 | [ArrowFunctionExpr] (x) => x | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
|
||||
| arrays.js:84:26:84:33 | [ArrowFunctionExpr] (x) => x | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
|
||||
| arrays.js:85:3:85:37 | [CallExpr] sink([" ... > !!x)) | arrays.js:85:3:85:6 | [VarRef] sink | semmle.label | 0 |
|
||||
| arrays.js:85:3:85:37 | [CallExpr] sink([" ... > !!x)) | arrays.js:85:3:85:6 | [VarRef] sink | semmle.order | 0 |
|
||||
| arrays.js:85:3:85:37 | [CallExpr] sink([" ... > !!x)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
|
||||
| arrays.js:85:3:85:37 | [CallExpr] sink([" ... > !!x)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
|
||||
| arrays.js:85:3:85:37 | [ExprStmt] sink([" ... > !!x)) | arrays.js:85:3:85:37 | [CallExpr] sink([" ... > !!x)) | semmle.label | 1 |
|
||||
| arrays.js:85:3:85:37 | [ExprStmt] sink([" ... > !!x)) | arrays.js:85:3:85:37 | [CallExpr] sink([" ... > !!x)) | semmle.order | 1 |
|
||||
| arrays.js:85:8:85:17 | [ArrayExpr] ["source"] | arrays.js:85:9:85:16 | [Literal] "source" | semmle.label | 1 |
|
||||
| arrays.js:85:8:85:17 | [ArrayExpr] ["source"] | arrays.js:85:9:85:16 | [Literal] "source" | semmle.order | 1 |
|
||||
| arrays.js:85:8:85:24 | [DotExpr] ["source"].filter | arrays.js:85:8:85:17 | [ArrayExpr] ["source"] | semmle.label | 1 |
|
||||
| arrays.js:85:8:85:24 | [DotExpr] ["source"].filter | arrays.js:85:8:85:17 | [ArrayExpr] ["source"] | semmle.order | 1 |
|
||||
| arrays.js:85:8:85:24 | [DotExpr] ["source"].filter | arrays.js:85:19:85:24 | [Label] filter | semmle.label | 2 |
|
||||
| arrays.js:85:8:85:24 | [DotExpr] ["source"].filter | arrays.js:85:19:85:24 | [Label] filter | semmle.order | 2 |
|
||||
| arrays.js:85:8:85:36 | [MethodCallExpr] ["sourc ... => !!x) | arrays.js:85:8:85:24 | [DotExpr] ["source"].filter | semmle.label | 0 |
|
||||
| arrays.js:85:8:85:36 | [MethodCallExpr] ["sourc ... => !!x) | arrays.js:85:8:85:24 | [DotExpr] ["source"].filter | semmle.order | 0 |
|
||||
| arrays.js:85:8:85:36 | [MethodCallExpr] ["sourc ... => !!x) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
|
||||
| arrays.js:85:8:85:36 | [MethodCallExpr] ["sourc ... => !!x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
|
||||
| arrays.js:85:26:85:35 | [ArrowFunctionExpr] (x) => !!x | arrays.js:85:33:85:35 | [UnaryExpr] !!x | semmle.label | 5 |
|
||||
| arrays.js:85:26:85:35 | [ArrowFunctionExpr] (x) => !!x | arrays.js:85:33:85:35 | [UnaryExpr] !!x | semmle.order | 5 |
|
||||
| arrays.js:85:26:85:35 | [ArrowFunctionExpr] (x) => !!x | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
|
||||
| arrays.js:85:26:85:35 | [ArrowFunctionExpr] (x) => !!x | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
|
||||
| arrays.js:85:33:85:35 | [UnaryExpr] !!x | arrays.js:85:34:85:35 | [UnaryExpr] !x | semmle.label | 1 |
|
||||
| arrays.js:85:33:85:35 | [UnaryExpr] !!x | arrays.js:85:34:85:35 | [UnaryExpr] !x | semmle.order | 1 |
|
||||
| arrays.js:85:34:85:35 | [UnaryExpr] !x | arrays.js:85:35:85:35 | [VarRef] x | semmle.label | 1 |
|
||||
| arrays.js:85:34:85:35 | [UnaryExpr] !x | arrays.js:85:35:85:35 | [VarRef] x | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:8:12:8:17 | [VarRef] source | semmle.label | 0 |
|
||||
@@ -1218,14 +1140,6 @@ edges
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:80:24:80:26 | [VarRef] arr | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:81:10:81:10 | [VarRef] x | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:81:10:81:10 | [VarRef] x | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:84:8:84:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:84:8:84:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:84:26:84:33 | [ArrowFunctionExpr] (x) => x | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:84:26:84:33 | [ArrowFunctionExpr] (x) => x | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:85:8:85:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:85:8:85:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:85:26:85:35 | [ArrowFunctionExpr] (x) => !!x | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:85:26:85:35 | [ArrowFunctionExpr] (x) => !!x | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:16:12:16:12 | [SimpleParameter] e | semmle.label | 0 |
|
||||
@@ -1240,9 +1154,5 @@ edges
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:44:26:44:26 | [SimpleParameter] i | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:44:29:44:31 | [SimpleParameter] ary | semmle.label | 2 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:44:29:44:31 | [SimpleParameter] ary | semmle.order | 2 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:84:27:84:27 | [SimpleParameter] x | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:84:27:84:27 | [SimpleParameter] x | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:85:27:85:27 | [SimpleParameter] x | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:85:27:85:27 | [SimpleParameter] x | semmle.order | 0 |
|
||||
graphProperties
|
||||
| semmle.graphKind | tree |
|
||||
|
||||
38
ruby/ql/lib/codeql/ruby/ApplicationHeuristics.qll
Normal file
38
ruby/ql/lib/codeql/ruby/ApplicationHeuristics.qll
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Provides predicates to guess whether the codebase is an application or a gem.
|
||||
*/
|
||||
|
||||
private import ruby
|
||||
|
||||
/**
|
||||
* Provides predicates to guess whether the codebase is an application or a gem.
|
||||
*/
|
||||
module Application {
|
||||
/**
|
||||
* Holds if the codebase has a .gemspec file.
|
||||
* This indicates it is a gem, or contains a gem.
|
||||
*/
|
||||
private predicate hasGemspec() { exists(File f | f.getExtension() = "gemspec") }
|
||||
|
||||
/**
|
||||
* Holds if the codebase has a Gemfile.
|
||||
*/
|
||||
private predicate hasGemfile() { exists(File f | f.getBaseName() = "Gemfile") }
|
||||
|
||||
/**
|
||||
* Holds if the codebase has a Gemfile.lock
|
||||
* This indicates it is probably an application (though some gems erroneously have this file, too).
|
||||
*/
|
||||
private predicate hasGemfileLock() { exists(File f | f.getBaseName() = "Gemfile.lock") }
|
||||
|
||||
/**
|
||||
* Holds if the codebase is likely to be a gem.
|
||||
* This is a heuristic, so may be wrong.
|
||||
* In particular, it will be confused by applications that contain vendored gems.
|
||||
*/
|
||||
predicate isGem() {
|
||||
hasGemspec()
|
||||
or
|
||||
hasGemfile() and not hasGemfileLock()
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,21 @@ class Expr extends Stmt, TExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `SelfVariableAccess` instead. */
|
||||
deprecated class Self = SelfVariableAccess;
|
||||
/**
|
||||
* A reference to the current object. For example:
|
||||
* - `self == other`
|
||||
* - `self.method_name`
|
||||
* - `def self.method_name ... end`
|
||||
*
|
||||
* This also includes implicit references to the current object in method
|
||||
* calls. For example, the method call `foo(123)` has an implicit `self`
|
||||
* receiver, and is equivalent to the explicit `self.foo(123)`.
|
||||
*/
|
||||
class Self extends Expr, TSelf {
|
||||
final override string getAPrimaryQlClass() { result = "Self" }
|
||||
|
||||
final override string toString() { result = "self" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence of expressions in the right-hand side of an assignment or
|
||||
|
||||
@@ -201,16 +201,7 @@ class ClassVariableWriteAccess extends ClassVariableAccess, VariableWriteAccess
|
||||
/** An access to a class variable where the value is read. */
|
||||
class ClassVariableReadAccess extends ClassVariableAccess, VariableReadAccess { }
|
||||
|
||||
/**
|
||||
* An access to the `self` variable. For example:
|
||||
* - `self == other`
|
||||
* - `self.method_name`
|
||||
* - `def self.method_name ... end`
|
||||
*
|
||||
* This also includes implicit references to the current object in method
|
||||
* calls. For example, the method call `foo(123)` has an implicit `self`
|
||||
* receiver, and is equivalent to the explicit `self.foo(123)`.
|
||||
*/
|
||||
/** An access to the `self` variable */
|
||||
class SelfVariableAccess extends LocalVariableAccess instanceof SelfVariableAccessImpl {
|
||||
final override string getAPrimaryQlClass() { result = "SelfVariableAccess" }
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ private module Cached {
|
||||
m = resolveConstantReadAccess(c.getReceiver())
|
||||
or
|
||||
m = enclosingModule(c).getModule() and
|
||||
c.getReceiver() instanceof SelfVariableAccess
|
||||
c.getReceiver() instanceof Self
|
||||
) and
|
||||
result = resolveConstantReadAccess(c.getAnArgument())
|
||||
}
|
||||
@@ -437,7 +437,7 @@ private module ResolveImpl {
|
||||
encl = enclosingModule(this) and
|
||||
result = [qualifiedModuleNameNonRec(encl, _, _), qualifiedModuleNameRec(encl, _, _)]
|
||||
|
|
||||
this.getReceiver() instanceof SelfVariableAccess
|
||||
this.getReceiver() instanceof Self
|
||||
or
|
||||
not exists(this.getReceiver())
|
||||
)
|
||||
|
||||
@@ -366,23 +366,7 @@ private module Cached {
|
||||
|
||||
cached
|
||||
predicate isCapturedAccess(LocalVariableAccess access) {
|
||||
exists(Scope scope1, Scope scope2 |
|
||||
scope1 = access.getVariable().getDeclaringScope() and
|
||||
scope2 = access.getCfgScope() and
|
||||
scope1 != scope2
|
||||
|
|
||||
if access instanceof SelfVariableAccess
|
||||
then
|
||||
// ```
|
||||
// class C
|
||||
// def self.m // not a captured access
|
||||
// end
|
||||
// end
|
||||
// ```
|
||||
not scope2 instanceof Toplevel or
|
||||
not access = any(SingletonMethod m).getObject()
|
||||
else any()
|
||||
)
|
||||
access.getVariable().getDeclaringScope() != access.getCfgScope()
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -14,7 +14,7 @@ class EntryNode extends CfgNode, TEntryNode {
|
||||
|
||||
EntryNode() { this = TEntryNode(scope) }
|
||||
|
||||
final override EntryBasicBlock getBasicBlock() { result = super.getBasicBlock() }
|
||||
final override EntryBasicBlock getBasicBlock() { result = CfgNode.super.getBasicBlock() }
|
||||
|
||||
final override Location getLocation() { result = scope.getLocation() }
|
||||
|
||||
@@ -31,7 +31,7 @@ class AnnotatedExitNode extends CfgNode, TAnnotatedExitNode {
|
||||
/** Holds if this node represent a normal exit. */
|
||||
final predicate isNormal() { normal = true }
|
||||
|
||||
final override AnnotatedExitBasicBlock getBasicBlock() { result = super.getBasicBlock() }
|
||||
final override AnnotatedExitBasicBlock getBasicBlock() { result = CfgNode.super.getBasicBlock() }
|
||||
|
||||
final override Location getLocation() { result = scope.getLocation() }
|
||||
|
||||
|
||||
@@ -233,8 +233,6 @@ module Ssa {
|
||||
)
|
||||
}
|
||||
|
||||
override SelfVariable getSourceVariable() { result = v }
|
||||
|
||||
final override string toString() { result = "self (" + v.getDeclaringScope() + ")" }
|
||||
|
||||
final override Location getLocation() { result = this.getControlFlowNode().getLocation() }
|
||||
@@ -316,7 +314,7 @@ module Ssa {
|
||||
CapturedCallDefinition() {
|
||||
exists(Variable v, BasicBlock bb, int i |
|
||||
this.definesAt(v, bb, i) and
|
||||
SsaImpl::capturedCallWrite(_, bb, i, v)
|
||||
SsaImpl::capturedCallWrite(bb, i, v)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ private module Cached {
|
||||
result = lookupMethod(tp, method) and
|
||||
if result.(Method).isPrivate()
|
||||
then
|
||||
exists(SelfVariableAccess self |
|
||||
exists(Self self |
|
||||
self = call.getReceiver().getExpr() and
|
||||
pragma[only_bind_out](self.getEnclosingModule().getModule().getSuperClass*()) =
|
||||
pragma[only_bind_out](result.getEnclosingModule().getModule())
|
||||
@@ -232,18 +232,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a viable run-time target for the call `call`. */
|
||||
cached
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
result = TCfgScope(getTarget(call.asCall())) and
|
||||
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
|
||||
or
|
||||
exists(LibraryCallable callable |
|
||||
result = TLibraryCallable(callable) and
|
||||
call.asCall().getExpr() = callable.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TArgumentPosition =
|
||||
TSelfArgumentPosition() or
|
||||
@@ -312,14 +300,28 @@ private DataFlow::LocalSourceNode trackInstance(Module tp, TypeTracker t) {
|
||||
)
|
||||
or
|
||||
// `self` in method
|
||||
tp = result.(SsaSelfDefinitionNode).getSelfScope().(Method).getEnclosingModule().getModule()
|
||||
exists(Self self, Method enclosing |
|
||||
self = result.asExpr().getExpr() and
|
||||
enclosing = self.getEnclosingMethod() and
|
||||
tp = enclosing.getEnclosingModule().getModule() and
|
||||
not self.getEnclosingModule().getEnclosingMethod() = enclosing
|
||||
)
|
||||
or
|
||||
// `self` in singleton method
|
||||
flowsToSingletonMethodObject(trackInstance(tp), result.(SsaSelfDefinitionNode).getSelfScope())
|
||||
exists(Self self, MethodBase enclosing |
|
||||
self = result.asExpr().getExpr() and
|
||||
flowsToSingletonMethodObject(trackInstance(tp), enclosing) and
|
||||
enclosing = self.getEnclosingMethod() and
|
||||
not self.getEnclosingModule().getEnclosingMethod() = enclosing
|
||||
)
|
||||
or
|
||||
// `self` in top-level
|
||||
result.(SsaSelfDefinitionNode).getSelfScope() instanceof Toplevel and
|
||||
tp = TResolved("Object")
|
||||
exists(Self self, Toplevel enclosing |
|
||||
self = result.asExpr().getExpr() and
|
||||
enclosing = self.getEnclosingModule() and
|
||||
tp = TResolved("Object") and
|
||||
not self.getEnclosingMethod().getEnclosingModule() = enclosing
|
||||
)
|
||||
or
|
||||
// a module or class
|
||||
exists(Module m |
|
||||
@@ -369,7 +371,7 @@ private predicate singletonMethod(MethodBase method, Expr object) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowsToSingletonMethodObject(DataFlow::LocalSourceNode nodeFrom, MethodBase method) {
|
||||
exists(DataFlow::Node nodeTo |
|
||||
exists(DataFlow::LocalSourceNode nodeTo |
|
||||
nodeFrom.flowsTo(nodeTo) and
|
||||
singletonMethod(method, nodeTo.asExpr().getExpr())
|
||||
)
|
||||
@@ -407,8 +409,13 @@ private DataFlow::LocalSourceNode trackSingletonMethod(MethodBase m, string name
|
||||
name = m.getName()
|
||||
}
|
||||
|
||||
private SsaSelfDefinitionNode selfInModule(Module tp) {
|
||||
tp = result.getSelfScope().(ModuleBase).getModule()
|
||||
private DataFlow::Node selfInModule(Module tp) {
|
||||
exists(Self self, ModuleBase enclosing |
|
||||
self = result.asExpr().getExpr() and
|
||||
enclosing = self.getEnclosingModule() and
|
||||
tp = enclosing.getModule() and
|
||||
not self.getEnclosingMethod().getEnclosingModule() = enclosing
|
||||
)
|
||||
}
|
||||
|
||||
private DataFlow::LocalSourceNode trackModule(Module tp, TypeTracker t) {
|
||||
@@ -435,6 +442,17 @@ private DataFlow::LocalSourceNode trackModule(Module tp) {
|
||||
result = trackModule(tp, TypeTracker::end())
|
||||
}
|
||||
|
||||
/** Gets a viable run-time target for the call `call`. */
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
result = TCfgScope(getTarget(call.asCall())) and
|
||||
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
|
||||
or
|
||||
exists(LibraryCallable callable |
|
||||
result = TLibraryCallable(callable) and
|
||||
call.asCall().getExpr() = callable.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context. This is the case if the
|
||||
|
||||
@@ -70,20 +70,6 @@ module LocalFlow {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the SSA definition node corresponding to the implicit `self` parameter for `m`. */
|
||||
private SsaDefinitionNode getSelfParameterDefNode(MethodBase m) {
|
||||
result.getDefinition().(Ssa::SelfDefinition).getSourceVariable().getDeclaringScope() = m
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node.
|
||||
*/
|
||||
predicate localFlowSsaParamInput(Node nodeFrom, Node nodeTo) {
|
||||
nodeTo = getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
|
||||
or
|
||||
nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNode).getMethod())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
|
||||
* involving SSA definition `def`.
|
||||
@@ -129,6 +115,9 @@ module LocalFlow {
|
||||
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
|
||||
localSsaFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
nodeFrom.(SelfParameterNode).getMethod() = nodeTo.asExpr().getExpr().getEnclosingCallable() and
|
||||
nodeTo.asExpr().getExpr() instanceof Self
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
|
||||
@@ -247,7 +236,7 @@ private module Cached {
|
||||
or
|
||||
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
|
||||
or
|
||||
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
nodeTo = LocalFlow::getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
|
||||
or
|
||||
nodeTo.(SynthReturnNode).getAnInput() = nodeFrom
|
||||
or
|
||||
@@ -264,7 +253,7 @@ private module Cached {
|
||||
or
|
||||
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
|
||||
or
|
||||
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
nodeTo = LocalFlow::getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
|
||||
or
|
||||
@@ -286,34 +275,27 @@ private module Cached {
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
private predicate entrySsaDefinition(SsaDefinitionNode n) {
|
||||
n = LocalFlow::getParameterDefNode(_)
|
||||
or
|
||||
exists(Ssa::Definition def | def = n.getDefinition() |
|
||||
def instanceof Ssa::SelfDefinition
|
||||
or
|
||||
def instanceof Ssa::CapturedEntryDefinition
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isLocalSourceNode(Node n) {
|
||||
n instanceof ParameterNode
|
||||
or
|
||||
n instanceof PostUpdateNodes::ExprPostUpdateNode
|
||||
// This case should not be needed once we have proper use-use flow
|
||||
// for `self`. At that point, the `self`s returned by `trackInstance`
|
||||
// in `DataFlowDispatch.qll` should refer to the post-update node,
|
||||
// and we can remove this case.
|
||||
n.asExpr().getExpr() instanceof Self
|
||||
or
|
||||
// Expressions that can't be reached from another entry definition or expression.
|
||||
not localFlowStepTypeTracker+(any(Node n0 |
|
||||
n0 instanceof ExprNode
|
||||
// Nodes that can't be reached from another parameter or expression.
|
||||
not localFlowStepTypeTracker+(any(Node e |
|
||||
e instanceof ExprNode
|
||||
or
|
||||
entrySsaDefinition(n0)
|
||||
), n.(ExprNode))
|
||||
e instanceof ParameterNode
|
||||
), n)
|
||||
or
|
||||
// Ensure all entry SSA definitions are local sources -- for parameters, this
|
||||
// is needed by type tracking. Note that when the parameter has a default value,
|
||||
// it will be reachable from an expression (the default value) and therefore
|
||||
// won't be caught by the rule above.
|
||||
entrySsaDefinition(n)
|
||||
// Ensure all parameter SSA nodes are local sources -- this is needed by type tracking.
|
||||
// Note that when the parameter has a default value, it will be reachable from an
|
||||
// expression (the default value) and therefore won't be caught by the rule above.
|
||||
n = LocalFlow::getParameterDefNode(_)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -376,16 +358,6 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
|
||||
override string toStringImpl() { result = def.toString() }
|
||||
}
|
||||
|
||||
/** An SSA definition for a `self` variable. */
|
||||
class SsaSelfDefinitionNode extends LocalSourceNode, SsaDefinitionNode {
|
||||
private SelfVariable self;
|
||||
|
||||
SsaSelfDefinitionNode() { self = def.getSourceVariable() }
|
||||
|
||||
/** Gets the scope in which the `self` variable is declared. */
|
||||
Scope getSelfScope() { result = self.getDeclaringScope() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A value returning statement, viewed as a node in a data flow graph.
|
||||
*
|
||||
@@ -773,6 +745,13 @@ predicate jumpStep(Node pred, Node succ) {
|
||||
SsaImpl::captureFlowOut(pred.(SsaDefinitionNode).getDefinition(),
|
||||
succ.(SsaDefinitionNode).getDefinition())
|
||||
or
|
||||
exists(Self s, Method m |
|
||||
s = succ.asExpr().getExpr() and
|
||||
pred.(SelfParameterNode).getMethod() = m and
|
||||
m = s.getEnclosingMethod() and
|
||||
m != s.getEnclosingCallable()
|
||||
)
|
||||
or
|
||||
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
private import SsaImplCommon
|
||||
private import SsaImplSpecific as SsaImplSpecific
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.CFG
|
||||
private import codeql.ruby.ast.Variable
|
||||
@@ -41,50 +40,58 @@ private predicate capturedExitRead(AnnotatedExitBasicBlock bb, int i, LocalVaria
|
||||
i = bb.length()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if captured variable `v` is read directly inside `scope`,
|
||||
* or inside a (transitively) nested scope of `scope`.
|
||||
*/
|
||||
private CfgScope getCaptureOuterCfgScope(CfgScope scope) {
|
||||
result = scope.getOuterCfgScope() and
|
||||
(
|
||||
scope instanceof Block
|
||||
or
|
||||
scope instanceof Lambda
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if captured variable `v` is read inside `scope`. */
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedRead(Variable v, CfgScope scope) {
|
||||
any(LocalVariableReadAccess read |
|
||||
read.getVariable() = v and scope = read.getCfgScope().getOuterCfgScope*()
|
||||
read.getVariable() = v and scope = getCaptureOuterCfgScope*(read.getCfgScope())
|
||||
).isCapturedAccess()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is written inside basic block `bb`, which is in the immediate
|
||||
* outer scope of `scope`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate variableWriteInOuterScope(BasicBlock bb, LocalVariable v, CfgScope scope) {
|
||||
SsaImplSpecific::variableWrite(bb, _, v, _) and
|
||||
scope.getOuterCfgScope() = bb.getScope()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasVariableWriteWithCapturedRead(BasicBlock bb, LocalVariable v, CfgScope scope) {
|
||||
hasCapturedRead(v, scope) and
|
||||
variableWriteInOuterScope(bb, v, scope)
|
||||
exists(VariableWriteAccess write |
|
||||
write = bb.getANode().getNode() and
|
||||
write.getVariable() = v and
|
||||
bb.getScope() = scope.getOuterCfgScope()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call `call` at index `i` in basic block `bb` may reach
|
||||
* a callable that reads captured variable `v`.
|
||||
* Holds if the call at index `i` in basic block `bb` may reach a callable
|
||||
* that reads captured variable `v`.
|
||||
*/
|
||||
private predicate capturedCallRead(Call call, BasicBlock bb, int i, LocalVariable v) {
|
||||
private predicate capturedCallRead(BasicBlock bb, int i, LocalVariable v) {
|
||||
exists(CfgScope scope |
|
||||
hasVariableWriteWithCapturedRead(bb.getAPredecessor*(), v, scope) and
|
||||
call = bb.getNode(i).getNode()
|
||||
bb.getNode(i).getNode() instanceof Call
|
||||
|
|
||||
// If the read happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
not scope instanceof Block
|
||||
or
|
||||
scope = call.(MethodCall).getBlock()
|
||||
// If the read happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
scope = any(MethodCall c | bb.getNode(i) = c.getAControlFlowNode()).getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if captured variable `v` is written inside `scope`. */
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedWrite(Variable v, CfgScope scope) {
|
||||
any(LocalVariableWriteAccess write |
|
||||
write.getVariable() = v and scope = getCaptureOuterCfgScope*(write.getCfgScope())
|
||||
).isCapturedAccess()
|
||||
}
|
||||
|
||||
/** Holds if `v` is read at index `i` in basic block `bb`. */
|
||||
private predicate variableReadActual(BasicBlock bb, int i, LocalVariable v) {
|
||||
exists(VariableReadAccess read |
|
||||
@@ -97,38 +104,21 @@ predicate variableRead(BasicBlock bb, int i, LocalVariable v, boolean certain) {
|
||||
variableReadActual(bb, i, v) and
|
||||
certain = true
|
||||
or
|
||||
capturedCallRead(_, bb, i, v) and
|
||||
capturedCallRead(bb, i, v) and
|
||||
certain = false
|
||||
or
|
||||
capturedExitRead(bb, i, v) and
|
||||
certain = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if captured variable `v` is written directly inside `scope`,
|
||||
* or inside a (transitively) nested scope of `scope`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedWrite(Variable v, CfgScope scope) {
|
||||
any(LocalVariableWriteAccess write |
|
||||
write.getVariable() = v and scope = write.getCfgScope().getOuterCfgScope*()
|
||||
).isCapturedAccess()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is read inside basic block `bb`, which is in the immediate
|
||||
* outer scope of `scope`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate variableReadActualInOuterScope(BasicBlock bb, LocalVariable v, CfgScope scope) {
|
||||
variableReadActual(bb, _, v) and
|
||||
bb.getScope() = scope.getOuterCfgScope()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasVariableReadWithCapturedWrite(BasicBlock bb, LocalVariable v, CfgScope scope) {
|
||||
hasCapturedWrite(v, scope) and
|
||||
variableReadActualInOuterScope(bb, v, scope)
|
||||
exists(VariableReadAccess read |
|
||||
read = bb.getANode().getNode() and
|
||||
read.getVariable() = v and
|
||||
bb.getScope() = scope.getOuterCfgScope()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -144,20 +134,20 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call `call` at index `i` in basic block `bb` may reach a callable
|
||||
* Holds if the call at index `i` in basic block `bb` may reach a callable
|
||||
* that writes captured variable `v`.
|
||||
*/
|
||||
cached
|
||||
predicate capturedCallWrite(Call call, BasicBlock bb, int i, LocalVariable v) {
|
||||
predicate capturedCallWrite(BasicBlock bb, int i, LocalVariable v) {
|
||||
exists(CfgScope scope |
|
||||
hasVariableReadWithCapturedWrite(bb.getASuccessor*(), v, scope) and
|
||||
call = bb.getNode(i).getNode()
|
||||
bb.getNode(i).getNode() instanceof Call
|
||||
|
|
||||
// If the write happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
not scope instanceof Block
|
||||
or
|
||||
scope = call.(MethodCall).getBlock()
|
||||
// If the write happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
scope = any(MethodCall c | bb.getNode(i) = c.getAControlFlowNode()).getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -187,26 +177,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate defReachesCallReadInOuterScope(
|
||||
Definition def, Call call, LocalVariable v, CfgScope scope
|
||||
) {
|
||||
exists(BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
capturedCallRead(call, bb, i, v) and
|
||||
scope.getOuterCfgScope() = bb.getScope()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedEntryWrite(Definition entry, LocalVariable v, CfgScope scope) {
|
||||
exists(BasicBlock bb, int i |
|
||||
capturedEntryWrite(bb, i, v) and
|
||||
entry.definesAt(v, bb, i) and
|
||||
bb.getScope().getOuterCfgScope*() = scope
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is flow for a captured variable from the enclosing scope into a block.
|
||||
* ```rb
|
||||
@@ -218,35 +188,13 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate captureFlowIn(Definition def, Definition entry) {
|
||||
exists(Call call, LocalVariable v, CfgScope scope |
|
||||
defReachesCallReadInOuterScope(def, call, v, scope) and
|
||||
hasCapturedEntryWrite(entry, v, scope)
|
||||
|
|
||||
// If the read happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
not scope instanceof Block
|
||||
or
|
||||
scope = call.(MethodCall).getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
|
||||
pragma[noinline]
|
||||
private predicate defReachesExitReadInInnerScope(Definition def, LocalVariable v, CfgScope scope) {
|
||||
exists(BasicBlock bb, int i |
|
||||
exists(LocalVariable v, BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
capturedExitRead(bb, i, v) and
|
||||
scope = bb.getScope().getOuterCfgScope*()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedExitRead(Definition exit, Call call, LocalVariable v, CfgScope scope) {
|
||||
exists(BasicBlock bb, int i |
|
||||
capturedCallWrite(call, bb, i, v) and
|
||||
exit.definesAt(v, bb, i) and
|
||||
bb.getScope() = scope.getOuterCfgScope()
|
||||
capturedCallRead(bb, i, v) and
|
||||
exists(BasicBlock bb2, int i2 |
|
||||
capturedEntryWrite(bb2, i2, v) and
|
||||
entry.definesAt(v, bb2, i2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -262,15 +210,13 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate captureFlowOut(Definition def, Definition exit) {
|
||||
exists(Call call, LocalVariable v, CfgScope scope |
|
||||
defReachesExitReadInInnerScope(def, v, scope) and
|
||||
hasCapturedExitRead(exit, call, v, _)
|
||||
|
|
||||
// If the read happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
not scope instanceof Block
|
||||
or
|
||||
scope = call.(MethodCall).getBlock()
|
||||
exists(LocalVariable v, BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
capturedExitRead(bb, i, v) and
|
||||
exists(BasicBlock bb2, int i2 |
|
||||
capturedCallWrite(bb2, i2, v) and
|
||||
exit.definesAt(v, bb2, i2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain)
|
||||
) and
|
||||
certain = true
|
||||
or
|
||||
SsaImpl::capturedCallWrite(_, bb, i, v) and
|
||||
SsaImpl::capturedCallWrite(bb, i, v) and
|
||||
certain = false
|
||||
}
|
||||
|
||||
|
||||
@@ -66,53 +66,35 @@ private CfgNodes::ExprNodes::VariableWriteAccessCfgNode variablesInPattern(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included
|
||||
* in all global taint flow configurations.
|
||||
*/
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included
|
||||
* in all global taint flow configurations.
|
||||
*/
|
||||
cached
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// value of `case` expression into variables in patterns
|
||||
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::ExprNodes::InClauseCfgNode clause |
|
||||
nodeFrom.asExpr() = case.getValue() and
|
||||
clause = case.getBranch(_) and
|
||||
nodeTo.(SsaDefinitionNode).getDefinition().getControlFlowNode() =
|
||||
variablesInPattern(clause.getPattern())
|
||||
)
|
||||
or
|
||||
// operation involving `nodeFrom`
|
||||
exists(CfgNodes::ExprNodes::OperationCfgNode op |
|
||||
op = nodeTo.asExpr() and
|
||||
op.getAnOperand() = nodeFrom.asExpr() and
|
||||
not op.getExpr() instanceof AssignExpr
|
||||
)
|
||||
or
|
||||
// string interpolation of `nodeFrom` into `nodeTo`
|
||||
nodeFrom.asExpr() =
|
||||
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
|
||||
or
|
||||
// Although flow through arrays is modelled precisely using stores/reads, we still
|
||||
// allow flow out of a _tainted_ array. This is needed in order to support taint-
|
||||
// tracking configurations where the source is an array.
|
||||
readStep(nodeFrom, any(DataFlow::Content::ArrayElementContent c), nodeTo)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step.
|
||||
*/
|
||||
cached
|
||||
predicate localTaintStepCached(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
defaultAdditionalTaintStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Simple flow through library code is included in the exposed local
|
||||
// step relation, even though flow is technically inter-procedural
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false)
|
||||
}
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// value of `case` expression into variables in patterns
|
||||
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::ExprNodes::InClauseCfgNode clause |
|
||||
nodeFrom.asExpr() = case.getValue() and
|
||||
clause = case.getBranch(_) and
|
||||
nodeTo.(SsaDefinitionNode).getDefinition().getControlFlowNode() =
|
||||
variablesInPattern(clause.getPattern())
|
||||
)
|
||||
or
|
||||
// operation involving `nodeFrom`
|
||||
exists(CfgNodes::ExprNodes::OperationCfgNode op |
|
||||
op = nodeTo.asExpr() and
|
||||
op.getAnOperand() = nodeFrom.asExpr() and
|
||||
not op.getExpr() instanceof AssignExpr
|
||||
)
|
||||
or
|
||||
// string interpolation of `nodeFrom` into `nodeTo`
|
||||
nodeFrom.asExpr() =
|
||||
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
|
||||
or
|
||||
// Although flow through arrays is modelled precisely using stores/reads, we still
|
||||
// allow flow out of a _tainted_ array. This is needed in order to support taint-
|
||||
// tracking configurations where the source is an array.
|
||||
readStep(nodeFrom, any(DataFlow::Content::ArrayElementContent c), nodeTo)
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
@@ -20,4 +20,14 @@ predicate localExprTaint(CfgNodes::ExprCfgNode e1, CfgNodes::ExprCfgNode e2) {
|
||||
localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2))
|
||||
}
|
||||
|
||||
predicate localTaintStep = localTaintStepCached/2;
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step.
|
||||
*/
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
defaultAdditionalTaintStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Simple flow through library code is included in the exposed local
|
||||
// step relation, even though flow is technically inter-procedural
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false)
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ private class ActionControllerContextCall extends MethodCall {
|
||||
private ActionControllerControllerClass controllerClass;
|
||||
|
||||
ActionControllerContextCall() {
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
this.getReceiver() instanceof Self and
|
||||
this.getEnclosingModule() = controllerClass
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ private class ActionViewHtmlEscapeCall extends HtmlEscapeCall {
|
||||
// A call in a context where some commonly used `ActionView` methods are available.
|
||||
private class ActionViewContextCall extends MethodCall {
|
||||
ActionViewContextCall() {
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
this.getReceiver() instanceof Self and
|
||||
inActionViewContext(this)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.controlflow.CfgNodes
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
private import codeql.ruby.dataflow.internal.DataFlowPrivate
|
||||
private import codeql.ruby.ast.internal.Module
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.frameworks.Stdlib
|
||||
@@ -101,7 +100,7 @@ class ActiveRecordModelClassMethodCall extends MethodCall {
|
||||
recvCls = this.getReceiver().(ActiveRecordModelClassMethodCall).getReceiverClass()
|
||||
or
|
||||
// e.g. self.where(...) within an ActiveRecordModelClass
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
this.getReceiver() instanceof Self and
|
||||
this.getEnclosingModule() = recvCls
|
||||
}
|
||||
|
||||
@@ -284,15 +283,14 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation
|
||||
}
|
||||
|
||||
// A `self` reference that may resolve to an active record model object
|
||||
private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation,
|
||||
SsaSelfDefinitionNode {
|
||||
private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation {
|
||||
private ActiveRecordModelClass cls;
|
||||
|
||||
ActiveRecordModelClassSelfReference() {
|
||||
exists(MethodBase m |
|
||||
m = this.getCfgScope() and
|
||||
m.getEnclosingModule() = cls and
|
||||
m = cls.getAMethod()
|
||||
exists(Self s |
|
||||
s.getEnclosingModule() = cls and
|
||||
s.getEnclosingMethod() = cls.getAMethod() and
|
||||
s = this.asExpr().getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ private class GraphqlSchemaObjectClassMethodCall extends MethodCall {
|
||||
recvCls.getModule() = resolveConstantReadAccess(this.getReceiver())
|
||||
or
|
||||
// e.g. self.some_method(...) within a graphql Object or Interface
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
this.getReceiver() instanceof Self and
|
||||
this.getEnclosingModule() = recvCls
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.FlowSummary
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
private import codeql.ruby.controlflow.CfgNodes
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
|
||||
/** Provides modeling for the `Kernel` class. */
|
||||
module Kernel {
|
||||
@@ -27,7 +29,7 @@ module Kernel {
|
||||
or
|
||||
methodCall instanceof UnknownMethodCall and
|
||||
(
|
||||
this.getReceiver().asExpr().getExpr() instanceof SelfVariableAccess and
|
||||
this.getReceiver().asExpr().getExpr() instanceof Self and
|
||||
isPrivateKernelMethod(methodCall.getMethodName())
|
||||
or
|
||||
isPublicKernelMethod(methodCall.getMethodName())
|
||||
@@ -145,6 +147,43 @@ module Kernel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A system command executed via the `Kernel.open` method.
|
||||
* If the first argument passed to `Kernel.open` starts with "|" then the rest
|
||||
* of the string will be interpreted as a shell command and executed.
|
||||
* Ruby documentation: https://docs.ruby-lang.org/en/3.0.0/Kernel.html#method-i-open
|
||||
*/
|
||||
class KernelOpenCall extends SystemCommandExecution::Range, KernelMethodCall {
|
||||
KernelOpenCall() { this.getMethodName() = "open" }
|
||||
|
||||
override DataFlow::Node getAnArgument() { result = this.getArgument(_) }
|
||||
|
||||
// Kernel.open invokes a subshell if the argument starts with "|".
|
||||
// If we don't know the prefix of the argument, assume it could start with "|".
|
||||
override predicate isShellInterpreted(DataFlow::Node arg) {
|
||||
arg = this.getAnArgument() and
|
||||
not stringArgumentCannotStartWithPipe(arg)
|
||||
}
|
||||
|
||||
predicate stringArgumentCannotStartWithPipe(DataFlow::Node arg) {
|
||||
// open("prefix#{expr}")
|
||||
arg.asExpr()
|
||||
.(ExprNodes::StringlikeLiteralCfgNode)
|
||||
.getComponent(0)
|
||||
.getConstantValue()
|
||||
.getString()
|
||||
.charAt(0) != "|"
|
||||
or
|
||||
// arg = "prefix#{expr}"
|
||||
// open(arg)
|
||||
exists(Ssa::WriteDefinition d, ExprNodes::StringlikeLiteralCfgNode s |
|
||||
d.getARead() = arg.asExpr() and d.assigns(s)
|
||||
|
|
||||
s.getComponent(0).getConstantValue().getString().charAt(0) != "|"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Kernel.eval`, which executes its first argument as Ruby code.
|
||||
* ```ruby
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
* adding your own.
|
||||
*/
|
||||
|
||||
private import ruby
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.RemoteFlowSources
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.Frameworks
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.ApplicationHeuristics
|
||||
|
||||
module CommandInjection {
|
||||
/**
|
||||
@@ -36,6 +38,19 @@ module CommandInjection {
|
||||
override string getSourceType() { result = "a user-provided value" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Input to a public method, considered as a flow source.
|
||||
* This is only correct if the codebase is a Ruby gem, rather than an application.
|
||||
*/
|
||||
class LibraryInput extends Source {
|
||||
LibraryInput() {
|
||||
Application::isGem() and
|
||||
exists(Method m | not m.isPrivate() | this.asParameter() = m.getAParameter())
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "user-provided input" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A command argument to a function that initiates an operating system command.
|
||||
*/
|
||||
|
||||
@@ -88,7 +88,10 @@ predicate callStep(Node nodeFrom, Node nodeTo) {
|
||||
// we model it as a call step, in order to avoid computing a potential
|
||||
// self-cross product of all calls to a function that returns one of its parameters
|
||||
// (only to later filter that flow out using `TypeTracker::append`).
|
||||
DataFlowPrivate::LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
nodeTo =
|
||||
DataFlowPrivate::LocalFlow::getParameterDefNode(nodeFrom
|
||||
.(DataFlowPublic::ParameterNode)
|
||||
.getParameter())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ calls/calls.rb:
|
||||
# 58| getDesugared: [MethodCall] call to []
|
||||
# 58| getReceiver: [ConstantReadAccess] Array
|
||||
# 58| getArgument: [MethodCall] call to foo
|
||||
# 58| getReceiver: [SelfVariableAccess] self
|
||||
# 58| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 59| [ArrayLiteral] [...]
|
||||
# 59| getDesugared: [MethodCall] call to []
|
||||
# 59| getReceiver: [ConstantReadAccess] Array
|
||||
@@ -15,7 +15,7 @@ calls/calls.rb:
|
||||
# 66| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 66| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] var1
|
||||
# 66| getAnOperand/getArgument/getRightOperand: [MethodCall] call to bar
|
||||
# 66| getReceiver: [SelfVariableAccess] self
|
||||
# 66| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 67| [AssignAddExpr] ... += ...
|
||||
# 67| getDesugared: [AssignExpr] ... = ...
|
||||
# 67| getAnOperand/getLeftOperand: [LocalVariableAccess] var1
|
||||
@@ -32,9 +32,9 @@ calls/calls.rb:
|
||||
# 226| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 226| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 227| getStmt: [MethodCall] call to baz
|
||||
# 227| getReceiver: [SelfVariableAccess] self
|
||||
# 227| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 226| getReceiver: [MethodCall] call to bar
|
||||
# 226| getReceiver: [SelfVariableAccess] self
|
||||
# 226| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 229| [ForExpr] for ... in ...
|
||||
# 229| getDesugared: [MethodCall] call to each
|
||||
# 229| getBlock: [BraceBlock] { ... }
|
||||
@@ -52,9 +52,9 @@ calls/calls.rb:
|
||||
# 249| getReceiver: [ConstantReadAccess] Hash
|
||||
# 249| getArgument: [Pair] Pair
|
||||
# 249| getKey: [MethodCall] call to foo
|
||||
# 249| getReceiver: [SelfVariableAccess] self
|
||||
# 249| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 249| getValue: [MethodCall] call to bar
|
||||
# 249| getReceiver: [SelfVariableAccess] self
|
||||
# 249| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 249| getArgument: [Pair] Pair
|
||||
# 249| getKey: [MethodCall] call to foo
|
||||
# 249| getReceiver: [ConstantReadAccess] X
|
||||
@@ -63,7 +63,7 @@ calls/calls.rb:
|
||||
# 314| [AssignExpr] ... = ...
|
||||
# 314| getDesugared: [StmtSequence] ...
|
||||
# 314| getStmt: [SetterMethodCall] call to foo=
|
||||
# 314| getReceiver: [SelfVariableAccess] self
|
||||
# 314| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 314| getArgument: [AssignExpr] ... = ...
|
||||
# 314| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 314| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
@@ -72,7 +72,7 @@ calls/calls.rb:
|
||||
# 315| getDesugared: [StmtSequence] ...
|
||||
# 315| getStmt: [SetterMethodCall] call to []=
|
||||
# 315| getReceiver: [MethodCall] call to foo
|
||||
# 315| getReceiver: [SelfVariableAccess] self
|
||||
# 315| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 315| getArgument: [AssignExpr] ... = ...
|
||||
# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 315| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
@@ -84,7 +84,7 @@ calls/calls.rb:
|
||||
# 316| getAnOperand/getLeftOperand: [MethodCall] call to foo
|
||||
# 316| getDesugared: [StmtSequence] ...
|
||||
# 316| getStmt: [SetterMethodCall] call to foo=
|
||||
# 316| getReceiver: [SelfVariableAccess] self
|
||||
# 316| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 316| getArgument: [AssignExpr] ... = ...
|
||||
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 316| getArgument: [IntegerLiteral] 0
|
||||
@@ -95,7 +95,7 @@ calls/calls.rb:
|
||||
# 316| getAnOperand/getLeftOperand: [MethodCall] call to bar
|
||||
# 316| getDesugared: [StmtSequence] ...
|
||||
# 316| getStmt: [SetterMethodCall] call to bar=
|
||||
# 316| getReceiver: [SelfVariableAccess] self
|
||||
# 316| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 316| getArgument: [AssignExpr] ... = ...
|
||||
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 316| getArgument: [RangeLiteral] _ .. _
|
||||
@@ -109,7 +109,7 @@ calls/calls.rb:
|
||||
# 316| getDesugared: [StmtSequence] ...
|
||||
# 316| getStmt: [SetterMethodCall] call to []=
|
||||
# 316| getReceiver: [MethodCall] call to foo
|
||||
# 316| getReceiver: [SelfVariableAccess] self
|
||||
# 316| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 316| getArgument: [AssignExpr] ... = ...
|
||||
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 316| getArgument: [IntegerLiteral] -1
|
||||
@@ -139,7 +139,7 @@ calls/calls.rb:
|
||||
# 317| getDesugared: [StmtSequence] ...
|
||||
# 317| getStmt: [SetterMethodCall] call to []=
|
||||
# 317| getReceiver: [MethodCall] call to foo
|
||||
# 317| getReceiver: [SelfVariableAccess] self
|
||||
# 317| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 317| getArgument: [AssignExpr] ... = ...
|
||||
# 317| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 317| getArgument: [RangeLiteral] _ .. _
|
||||
@@ -161,7 +161,7 @@ calls/calls.rb:
|
||||
# 318| [AssignAddExpr] ... += ...
|
||||
# 318| getDesugared: [StmtSequence] ...
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
|
||||
# 318| getAnOperand/getRightOperand: [Self, SelfVariableAccess] self
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 318| getStmt: [SetterMethodCall] call to count=
|
||||
# 318| getReceiver: [LocalVariableAccess] __synth__0
|
||||
@@ -177,7 +177,7 @@ calls/calls.rb:
|
||||
# 319| getDesugared: [StmtSequence] ...
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getRightOperand: [MethodCall] call to foo
|
||||
# 319| getReceiver: [SelfVariableAccess] self
|
||||
# 319| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 319| getStmt: [SetterMethodCall] call to []=
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__0
|
||||
@@ -199,7 +199,7 @@ calls/calls.rb:
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [MethodCall] call to bar
|
||||
# 320| getReceiver: [MethodCall] call to foo
|
||||
# 320| getReceiver: [SelfVariableAccess] self
|
||||
# 320| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 320| getStmt: [SetterMethodCall] call to []=
|
||||
# 320| getReceiver: [LocalVariableAccess] __synth__0
|
||||
@@ -213,13 +213,13 @@ calls/calls.rb:
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [MethodCall] call to baz
|
||||
# 320| getReceiver: [MethodCall] call to foo
|
||||
# 320| getReceiver: [SelfVariableAccess] self
|
||||
# 320| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 320| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to boo
|
||||
# 320| getReceiver: [MethodCall] call to foo
|
||||
# 320| getReceiver: [SelfVariableAccess] self
|
||||
# 320| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 320| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
@@ -260,7 +260,7 @@ calls/calls.rb:
|
||||
# 340| getReceiver: [LocalVariableAccess] __synth__0__1
|
||||
# 340| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
|
||||
# 341| getStmt: [MethodCall] call to foo
|
||||
# 341| getReceiver: [SelfVariableAccess] self
|
||||
# 341| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 341| getArgument: [LocalVariableAccess] x
|
||||
# 341| getArgument: [LocalVariableAccess] y
|
||||
# 341| getArgument: [LocalVariableAccess] z
|
||||
@@ -476,7 +476,7 @@ literals/literals.rb:
|
||||
# 118| getValue: [IntegerLiteral] 7
|
||||
# 118| getArgument: [HashSplatExpr] ** ...
|
||||
# 118| getAnOperand/getOperand/getReceiver: [MethodCall] call to baz
|
||||
# 118| getReceiver: [SelfVariableAccess] self
|
||||
# 118| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 185| [HashLiteral] {...}
|
||||
# 185| getDesugared: [MethodCall] call to []
|
||||
# 185| getReceiver: [ConstantReadAccess] Hash
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
| local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self |
|
||||
| local_dataflow.rb:1:1:7:3 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self |
|
||||
| local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:1:1:7:3 | self (foo) |
|
||||
| local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:3:8:3:10 | self |
|
||||
| local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:1:9:1:9 | a |
|
||||
| local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:2:7:2:7 | a |
|
||||
| local_dataflow.rb:2:3:2:7 | ... = ... | local_dataflow.rb:3:13:3:13 | b |
|
||||
@@ -71,7 +71,16 @@
|
||||
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:51:20:51:20 | x |
|
||||
| local_dataflow.rb:51:9:51:15 | "break" | local_dataflow.rb:51:3:51:15 | break |
|
||||
| local_dataflow.rb:60:1:90:3 | self (test_case) | local_dataflow.rb:78:12:78:20 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:60:1:90:3 | self (test_case) |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:78:12:78:20 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:79:20:79:26 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:80:24:80:30 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:82:7:82:13 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:83:7:83:13 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:84:7:84:13 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:85:22:85:28 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:86:28:86:34 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:87:20:87:26 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:89:3:89:9 | self |
|
||||
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:60:15:60:15 | x |
|
||||
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:61:12:61:12 | x |
|
||||
| local_dataflow.rb:61:7:68:5 | case ... | local_dataflow.rb:61:3:68:5 | ... = ... |
|
||||
|
||||
@@ -201,6 +201,7 @@ edges
|
||||
| string_flow.rb:241:10:241:10 | b [array element] : | string_flow.rb:241:10:241:13 | ...[...] |
|
||||
| string_flow.rb:242:10:242:10 | b [array element] : | string_flow.rb:242:10:242:13 | ...[...] |
|
||||
| string_flow.rb:246:5:246:18 | ... = ... : | string_flow.rb:250:26:250:26 | a : |
|
||||
| string_flow.rb:246:5:246:18 | ... = ... : | string_flow.rb:258:27:258:27 | a : |
|
||||
| string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:246:5:246:18 | ... = ... : |
|
||||
| string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:247:10:247:10 | a : |
|
||||
| string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:248:20:248:20 | a : |
|
||||
@@ -214,6 +215,7 @@ edges
|
||||
| string_flow.rb:250:26:250:26 | a : | string_flow.rb:250:10:250:28 | call to scrub |
|
||||
| string_flow.rb:252:10:252:10 | a : | string_flow.rb:252:10:252:22 | call to scrub! |
|
||||
| string_flow.rb:253:21:253:21 | a : | string_flow.rb:253:10:253:22 | call to scrub! |
|
||||
| string_flow.rb:255:5:255:18 | ... = ... : | string_flow.rb:250:26:250:26 | a : |
|
||||
| string_flow.rb:255:5:255:18 | ... = ... : | string_flow.rb:258:27:258:27 | a : |
|
||||
| string_flow.rb:255:9:255:18 | call to source : | string_flow.rb:255:5:255:18 | ... = ... : |
|
||||
| string_flow.rb:255:9:255:18 | call to source : | string_flow.rb:256:5:256:5 | a : |
|
||||
|
||||
@@ -5,7 +5,6 @@ track
|
||||
| type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker without call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
@@ -17,10 +16,17 @@ track
|
||||
| type_tracker.rb:3:9:3:23 | [post] self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:9:3:23 | [post] self | type tracker without call steps | type_tracker.rb:3:9:3:23 | [post] self |
|
||||
| type_tracker.rb:3:9:3:23 | call to puts | type tracker without call steps | type_tracker.rb:3:9:3:23 | call to puts |
|
||||
| type_tracker.rb:3:9:3:23 | self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:9:3:23 | self | type tracker without call steps | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:3:14:3:17 | [post] self | type tracker without call steps | type_tracker.rb:3:14:3:17 | [post] self |
|
||||
| type_tracker.rb:3:14:3:17 | self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:14:3:17 | self | type tracker without call steps | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:3:14:3:23 | [post] call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | [post] call to field |
|
||||
| type_tracker.rb:3:14:3:23 | call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:4:9:4:14 | @field | type tracker without call steps | type_tracker.rb:4:9:4:14 | @field |
|
||||
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:4:18:4:20 | val |
|
||||
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:7:5:9:7 | &block | type tracker without call steps | type_tracker.rb:7:5:9:7 | &block |
|
||||
| type_tracker.rb:7:5:9:7 | field | type tracker without call steps | type_tracker.rb:7:5:9:7 | field |
|
||||
| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
@@ -35,22 +41,15 @@ track
|
||||
| type_tracker.rb:12:1:16:3 | m | type tracker without call steps | type_tracker.rb:12:1:16:3 | m |
|
||||
| type_tracker.rb:12:1:16:3 | return return in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type tracker without call steps | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type tracker with call steps | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | self in m |
|
||||
| type_tracker.rb:13:5:13:7 | var | type tracker without call steps | type_tracker.rb:13:5:13:7 | var |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker without call steps | type_tracker.rb:13:5:13:23 | ... = ... |
|
||||
| type_tracker.rb:13:11:13:19 | Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | Container |
|
||||
| type_tracker.rb:13:11:13:19 | [post] Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | [post] Container |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker without call steps | type_tracker.rb:13:11:13:23 | call to new |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type tracker without call steps | type_tracker.rb:14:5:14:7 | [post] var |
|
||||
| type_tracker.rb:14:5:14:13 | ... = ... | type tracker without call steps | type_tracker.rb:14:5:14:13 | ... = ... |
|
||||
| type_tracker.rb:14:5:14:13 | [post] ... = ... | type tracker without call steps | type_tracker.rb:14:5:14:13 | [post] ... = ... |
|
||||
| type_tracker.rb:14:5:14:13 | __synth__0 | type tracker without call steps | type_tracker.rb:14:5:14:13 | __synth__0 |
|
||||
| type_tracker.rb:14:5:14:13 | call to field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
@@ -64,6 +63,7 @@ track
|
||||
| type_tracker.rb:15:5:15:18 | [post] self | type tracker without call steps | type_tracker.rb:15:5:15:18 | [post] self |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:15:5:15:18 | call to puts |
|
||||
| type_tracker.rb:15:5:15:18 | self | type tracker without call steps | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:15:10:15:12 | [post] var | type tracker without call steps | type_tracker.rb:15:10:15:12 | [post] var |
|
||||
| type_tracker.rb:15:10:15:18 | [post] call to field | type tracker without call steps | type_tracker.rb:15:10:15:18 | [post] call to field |
|
||||
| type_tracker.rb:15:10:15:18 | call to field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
@@ -76,7 +76,6 @@ trackEnd
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:14:3:17 | self |
|
||||
@@ -95,10 +94,19 @@ trackEnd
|
||||
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:9:3:23 | call to puts | type_tracker.rb:3:9:3:23 | call to puts |
|
||||
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:14:3:17 | [post] self | type_tracker.rb:3:14:3:17 | [post] self |
|
||||
| type_tracker.rb:3:14:3:17 | self | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:3:14:3:17 | self | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:14:3:23 | [post] call to field | type_tracker.rb:3:14:3:23 | [post] call to field |
|
||||
| type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:4:9:4:14 | @field | type_tracker.rb:4:9:4:14 | @field |
|
||||
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:9:4:20 | ... = ... |
|
||||
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:18:4:20 | val |
|
||||
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:7:5:9:7 | &block | type_tracker.rb:7:5:9:7 | &block |
|
||||
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:1:1:10:3 | Container |
|
||||
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:7:5:9:7 | field |
|
||||
@@ -115,21 +123,11 @@ trackEnd
|
||||
| type_tracker.rb:12:1:16:3 | return return in m | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self in m |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:13:5:13:7 | var | type_tracker.rb:13:5:13:7 | var |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:13:5:13:23 | ... = ... |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:14:5:14:7 | var |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:15:10:15:12 | var |
|
||||
| type_tracker.rb:13:11:13:19 | Container | type_tracker.rb:13:11:13:19 | Container |
|
||||
| type_tracker.rb:13:11:13:19 | [post] Container | type_tracker.rb:13:11:13:19 | [post] Container |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:14:3:17 | self |
|
||||
@@ -142,9 +140,6 @@ trackEnd
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:14:5:14:7 | [post] var |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:15:10:15:12 | var |
|
||||
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:13 | ... = ... |
|
||||
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:13 | __synth__0 |
|
||||
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:23 | ... |
|
||||
| type_tracker.rb:14:5:14:13 | [post] ... = ... | type_tracker.rb:14:5:14:13 | [post] ... = ... |
|
||||
| type_tracker.rb:14:5:14:13 | __synth__0 | type_tracker.rb:14:5:14:13 | __synth__0 |
|
||||
| type_tracker.rb:14:5:14:13 | call to field= | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
@@ -162,6 +157,7 @@ trackEnd
|
||||
| type_tracker.rb:15:5:15:18 | [post] self | type_tracker.rb:15:5:15:18 | [post] self |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:15:5:15:18 | call to puts |
|
||||
| type_tracker.rb:15:5:15:18 | self | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:15:10:15:12 | [post] var | type_tracker.rb:15:10:15:12 | [post] var |
|
||||
| type_tracker.rb:15:10:15:18 | [post] call to field | type_tracker.rb:15:10:15:18 | [post] call to field |
|
||||
| type_tracker.rb:15:10:15:18 | call to field | type_tracker.rb:15:10:15:18 | call to field |
|
||||
|
||||
@@ -45,9 +45,9 @@ potentiallyUnsafeSqlExecutingMethodCall
|
||||
| ActiveRecordInjection.rb:75:5:75:29 | call to order |
|
||||
| ActiveRecordInjection.rb:80:7:80:40 | call to find_by |
|
||||
activeRecordModelInstantiations
|
||||
| ActiveRecordInjection.rb:8:3:11:5 | self (authenticate) | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
| ActiveRecordInjection.rb:10:5:10:68 | self | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
| ActiveRecordInjection.rb:15:5:15:40 | call to find_by | ActiveRecordInjection.rb:1:1:3:3 | UserGroup |
|
||||
| ActiveRecordInjection.rb:20:3:24:5 | self (delete_by) | ActiveRecordInjection.rb:19:1:25:3 | Admin |
|
||||
| ActiveRecordInjection.rb:23:5:23:25 | self | ActiveRecordInjection.rb:19:1:25:3 | Admin |
|
||||
| ActiveRecordInjection.rb:80:7:80:40 | call to find_by | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
| ActiveRecordInjection.rb:85:5:85:33 | call to find_by | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
| ActiveRecordInjection.rb:88:5:88:34 | call to find | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
|
||||
@@ -37,6 +37,12 @@ kernelSpawnCallExecutions
|
||||
| Kernel.rb:67:1:67:58 | call to spawn |
|
||||
| Kernel.rb:68:1:68:61 | call to spawn |
|
||||
| Kernel.rb:69:1:69:71 | call to spawn |
|
||||
kernelOpenCallExecutions
|
||||
| Kernel.rb:77:1:77:21 | call to open | Kernel.rb:77:6:77:20 | "\| cat foo.txt" |
|
||||
| Kernel.rb:78:1:78:26 | call to open | Kernel.rb:78:6:78:20 | "\| cat foo.txt" |
|
||||
| Kernel.rb:79:1:79:51 | call to open | Kernel.rb:79:6:79:20 | "\| cat foo.txt" |
|
||||
| Kernel.rb:82:1:82:9 | call to open | Kernel.rb:82:6:82:8 | cmd |
|
||||
| Kernel.rb:88:3:88:17 | call to open | Kernel.rb:88:8:88:16 | maybe_cmd |
|
||||
sendCallCodeExecutions
|
||||
| Kernel.rb:2:1:2:22 | call to send | Kernel.rb:2:6:2:12 | "raise" |
|
||||
| Kernel.rb:5:1:5:19 | call to send | Kernel.rb:5:8:5:13 | "push" |
|
||||
|
||||
@@ -7,6 +7,10 @@ query predicate kernelExecCallExecutions(KernelExecCall c) { any() }
|
||||
|
||||
query predicate kernelSpawnCallExecutions(KernelSpawnCall c) { any() }
|
||||
|
||||
query predicate kernelOpenCallExecutions(KernelOpenCall c, DataFlow::Node arg) {
|
||||
c.isShellInterpreted(arg)
|
||||
}
|
||||
|
||||
query DataFlow::Node sendCallCodeExecutions(SendCallCodeExecution e) { result = e.getCode() }
|
||||
|
||||
query DataFlow::Node evalCallCodeExecutions(EvalCallCodeExecution e) { result = e.getCode() }
|
||||
|
||||
@@ -68,6 +68,29 @@ spawn({"FOO" => "BAR"}, "echo foo", unsetenv_others: true)
|
||||
spawn({"FOO" => "BAR"}, "echo", "foo", unsetenv_others: true)
|
||||
spawn({"FOO" => "BAR"}, ["echo", "echo"], "foo", unsetenv_others: true)
|
||||
|
||||
# GOOD
|
||||
open("foo.txt")
|
||||
open("foo.txt", "r")
|
||||
open("foo.txt", "r") { |f| f.write("hello") }
|
||||
|
||||
# BAD
|
||||
open("| cat foo.txt")
|
||||
open("| cat foo.txt", "w")
|
||||
open("| cat foo.txt", "w") { |f| f.write("hello") }
|
||||
|
||||
cmd = "| cat foo.txt"
|
||||
open(cmd) # BAD
|
||||
|
||||
file = "foo.txt"
|
||||
open(file) # GOOD
|
||||
|
||||
def open_wrapped(maybe_cmd)
|
||||
open(maybe_cmd) # BAD - string could start with '|'
|
||||
open("foo#{maybe_cmd}.txt") # GOOD - won't cause shell execution because string doesn't start with '|'
|
||||
file = "foo#{maybe_cmd}.txt"
|
||||
open(file) # GOOD - same as above
|
||||
end
|
||||
|
||||
module MockSystem
|
||||
def system(*args)
|
||||
args
|
||||
|
||||
@@ -29,14 +29,12 @@ definition
|
||||
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self |
|
||||
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a |
|
||||
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d |
|
||||
| parameters.rb:1:1:1:1 | self (parameters.rb) | parameters.rb:1:1:62:1 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self |
|
||||
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x |
|
||||
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y |
|
||||
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas |
|
||||
| parameters.rb:15:1:19:3 | self (print_map) | parameters.rb:15:1:19:3 | self |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map |
|
||||
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key |
|
||||
@@ -112,7 +110,6 @@ definition
|
||||
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self |
|
||||
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
|
||||
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem |
|
||||
| ssa.rb:32:1:36:3 | self (m3) | ssa.rb:32:1:36:3 | self |
|
||||
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self |
|
||||
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x |
|
||||
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self |
|
||||
|
||||
Reference in New Issue
Block a user