mirror of
https://github.com/github/codeql.git
synced 2025-12-21 03:06:31 +01:00
Merge branch 'main' into rc/3.7
This commit is contained in:
@@ -413,7 +413,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 dotnet build --no-incremental 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 +440,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[@"dotnet build --no-incremental C:\Project/test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project/test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -715,9 +715,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 && msbuild C:\\Project\\test1.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /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 && msbuild C:\\Project\\test2.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /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 +746,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 && msbuild C:\\Project\\test1.csproj /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /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 && msbuild C:\\Project\\test2.csproj /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /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 +791,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 && msbuild C:\\Project\\test1.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /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 +817,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 && msbuild C:\\Project\\test1.sln /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /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 /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /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 +862,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[@"dotnet build --no-incremental --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 +894,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:\Project/.dotnet/dotnet build --no-incremental C:\Project/test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists["test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -929,7 +929,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:\Project/.dotnet/dotnet build --no-incremental C:\Project/test.csproj"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists["test.csproj"] = true;
|
||||
actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
|
||||
@@ -960,7 +960,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:\Project\.dotnet\dotnet build --no-incremental 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 +1008,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 && msbuild C:\\Project\\dirs.proj /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /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 +1052,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[@"msbuild C:\Project/dirs.proj /t:rebuild"] = 0;
|
||||
actions.FileExists["csharp.log"] = true;
|
||||
actions.FileExists[@"C:\Project/a/test.csproj"] = true;
|
||||
actions.FileExists[@"C:\Project/dirs.proj"] = true;
|
||||
|
||||
@@ -5,7 +5,6 @@ using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Semmle.Util;
|
||||
using System.Text.RegularExpressions;
|
||||
using Semmle.Autobuild.Shared;
|
||||
|
||||
namespace Semmle.Autobuild.CSharp
|
||||
@@ -81,9 +80,6 @@ namespace Semmle.Autobuild.CSharp
|
||||
env = null;
|
||||
}
|
||||
|
||||
if (env is null)
|
||||
env = new Dictionary<string, string>();
|
||||
env.Add("UseSharedCompilation", "false");
|
||||
return f(installDir, env);
|
||||
});
|
||||
}
|
||||
@@ -245,8 +241,7 @@ namespace Semmle.Autobuild.CSharp
|
||||
Argument("--no-incremental");
|
||||
|
||||
return
|
||||
script.Argument("/p:UseSharedCompilation=false").
|
||||
Argument(builder.Options.DotNetArguments).
|
||||
script.Argument(builder.Options.DotNetArguments).
|
||||
QuoteArgument(projOrSln).
|
||||
Script;
|
||||
}
|
||||
|
||||
@@ -98,8 +98,6 @@ namespace Semmle.Autobuild.Shared
|
||||
command.RunCommand(msBuild);
|
||||
command.QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
command.Argument("/p:UseSharedCompilation=false");
|
||||
|
||||
var target = builder.Options.MsBuildTarget ?? "rebuild";
|
||||
var platform = builder.Options.MsBuildPlatform ?? (projectOrSolution is ISolution s1 ? s1.DefaultPlatformName : null);
|
||||
var configuration = builder.Options.MsBuildConfiguration ?? (projectOrSolution is ISolution s2 ? s2.DefaultConfigurationName : null);
|
||||
@@ -109,7 +107,6 @@ namespace Semmle.Autobuild.Shared
|
||||
command.Argument(string.Format("/p:Platform=\"{0}\"", platform));
|
||||
if (configuration is not null)
|
||||
command.Argument(string.Format("/p:Configuration=\"{0}\"", configuration));
|
||||
command.Argument("/p:MvcBuildViews=true");
|
||||
|
||||
command.Argument(builder.Options.MsBuildArguments);
|
||||
|
||||
|
||||
@@ -35,3 +35,10 @@ options:
|
||||
the code (for example if it uses inaccessible dependencies).
|
||||
type: string
|
||||
pattern: "^(false|true)$"
|
||||
cil:
|
||||
title: Whether to enable CIL extraction.
|
||||
description: >
|
||||
A value indicating, whether CIL extraction should be enabled.
|
||||
The default is 'true'.
|
||||
type: string
|
||||
pattern: "^(false|true)$"
|
||||
|
||||
@@ -9,7 +9,7 @@ Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,45,1
|
||||
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,80,3
|
||||
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,62,
|
||||
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,12,
|
||||
Microsoft.Extensions.FileProviders,,,15,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,16,
|
||||
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,13,2
|
||||
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,16,1
|
||||
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,10,
|
||||
@@ -19,10 +19,10 @@ Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,63,
|
||||
Microsoft.Interop,,,27,,,,,,,,,,,,27,
|
||||
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,1,
|
||||
Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,4,
|
||||
Microsoft.VisualBasic,,,9,,,,,,,,,,,,5,4
|
||||
Microsoft.VisualBasic,,,10,,,,,,,,,,,,5,5
|
||||
Microsoft.Win32,,,8,,,,,,,,,,,,8,
|
||||
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,,,,,,73,18
|
||||
ServiceStack,194,,7,27,,,,,,75,92,,,,7,
|
||||
System,43,4,11809,,1,1,1,,4,,33,3,1,3,9867,1942
|
||||
System,65,4,12131,,8,8,9,,4,,33,3,1,3,10139,1992
|
||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,
|
||||
|
||||
|
@@ -8,7 +8,7 @@ C# framework & library support
|
||||
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",4,11809,43,7
|
||||
Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,554,138,
|
||||
Totals,,4,12370,375,7
|
||||
System,"``System.*``, ``System``",4,12131,65,7
|
||||
Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,556,138,
|
||||
Totals,,4,12694,397,7
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Introduce '--cil' flag in the comments. This does not make any changes to the dbscheme.
|
||||
compatibility: full
|
||||
@@ -13,31 +13,6 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
Extractor.SetInvariantCulture();
|
||||
|
||||
Console.WriteLine($"Semmle.Extraction.CSharp.Driver: called with {string.Join(", ", args)}");
|
||||
|
||||
if (args.Length > 0 && args[0] == "--dotnetexec")
|
||||
{
|
||||
var compilerRegEx = new Regex(@"csc\.exe|mcs\.exe|csc\.dll", RegexOptions.Compiled);
|
||||
var cil = args.Length > 1 && args[1] == "--cil";
|
||||
for (var i = cil ? 2 : 1; i < args.Length; i++)
|
||||
{
|
||||
if (compilerRegEx.IsMatch(args[i]))
|
||||
{
|
||||
var argsList = new List<string>();
|
||||
if (cil)
|
||||
argsList.Add("--cil");
|
||||
argsList.Add("--compiler");
|
||||
argsList.Add(args[i]);
|
||||
if (i + 1 < args.Length)
|
||||
argsList.AddRange(args[(i + 1)..]);
|
||||
return (int)Extractor.Run(argsList.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"Semmle.Extraction.CSharp.Driver: not a compiler invocation");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)Extractor.Run(args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
CSharp.Extractor.SetInvariantCulture();
|
||||
|
||||
var options = Options.Create(args);
|
||||
// options.CIL = true; // To do: Enable this
|
||||
|
||||
if (options.Help)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Semmle.Extraction.Tests
|
||||
{
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.True(options.Cache);
|
||||
Assert.False(options.CIL);
|
||||
Assert.True(options.CIL);
|
||||
Assert.Null(options.Framework);
|
||||
Assert.Null(options.CompilerName);
|
||||
Assert.Empty(options.CompilerArguments);
|
||||
@@ -51,10 +51,20 @@ namespace Semmle.Extraction.Tests
|
||||
[Fact]
|
||||
public void CIL()
|
||||
{
|
||||
options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil" });
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.True(options.CIL);
|
||||
options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil", "--nocil" });
|
||||
|
||||
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", "false");
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.False(options.CIL);
|
||||
|
||||
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", "true");
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.True(options.CIL);
|
||||
|
||||
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", null);
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.True(options.CIL);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -121,22 +131,6 @@ namespace Semmle.Extraction.Tests
|
||||
Assert.Equal("foo", options.Framework);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnvironmentVariables()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "--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("LGTM_INDEX_EXTRACTOR", "--nocil");
|
||||
options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil" });
|
||||
Assert.False(options.CIL);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StandaloneDefaults()
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// Holds if CIL should be extracted.
|
||||
/// </summary>
|
||||
public bool CIL { get; private set; } = false;
|
||||
public bool CIL { get; private set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Holds if assemblies shouldn't be extracted twice.
|
||||
@@ -50,7 +50,6 @@ namespace Semmle.Extraction
|
||||
/// </summary>
|
||||
public bool QlTest { get; private set; } = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The compression algorithm used for trap files.
|
||||
/// </summary>
|
||||
@@ -73,6 +72,9 @@ namespace Semmle.Extraction
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case "cil":
|
||||
CIL = Boolean.Parse(value);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -97,9 +99,6 @@ namespace Semmle.Extraction
|
||||
case "cache":
|
||||
Cache = value;
|
||||
return true;
|
||||
case "cil":
|
||||
CIL = value;
|
||||
return true;
|
||||
case "pdb":
|
||||
PDB = value;
|
||||
CIL = true;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Semmle.Util
|
||||
bool HandleOption(string key, string value);
|
||||
|
||||
/// <summary>
|
||||
/// Handle a flag of the form "--cil" or "--nocil"
|
||||
/// Handle a flag of the form "--cache" or "--nocache"
|
||||
/// </summary>
|
||||
/// <param name="key">The name of the flag. This is case sensitive.</param>
|
||||
/// <param name="value">True if set, or false if prefixed by "--no"</param>
|
||||
@@ -40,6 +40,7 @@ namespace Semmle.Util
|
||||
|
||||
public static class OptionsExtensions
|
||||
{
|
||||
private static readonly string[] ExtractorOptions = new[] { "trap_compression", "cil" };
|
||||
private static string? GetExtractorOption(string name) =>
|
||||
Environment.GetEnvironmentVariable($"CODEQL_EXTRACTOR_CSHARP_OPTION_{name.ToUpper()}");
|
||||
|
||||
@@ -47,12 +48,14 @@ namespace Semmle.Util
|
||||
{
|
||||
var extractorOptions = new List<string>();
|
||||
|
||||
var trapCompression = GetExtractorOption("trap_compression");
|
||||
if (!string.IsNullOrEmpty(trapCompression))
|
||||
foreach (var option in ExtractorOptions)
|
||||
{
|
||||
extractorOptions.Add($"--trap_compression:{trapCompression}");
|
||||
var value = GetExtractorOption(option);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
extractorOptions.Add($"--{option}:{value}");
|
||||
}
|
||||
}
|
||||
|
||||
return extractorOptions;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import experimental.code.csharp.Cryptography.NonCryptographicHashes
|
||||
|
||||
from Variable v, Literal l, LoopStmt loop, Expr additional_xor
|
||||
where
|
||||
maybeUsedInFNVFunction(v, _, _, loop) and
|
||||
maybeUsedInFnvFunction(v, _, _, loop) and
|
||||
(
|
||||
exists(BitwiseXorExpr xor2 | xor2.getAnOperand() = l and additional_xor = xor2 |
|
||||
loop.getAControlFlowExitNode().getASuccessor*() = xor2.getAControlFlowNode() and
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.SsaImplCommon::Consistency
|
||||
import semmle.code.csharp.dataflow.internal.SsaImpl::Consistency as Consistency
|
||||
import Ssa
|
||||
|
||||
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
class MyRelevantDefinition extends Consistency::RelevantDefinition, Ssa::Definition {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
@@ -10,6 +10,14 @@ class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
}
|
||||
}
|
||||
|
||||
query predicate nonUniqueDef = Consistency::nonUniqueDef/4;
|
||||
|
||||
query predicate readWithoutDef = Consistency::readWithoutDef/3;
|
||||
|
||||
query predicate deadDef = Consistency::deadDef/2;
|
||||
|
||||
query predicate notDominatedByDef = Consistency::notDominatedByDef/4;
|
||||
|
||||
query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) {
|
||||
// Local variables in C# must be initialized before every use, so uninitialized
|
||||
// local variables should not have an SSA definition, as that would imply that
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Console.WriteLine(args[0]);
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
from create_database_utils import *
|
||||
|
||||
run_codeql_database_create(['dotnet build'], test_db="default-db", db=None, lang="csharp")
|
||||
2
csharp/ql/integration-tests/all-platforms/qlpack.yml
Normal file
2
csharp/ql/integration-tests/all-platforms/qlpack.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
libraryPathDependencies:
|
||||
- codeql-csharp
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
|
||||
5
csharp/ql/lib/change-notes/2022-09-12-uppercase.md
Normal file
5
csharp/ql/lib/change-notes/2022-09-12-uppercase.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
@@ -13,7 +13,7 @@ private import semmle.code.csharp.dataflow.TaintTracking2
|
||||
predicate maybeANonCryptogrphicHash(Callable callable, Variable v, Expr xor, Expr mul, LoopStmt loop) {
|
||||
callable = loop.getEnclosingCallable() and
|
||||
(
|
||||
maybeUsedInFNVFunction(v, xor, mul, loop) or
|
||||
maybeUsedInFnvFunction(v, xor, mul, loop) or
|
||||
maybeUsedInElfHashFunction(v, xor, mul, loop)
|
||||
)
|
||||
}
|
||||
@@ -23,7 +23,7 @@ predicate maybeANonCryptogrphicHash(Callable callable, Variable v, Expr xor, Exp
|
||||
* where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression
|
||||
* followed by a multiplication `mul` expression.
|
||||
*/
|
||||
predicate maybeUsedInFNVFunction(Variable v, Operation xor, Operation mul, LoopStmt loop) {
|
||||
predicate maybeUsedInFnvFunction(Variable v, Operation xor, Operation mul, LoopStmt loop) {
|
||||
exists(Expr e1, Expr e2 |
|
||||
e1.getAChild*() = v.getAnAccess() and
|
||||
e2.getAChild*() = v.getAnAccess() and
|
||||
@@ -37,6 +37,9 @@ predicate maybeUsedInFNVFunction(Variable v, Operation xor, Operation mul, LoopS
|
||||
loop.getAChild*() = xor.getEnclosingStmt()
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for maybeUsedInFnvFunction */
|
||||
deprecated predicate maybeUsedInFNVFunction = maybeUsedInFnvFunction/4;
|
||||
|
||||
/**
|
||||
* Holds if the arguments are used in a way that resembles an Elf-Hash hash function
|
||||
* where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression
|
||||
|
||||
@@ -5,3 +5,5 @@ dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
library: true
|
||||
upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/ssa: 0.0.1
|
||||
|
||||
@@ -56,7 +56,7 @@ private predicate alwaysNotNullVariableUpdate(VariableUpdate vu) {
|
||||
|
||||
/** Holds if expression `expr` always evaluates to non-null. */
|
||||
private predicate alwaysNotNullExpr(Expr expr) {
|
||||
expr instanceof Opcodes::Newobj
|
||||
expr instanceof Opcodes::NewObj
|
||||
or
|
||||
expr instanceof Literal and not expr instanceof NullLiteral
|
||||
or
|
||||
|
||||
@@ -766,7 +766,7 @@ module Opcodes {
|
||||
}
|
||||
|
||||
/** A `newobj` instruction. */
|
||||
class Newobj extends Call, @cil_newobj {
|
||||
class NewObj extends Call, @cil_newobj {
|
||||
override string getOpcodeName() { result = "newobj" }
|
||||
|
||||
override int getPushCount() { result = 1 }
|
||||
@@ -788,6 +788,9 @@ module Opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for NewObj */
|
||||
deprecated class Newobj = NewObj;
|
||||
|
||||
/** An `initobj` instruction. */
|
||||
class Initobj extends Instruction, @cil_initobj {
|
||||
override string getOpcodeName() { result = "initobj" }
|
||||
@@ -847,10 +850,13 @@ module Opcodes {
|
||||
}
|
||||
|
||||
/** A `rethrow` instruction. */
|
||||
class Rethrow extends Throw, @cil_rethrow {
|
||||
class ReThrow extends Throw, @cil_rethrow {
|
||||
override string getOpcodeName() { result = "rethrow" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ReThrow */
|
||||
deprecated class Rethrow = ReThrow;
|
||||
|
||||
/** A `ldlen` instruction. */
|
||||
class Ldlen extends UnaryExpr, @cil_ldlen {
|
||||
override string getOpcodeName() { result = "ldlen" }
|
||||
|
||||
@@ -8,13 +8,12 @@ private import CIL
|
||||
* Provides classes for working with static single assignment (SSA) form.
|
||||
*/
|
||||
module Ssa {
|
||||
private import internal.SsaImplCommon as SsaImpl
|
||||
private import internal.SsaImpl
|
||||
private import internal.SsaImpl as SsaImpl
|
||||
|
||||
/** An SSA definition. */
|
||||
class Definition extends SsaImpl::Definition {
|
||||
/** Gets a read of this SSA definition. */
|
||||
final ReadAccess getARead() { result = getARead(this) }
|
||||
final ReadAccess getARead() { result = SsaImpl::getARead(this) }
|
||||
|
||||
/** Gets the underlying variable update, if any. */
|
||||
final VariableUpdate getVariableUpdate() {
|
||||
@@ -25,11 +24,11 @@ module Ssa {
|
||||
}
|
||||
|
||||
/** Gets a first read of this SSA definition. */
|
||||
final ReadAccess getAFirstRead() { result = getAFirstRead(this) }
|
||||
final ReadAccess getAFirstRead() { result = SsaImpl::getAFirstRead(this) }
|
||||
|
||||
/** Holds if `first` and `second` are adjacent reads of this SSA definition. */
|
||||
final predicate hasAdjacentReads(ReadAccess first, ReadAccess second) {
|
||||
hasAdjacentReads(this, first, second)
|
||||
SsaImpl::hasAdjacentReads(this, first, second)
|
||||
}
|
||||
|
||||
private Definition getAPhiInput() { result = this.(PhiNode).getAnInput() }
|
||||
@@ -52,7 +51,7 @@ module Ssa {
|
||||
final override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
|
||||
/** Gets an input to this phi node. */
|
||||
final Definition getAnInput() { result = getAPhiInput(this) }
|
||||
final Definition getAnInput() { result = SsaImpl::getAPhiInput(this) }
|
||||
|
||||
/**
|
||||
* Holds if if `def` is an input to this phi node, and a reference to `def` at
|
||||
@@ -60,7 +59,7 @@ module Ssa {
|
||||
* other references.
|
||||
*/
|
||||
final predicate hasLastInputRef(Definition def, BasicBlock bb, int i) {
|
||||
hasLastInputRef(this, def, bb, i)
|
||||
SsaImpl::hasLastInputRef(this, def, bb, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,40 @@
|
||||
private import semmle.code.cil.CIL
|
||||
private import SsaImplCommon
|
||||
private import cil
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig {
|
||||
class BasicBlock = CIL::BasicBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock = CIL::ExitBasicBlock;
|
||||
|
||||
class SourceVariable = CIL::StackVariable;
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
forceCachingInSameStage() and
|
||||
exists(CIL::VariableUpdate vu |
|
||||
vu.updatesAt(bb, i) and
|
||||
v = vu.getVariable() and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(CIL::ReadAccess ra | bb.getNode(i) = ra |
|
||||
ra.getTarget() = v and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<SsaInput>
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private import CIL
|
||||
|
||||
cached
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
|
||||
@@ -1,795 +0,0 @@
|
||||
/**
|
||||
* Provides a language-independent implementation of static single assignment
|
||||
* (SSA) form.
|
||||
*/
|
||||
|
||||
private import SsaImplSpecific
|
||||
|
||||
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb }
|
||||
|
||||
/**
|
||||
* Liveness analysis (based on source variables) to restrict the size of the
|
||||
* SSA representation.
|
||||
*/
|
||||
private module Liveness {
|
||||
/**
|
||||
* A classification of variable references into reads (of a given kind) and
|
||||
* (certain or uncertain) writes.
|
||||
*/
|
||||
private newtype TRefKind =
|
||||
Read(boolean certain) { certain in [false, true] } or
|
||||
Write(boolean certain) { certain in [false, true] }
|
||||
|
||||
private class RefKind extends TRefKind {
|
||||
string toString() {
|
||||
exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")")
|
||||
or
|
||||
exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")")
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this = Read(_) and
|
||||
result = 0
|
||||
or
|
||||
this = Write(_) and
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
|
||||
*/
|
||||
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
|
||||
or
|
||||
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
|
||||
}
|
||||
|
||||
private newtype OrderedRefIndex =
|
||||
MkOrderedRefIndex(int i, int tag) {
|
||||
exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder())
|
||||
}
|
||||
|
||||
private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) {
|
||||
ref(bb, i, v, k) and
|
||||
result = MkOrderedRefIndex(i, ord) and
|
||||
ord = k.getOrder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of
|
||||
* basic block `bb`, which has the given reference kind `k`.
|
||||
*
|
||||
* Reads are considered before writes when they happen at the same index.
|
||||
*/
|
||||
private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
refOrd(bb, i, v, k, _) =
|
||||
rank[result](int j, int ord, OrderedRefIndex res |
|
||||
res = refOrd(bb, j, v, _, ord)
|
||||
|
|
||||
res order by j, ord
|
||||
)
|
||||
}
|
||||
|
||||
private int maxRefRank(BasicBlock bb, SourceVariable v) {
|
||||
result = refRank(bb, _, v, _) and
|
||||
not result + 1 = refRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
|
||||
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
|
||||
* that is either a read or a certain write.
|
||||
*/
|
||||
private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) {
|
||||
result =
|
||||
min(int r, RefKind k |
|
||||
r = refRank(bb, _, v, k) and
|
||||
k != Write(false)
|
||||
|
|
||||
r
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if source variable `v` is live at the beginning of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtEntry(BasicBlock bb, SourceVariable v) {
|
||||
// The first read or certain write to `v` inside `bb` is a read
|
||||
refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v)
|
||||
or
|
||||
// There is no certain write to `v` inside `bb`, but `v` is live at entry
|
||||
// to a successor basic block of `bb`
|
||||
not exists(firstReadOrCertainWrite(bb, v)) and
|
||||
liveAtExit(bb, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if source variable `v` is live at the end of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
|
||||
liveAtEntry(getABasicBlockSuccessor(bb), v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live in basic block `bb` at index `i`.
|
||||
* The rank of `i` is `rnk` as defined by `refRank()`.
|
||||
*/
|
||||
private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) {
|
||||
exists(RefKind kind | rnk = refRank(bb, i, v, kind) |
|
||||
rnk = maxRefRank(bb, v) and
|
||||
liveAtExit(bb, v)
|
||||
or
|
||||
ref(bb, i, v, kind) and
|
||||
kind = Read(_)
|
||||
or
|
||||
exists(RefKind nextKind |
|
||||
liveAtRank(bb, _, v, rnk + 1) and
|
||||
rnk + 1 = refRank(bb, _, v, nextKind) and
|
||||
nextKind != Write(true)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live after the (certain or uncertain) write at
|
||||
* index `i` inside basic block `bb`.
|
||||
*/
|
||||
predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) {
|
||||
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk))
|
||||
}
|
||||
}
|
||||
|
||||
private import Liveness
|
||||
|
||||
/**
|
||||
* Holds if `df` is in the dominance frontier of `bb`.
|
||||
*
|
||||
* This is equivalent to:
|
||||
*
|
||||
* ```ql
|
||||
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
|
||||
* not bb = getImmediateBasicBlockDominator+(df)
|
||||
* ```
|
||||
*/
|
||||
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
|
||||
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
|
||||
or
|
||||
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
|
||||
bb = getImmediateBasicBlockDominator(prev) and
|
||||
not bb = getImmediateBasicBlockDominator(df)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* definition of `v`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock defbb, Definition def |
|
||||
def.definesAt(v, defbb, _) and
|
||||
inDominanceFrontier(defbb, bb)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TDefinition =
|
||||
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableWrite(bb, i, v, _) and
|
||||
liveAfterWrite(bb, i, v)
|
||||
} or
|
||||
TPhiNode(SourceVariable v, BasicBlock bb) {
|
||||
inDefDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v)
|
||||
}
|
||||
|
||||
private module SsaDefReaches {
|
||||
newtype TSsaRefKind =
|
||||
SsaActualRead() or
|
||||
SsaPhiRead() or
|
||||
SsaDef()
|
||||
|
||||
class SsaRead = SsaActualRead or SsaPhiRead;
|
||||
|
||||
/**
|
||||
* A classification of SSA variable references into reads and definitions.
|
||||
*/
|
||||
class SsaRefKind extends TSsaRefKind {
|
||||
string toString() {
|
||||
this = SsaActualRead() and
|
||||
result = "SsaActualRead"
|
||||
or
|
||||
this = SsaPhiRead() and
|
||||
result = "SsaPhiRead"
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = "SsaDef"
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this instanceof SsaRead and
|
||||
result = 0
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* read of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
|
||||
lastRefIsRead(readbb, v)
|
||||
or
|
||||
phiRead(readbb, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a phi-read node should be inserted for variable `v` at the beginning
|
||||
* of basic block `bb`.
|
||||
*
|
||||
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
|
||||
* instead of writes, and only if the dominance-frontier block does not already
|
||||
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
|
||||
* an internal implementation detail that is not exposed.
|
||||
*
|
||||
* The motivation for adding phi-reads is to improve performance of the use-use
|
||||
* calculation in cases where there is a large number of reads that can reach the
|
||||
* same join-point, and from there reach a large number of basic blocks. Example:
|
||||
*
|
||||
* ```cs
|
||||
* if (a)
|
||||
* use(x);
|
||||
* else if (b)
|
||||
* use(x);
|
||||
* else if (c)
|
||||
* use(x);
|
||||
* else if (d)
|
||||
* use(x);
|
||||
* // many more ifs ...
|
||||
*
|
||||
* // phi-read for `x` inserted here
|
||||
*
|
||||
* // program not mentioning `x`, with large basic block graph
|
||||
*
|
||||
* use(x);
|
||||
* ```
|
||||
*
|
||||
* Without phi-reads, the analysis has to replicate reachability for each of
|
||||
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
|
||||
* each conditional use of `x` to reach the basic block containing the phi-read
|
||||
* node for `x`, and only that basic block will have to compute reachability
|
||||
* through the remainder of the large program.
|
||||
*
|
||||
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
|
||||
* one SSA definition (without passing through another definition): Assume, for
|
||||
* the sake of contradiction, that there are two reaching definitions `def1` and
|
||||
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
|
||||
* dominating definition will prevent the other from reaching `phi-read`. So, at
|
||||
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
|
||||
* Then `def1` must go through one of its dominance-frontier blocks in order to
|
||||
* reach `phi-read`. However, such a block will always start with a (normal) phi
|
||||
* node, which contradicts reachability.
|
||||
*
|
||||
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
|
||||
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
|
||||
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
|
||||
* which contradicts reachability.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiRead(BasicBlock bb, SourceVariable v) {
|
||||
inReadDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v) and
|
||||
// only if there are no other references to `v` inside `bb`
|
||||
not ref(bb, _, v, _) and
|
||||
not exists(Definition def | def.definesAt(v, bb, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
|
||||
* is `SsaDef()`).
|
||||
*
|
||||
* Unlike `Liveness::ref`, this includes `phi` nodes.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
variableRead(bb, i, v, _) and
|
||||
k = SsaActualRead()
|
||||
or
|
||||
phiRead(bb, v) and
|
||||
i = -1 and
|
||||
k = SsaPhiRead()
|
||||
or
|
||||
any(Definition def).definesAt(v, bb, i) and
|
||||
k = SsaDef()
|
||||
}
|
||||
|
||||
private newtype OrderedSsaRefIndex =
|
||||
MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) }
|
||||
|
||||
private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) {
|
||||
ssaRef(bb, i, v, k) and
|
||||
result = MkOrderedSsaRefIndex(i, k) and
|
||||
ord = k.getOrder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
|
||||
* block `bb`, which has the given reference kind `k`.
|
||||
*
|
||||
* For example, if `bb` is a basic block with a phi node for `v` (considered
|
||||
* to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
|
||||
*
|
||||
* ```ql
|
||||
* ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
|
||||
* ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
|
||||
* ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
|
||||
* ```
|
||||
*
|
||||
* Reads are considered before writes when they happen at the same index.
|
||||
*/
|
||||
int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
ssaRefOrd(bb, i, v, k, _) =
|
||||
rank[result](int j, int ord, OrderedSsaRefIndex res |
|
||||
res = ssaRefOrd(bb, j, v, _, ord)
|
||||
|
|
||||
res order by j, ord
|
||||
)
|
||||
}
|
||||
|
||||
int maxSsaRefRank(BasicBlock bb, SourceVariable v) {
|
||||
result = ssaRefRank(bb, _, v, _) and
|
||||
not result + 1 = ssaRefRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA definition `def` reaches rank index `rnk` in its own
|
||||
* basic block `bb`.
|
||||
*/
|
||||
predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) {
|
||||
exists(int i |
|
||||
rnk = ssaRefRank(bb, i, v, SsaDef()) and
|
||||
def.definesAt(v, bb, i)
|
||||
)
|
||||
or
|
||||
ssaDefReachesRank(bb, def, rnk - 1, v) and
|
||||
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA definition of `v` at `def` reaches index `i` in the same
|
||||
* basic block `bb`, without crossing another SSA definition of `v`.
|
||||
*/
|
||||
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
exists(int rnk |
|
||||
ssaDefReachesRank(bb, def, rnk, v) and
|
||||
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||
*/
|
||||
int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) {
|
||||
v = def.getSourceVariable() and
|
||||
result = ssaRefRank(bb, i, v, k) and
|
||||
(
|
||||
ssaDefReachesRead(_, def, bb, i)
|
||||
or
|
||||
def.definesAt(_, bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the reference to `def` at index `i` in basic block `bb` is the
|
||||
* last reference to `v` inside `bb`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
|
||||
}
|
||||
|
||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
|
||||
exists(ssaDefRank(def, v, bb, _, k))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
|
||||
ssaDefReachesEndOfBlock(bb, def, _) and
|
||||
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
|
||||
* predecessor of `bb2`, and the underlying variable for `def` is neither read
|
||||
* nor written in any block on the path between `bb1` and `bb2`.
|
||||
*
|
||||
* Phi reads are considered as normal reads for this predicate.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
defOccursInBlock(def, bb1, _, _) and
|
||||
bb2 = getABasicBlockSuccessor(bb1)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesInclPhiRead(def, bb1, mid) and
|
||||
ssaDefReachesThroughBlock(def, mid) and
|
||||
bb2 = getABasicBlockSuccessor(mid)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(def, bb1, bb2) and
|
||||
defOccursInBlock(def, bb2, v, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
|
||||
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExclPhiRead(def, mid, bb2) and
|
||||
phiReadStep(def, _, bb1, mid)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* the underlying variable `v` of `def` is accessed in basic block `bb2`
|
||||
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
|
||||
* `v` is neither read nor written in any block on the path between `bb1`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesExclPhiRead(def, bb1, bb2) and
|
||||
not defOccursInBlock(def, bb1, _, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
|
||||
varBlockReaches(def, bb1, bb2) and
|
||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
|
||||
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
|
||||
* and `v` is neither read nor written in any block on the path between `bb`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
|
||||
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
|
||||
not defOccursInBlock(def, bb2, _, _) and
|
||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExit(def, mid) and
|
||||
phiReadStep(def, _, bb, mid)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate phiReadExposedForTesting = phiRead/2;
|
||||
|
||||
private import SsaDefReaches
|
||||
|
||||
pragma[nomagic]
|
||||
predicate liveThrough(BasicBlock bb, SourceVariable v) {
|
||||
liveAtExit(bb, v) and
|
||||
not ssaRef(bb, _, v, SsaDef())
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the SSA definition of `v` at `def` reaches the end of basic
|
||||
* block `bb`, at which point it is still live, without crossing another
|
||||
* SSA definition of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
|
||||
exists(int last |
|
||||
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
|
||||
ssaDefReachesRank(bb, def, last, v) and
|
||||
liveAtExit(bb, v)
|
||||
)
|
||||
or
|
||||
// The construction of SSA form ensures that each read of a variable is
|
||||
// dominated by its definition. An SSA definition therefore reaches a
|
||||
// control flow node if it is the _closest_ SSA definition that dominates
|
||||
// the node. If two definitions dominate a node then one must dominate the
|
||||
// other, so therefore the definition of _closest_ is given by the dominator
|
||||
// tree. Thus, reaching definitions can be calculated in terms of dominance.
|
||||
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
|
||||
liveThrough(bb, pragma[only_bind_into](v))
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
|
||||
exists(SourceVariable v, BasicBlock bbDef |
|
||||
phi.definesAt(v, bbDef, _) and
|
||||
getABasicBlockPredecessor(bbDef) = bb and
|
||||
ssaDefReachesEndOfBlock(bb, inp, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
|
||||
* basic block `bb`, without crossing another SSA definition of `v`. The read
|
||||
* is of kind `rk`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
||||
or
|
||||
ssaRef(bb, i, v, any(SsaRead k)) and
|
||||
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
|
||||
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
|
||||
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
|
||||
* path between them without any read of `def`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
exists(int rnk |
|
||||
rnk = ssaDefRank(def, _, bb1, i1, _) and
|
||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
|
||||
variableRead(bb1, i2, _, _) and
|
||||
bb2 = bb1
|
||||
)
|
||||
or
|
||||
lastSsaRef(def, _, bb1, i1) and
|
||||
defAdjacentRead(def, bb1, bb2, i2)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate adjacentDefRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
|
||||
) {
|
||||
adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
|
||||
ssaRef(bb1, i1, v, SsaDef())
|
||||
or
|
||||
variableRead(bb1, i1, v, true)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
|
||||
variableRead(bb3, i3, _, false) and
|
||||
adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `adjacentDefRead`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
variableRead(bb2, i2, _, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
|
||||
* `def`. The reference is last because it can reach another write `next`,
|
||||
* without passing through another read or write.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
|
||||
exists(SourceVariable v |
|
||||
// Next reference to `v` inside `bb` is a write
|
||||
exists(int rnk, int j |
|
||||
rnk = ssaDefRank(def, v, bb, i, _) and
|
||||
next.definesAt(v, bb, j) and
|
||||
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
|
||||
)
|
||||
or
|
||||
// Can reach a write using one or more steps
|
||||
lastSsaRef(def, v, bb, i) and
|
||||
exists(BasicBlock bb2 |
|
||||
varBlockReaches(def, bb, bb2) and
|
||||
1 = ssaDefRank(next, v, bb2, _, SsaDef())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `inp` is an immediately preceding definition of uncertain definition
|
||||
* `def`. Since `def` is uncertain, the value from the preceding definition might
|
||||
* still be valid.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
|
||||
lastRefRedef(inp, _, _, def)
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesUncertainRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
variableRead(bb2, i2, _, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `lastRefRedef`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) {
|
||||
lastRefRedef(def, bb, i, next) and
|
||||
not variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
lastRefRedef(def, bb0, i0, next) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA
|
||||
* definition `def`.
|
||||
*
|
||||
* That is, the node can reach the end of the enclosing callable, or another
|
||||
* SSA definition for the underlying source variable, without passing through
|
||||
* another read.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRef(Definition def, BasicBlock bb, int i) {
|
||||
// Can reach another definition
|
||||
lastRefRedef(def, bb, i, _)
|
||||
or
|
||||
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
|
||||
// Can reach exit directly
|
||||
bb instanceof ExitBasicBlock
|
||||
or
|
||||
// Can reach a block using one or more steps, where `def` is no longer live
|
||||
varBlockReachesExit(def, bb)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `lastRefRedef`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) {
|
||||
lastRef(def, bb, i) and
|
||||
not variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/** A static single assignment (SSA) definition. */
|
||||
class Definition extends TDefinition {
|
||||
/** Gets the source variable underlying this SSA definition. */
|
||||
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
|
||||
* Phi nodes are considered to be at index `-1`, while normal variable writes
|
||||
* are at the index of the control flow node they wrap.
|
||||
*/
|
||||
final predicate definesAt(SourceVariable v, BasicBlock bb, int i) {
|
||||
this = TWriteDef(v, bb, i)
|
||||
or
|
||||
this = TPhiNode(v, bb) and i = -1
|
||||
}
|
||||
|
||||
/** Gets the basic block to which this SSA definition belongs. */
|
||||
final BasicBlock getBasicBlock() { this.definesAt(_, result, _) }
|
||||
|
||||
/** Gets a textual representation of this SSA definition. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/** An SSA definition that corresponds to a write. */
|
||||
class WriteDefinition extends Definition, TWriteDef {
|
||||
private SourceVariable v;
|
||||
private BasicBlock bb;
|
||||
private int i;
|
||||
|
||||
WriteDefinition() { this = TWriteDef(v, bb, i) }
|
||||
|
||||
override string toString() { result = "WriteDef" }
|
||||
}
|
||||
|
||||
/** A phi node. */
|
||||
class PhiNode extends Definition, TPhiNode {
|
||||
override string toString() { result = "Phi" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition that represents an uncertain update of the underlying
|
||||
* source variable.
|
||||
*/
|
||||
class UncertainWriteDefinition extends WriteDefinition {
|
||||
UncertainWriteDefinition() {
|
||||
exists(SourceVariable v, BasicBlock bb, int i |
|
||||
this.definesAt(v, bb, i) and
|
||||
variableWrite(bb, i, v, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a set of consistency queries. */
|
||||
module Consistency {
|
||||
abstract class RelevantDefinition extends Definition {
|
||||
abstract predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
}
|
||||
|
||||
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
|
||||
}
|
||||
|
||||
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableRead(bb, i, v, _) and
|
||||
not ssaDefReachesRead(v, _, bb, i)
|
||||
}
|
||||
|
||||
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
|
||||
v = def.getSourceVariable() and
|
||||
not ssaDefReachesRead(_, def, _, _) and
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/** Provides the CIL specific parameters for `SsaImplCommon.qll`. */
|
||||
|
||||
private import cil
|
||||
private import SsaImpl
|
||||
|
||||
class BasicBlock = CIL::BasicBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock = CIL::ExitBasicBlock;
|
||||
|
||||
class SourceVariable = CIL::StackVariable;
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
forceCachingInSameStage() and
|
||||
exists(CIL::VariableUpdate vu |
|
||||
vu.updatesAt(bb, i) and
|
||||
v = vu.getVariable() and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(CIL::ReadAccess ra | bb.getNode(i) = ra |
|
||||
ra.getTarget() = v and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
@@ -192,8 +192,7 @@ class BasicBlock extends TBasicBlockStart {
|
||||
* Gets the basic block that immediately dominates this basic block, if any.
|
||||
*
|
||||
* That is, all paths reaching this basic block from some entry point
|
||||
* basic block must go through the result, which is an immediate basic block
|
||||
* predecessor of this basic block.
|
||||
* basic block must go through the result.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@@ -207,8 +206,7 @@ class BasicBlock extends TBasicBlockStart {
|
||||
*
|
||||
* The basic block starting on line 2 is an immediate dominator of
|
||||
* the basic block online 4 (all paths from the entry point of `M`
|
||||
* to `return s.Length;` must go through the null check, and the null check
|
||||
* is an immediate predecessor of `return s.Length;`).
|
||||
* to `return s.Length;` must go through the null check.
|
||||
*/
|
||||
BasicBlock getImmediateDominator() { bbIDominates(result, this) }
|
||||
|
||||
|
||||
@@ -6,26 +6,158 @@ import csharp
|
||||
* scope variables.
|
||||
*/
|
||||
module PreSsa {
|
||||
import pressa.SsaImplSpecific
|
||||
private import pressa.SsaImplCommon as SsaImpl
|
||||
private import AssignableDefinitions
|
||||
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
|
||||
private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
|
||||
private predicate definitionAt(
|
||||
AssignableDefinition def, SsaInput::BasicBlock bb, int i, SsaInput::SourceVariable v
|
||||
) {
|
||||
bb.getElement(i) = def.getExpr() and
|
||||
v = def.getTarget() and
|
||||
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
|
||||
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
|
||||
second.getAssignment() = first.getAssignment() and
|
||||
second.getEvaluationOrder() > first.getEvaluationOrder() and
|
||||
second.getTarget() = v
|
||||
)
|
||||
or
|
||||
def.(ImplicitParameterDefinition).getParameter() = v and
|
||||
exists(Callable c | v = c.getAParameter() |
|
||||
scopeFirst(c, bb) and
|
||||
i = -1
|
||||
)
|
||||
}
|
||||
|
||||
predicate implicitEntryDef(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v) {
|
||||
not v instanceof LocalScopeVariable and
|
||||
c = v.getACallable() and
|
||||
scopeFirst(c, bb)
|
||||
}
|
||||
|
||||
module SsaInput implements SsaImplCommon::InputSig {
|
||||
class BasicBlock = PreBasicBlocks::PreBasicBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock extends BasicBlock {
|
||||
ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) }
|
||||
}
|
||||
|
||||
/** Holds if `a` is assigned in non-constructor callable `c`. */
|
||||
pragma[nomagic]
|
||||
private predicate assignableDefinition(Assignable a, Callable c) {
|
||||
exists(AssignableDefinition def | def.getTarget() = a |
|
||||
c = def.getEnclosingCallable() and
|
||||
not c instanceof Constructor
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `a` is accessed in callable `c`. */
|
||||
pragma[nomagic]
|
||||
private predicate assignableAccess(Assignable a, Callable c) {
|
||||
exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate assignableNoCapturing(Assignable a, Callable c) {
|
||||
assignableAccess(a, c) and
|
||||
/*
|
||||
* The code below is equivalent to
|
||||
* ```ql
|
||||
* not exists(Callable other | assignableDefinition(a, other) | other != c)
|
||||
* ```
|
||||
* but it avoids a Cartesian product in the compiler generated antijoin
|
||||
* predicate.
|
||||
*/
|
||||
|
||||
(
|
||||
not assignableDefinition(a, _)
|
||||
or
|
||||
c = unique(Callable c0 | assignableDefinition(a, c0) | c0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate assignableNoComplexQualifiers(Assignable a) {
|
||||
forall(QualifiableExpr qe | qe.(AssignableAccess).getTarget() = a | qe.targetIsThisInstance())
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple assignable. Either a local scope variable or a field/property
|
||||
* that behaves like a local scope variable.
|
||||
*/
|
||||
class SourceVariable extends Assignable {
|
||||
private Callable c;
|
||||
|
||||
SourceVariable() {
|
||||
(
|
||||
this instanceof LocalScopeVariable
|
||||
or
|
||||
this = any(Field f | not f.isVolatile())
|
||||
or
|
||||
this = any(TrivialProperty tp | not tp.isOverridableOrImplementable())
|
||||
) and
|
||||
assignableNoCapturing(this, c) and
|
||||
assignableNoComplexQualifiers(this)
|
||||
}
|
||||
|
||||
/** Gets a callable in which this simple assignable can be analyzed. */
|
||||
Callable getACallable() { result = c }
|
||||
}
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableDefinition def |
|
||||
definitionAt(def, bb, i, v) and
|
||||
if def.getTargetAccess().isRefArgument() then certain = false else certain = true
|
||||
)
|
||||
or
|
||||
exists(Callable c |
|
||||
implicitEntryDef(c, bb, v) and
|
||||
i = -1 and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableRead read |
|
||||
read = bb.getElement(i) and
|
||||
read.getTarget() = v and
|
||||
certain = true
|
||||
)
|
||||
or
|
||||
v =
|
||||
any(LocalScopeVariable lsv |
|
||||
lsv.getCallable() = bb.(ExitBasicBlock).getEnclosingCallable() and
|
||||
i = bb.length() and
|
||||
(lsv.isRef() or v.(Parameter).isOut()) and
|
||||
certain = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
|
||||
|
||||
class Definition extends SsaImpl::Definition {
|
||||
final AssignableRead getARead() {
|
||||
exists(BasicBlock bb, int i |
|
||||
exists(SsaInput::BasicBlock bb, int i |
|
||||
SsaImpl::ssaDefReachesRead(_, this, bb, i) and
|
||||
result = bb.getElement(i)
|
||||
)
|
||||
}
|
||||
|
||||
final AssignableDefinition getDefinition() {
|
||||
exists(BasicBlock bb, int i, SourceVariable v |
|
||||
exists(SsaInput::BasicBlock bb, int i, SsaInput::SourceVariable v |
|
||||
this.definesAt(v, bb, i) and
|
||||
definitionAt(result, bb, i, v)
|
||||
)
|
||||
}
|
||||
|
||||
final AssignableRead getAFirstRead() {
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
exists(SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 |
|
||||
this.definesAt(_, bb1, i1) and
|
||||
SsaImpl::adjacentDefRead(this, bb1, i1, bb2, i2) and
|
||||
result = bb2.getElement(i2)
|
||||
@@ -42,14 +174,14 @@ module PreSsa {
|
||||
not result instanceof PhiNode
|
||||
}
|
||||
|
||||
final predicate isLiveAtEndOfBlock(BasicBlock bb) {
|
||||
final predicate isLiveAtEndOfBlock(SsaInput::BasicBlock bb) {
|
||||
SsaImpl::ssaDefReachesEndOfBlock(bb, this, _)
|
||||
}
|
||||
|
||||
Location getLocation() {
|
||||
result = this.getDefinition().getLocation()
|
||||
or
|
||||
exists(Callable c, BasicBlock bb, SourceVariable v |
|
||||
exists(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v |
|
||||
this.definesAt(v, bb, -1) and
|
||||
implicitEntryDef(c, bb, v) and
|
||||
result = c.getLocation()
|
||||
@@ -64,9 +196,9 @@ module PreSsa {
|
||||
}
|
||||
|
||||
predicate adjacentReadPairSameVar(AssignableRead read1, AssignableRead read2) {
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
exists(SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 |
|
||||
read1 = bb1.getElement(i1) and
|
||||
variableRead(bb1, i1, _, true) and
|
||||
SsaInput::variableRead(bb1, i1, _, true) and
|
||||
SsaImpl::adjacentDefRead(_, bb1, i1, bb2, i2) and
|
||||
read2 = bb2.getElement(i2)
|
||||
)
|
||||
|
||||
@@ -1,795 +0,0 @@
|
||||
/**
|
||||
* Provides a language-independent implementation of static single assignment
|
||||
* (SSA) form.
|
||||
*/
|
||||
|
||||
private import SsaImplSpecific
|
||||
|
||||
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb }
|
||||
|
||||
/**
|
||||
* Liveness analysis (based on source variables) to restrict the size of the
|
||||
* SSA representation.
|
||||
*/
|
||||
private module Liveness {
|
||||
/**
|
||||
* A classification of variable references into reads (of a given kind) and
|
||||
* (certain or uncertain) writes.
|
||||
*/
|
||||
private newtype TRefKind =
|
||||
Read(boolean certain) { certain in [false, true] } or
|
||||
Write(boolean certain) { certain in [false, true] }
|
||||
|
||||
private class RefKind extends TRefKind {
|
||||
string toString() {
|
||||
exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")")
|
||||
or
|
||||
exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")")
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this = Read(_) and
|
||||
result = 0
|
||||
or
|
||||
this = Write(_) and
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
|
||||
*/
|
||||
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
|
||||
or
|
||||
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
|
||||
}
|
||||
|
||||
private newtype OrderedRefIndex =
|
||||
MkOrderedRefIndex(int i, int tag) {
|
||||
exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder())
|
||||
}
|
||||
|
||||
private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) {
|
||||
ref(bb, i, v, k) and
|
||||
result = MkOrderedRefIndex(i, ord) and
|
||||
ord = k.getOrder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of
|
||||
* basic block `bb`, which has the given reference kind `k`.
|
||||
*
|
||||
* Reads are considered before writes when they happen at the same index.
|
||||
*/
|
||||
private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
refOrd(bb, i, v, k, _) =
|
||||
rank[result](int j, int ord, OrderedRefIndex res |
|
||||
res = refOrd(bb, j, v, _, ord)
|
||||
|
|
||||
res order by j, ord
|
||||
)
|
||||
}
|
||||
|
||||
private int maxRefRank(BasicBlock bb, SourceVariable v) {
|
||||
result = refRank(bb, _, v, _) and
|
||||
not result + 1 = refRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
|
||||
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
|
||||
* that is either a read or a certain write.
|
||||
*/
|
||||
private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) {
|
||||
result =
|
||||
min(int r, RefKind k |
|
||||
r = refRank(bb, _, v, k) and
|
||||
k != Write(false)
|
||||
|
|
||||
r
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if source variable `v` is live at the beginning of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtEntry(BasicBlock bb, SourceVariable v) {
|
||||
// The first read or certain write to `v` inside `bb` is a read
|
||||
refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v)
|
||||
or
|
||||
// There is no certain write to `v` inside `bb`, but `v` is live at entry
|
||||
// to a successor basic block of `bb`
|
||||
not exists(firstReadOrCertainWrite(bb, v)) and
|
||||
liveAtExit(bb, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if source variable `v` is live at the end of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
|
||||
liveAtEntry(getABasicBlockSuccessor(bb), v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live in basic block `bb` at index `i`.
|
||||
* The rank of `i` is `rnk` as defined by `refRank()`.
|
||||
*/
|
||||
private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) {
|
||||
exists(RefKind kind | rnk = refRank(bb, i, v, kind) |
|
||||
rnk = maxRefRank(bb, v) and
|
||||
liveAtExit(bb, v)
|
||||
or
|
||||
ref(bb, i, v, kind) and
|
||||
kind = Read(_)
|
||||
or
|
||||
exists(RefKind nextKind |
|
||||
liveAtRank(bb, _, v, rnk + 1) and
|
||||
rnk + 1 = refRank(bb, _, v, nextKind) and
|
||||
nextKind != Write(true)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live after the (certain or uncertain) write at
|
||||
* index `i` inside basic block `bb`.
|
||||
*/
|
||||
predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) {
|
||||
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk))
|
||||
}
|
||||
}
|
||||
|
||||
private import Liveness
|
||||
|
||||
/**
|
||||
* Holds if `df` is in the dominance frontier of `bb`.
|
||||
*
|
||||
* This is equivalent to:
|
||||
*
|
||||
* ```ql
|
||||
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
|
||||
* not bb = getImmediateBasicBlockDominator+(df)
|
||||
* ```
|
||||
*/
|
||||
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
|
||||
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
|
||||
or
|
||||
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
|
||||
bb = getImmediateBasicBlockDominator(prev) and
|
||||
not bb = getImmediateBasicBlockDominator(df)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* definition of `v`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock defbb, Definition def |
|
||||
def.definesAt(v, defbb, _) and
|
||||
inDominanceFrontier(defbb, bb)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TDefinition =
|
||||
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableWrite(bb, i, v, _) and
|
||||
liveAfterWrite(bb, i, v)
|
||||
} or
|
||||
TPhiNode(SourceVariable v, BasicBlock bb) {
|
||||
inDefDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v)
|
||||
}
|
||||
|
||||
private module SsaDefReaches {
|
||||
newtype TSsaRefKind =
|
||||
SsaActualRead() or
|
||||
SsaPhiRead() or
|
||||
SsaDef()
|
||||
|
||||
class SsaRead = SsaActualRead or SsaPhiRead;
|
||||
|
||||
/**
|
||||
* A classification of SSA variable references into reads and definitions.
|
||||
*/
|
||||
class SsaRefKind extends TSsaRefKind {
|
||||
string toString() {
|
||||
this = SsaActualRead() and
|
||||
result = "SsaActualRead"
|
||||
or
|
||||
this = SsaPhiRead() and
|
||||
result = "SsaPhiRead"
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = "SsaDef"
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this instanceof SsaRead and
|
||||
result = 0
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* read of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
|
||||
lastRefIsRead(readbb, v)
|
||||
or
|
||||
phiRead(readbb, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a phi-read node should be inserted for variable `v` at the beginning
|
||||
* of basic block `bb`.
|
||||
*
|
||||
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
|
||||
* instead of writes, and only if the dominance-frontier block does not already
|
||||
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
|
||||
* an internal implementation detail that is not exposed.
|
||||
*
|
||||
* The motivation for adding phi-reads is to improve performance of the use-use
|
||||
* calculation in cases where there is a large number of reads that can reach the
|
||||
* same join-point, and from there reach a large number of basic blocks. Example:
|
||||
*
|
||||
* ```cs
|
||||
* if (a)
|
||||
* use(x);
|
||||
* else if (b)
|
||||
* use(x);
|
||||
* else if (c)
|
||||
* use(x);
|
||||
* else if (d)
|
||||
* use(x);
|
||||
* // many more ifs ...
|
||||
*
|
||||
* // phi-read for `x` inserted here
|
||||
*
|
||||
* // program not mentioning `x`, with large basic block graph
|
||||
*
|
||||
* use(x);
|
||||
* ```
|
||||
*
|
||||
* Without phi-reads, the analysis has to replicate reachability for each of
|
||||
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
|
||||
* each conditional use of `x` to reach the basic block containing the phi-read
|
||||
* node for `x`, and only that basic block will have to compute reachability
|
||||
* through the remainder of the large program.
|
||||
*
|
||||
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
|
||||
* one SSA definition (without passing through another definition): Assume, for
|
||||
* the sake of contradiction, that there are two reaching definitions `def1` and
|
||||
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
|
||||
* dominating definition will prevent the other from reaching `phi-read`. So, at
|
||||
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
|
||||
* Then `def1` must go through one of its dominance-frontier blocks in order to
|
||||
* reach `phi-read`. However, such a block will always start with a (normal) phi
|
||||
* node, which contradicts reachability.
|
||||
*
|
||||
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
|
||||
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
|
||||
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
|
||||
* which contradicts reachability.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiRead(BasicBlock bb, SourceVariable v) {
|
||||
inReadDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v) and
|
||||
// only if there are no other references to `v` inside `bb`
|
||||
not ref(bb, _, v, _) and
|
||||
not exists(Definition def | def.definesAt(v, bb, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
|
||||
* is `SsaDef()`).
|
||||
*
|
||||
* Unlike `Liveness::ref`, this includes `phi` nodes.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
variableRead(bb, i, v, _) and
|
||||
k = SsaActualRead()
|
||||
or
|
||||
phiRead(bb, v) and
|
||||
i = -1 and
|
||||
k = SsaPhiRead()
|
||||
or
|
||||
any(Definition def).definesAt(v, bb, i) and
|
||||
k = SsaDef()
|
||||
}
|
||||
|
||||
private newtype OrderedSsaRefIndex =
|
||||
MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) }
|
||||
|
||||
private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) {
|
||||
ssaRef(bb, i, v, k) and
|
||||
result = MkOrderedSsaRefIndex(i, k) and
|
||||
ord = k.getOrder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
|
||||
* block `bb`, which has the given reference kind `k`.
|
||||
*
|
||||
* For example, if `bb` is a basic block with a phi node for `v` (considered
|
||||
* to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
|
||||
*
|
||||
* ```ql
|
||||
* ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
|
||||
* ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
|
||||
* ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
|
||||
* ```
|
||||
*
|
||||
* Reads are considered before writes when they happen at the same index.
|
||||
*/
|
||||
int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
ssaRefOrd(bb, i, v, k, _) =
|
||||
rank[result](int j, int ord, OrderedSsaRefIndex res |
|
||||
res = ssaRefOrd(bb, j, v, _, ord)
|
||||
|
|
||||
res order by j, ord
|
||||
)
|
||||
}
|
||||
|
||||
int maxSsaRefRank(BasicBlock bb, SourceVariable v) {
|
||||
result = ssaRefRank(bb, _, v, _) and
|
||||
not result + 1 = ssaRefRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA definition `def` reaches rank index `rnk` in its own
|
||||
* basic block `bb`.
|
||||
*/
|
||||
predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) {
|
||||
exists(int i |
|
||||
rnk = ssaRefRank(bb, i, v, SsaDef()) and
|
||||
def.definesAt(v, bb, i)
|
||||
)
|
||||
or
|
||||
ssaDefReachesRank(bb, def, rnk - 1, v) and
|
||||
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA definition of `v` at `def` reaches index `i` in the same
|
||||
* basic block `bb`, without crossing another SSA definition of `v`.
|
||||
*/
|
||||
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
exists(int rnk |
|
||||
ssaDefReachesRank(bb, def, rnk, v) and
|
||||
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||
*/
|
||||
int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) {
|
||||
v = def.getSourceVariable() and
|
||||
result = ssaRefRank(bb, i, v, k) and
|
||||
(
|
||||
ssaDefReachesRead(_, def, bb, i)
|
||||
or
|
||||
def.definesAt(_, bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the reference to `def` at index `i` in basic block `bb` is the
|
||||
* last reference to `v` inside `bb`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
|
||||
}
|
||||
|
||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
|
||||
exists(ssaDefRank(def, v, bb, _, k))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
|
||||
ssaDefReachesEndOfBlock(bb, def, _) and
|
||||
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
|
||||
* predecessor of `bb2`, and the underlying variable for `def` is neither read
|
||||
* nor written in any block on the path between `bb1` and `bb2`.
|
||||
*
|
||||
* Phi reads are considered as normal reads for this predicate.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
defOccursInBlock(def, bb1, _, _) and
|
||||
bb2 = getABasicBlockSuccessor(bb1)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesInclPhiRead(def, bb1, mid) and
|
||||
ssaDefReachesThroughBlock(def, mid) and
|
||||
bb2 = getABasicBlockSuccessor(mid)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(def, bb1, bb2) and
|
||||
defOccursInBlock(def, bb2, v, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
|
||||
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExclPhiRead(def, mid, bb2) and
|
||||
phiReadStep(def, _, bb1, mid)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* the underlying variable `v` of `def` is accessed in basic block `bb2`
|
||||
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
|
||||
* `v` is neither read nor written in any block on the path between `bb1`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesExclPhiRead(def, bb1, bb2) and
|
||||
not defOccursInBlock(def, bb1, _, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
|
||||
varBlockReaches(def, bb1, bb2) and
|
||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
|
||||
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
|
||||
* and `v` is neither read nor written in any block on the path between `bb`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
|
||||
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
|
||||
not defOccursInBlock(def, bb2, _, _) and
|
||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExit(def, mid) and
|
||||
phiReadStep(def, _, bb, mid)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate phiReadExposedForTesting = phiRead/2;
|
||||
|
||||
private import SsaDefReaches
|
||||
|
||||
pragma[nomagic]
|
||||
predicate liveThrough(BasicBlock bb, SourceVariable v) {
|
||||
liveAtExit(bb, v) and
|
||||
not ssaRef(bb, _, v, SsaDef())
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the SSA definition of `v` at `def` reaches the end of basic
|
||||
* block `bb`, at which point it is still live, without crossing another
|
||||
* SSA definition of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
|
||||
exists(int last |
|
||||
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
|
||||
ssaDefReachesRank(bb, def, last, v) and
|
||||
liveAtExit(bb, v)
|
||||
)
|
||||
or
|
||||
// The construction of SSA form ensures that each read of a variable is
|
||||
// dominated by its definition. An SSA definition therefore reaches a
|
||||
// control flow node if it is the _closest_ SSA definition that dominates
|
||||
// the node. If two definitions dominate a node then one must dominate the
|
||||
// other, so therefore the definition of _closest_ is given by the dominator
|
||||
// tree. Thus, reaching definitions can be calculated in terms of dominance.
|
||||
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
|
||||
liveThrough(bb, pragma[only_bind_into](v))
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
|
||||
exists(SourceVariable v, BasicBlock bbDef |
|
||||
phi.definesAt(v, bbDef, _) and
|
||||
getABasicBlockPredecessor(bbDef) = bb and
|
||||
ssaDefReachesEndOfBlock(bb, inp, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
|
||||
* basic block `bb`, without crossing another SSA definition of `v`. The read
|
||||
* is of kind `rk`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
||||
or
|
||||
ssaRef(bb, i, v, any(SsaRead k)) and
|
||||
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
|
||||
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
|
||||
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
|
||||
* path between them without any read of `def`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
exists(int rnk |
|
||||
rnk = ssaDefRank(def, _, bb1, i1, _) and
|
||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
|
||||
variableRead(bb1, i2, _, _) and
|
||||
bb2 = bb1
|
||||
)
|
||||
or
|
||||
lastSsaRef(def, _, bb1, i1) and
|
||||
defAdjacentRead(def, bb1, bb2, i2)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate adjacentDefRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
|
||||
) {
|
||||
adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
|
||||
ssaRef(bb1, i1, v, SsaDef())
|
||||
or
|
||||
variableRead(bb1, i1, v, true)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
|
||||
variableRead(bb3, i3, _, false) and
|
||||
adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `adjacentDefRead`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
variableRead(bb2, i2, _, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
|
||||
* `def`. The reference is last because it can reach another write `next`,
|
||||
* without passing through another read or write.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
|
||||
exists(SourceVariable v |
|
||||
// Next reference to `v` inside `bb` is a write
|
||||
exists(int rnk, int j |
|
||||
rnk = ssaDefRank(def, v, bb, i, _) and
|
||||
next.definesAt(v, bb, j) and
|
||||
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
|
||||
)
|
||||
or
|
||||
// Can reach a write using one or more steps
|
||||
lastSsaRef(def, v, bb, i) and
|
||||
exists(BasicBlock bb2 |
|
||||
varBlockReaches(def, bb, bb2) and
|
||||
1 = ssaDefRank(next, v, bb2, _, SsaDef())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `inp` is an immediately preceding definition of uncertain definition
|
||||
* `def`. Since `def` is uncertain, the value from the preceding definition might
|
||||
* still be valid.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
|
||||
lastRefRedef(inp, _, _, def)
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesUncertainRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
variableRead(bb2, i2, _, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `lastRefRedef`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) {
|
||||
lastRefRedef(def, bb, i, next) and
|
||||
not variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
lastRefRedef(def, bb0, i0, next) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA
|
||||
* definition `def`.
|
||||
*
|
||||
* That is, the node can reach the end of the enclosing callable, or another
|
||||
* SSA definition for the underlying source variable, without passing through
|
||||
* another read.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRef(Definition def, BasicBlock bb, int i) {
|
||||
// Can reach another definition
|
||||
lastRefRedef(def, bb, i, _)
|
||||
or
|
||||
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
|
||||
// Can reach exit directly
|
||||
bb instanceof ExitBasicBlock
|
||||
or
|
||||
// Can reach a block using one or more steps, where `def` is no longer live
|
||||
varBlockReachesExit(def, bb)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `lastRefRedef`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) {
|
||||
lastRef(def, bb, i) and
|
||||
not variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/** A static single assignment (SSA) definition. */
|
||||
class Definition extends TDefinition {
|
||||
/** Gets the source variable underlying this SSA definition. */
|
||||
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
|
||||
* Phi nodes are considered to be at index `-1`, while normal variable writes
|
||||
* are at the index of the control flow node they wrap.
|
||||
*/
|
||||
final predicate definesAt(SourceVariable v, BasicBlock bb, int i) {
|
||||
this = TWriteDef(v, bb, i)
|
||||
or
|
||||
this = TPhiNode(v, bb) and i = -1
|
||||
}
|
||||
|
||||
/** Gets the basic block to which this SSA definition belongs. */
|
||||
final BasicBlock getBasicBlock() { this.definesAt(_, result, _) }
|
||||
|
||||
/** Gets a textual representation of this SSA definition. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/** An SSA definition that corresponds to a write. */
|
||||
class WriteDefinition extends Definition, TWriteDef {
|
||||
private SourceVariable v;
|
||||
private BasicBlock bb;
|
||||
private int i;
|
||||
|
||||
WriteDefinition() { this = TWriteDef(v, bb, i) }
|
||||
|
||||
override string toString() { result = "WriteDef" }
|
||||
}
|
||||
|
||||
/** A phi node. */
|
||||
class PhiNode extends Definition, TPhiNode {
|
||||
override string toString() { result = "Phi" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition that represents an uncertain update of the underlying
|
||||
* source variable.
|
||||
*/
|
||||
class UncertainWriteDefinition extends WriteDefinition {
|
||||
UncertainWriteDefinition() {
|
||||
exists(SourceVariable v, BasicBlock bb, int i |
|
||||
this.definesAt(v, bb, i) and
|
||||
variableWrite(bb, i, v, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a set of consistency queries. */
|
||||
module Consistency {
|
||||
abstract class RelevantDefinition extends Definition {
|
||||
abstract predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
}
|
||||
|
||||
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
|
||||
}
|
||||
|
||||
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableRead(bb, i, v, _) and
|
||||
not ssaDefReachesRead(v, _, bb, i)
|
||||
}
|
||||
|
||||
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
|
||||
v = def.getSourceVariable() and
|
||||
not ssaDefReachesRead(_, def, _, _) and
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/** Provides the C# specific parameters for `SsaImplCommon.qll`. */
|
||||
|
||||
private import csharp
|
||||
private import AssignableDefinitions
|
||||
private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks
|
||||
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
|
||||
|
||||
class BasicBlock = PreBasicBlocks::PreBasicBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock extends BasicBlock {
|
||||
ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) }
|
||||
}
|
||||
|
||||
/** Holds if `a` is assigned in non-constructor callable `c`. */
|
||||
pragma[nomagic]
|
||||
private predicate assignableDefinition(Assignable a, Callable c) {
|
||||
exists(AssignableDefinition def | def.getTarget() = a |
|
||||
c = def.getEnclosingCallable() and
|
||||
not c instanceof Constructor
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `a` is accessed in callable `c`. */
|
||||
pragma[nomagic]
|
||||
private predicate assignableAccess(Assignable a, Callable c) {
|
||||
exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate assignableNoCapturing(Assignable a, Callable c) {
|
||||
assignableAccess(a, c) and
|
||||
/*
|
||||
* The code below is equivalent to
|
||||
* ```ql
|
||||
* not exists(Callable other | assignableDefinition(a, other) | other != c)
|
||||
* ```
|
||||
* but it avoids a Cartesian product in the compiler generated antijoin
|
||||
* predicate.
|
||||
*/
|
||||
|
||||
(
|
||||
not assignableDefinition(a, _)
|
||||
or
|
||||
c = unique(Callable c0 | assignableDefinition(a, c0) | c0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate assignableNoComplexQualifiers(Assignable a) {
|
||||
forall(QualifiableExpr qe | qe.(AssignableAccess).getTarget() = a | qe.targetIsThisInstance())
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple assignable. Either a local scope variable or a field/property
|
||||
* that behaves like a local scope variable.
|
||||
*/
|
||||
class SourceVariable extends Assignable {
|
||||
private Callable c;
|
||||
|
||||
SourceVariable() {
|
||||
(
|
||||
this instanceof LocalScopeVariable
|
||||
or
|
||||
this = any(Field f | not f.isVolatile())
|
||||
or
|
||||
this = any(TrivialProperty tp | not tp.isOverridableOrImplementable())
|
||||
) and
|
||||
assignableNoCapturing(this, c) and
|
||||
assignableNoComplexQualifiers(this)
|
||||
}
|
||||
|
||||
/** Gets a callable in which this simple assignable can be analyzed. */
|
||||
Callable getACallable() { result = c }
|
||||
}
|
||||
|
||||
predicate definitionAt(AssignableDefinition def, BasicBlock bb, int i, SourceVariable v) {
|
||||
bb.getElement(i) = def.getExpr() and
|
||||
v = def.getTarget() and
|
||||
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
|
||||
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
|
||||
second.getAssignment() = first.getAssignment() and
|
||||
second.getEvaluationOrder() > first.getEvaluationOrder() and
|
||||
second.getTarget() = v
|
||||
)
|
||||
or
|
||||
def.(ImplicitParameterDefinition).getParameter() = v and
|
||||
exists(Callable c | v = c.getAParameter() |
|
||||
scopeFirst(c, bb) and
|
||||
i = -1
|
||||
)
|
||||
}
|
||||
|
||||
predicate implicitEntryDef(Callable c, BasicBlock bb, SourceVariable v) {
|
||||
not v instanceof LocalScopeVariable and
|
||||
c = v.getACallable() and
|
||||
scopeFirst(c, bb)
|
||||
}
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableDefinition def |
|
||||
definitionAt(def, bb, i, v) and
|
||||
if def.getTargetAccess().isRefArgument() then certain = false else certain = true
|
||||
)
|
||||
or
|
||||
exists(Callable c |
|
||||
implicitEntryDef(c, bb, v) and
|
||||
i = -1 and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableRead read |
|
||||
read = bb.getElement(i) and
|
||||
read.getTarget() = v and
|
||||
certain = true
|
||||
)
|
||||
or
|
||||
v =
|
||||
any(LocalScopeVariable lsv |
|
||||
lsv.getCallable() = bb.(ExitBasicBlock).getEnclosingCallable() and
|
||||
i = bb.length() and
|
||||
(lsv.isRef() or v.(Parameter).isOut()) and
|
||||
certain = false
|
||||
)
|
||||
}
|
||||
@@ -12,6 +12,8 @@
|
||||
* `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance`
|
||||
* - Negative Summaries:
|
||||
* `namespace; type; name; signature; provenance`
|
||||
* A negative summary is used to indicate that there is no flow via a callable.
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
* 1. The `namespace` column selects a namespace.
|
||||
@@ -100,6 +102,7 @@ private module Frameworks {
|
||||
private import semmle.code.csharp.frameworks.ServiceStack
|
||||
private import semmle.code.csharp.frameworks.Sql
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.system.CodeDom
|
||||
private import semmle.code.csharp.frameworks.system.Collections
|
||||
private import semmle.code.csharp.frameworks.system.collections.Concurrent
|
||||
private import semmle.code.csharp.frameworks.system.collections.Generic
|
||||
@@ -108,6 +111,7 @@ private module Frameworks {
|
||||
private import semmle.code.csharp.frameworks.system.collections.Specialized
|
||||
private import semmle.code.csharp.frameworks.system.ComponentModel
|
||||
private import semmle.code.csharp.frameworks.system.componentmodel.Design
|
||||
private import semmle.code.csharp.frameworks.system.Configuration
|
||||
private import semmle.code.csharp.frameworks.system.Data
|
||||
private import semmle.code.csharp.frameworks.system.data.Common
|
||||
private import semmle.code.csharp.frameworks.system.Diagnostics
|
||||
@@ -119,6 +123,7 @@ private module Frameworks {
|
||||
private import semmle.code.csharp.frameworks.system.IO
|
||||
private import semmle.code.csharp.frameworks.system.io.Compression
|
||||
private import semmle.code.csharp.frameworks.system.runtime.CompilerServices
|
||||
private import semmle.code.csharp.frameworks.system.Security
|
||||
private import semmle.code.csharp.frameworks.system.security.Cryptography
|
||||
private import semmle.code.csharp.frameworks.system.security.cryptography.X509Certificates
|
||||
private import semmle.code.csharp.frameworks.system.Text
|
||||
|
||||
@@ -4,19 +4,74 @@ import csharp
|
||||
* Provides a simple SSA implementation for local scope variables.
|
||||
*/
|
||||
module BaseSsa {
|
||||
import basessa.SsaImplSpecific
|
||||
private import basessa.SsaImplCommon as SsaImpl
|
||||
private import AssignableDefinitions
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is assignable definition `def`,
|
||||
* targeting local scope variable `v`.
|
||||
*/
|
||||
private predicate definitionAt(
|
||||
AssignableDefinition def, ControlFlow::BasicBlock bb, int i, SsaInput::SourceVariable v
|
||||
) {
|
||||
bb.getNode(i) = def.getAControlFlowNode() and
|
||||
v = def.getTarget() and
|
||||
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
|
||||
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
|
||||
second.getAssignment() = first.getAssignment() and
|
||||
second.getEvaluationOrder() > first.getEvaluationOrder() and
|
||||
second.getTarget() = v
|
||||
)
|
||||
}
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig {
|
||||
class BasicBlock = ControlFlow::BasicBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = bb.getImmediateDominator()
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock;
|
||||
|
||||
pragma[noinline]
|
||||
private Callable getAnAssigningCallable(LocalScopeVariable v) {
|
||||
result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable()
|
||||
}
|
||||
|
||||
class SourceVariable extends LocalScopeVariable {
|
||||
SourceVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) }
|
||||
}
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableDefinition def |
|
||||
definitionAt(def, bb, i, v) and
|
||||
if def.isCertain() then certain = true else certain = false
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableRead read |
|
||||
read.getAControlFlowNode() = bb.getNode(i) and
|
||||
read.getTarget() = v and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
|
||||
|
||||
class Definition extends SsaImpl::Definition {
|
||||
final AssignableRead getARead() {
|
||||
exists(BasicBlock bb, int i |
|
||||
exists(ControlFlow::BasicBlock bb, int i |
|
||||
SsaImpl::ssaDefReachesRead(_, this, bb, i) and
|
||||
result.getAControlFlowNode() = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
final AssignableDefinition getDefinition() {
|
||||
exists(BasicBlock bb, int i, SourceVariable v |
|
||||
exists(ControlFlow::BasicBlock bb, int i, SsaInput::SourceVariable v |
|
||||
this.definesAt(v, bb, i) and
|
||||
definitionAt(result, bb, i, v)
|
||||
)
|
||||
|
||||
@@ -226,15 +226,6 @@ module Public {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside `content` are cleared on objects passed as
|
||||
* arguments at position `pos` to this callable.
|
||||
*
|
||||
* TODO: Remove once all languages support `WithoutContent` tokens.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate clearsContent(ParameterPosition pos, ContentSet content) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the summary is auto generated.
|
||||
*/
|
||||
@@ -328,23 +319,6 @@ module Private {
|
||||
SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and
|
||||
preservesValue = preservesValue1.booleanAnd(preservesValue2)
|
||||
)
|
||||
or
|
||||
exists(ParameterPosition ppos, ContentSet cs |
|
||||
c.clearsContent(ppos, cs) and
|
||||
input = SummaryComponentStack::push(SummaryComponent::withoutContent(cs), output) and
|
||||
output = SummaryComponentStack::argument(ppos) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
|
||||
private class MkClearStack extends RequiredSummaryComponentStack {
|
||||
override predicate required(SummaryComponent head, SummaryComponentStack tail) {
|
||||
exists(SummarizedCallable sc, ParameterPosition ppos, ContentSet cs |
|
||||
sc.clearsContent(ppos, cs) and
|
||||
head = SummaryComponent::withoutContent(cs) and
|
||||
tail = SummaryComponentStack::argument(ppos)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -945,8 +919,7 @@ module Private {
|
||||
AccessPath inSpec, AccessPath outSpec, string kind
|
||||
) {
|
||||
summaryElement(this, inSpec, outSpec, kind, true) and
|
||||
not summaryElement(this, _, _, _, false) and
|
||||
not this.clearsContent(_, _)
|
||||
not summaryElement(this, _, _, _, false)
|
||||
}
|
||||
|
||||
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
|
||||
|
||||
@@ -163,6 +163,10 @@ bindingset[c]
|
||||
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
|
||||
c = "Element" and result = SummaryComponent::content(any(ElementContent ec))
|
||||
or
|
||||
c = "WithoutElement" and result = SummaryComponent::withoutContent(any(ElementContent ec))
|
||||
or
|
||||
c = "WithElement" and result = SummaryComponent::withContent(any(ElementContent ec))
|
||||
or
|
||||
// Qualified names may contain commas,such as in `Tuple<,>`, so get the entire argument list
|
||||
// rather than an individual argument.
|
||||
exists(Field f |
|
||||
@@ -199,6 +203,10 @@ private string getContentSpecificCsv(Content c) {
|
||||
string getComponentSpecificCsv(SummaryComponent sc) {
|
||||
exists(Content c | sc = TContentSummaryComponent(c) and result = getContentSpecificCsv(c))
|
||||
or
|
||||
exists(Content c | sc = TWithoutContentSummaryComponent(c) and result = "WithoutElement")
|
||||
or
|
||||
exists(Content c | sc = TWithContentSummaryComponent(c) and result = "WithElement")
|
||||
or
|
||||
exists(ReturnKind rk |
|
||||
sc = TReturnSummaryComponent(rk) and
|
||||
result = "ReturnValue[" + rk + "]" and
|
||||
|
||||
@@ -3,7 +3,53 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import SsaImplCommon
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
private import AssignableDefinitions
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig {
|
||||
class BasicBlock = ControlFlow::BasicBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock;
|
||||
|
||||
class SourceVariable = Ssa::SourceVariable;
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a (potential) write to source
|
||||
* variable `v`. The Boolean `certain` indicates whether the write is certain.
|
||||
*
|
||||
* This includes implicit writes via calls.
|
||||
*/
|
||||
predicate variableWrite(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
|
||||
variableWriteDirect(bb, i, v, certain)
|
||||
or
|
||||
variableWriteQualifier(bb, i, v, certain)
|
||||
or
|
||||
updatesNamedFieldOrProp(bb, i, _, v, _) and
|
||||
certain = false
|
||||
or
|
||||
updatesCapturedVariable(bb, i, _, v, _, _) and
|
||||
certain = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th of basic block `bb` reads source variable `v`.
|
||||
*
|
||||
* This includes implicit reads via calls.
|
||||
*/
|
||||
predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
|
||||
variableReadActual(bb, i, v) and
|
||||
certain = true
|
||||
or
|
||||
variableReadPseudo(bb, i, v) and
|
||||
certain = false
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<SsaInput>
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` reads source variable `v`.
|
||||
@@ -805,24 +851,6 @@ private module CapturedVariableImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a (potential) write to source
|
||||
* variable `v`. The Boolean `certain` indicates whether the write is certain.
|
||||
*
|
||||
* This includes implicit writes via calls.
|
||||
*/
|
||||
predicate variableWrite(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
|
||||
variableWriteDirect(bb, i, v, certain)
|
||||
or
|
||||
variableWriteQualifier(bb, i, v, certain)
|
||||
or
|
||||
updatesNamedFieldOrProp(bb, i, _, v, _) and
|
||||
certain = false
|
||||
or
|
||||
updatesCapturedVariable(bb, i, _, v, _, _) and
|
||||
certain = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Liveness analysis to restrict the size of the SSA representation for
|
||||
* captured variables.
|
||||
@@ -1039,19 +1067,6 @@ private predicate variableReadPseudo(ControlFlow::BasicBlock bb, int i, Ssa::Sou
|
||||
capturedReadIn(bb, i, v, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th of basic block `bb` reads source variable `v`.
|
||||
*
|
||||
* This includes implicit reads via calls.
|
||||
*/
|
||||
predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
|
||||
variableReadActual(bb, i, v) and
|
||||
certain = true
|
||||
or
|
||||
variableReadPseudo(bb, i, v) and
|
||||
certain = false
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
@@ -1151,7 +1166,7 @@ private module Cached {
|
||||
predicate variableWriteQualifier(
|
||||
ControlFlow::BasicBlock bb, int i, QualifiedFieldOrPropSourceVariable v, boolean certain
|
||||
) {
|
||||
variableWrite(bb, i, v.getQualifier(), certain) and
|
||||
SsaInput::variableWrite(bb, i, v.getQualifier(), certain) and
|
||||
// Eliminate corner case where a call definition can overlap with a
|
||||
// qualifier definition: if method `M` updates field `F`, then a call
|
||||
// to `M` is both an update of `x.M` and `x.M.M`, so the former call
|
||||
|
||||
@@ -1,795 +0,0 @@
|
||||
/**
|
||||
* Provides a language-independent implementation of static single assignment
|
||||
* (SSA) form.
|
||||
*/
|
||||
|
||||
private import SsaImplSpecific
|
||||
|
||||
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb }
|
||||
|
||||
/**
|
||||
* Liveness analysis (based on source variables) to restrict the size of the
|
||||
* SSA representation.
|
||||
*/
|
||||
private module Liveness {
|
||||
/**
|
||||
* A classification of variable references into reads (of a given kind) and
|
||||
* (certain or uncertain) writes.
|
||||
*/
|
||||
private newtype TRefKind =
|
||||
Read(boolean certain) { certain in [false, true] } or
|
||||
Write(boolean certain) { certain in [false, true] }
|
||||
|
||||
private class RefKind extends TRefKind {
|
||||
string toString() {
|
||||
exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")")
|
||||
or
|
||||
exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")")
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this = Read(_) and
|
||||
result = 0
|
||||
or
|
||||
this = Write(_) and
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
|
||||
*/
|
||||
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
|
||||
or
|
||||
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
|
||||
}
|
||||
|
||||
private newtype OrderedRefIndex =
|
||||
MkOrderedRefIndex(int i, int tag) {
|
||||
exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder())
|
||||
}
|
||||
|
||||
private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) {
|
||||
ref(bb, i, v, k) and
|
||||
result = MkOrderedRefIndex(i, ord) and
|
||||
ord = k.getOrder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of
|
||||
* basic block `bb`, which has the given reference kind `k`.
|
||||
*
|
||||
* Reads are considered before writes when they happen at the same index.
|
||||
*/
|
||||
private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
refOrd(bb, i, v, k, _) =
|
||||
rank[result](int j, int ord, OrderedRefIndex res |
|
||||
res = refOrd(bb, j, v, _, ord)
|
||||
|
|
||||
res order by j, ord
|
||||
)
|
||||
}
|
||||
|
||||
private int maxRefRank(BasicBlock bb, SourceVariable v) {
|
||||
result = refRank(bb, _, v, _) and
|
||||
not result + 1 = refRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
|
||||
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
|
||||
* that is either a read or a certain write.
|
||||
*/
|
||||
private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) {
|
||||
result =
|
||||
min(int r, RefKind k |
|
||||
r = refRank(bb, _, v, k) and
|
||||
k != Write(false)
|
||||
|
|
||||
r
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if source variable `v` is live at the beginning of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtEntry(BasicBlock bb, SourceVariable v) {
|
||||
// The first read or certain write to `v` inside `bb` is a read
|
||||
refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v)
|
||||
or
|
||||
// There is no certain write to `v` inside `bb`, but `v` is live at entry
|
||||
// to a successor basic block of `bb`
|
||||
not exists(firstReadOrCertainWrite(bb, v)) and
|
||||
liveAtExit(bb, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if source variable `v` is live at the end of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
|
||||
liveAtEntry(getABasicBlockSuccessor(bb), v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live in basic block `bb` at index `i`.
|
||||
* The rank of `i` is `rnk` as defined by `refRank()`.
|
||||
*/
|
||||
private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) {
|
||||
exists(RefKind kind | rnk = refRank(bb, i, v, kind) |
|
||||
rnk = maxRefRank(bb, v) and
|
||||
liveAtExit(bb, v)
|
||||
or
|
||||
ref(bb, i, v, kind) and
|
||||
kind = Read(_)
|
||||
or
|
||||
exists(RefKind nextKind |
|
||||
liveAtRank(bb, _, v, rnk + 1) and
|
||||
rnk + 1 = refRank(bb, _, v, nextKind) and
|
||||
nextKind != Write(true)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live after the (certain or uncertain) write at
|
||||
* index `i` inside basic block `bb`.
|
||||
*/
|
||||
predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) {
|
||||
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk))
|
||||
}
|
||||
}
|
||||
|
||||
private import Liveness
|
||||
|
||||
/**
|
||||
* Holds if `df` is in the dominance frontier of `bb`.
|
||||
*
|
||||
* This is equivalent to:
|
||||
*
|
||||
* ```ql
|
||||
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
|
||||
* not bb = getImmediateBasicBlockDominator+(df)
|
||||
* ```
|
||||
*/
|
||||
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
|
||||
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
|
||||
or
|
||||
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
|
||||
bb = getImmediateBasicBlockDominator(prev) and
|
||||
not bb = getImmediateBasicBlockDominator(df)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* definition of `v`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock defbb, Definition def |
|
||||
def.definesAt(v, defbb, _) and
|
||||
inDominanceFrontier(defbb, bb)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TDefinition =
|
||||
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableWrite(bb, i, v, _) and
|
||||
liveAfterWrite(bb, i, v)
|
||||
} or
|
||||
TPhiNode(SourceVariable v, BasicBlock bb) {
|
||||
inDefDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v)
|
||||
}
|
||||
|
||||
private module SsaDefReaches {
|
||||
newtype TSsaRefKind =
|
||||
SsaActualRead() or
|
||||
SsaPhiRead() or
|
||||
SsaDef()
|
||||
|
||||
class SsaRead = SsaActualRead or SsaPhiRead;
|
||||
|
||||
/**
|
||||
* A classification of SSA variable references into reads and definitions.
|
||||
*/
|
||||
class SsaRefKind extends TSsaRefKind {
|
||||
string toString() {
|
||||
this = SsaActualRead() and
|
||||
result = "SsaActualRead"
|
||||
or
|
||||
this = SsaPhiRead() and
|
||||
result = "SsaPhiRead"
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = "SsaDef"
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this instanceof SsaRead and
|
||||
result = 0
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* read of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
|
||||
lastRefIsRead(readbb, v)
|
||||
or
|
||||
phiRead(readbb, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a phi-read node should be inserted for variable `v` at the beginning
|
||||
* of basic block `bb`.
|
||||
*
|
||||
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
|
||||
* instead of writes, and only if the dominance-frontier block does not already
|
||||
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
|
||||
* an internal implementation detail that is not exposed.
|
||||
*
|
||||
* The motivation for adding phi-reads is to improve performance of the use-use
|
||||
* calculation in cases where there is a large number of reads that can reach the
|
||||
* same join-point, and from there reach a large number of basic blocks. Example:
|
||||
*
|
||||
* ```cs
|
||||
* if (a)
|
||||
* use(x);
|
||||
* else if (b)
|
||||
* use(x);
|
||||
* else if (c)
|
||||
* use(x);
|
||||
* else if (d)
|
||||
* use(x);
|
||||
* // many more ifs ...
|
||||
*
|
||||
* // phi-read for `x` inserted here
|
||||
*
|
||||
* // program not mentioning `x`, with large basic block graph
|
||||
*
|
||||
* use(x);
|
||||
* ```
|
||||
*
|
||||
* Without phi-reads, the analysis has to replicate reachability for each of
|
||||
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
|
||||
* each conditional use of `x` to reach the basic block containing the phi-read
|
||||
* node for `x`, and only that basic block will have to compute reachability
|
||||
* through the remainder of the large program.
|
||||
*
|
||||
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
|
||||
* one SSA definition (without passing through another definition): Assume, for
|
||||
* the sake of contradiction, that there are two reaching definitions `def1` and
|
||||
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
|
||||
* dominating definition will prevent the other from reaching `phi-read`. So, at
|
||||
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
|
||||
* Then `def1` must go through one of its dominance-frontier blocks in order to
|
||||
* reach `phi-read`. However, such a block will always start with a (normal) phi
|
||||
* node, which contradicts reachability.
|
||||
*
|
||||
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
|
||||
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
|
||||
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
|
||||
* which contradicts reachability.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiRead(BasicBlock bb, SourceVariable v) {
|
||||
inReadDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v) and
|
||||
// only if there are no other references to `v` inside `bb`
|
||||
not ref(bb, _, v, _) and
|
||||
not exists(Definition def | def.definesAt(v, bb, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
|
||||
* is `SsaDef()`).
|
||||
*
|
||||
* Unlike `Liveness::ref`, this includes `phi` nodes.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
variableRead(bb, i, v, _) and
|
||||
k = SsaActualRead()
|
||||
or
|
||||
phiRead(bb, v) and
|
||||
i = -1 and
|
||||
k = SsaPhiRead()
|
||||
or
|
||||
any(Definition def).definesAt(v, bb, i) and
|
||||
k = SsaDef()
|
||||
}
|
||||
|
||||
private newtype OrderedSsaRefIndex =
|
||||
MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) }
|
||||
|
||||
private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) {
|
||||
ssaRef(bb, i, v, k) and
|
||||
result = MkOrderedSsaRefIndex(i, k) and
|
||||
ord = k.getOrder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
|
||||
* block `bb`, which has the given reference kind `k`.
|
||||
*
|
||||
* For example, if `bb` is a basic block with a phi node for `v` (considered
|
||||
* to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
|
||||
*
|
||||
* ```ql
|
||||
* ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
|
||||
* ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
|
||||
* ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
|
||||
* ```
|
||||
*
|
||||
* Reads are considered before writes when they happen at the same index.
|
||||
*/
|
||||
int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
ssaRefOrd(bb, i, v, k, _) =
|
||||
rank[result](int j, int ord, OrderedSsaRefIndex res |
|
||||
res = ssaRefOrd(bb, j, v, _, ord)
|
||||
|
|
||||
res order by j, ord
|
||||
)
|
||||
}
|
||||
|
||||
int maxSsaRefRank(BasicBlock bb, SourceVariable v) {
|
||||
result = ssaRefRank(bb, _, v, _) and
|
||||
not result + 1 = ssaRefRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA definition `def` reaches rank index `rnk` in its own
|
||||
* basic block `bb`.
|
||||
*/
|
||||
predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) {
|
||||
exists(int i |
|
||||
rnk = ssaRefRank(bb, i, v, SsaDef()) and
|
||||
def.definesAt(v, bb, i)
|
||||
)
|
||||
or
|
||||
ssaDefReachesRank(bb, def, rnk - 1, v) and
|
||||
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA definition of `v` at `def` reaches index `i` in the same
|
||||
* basic block `bb`, without crossing another SSA definition of `v`.
|
||||
*/
|
||||
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
exists(int rnk |
|
||||
ssaDefReachesRank(bb, def, rnk, v) and
|
||||
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||
*/
|
||||
int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) {
|
||||
v = def.getSourceVariable() and
|
||||
result = ssaRefRank(bb, i, v, k) and
|
||||
(
|
||||
ssaDefReachesRead(_, def, bb, i)
|
||||
or
|
||||
def.definesAt(_, bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the reference to `def` at index `i` in basic block `bb` is the
|
||||
* last reference to `v` inside `bb`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
|
||||
}
|
||||
|
||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
|
||||
exists(ssaDefRank(def, v, bb, _, k))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
|
||||
ssaDefReachesEndOfBlock(bb, def, _) and
|
||||
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
|
||||
* predecessor of `bb2`, and the underlying variable for `def` is neither read
|
||||
* nor written in any block on the path between `bb1` and `bb2`.
|
||||
*
|
||||
* Phi reads are considered as normal reads for this predicate.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
defOccursInBlock(def, bb1, _, _) and
|
||||
bb2 = getABasicBlockSuccessor(bb1)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesInclPhiRead(def, bb1, mid) and
|
||||
ssaDefReachesThroughBlock(def, mid) and
|
||||
bb2 = getABasicBlockSuccessor(mid)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(def, bb1, bb2) and
|
||||
defOccursInBlock(def, bb2, v, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
|
||||
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExclPhiRead(def, mid, bb2) and
|
||||
phiReadStep(def, _, bb1, mid)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* the underlying variable `v` of `def` is accessed in basic block `bb2`
|
||||
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
|
||||
* `v` is neither read nor written in any block on the path between `bb1`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesExclPhiRead(def, bb1, bb2) and
|
||||
not defOccursInBlock(def, bb1, _, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
|
||||
varBlockReaches(def, bb1, bb2) and
|
||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
|
||||
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
|
||||
* and `v` is neither read nor written in any block on the path between `bb`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
|
||||
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
|
||||
not defOccursInBlock(def, bb2, _, _) and
|
||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExit(def, mid) and
|
||||
phiReadStep(def, _, bb, mid)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate phiReadExposedForTesting = phiRead/2;
|
||||
|
||||
private import SsaDefReaches
|
||||
|
||||
pragma[nomagic]
|
||||
predicate liveThrough(BasicBlock bb, SourceVariable v) {
|
||||
liveAtExit(bb, v) and
|
||||
not ssaRef(bb, _, v, SsaDef())
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the SSA definition of `v` at `def` reaches the end of basic
|
||||
* block `bb`, at which point it is still live, without crossing another
|
||||
* SSA definition of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
|
||||
exists(int last |
|
||||
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
|
||||
ssaDefReachesRank(bb, def, last, v) and
|
||||
liveAtExit(bb, v)
|
||||
)
|
||||
or
|
||||
// The construction of SSA form ensures that each read of a variable is
|
||||
// dominated by its definition. An SSA definition therefore reaches a
|
||||
// control flow node if it is the _closest_ SSA definition that dominates
|
||||
// the node. If two definitions dominate a node then one must dominate the
|
||||
// other, so therefore the definition of _closest_ is given by the dominator
|
||||
// tree. Thus, reaching definitions can be calculated in terms of dominance.
|
||||
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
|
||||
liveThrough(bb, pragma[only_bind_into](v))
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
|
||||
exists(SourceVariable v, BasicBlock bbDef |
|
||||
phi.definesAt(v, bbDef, _) and
|
||||
getABasicBlockPredecessor(bbDef) = bb and
|
||||
ssaDefReachesEndOfBlock(bb, inp, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
|
||||
* basic block `bb`, without crossing another SSA definition of `v`. The read
|
||||
* is of kind `rk`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
||||
or
|
||||
ssaRef(bb, i, v, any(SsaRead k)) and
|
||||
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
|
||||
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
|
||||
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
|
||||
* path between them without any read of `def`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
exists(int rnk |
|
||||
rnk = ssaDefRank(def, _, bb1, i1, _) and
|
||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
|
||||
variableRead(bb1, i2, _, _) and
|
||||
bb2 = bb1
|
||||
)
|
||||
or
|
||||
lastSsaRef(def, _, bb1, i1) and
|
||||
defAdjacentRead(def, bb1, bb2, i2)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate adjacentDefRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
|
||||
) {
|
||||
adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
|
||||
ssaRef(bb1, i1, v, SsaDef())
|
||||
or
|
||||
variableRead(bb1, i1, v, true)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
|
||||
variableRead(bb3, i3, _, false) and
|
||||
adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `adjacentDefRead`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
variableRead(bb2, i2, _, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
|
||||
* `def`. The reference is last because it can reach another write `next`,
|
||||
* without passing through another read or write.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
|
||||
exists(SourceVariable v |
|
||||
// Next reference to `v` inside `bb` is a write
|
||||
exists(int rnk, int j |
|
||||
rnk = ssaDefRank(def, v, bb, i, _) and
|
||||
next.definesAt(v, bb, j) and
|
||||
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
|
||||
)
|
||||
or
|
||||
// Can reach a write using one or more steps
|
||||
lastSsaRef(def, v, bb, i) and
|
||||
exists(BasicBlock bb2 |
|
||||
varBlockReaches(def, bb, bb2) and
|
||||
1 = ssaDefRank(next, v, bb2, _, SsaDef())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `inp` is an immediately preceding definition of uncertain definition
|
||||
* `def`. Since `def` is uncertain, the value from the preceding definition might
|
||||
* still be valid.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
|
||||
lastRefRedef(inp, _, _, def)
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesUncertainRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
variableRead(bb2, i2, _, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `lastRefRedef`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) {
|
||||
lastRefRedef(def, bb, i, next) and
|
||||
not variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
lastRefRedef(def, bb0, i0, next) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA
|
||||
* definition `def`.
|
||||
*
|
||||
* That is, the node can reach the end of the enclosing callable, or another
|
||||
* SSA definition for the underlying source variable, without passing through
|
||||
* another read.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRef(Definition def, BasicBlock bb, int i) {
|
||||
// Can reach another definition
|
||||
lastRefRedef(def, bb, i, _)
|
||||
or
|
||||
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
|
||||
// Can reach exit directly
|
||||
bb instanceof ExitBasicBlock
|
||||
or
|
||||
// Can reach a block using one or more steps, where `def` is no longer live
|
||||
varBlockReachesExit(def, bb)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `lastRefRedef`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) {
|
||||
lastRef(def, bb, i) and
|
||||
not variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/** A static single assignment (SSA) definition. */
|
||||
class Definition extends TDefinition {
|
||||
/** Gets the source variable underlying this SSA definition. */
|
||||
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
|
||||
* Phi nodes are considered to be at index `-1`, while normal variable writes
|
||||
* are at the index of the control flow node they wrap.
|
||||
*/
|
||||
final predicate definesAt(SourceVariable v, BasicBlock bb, int i) {
|
||||
this = TWriteDef(v, bb, i)
|
||||
or
|
||||
this = TPhiNode(v, bb) and i = -1
|
||||
}
|
||||
|
||||
/** Gets the basic block to which this SSA definition belongs. */
|
||||
final BasicBlock getBasicBlock() { this.definesAt(_, result, _) }
|
||||
|
||||
/** Gets a textual representation of this SSA definition. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/** An SSA definition that corresponds to a write. */
|
||||
class WriteDefinition extends Definition, TWriteDef {
|
||||
private SourceVariable v;
|
||||
private BasicBlock bb;
|
||||
private int i;
|
||||
|
||||
WriteDefinition() { this = TWriteDef(v, bb, i) }
|
||||
|
||||
override string toString() { result = "WriteDef" }
|
||||
}
|
||||
|
||||
/** A phi node. */
|
||||
class PhiNode extends Definition, TPhiNode {
|
||||
override string toString() { result = "Phi" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition that represents an uncertain update of the underlying
|
||||
* source variable.
|
||||
*/
|
||||
class UncertainWriteDefinition extends WriteDefinition {
|
||||
UncertainWriteDefinition() {
|
||||
exists(SourceVariable v, BasicBlock bb, int i |
|
||||
this.definesAt(v, bb, i) and
|
||||
variableWrite(bb, i, v, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a set of consistency queries. */
|
||||
module Consistency {
|
||||
abstract class RelevantDefinition extends Definition {
|
||||
abstract predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
}
|
||||
|
||||
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
|
||||
}
|
||||
|
||||
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableRead(bb, i, v, _) and
|
||||
not ssaDefReachesRead(v, _, bb, i)
|
||||
}
|
||||
|
||||
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
|
||||
v = def.getSourceVariable() and
|
||||
not ssaDefReachesRead(_, def, _, _) and
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/** Provides the C# specific parameters for `SsaImplCommon.qll`. */
|
||||
|
||||
private import csharp
|
||||
private import AssignableDefinitions
|
||||
private import SsaImpl as SsaImpl
|
||||
|
||||
class BasicBlock = ControlFlow::BasicBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock;
|
||||
|
||||
class SourceVariable = Ssa::SourceVariable;
|
||||
|
||||
predicate variableWrite = SsaImpl::variableWrite/4;
|
||||
|
||||
predicate variableRead = SsaImpl::variableRead/4;
|
||||
@@ -1,795 +0,0 @@
|
||||
/**
|
||||
* Provides a language-independent implementation of static single assignment
|
||||
* (SSA) form.
|
||||
*/
|
||||
|
||||
private import SsaImplSpecific
|
||||
|
||||
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb }
|
||||
|
||||
/**
|
||||
* Liveness analysis (based on source variables) to restrict the size of the
|
||||
* SSA representation.
|
||||
*/
|
||||
private module Liveness {
|
||||
/**
|
||||
* A classification of variable references into reads (of a given kind) and
|
||||
* (certain or uncertain) writes.
|
||||
*/
|
||||
private newtype TRefKind =
|
||||
Read(boolean certain) { certain in [false, true] } or
|
||||
Write(boolean certain) { certain in [false, true] }
|
||||
|
||||
private class RefKind extends TRefKind {
|
||||
string toString() {
|
||||
exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")")
|
||||
or
|
||||
exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")")
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this = Read(_) and
|
||||
result = 0
|
||||
or
|
||||
this = Write(_) and
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
|
||||
*/
|
||||
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
|
||||
or
|
||||
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
|
||||
}
|
||||
|
||||
private newtype OrderedRefIndex =
|
||||
MkOrderedRefIndex(int i, int tag) {
|
||||
exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder())
|
||||
}
|
||||
|
||||
private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) {
|
||||
ref(bb, i, v, k) and
|
||||
result = MkOrderedRefIndex(i, ord) and
|
||||
ord = k.getOrder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of
|
||||
* basic block `bb`, which has the given reference kind `k`.
|
||||
*
|
||||
* Reads are considered before writes when they happen at the same index.
|
||||
*/
|
||||
private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
refOrd(bb, i, v, k, _) =
|
||||
rank[result](int j, int ord, OrderedRefIndex res |
|
||||
res = refOrd(bb, j, v, _, ord)
|
||||
|
|
||||
res order by j, ord
|
||||
)
|
||||
}
|
||||
|
||||
private int maxRefRank(BasicBlock bb, SourceVariable v) {
|
||||
result = refRank(bb, _, v, _) and
|
||||
not result + 1 = refRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
|
||||
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
|
||||
* that is either a read or a certain write.
|
||||
*/
|
||||
private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) {
|
||||
result =
|
||||
min(int r, RefKind k |
|
||||
r = refRank(bb, _, v, k) and
|
||||
k != Write(false)
|
||||
|
|
||||
r
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if source variable `v` is live at the beginning of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtEntry(BasicBlock bb, SourceVariable v) {
|
||||
// The first read or certain write to `v` inside `bb` is a read
|
||||
refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v)
|
||||
or
|
||||
// There is no certain write to `v` inside `bb`, but `v` is live at entry
|
||||
// to a successor basic block of `bb`
|
||||
not exists(firstReadOrCertainWrite(bb, v)) and
|
||||
liveAtExit(bb, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if source variable `v` is live at the end of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
|
||||
liveAtEntry(getABasicBlockSuccessor(bb), v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live in basic block `bb` at index `i`.
|
||||
* The rank of `i` is `rnk` as defined by `refRank()`.
|
||||
*/
|
||||
private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) {
|
||||
exists(RefKind kind | rnk = refRank(bb, i, v, kind) |
|
||||
rnk = maxRefRank(bb, v) and
|
||||
liveAtExit(bb, v)
|
||||
or
|
||||
ref(bb, i, v, kind) and
|
||||
kind = Read(_)
|
||||
or
|
||||
exists(RefKind nextKind |
|
||||
liveAtRank(bb, _, v, rnk + 1) and
|
||||
rnk + 1 = refRank(bb, _, v, nextKind) and
|
||||
nextKind != Write(true)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live after the (certain or uncertain) write at
|
||||
* index `i` inside basic block `bb`.
|
||||
*/
|
||||
predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) {
|
||||
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk))
|
||||
}
|
||||
}
|
||||
|
||||
private import Liveness
|
||||
|
||||
/**
|
||||
* Holds if `df` is in the dominance frontier of `bb`.
|
||||
*
|
||||
* This is equivalent to:
|
||||
*
|
||||
* ```ql
|
||||
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
|
||||
* not bb = getImmediateBasicBlockDominator+(df)
|
||||
* ```
|
||||
*/
|
||||
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
|
||||
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
|
||||
or
|
||||
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
|
||||
bb = getImmediateBasicBlockDominator(prev) and
|
||||
not bb = getImmediateBasicBlockDominator(df)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* definition of `v`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock defbb, Definition def |
|
||||
def.definesAt(v, defbb, _) and
|
||||
inDominanceFrontier(defbb, bb)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TDefinition =
|
||||
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableWrite(bb, i, v, _) and
|
||||
liveAfterWrite(bb, i, v)
|
||||
} or
|
||||
TPhiNode(SourceVariable v, BasicBlock bb) {
|
||||
inDefDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v)
|
||||
}
|
||||
|
||||
private module SsaDefReaches {
|
||||
newtype TSsaRefKind =
|
||||
SsaActualRead() or
|
||||
SsaPhiRead() or
|
||||
SsaDef()
|
||||
|
||||
class SsaRead = SsaActualRead or SsaPhiRead;
|
||||
|
||||
/**
|
||||
* A classification of SSA variable references into reads and definitions.
|
||||
*/
|
||||
class SsaRefKind extends TSsaRefKind {
|
||||
string toString() {
|
||||
this = SsaActualRead() and
|
||||
result = "SsaActualRead"
|
||||
or
|
||||
this = SsaPhiRead() and
|
||||
result = "SsaPhiRead"
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = "SsaDef"
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this instanceof SsaRead and
|
||||
result = 0
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* read of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
|
||||
lastRefIsRead(readbb, v)
|
||||
or
|
||||
phiRead(readbb, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a phi-read node should be inserted for variable `v` at the beginning
|
||||
* of basic block `bb`.
|
||||
*
|
||||
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
|
||||
* instead of writes, and only if the dominance-frontier block does not already
|
||||
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
|
||||
* an internal implementation detail that is not exposed.
|
||||
*
|
||||
* The motivation for adding phi-reads is to improve performance of the use-use
|
||||
* calculation in cases where there is a large number of reads that can reach the
|
||||
* same join-point, and from there reach a large number of basic blocks. Example:
|
||||
*
|
||||
* ```cs
|
||||
* if (a)
|
||||
* use(x);
|
||||
* else if (b)
|
||||
* use(x);
|
||||
* else if (c)
|
||||
* use(x);
|
||||
* else if (d)
|
||||
* use(x);
|
||||
* // many more ifs ...
|
||||
*
|
||||
* // phi-read for `x` inserted here
|
||||
*
|
||||
* // program not mentioning `x`, with large basic block graph
|
||||
*
|
||||
* use(x);
|
||||
* ```
|
||||
*
|
||||
* Without phi-reads, the analysis has to replicate reachability for each of
|
||||
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
|
||||
* each conditional use of `x` to reach the basic block containing the phi-read
|
||||
* node for `x`, and only that basic block will have to compute reachability
|
||||
* through the remainder of the large program.
|
||||
*
|
||||
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
|
||||
* one SSA definition (without passing through another definition): Assume, for
|
||||
* the sake of contradiction, that there are two reaching definitions `def1` and
|
||||
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
|
||||
* dominating definition will prevent the other from reaching `phi-read`. So, at
|
||||
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
|
||||
* Then `def1` must go through one of its dominance-frontier blocks in order to
|
||||
* reach `phi-read`. However, such a block will always start with a (normal) phi
|
||||
* node, which contradicts reachability.
|
||||
*
|
||||
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
|
||||
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
|
||||
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
|
||||
* which contradicts reachability.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiRead(BasicBlock bb, SourceVariable v) {
|
||||
inReadDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v) and
|
||||
// only if there are no other references to `v` inside `bb`
|
||||
not ref(bb, _, v, _) and
|
||||
not exists(Definition def | def.definesAt(v, bb, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
|
||||
* is `SsaDef()`).
|
||||
*
|
||||
* Unlike `Liveness::ref`, this includes `phi` nodes.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
variableRead(bb, i, v, _) and
|
||||
k = SsaActualRead()
|
||||
or
|
||||
phiRead(bb, v) and
|
||||
i = -1 and
|
||||
k = SsaPhiRead()
|
||||
or
|
||||
any(Definition def).definesAt(v, bb, i) and
|
||||
k = SsaDef()
|
||||
}
|
||||
|
||||
private newtype OrderedSsaRefIndex =
|
||||
MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) }
|
||||
|
||||
private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) {
|
||||
ssaRef(bb, i, v, k) and
|
||||
result = MkOrderedSsaRefIndex(i, k) and
|
||||
ord = k.getOrder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
|
||||
* block `bb`, which has the given reference kind `k`.
|
||||
*
|
||||
* For example, if `bb` is a basic block with a phi node for `v` (considered
|
||||
* to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
|
||||
*
|
||||
* ```ql
|
||||
* ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
|
||||
* ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
|
||||
* ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
|
||||
* ```
|
||||
*
|
||||
* Reads are considered before writes when they happen at the same index.
|
||||
*/
|
||||
int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
ssaRefOrd(bb, i, v, k, _) =
|
||||
rank[result](int j, int ord, OrderedSsaRefIndex res |
|
||||
res = ssaRefOrd(bb, j, v, _, ord)
|
||||
|
|
||||
res order by j, ord
|
||||
)
|
||||
}
|
||||
|
||||
int maxSsaRefRank(BasicBlock bb, SourceVariable v) {
|
||||
result = ssaRefRank(bb, _, v, _) and
|
||||
not result + 1 = ssaRefRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA definition `def` reaches rank index `rnk` in its own
|
||||
* basic block `bb`.
|
||||
*/
|
||||
predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) {
|
||||
exists(int i |
|
||||
rnk = ssaRefRank(bb, i, v, SsaDef()) and
|
||||
def.definesAt(v, bb, i)
|
||||
)
|
||||
or
|
||||
ssaDefReachesRank(bb, def, rnk - 1, v) and
|
||||
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA definition of `v` at `def` reaches index `i` in the same
|
||||
* basic block `bb`, without crossing another SSA definition of `v`.
|
||||
*/
|
||||
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
exists(int rnk |
|
||||
ssaDefReachesRank(bb, def, rnk, v) and
|
||||
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||
*/
|
||||
int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) {
|
||||
v = def.getSourceVariable() and
|
||||
result = ssaRefRank(bb, i, v, k) and
|
||||
(
|
||||
ssaDefReachesRead(_, def, bb, i)
|
||||
or
|
||||
def.definesAt(_, bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the reference to `def` at index `i` in basic block `bb` is the
|
||||
* last reference to `v` inside `bb`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
|
||||
}
|
||||
|
||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
|
||||
exists(ssaDefRank(def, v, bb, _, k))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
|
||||
ssaDefReachesEndOfBlock(bb, def, _) and
|
||||
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
|
||||
* predecessor of `bb2`, and the underlying variable for `def` is neither read
|
||||
* nor written in any block on the path between `bb1` and `bb2`.
|
||||
*
|
||||
* Phi reads are considered as normal reads for this predicate.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
defOccursInBlock(def, bb1, _, _) and
|
||||
bb2 = getABasicBlockSuccessor(bb1)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesInclPhiRead(def, bb1, mid) and
|
||||
ssaDefReachesThroughBlock(def, mid) and
|
||||
bb2 = getABasicBlockSuccessor(mid)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(def, bb1, bb2) and
|
||||
defOccursInBlock(def, bb2, v, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
|
||||
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExclPhiRead(def, mid, bb2) and
|
||||
phiReadStep(def, _, bb1, mid)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* the underlying variable `v` of `def` is accessed in basic block `bb2`
|
||||
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
|
||||
* `v` is neither read nor written in any block on the path between `bb1`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesExclPhiRead(def, bb1, bb2) and
|
||||
not defOccursInBlock(def, bb1, _, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
|
||||
varBlockReaches(def, bb1, bb2) and
|
||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
|
||||
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
|
||||
* and `v` is neither read nor written in any block on the path between `bb`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
|
||||
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
|
||||
not defOccursInBlock(def, bb2, _, _) and
|
||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExit(def, mid) and
|
||||
phiReadStep(def, _, bb, mid)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate phiReadExposedForTesting = phiRead/2;
|
||||
|
||||
private import SsaDefReaches
|
||||
|
||||
pragma[nomagic]
|
||||
predicate liveThrough(BasicBlock bb, SourceVariable v) {
|
||||
liveAtExit(bb, v) and
|
||||
not ssaRef(bb, _, v, SsaDef())
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the SSA definition of `v` at `def` reaches the end of basic
|
||||
* block `bb`, at which point it is still live, without crossing another
|
||||
* SSA definition of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
|
||||
exists(int last |
|
||||
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
|
||||
ssaDefReachesRank(bb, def, last, v) and
|
||||
liveAtExit(bb, v)
|
||||
)
|
||||
or
|
||||
// The construction of SSA form ensures that each read of a variable is
|
||||
// dominated by its definition. An SSA definition therefore reaches a
|
||||
// control flow node if it is the _closest_ SSA definition that dominates
|
||||
// the node. If two definitions dominate a node then one must dominate the
|
||||
// other, so therefore the definition of _closest_ is given by the dominator
|
||||
// tree. Thus, reaching definitions can be calculated in terms of dominance.
|
||||
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
|
||||
liveThrough(bb, pragma[only_bind_into](v))
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
|
||||
exists(SourceVariable v, BasicBlock bbDef |
|
||||
phi.definesAt(v, bbDef, _) and
|
||||
getABasicBlockPredecessor(bbDef) = bb and
|
||||
ssaDefReachesEndOfBlock(bb, inp, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
|
||||
* basic block `bb`, without crossing another SSA definition of `v`. The read
|
||||
* is of kind `rk`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
||||
or
|
||||
ssaRef(bb, i, v, any(SsaRead k)) and
|
||||
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
|
||||
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
|
||||
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
|
||||
* path between them without any read of `def`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
exists(int rnk |
|
||||
rnk = ssaDefRank(def, _, bb1, i1, _) and
|
||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
|
||||
variableRead(bb1, i2, _, _) and
|
||||
bb2 = bb1
|
||||
)
|
||||
or
|
||||
lastSsaRef(def, _, bb1, i1) and
|
||||
defAdjacentRead(def, bb1, bb2, i2)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate adjacentDefRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
|
||||
) {
|
||||
adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
|
||||
ssaRef(bb1, i1, v, SsaDef())
|
||||
or
|
||||
variableRead(bb1, i1, v, true)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
|
||||
variableRead(bb3, i3, _, false) and
|
||||
adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `adjacentDefRead`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
variableRead(bb2, i2, _, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
|
||||
* `def`. The reference is last because it can reach another write `next`,
|
||||
* without passing through another read or write.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
|
||||
exists(SourceVariable v |
|
||||
// Next reference to `v` inside `bb` is a write
|
||||
exists(int rnk, int j |
|
||||
rnk = ssaDefRank(def, v, bb, i, _) and
|
||||
next.definesAt(v, bb, j) and
|
||||
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
|
||||
)
|
||||
or
|
||||
// Can reach a write using one or more steps
|
||||
lastSsaRef(def, v, bb, i) and
|
||||
exists(BasicBlock bb2 |
|
||||
varBlockReaches(def, bb, bb2) and
|
||||
1 = ssaDefRank(next, v, bb2, _, SsaDef())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if `inp` is an immediately preceding definition of uncertain definition
|
||||
* `def`. Since `def` is uncertain, the value from the preceding definition might
|
||||
* still be valid.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
|
||||
lastRefRedef(inp, _, _, def)
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesUncertainRead(
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
|
||||
variableRead(bb2, i2, _, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `lastRefRedef`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) {
|
||||
lastRefRedef(def, bb, i, next) and
|
||||
not variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
lastRefRedef(def, bb0, i0, next) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA
|
||||
* definition `def`.
|
||||
*
|
||||
* That is, the node can reach the end of the enclosing callable, or another
|
||||
* SSA definition for the underlying source variable, without passing through
|
||||
* another read.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRef(Definition def, BasicBlock bb, int i) {
|
||||
// Can reach another definition
|
||||
lastRefRedef(def, bb, i, _)
|
||||
or
|
||||
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
|
||||
// Can reach exit directly
|
||||
bb instanceof ExitBasicBlock
|
||||
or
|
||||
// Can reach a block using one or more steps, where `def` is no longer live
|
||||
varBlockReachesExit(def, bb)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
*
|
||||
* Same as `lastRefRedef`, but ignores uncertain reads.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) {
|
||||
lastRef(def, bb, i) and
|
||||
not variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
/** A static single assignment (SSA) definition. */
|
||||
class Definition extends TDefinition {
|
||||
/** Gets the source variable underlying this SSA definition. */
|
||||
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
|
||||
* Phi nodes are considered to be at index `-1`, while normal variable writes
|
||||
* are at the index of the control flow node they wrap.
|
||||
*/
|
||||
final predicate definesAt(SourceVariable v, BasicBlock bb, int i) {
|
||||
this = TWriteDef(v, bb, i)
|
||||
or
|
||||
this = TPhiNode(v, bb) and i = -1
|
||||
}
|
||||
|
||||
/** Gets the basic block to which this SSA definition belongs. */
|
||||
final BasicBlock getBasicBlock() { this.definesAt(_, result, _) }
|
||||
|
||||
/** Gets a textual representation of this SSA definition. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/** An SSA definition that corresponds to a write. */
|
||||
class WriteDefinition extends Definition, TWriteDef {
|
||||
private SourceVariable v;
|
||||
private BasicBlock bb;
|
||||
private int i;
|
||||
|
||||
WriteDefinition() { this = TWriteDef(v, bb, i) }
|
||||
|
||||
override string toString() { result = "WriteDef" }
|
||||
}
|
||||
|
||||
/** A phi node. */
|
||||
class PhiNode extends Definition, TPhiNode {
|
||||
override string toString() { result = "Phi" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition that represents an uncertain update of the underlying
|
||||
* source variable.
|
||||
*/
|
||||
class UncertainWriteDefinition extends WriteDefinition {
|
||||
UncertainWriteDefinition() {
|
||||
exists(SourceVariable v, BasicBlock bb, int i |
|
||||
this.definesAt(v, bb, i) and
|
||||
variableWrite(bb, i, v, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a set of consistency queries. */
|
||||
module Consistency {
|
||||
abstract class RelevantDefinition extends Definition {
|
||||
abstract predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
}
|
||||
|
||||
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
|
||||
}
|
||||
|
||||
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableRead(bb, i, v, _) and
|
||||
not ssaDefReachesRead(v, _, bb, i)
|
||||
}
|
||||
|
||||
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
|
||||
v = def.getSourceVariable() and
|
||||
not ssaDefReachesRead(_, def, _, _) and
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/** Provides the C# specific parameters for `SsaImplCommon.qll`. */
|
||||
|
||||
private import csharp
|
||||
private import AssignableDefinitions
|
||||
|
||||
class BasicBlock = ControlFlow::BasicBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock;
|
||||
|
||||
pragma[noinline]
|
||||
private Callable getAnAssigningCallable(LocalScopeVariable v) {
|
||||
result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable()
|
||||
}
|
||||
|
||||
class SourceVariable extends LocalScopeVariable {
|
||||
SourceVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is assignable definition `def`,
|
||||
* targeting local scope variable `v`.
|
||||
*/
|
||||
predicate definitionAt(AssignableDefinition def, BasicBlock bb, int i, SourceVariable v) {
|
||||
bb.getNode(i) = def.getAControlFlowNode() and
|
||||
v = def.getTarget() and
|
||||
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
|
||||
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
|
||||
second.getAssignment() = first.getAssignment() and
|
||||
second.getEvaluationOrder() > first.getEvaluationOrder() and
|
||||
second.getTarget() = v
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableDefinition def |
|
||||
definitionAt(def, bb, i, v) and
|
||||
if def.isCertain() then certain = true else certain = false
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableRead read |
|
||||
read.getAControlFlowNode() = bb.getNode(i) and
|
||||
read.getTarget() = v and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
@@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,12 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/** Provides a module for importing negative models. */
|
||||
|
||||
/**
|
||||
* A module importing all generated negative Models as Data models.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
private module GeneratedFrameworks {
|
||||
private import generated.dotnet.NegativeRuntime
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ private class SystemArrayFlowModelCsv extends SummaryModelCsv {
|
||||
row =
|
||||
[
|
||||
"System;Array;false;AsReadOnly<>;(T[]);;Argument[0].Element;ReturnValue.Element;value;manual",
|
||||
"System;Array;false;Clear;(System.Array,System.Int32,System.Int32);;Argument[0].WithoutElement;Argument[0];value;manual",
|
||||
"System;Array;false;Clear;(System.Array);;Argument[0].WithoutElement;Argument[0];value;manual",
|
||||
"System;Array;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual",
|
||||
"System;Array;false;CopyTo;(System.Array,System.Int64);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
"System;Array;false;Find<>;(T[],System.Predicate<T>);;Argument[0].Element;Argument[1].Parameter[0];value;manual",
|
||||
|
||||
@@ -3237,7 +3237,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;Close;();generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;DisposeAsync;();generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;Flush;();generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;FlushAsync;();generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;IndentedTextWriter;(System.IO.TextWriter);generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;OutputTabs;();generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;OutputTabsAsync;();generated",
|
||||
@@ -3281,7 +3280,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;WriteLineAsync;(System.String);generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;WriteLineNoTabs;(System.String);generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;WriteLineNoTabsAsync;(System.String);generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;get_Indent;();generated",
|
||||
"System.CodeDom.Compiler;IndentedTextWriter;set_Indent;(System.Int32);generated",
|
||||
"System.CodeDom.Compiler;TempFileCollection;AddFile;(System.String,System.Boolean);generated",
|
||||
@@ -3459,7 +3457,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.CodeDom;CodeNamespaceImport;set_LinePragma;(System.CodeDom.CodeLinePragma);generated",
|
||||
"System.CodeDom;CodeNamespaceImportCollection;Clear;();generated",
|
||||
"System.CodeDom;CodeNamespaceImportCollection;Contains;(System.Object);generated",
|
||||
"System.CodeDom;CodeNamespaceImportCollection;GetEnumerator;();generated",
|
||||
"System.CodeDom;CodeNamespaceImportCollection;IndexOf;(System.Object);generated",
|
||||
"System.CodeDom;CodeNamespaceImportCollection;Remove;(System.Object);generated",
|
||||
"System.CodeDom;CodeNamespaceImportCollection;RemoveAt;(System.Int32);generated",
|
||||
@@ -3612,7 +3609,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Concurrent;ConcurrentDictionary<,>;Contains;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
|
||||
"System.Collections.Concurrent;ConcurrentDictionary<,>;Contains;(System.Object);generated",
|
||||
"System.Collections.Concurrent;ConcurrentDictionary<,>;ContainsKey;(TKey);generated",
|
||||
"System.Collections.Concurrent;ConcurrentDictionary<,>;GetEnumerator;();generated",
|
||||
"System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
|
||||
"System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(System.Object);generated",
|
||||
"System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(TKey);generated",
|
||||
@@ -3676,9 +3672,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Generic;ByteEqualityComparer;Equals;(System.Object);generated",
|
||||
"System.Collections.Generic;ByteEqualityComparer;GetHashCode;();generated",
|
||||
"System.Collections.Generic;ByteEqualityComparer;GetHashCode;(System.Byte);generated",
|
||||
"System.Collections.Generic;CollectionExtensions;AsReadOnly<,>;(System.Collections.Generic.IDictionary<TKey,TValue>);generated",
|
||||
"System.Collections.Generic;CollectionExtensions;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>,TKey);generated",
|
||||
"System.Collections.Generic;CollectionExtensions;TryAdd<,>;(System.Collections.Generic.IDictionary<TKey,TValue>,TKey,TValue);generated",
|
||||
"System.Collections.Generic;Comparer<>;Compare;(System.Object,System.Object);generated",
|
||||
"System.Collections.Generic;Comparer<>;Compare;(T,T);generated",
|
||||
"System.Collections.Generic;Comparer<>;get_Default;();generated",
|
||||
@@ -3819,7 +3813,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
|
||||
"System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.String);generated",
|
||||
"System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.String,System.Exception);generated",
|
||||
"System.Collections.Generic;KeyValuePair;Create<,>;(TKey,TValue);generated",
|
||||
"System.Collections.Generic;KeyValuePair<,>;ToString;();generated",
|
||||
"System.Collections.Generic;LinkedList<>+Enumerator;Dispose;();generated",
|
||||
"System.Collections.Generic;LinkedList<>+Enumerator;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
|
||||
@@ -4172,9 +4165,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;();generated",
|
||||
"System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;(System.Collections.Generic.IEqualityComparer<TKey>);generated",
|
||||
"System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;(System.Collections.Generic.IEqualityComparer<TKey>,System.Collections.Generic.IEqualityComparer<TValue>);generated",
|
||||
"System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
|
||||
"System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEqualityComparer<TKey>,System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
|
||||
"System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEqualityComparer<TKey>,System.Collections.Generic.IEqualityComparer<TValue>,System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
|
||||
"System.Collections.Immutable;ImmutableDictionary;GetValueOrDefault<,>;(System.Collections.Immutable.IImmutableDictionary<TKey,TValue>,TKey);generated",
|
||||
"System.Collections.Immutable;ImmutableDictionary<,>+Builder;Clear;();generated",
|
||||
"System.Collections.Immutable;ImmutableDictionary<,>+Builder;Contains;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
|
||||
@@ -4264,10 +4254,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Immutable;ImmutableInterlocked;TryRemove<,>;(System.Collections.Immutable.ImmutableDictionary<TKey,TValue>,TKey,TValue);generated",
|
||||
"System.Collections.Immutable;ImmutableInterlocked;TryUpdate<,>;(System.Collections.Immutable.ImmutableDictionary<TKey,TValue>,TKey,TValue,TValue);generated",
|
||||
"System.Collections.Immutable;ImmutableList;Create<>;();generated",
|
||||
"System.Collections.Immutable;ImmutableList;Create<>;(T);generated",
|
||||
"System.Collections.Immutable;ImmutableList;Create<>;(T[]);generated",
|
||||
"System.Collections.Immutable;ImmutableList;CreateBuilder<>;();generated",
|
||||
"System.Collections.Immutable;ImmutableList;CreateRange<>;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList<T>,T);generated",
|
||||
"System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList<T>,T,System.Collections.Generic.IEqualityComparer<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList<T>,T,System.Int32);generated",
|
||||
@@ -4331,9 +4319,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Immutable;ImmutableQueue<>;get_IsEmpty;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary;Create<,>;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary;CreateBuilder<,>;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IComparer<TKey>,System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IComparer<TKey>,System.Collections.Generic.IEqualityComparer<TValue>,System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Clear;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Contains;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Contains;(System.Object);generated",
|
||||
@@ -4353,7 +4338,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;Dispose;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;MoveNext;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;Reset;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;get_Current;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>;Clear;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>;Contains;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>;Contains;(System.Object);generated",
|
||||
@@ -4370,8 +4354,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>;get_IsReadOnly;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedDictionary<,>;get_IsSynchronized;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet;Create<>;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet;Create<>;(System.Collections.Generic.IComparer<T>,T);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet;Create<>;(T);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet;Create<>;(T[]);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet;CreateBuilder<>;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;Clear;();generated",
|
||||
@@ -4385,7 +4367,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;Overlaps;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;Remove;(T);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;SetEquals;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;SymmetricExceptWith;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_Count;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_IsReadOnly;();generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_IsSynchronized;();generated",
|
||||
@@ -4399,7 +4380,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;ExceptWith;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;IndexOf;(System.Object);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;IndexOf;(T);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;Intersect;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;IntersectWith;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;IsProperSubsetOf;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;IsProperSupersetOf;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
@@ -4411,7 +4391,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;Remove;(T);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;RemoveAt;(System.Int32);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;SetEquals;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;SymmetricExcept;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;SymmetricExceptWith;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;UnionWith;(System.Collections.Generic.IEnumerable<T>);generated",
|
||||
"System.Collections.Immutable;ImmutableSortedSet<>;get_Count;();generated",
|
||||
@@ -4819,7 +4798,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.ComponentModel.Composition.Hosting;AggregateCatalog;AggregateCatalog;(System.Collections.Generic.IEnumerable<System.ComponentModel.Composition.Primitives.ComposablePartCatalog>);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AggregateCatalog;AggregateCatalog;(System.ComponentModel.Composition.Primitives.ComposablePartCatalog[]);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AggregateCatalog;Dispose;(System.Boolean);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AggregateCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AggregateCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AggregateCatalog;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AggregateExportProvider;AggregateExportProvider;(System.Collections.Generic.IEnumerable<System.ComponentModel.Composition.Hosting.ExportProvider>);generated",
|
||||
@@ -4827,13 +4805,11 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.ComponentModel.Composition.Hosting;AggregateExportProvider;Dispose;(System.Boolean);generated",
|
||||
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;ApplicationCatalog;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;Dispose;(System.Boolean);generated",
|
||||
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
|
||||
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;ToString;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;get_DisplayName;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;get_Origin;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;AssemblyCatalog;AssemblyCatalog;(System.String);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AssemblyCatalog;Dispose;(System.Boolean);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AssemblyCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
|
||||
"System.ComponentModel.Composition.Hosting;AssemblyCatalog;get_Origin;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;AtomicComposition;AtomicComposition;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;AtomicComposition;Complete;();generated",
|
||||
@@ -4869,7 +4845,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.ComponentModel.Composition.Hosting;CompositionContainer;SatisfyImportsOnce;(System.ComponentModel.Composition.Primitives.ComposablePart);generated",
|
||||
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;CompositionScopeDefinition;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;Dispose;(System.Boolean);generated",
|
||||
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
|
||||
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
|
||||
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
|
||||
"System.ComponentModel.Composition.Hosting;CompositionService;Dispose;();generated",
|
||||
@@ -4879,7 +4854,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;DirectoryCatalog;(System.String,System.Reflection.ReflectionContext);generated",
|
||||
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;DirectoryCatalog;(System.String,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);generated",
|
||||
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;Dispose;(System.Boolean);generated",
|
||||
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
|
||||
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
|
||||
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
|
||||
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;Refresh;();generated",
|
||||
@@ -4902,7 +4876,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;get_AtomicComposition;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;set_AtomicComposition;(System.ComponentModel.Composition.Hosting.AtomicComposition);generated",
|
||||
"System.ComponentModel.Composition.Hosting;FilteredCatalog;Dispose;(System.Boolean);generated",
|
||||
"System.ComponentModel.Composition.Hosting;FilteredCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
|
||||
"System.ComponentModel.Composition.Hosting;FilteredCatalog;IncludeDependencies;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;FilteredCatalog;IncludeDependents;();generated",
|
||||
"System.ComponentModel.Composition.Hosting;FilteredCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
|
||||
@@ -4936,7 +4909,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.ComponentModel.Composition.Primitives;ComposablePartCatalog;ComposablePartCatalog;();generated",
|
||||
"System.ComponentModel.Composition.Primitives;ComposablePartCatalog;Dispose;();generated",
|
||||
"System.ComponentModel.Composition.Primitives;ComposablePartCatalog;Dispose;(System.Boolean);generated",
|
||||
"System.ComponentModel.Composition.Primitives;ComposablePartCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
|
||||
"System.ComponentModel.Composition.Primitives;ComposablePartDefinition;ComposablePartDefinition;();generated",
|
||||
"System.ComponentModel.Composition.Primitives;ComposablePartDefinition;CreatePart;();generated",
|
||||
"System.ComponentModel.Composition.Primitives;ComposablePartDefinition;get_ExportDefinitions;();generated",
|
||||
@@ -6364,7 +6336,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_ComponentType;();generated",
|
||||
"System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_IsReadOnly;();generated",
|
||||
"System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_PropertyType;();generated",
|
||||
"System.ComponentModel;TypeConverter+StandardValuesCollection;GetEnumerator;();generated",
|
||||
"System.ComponentModel;TypeConverter+StandardValuesCollection;get_Count;();generated",
|
||||
"System.ComponentModel;TypeConverter+StandardValuesCollection;get_IsSynchronized;();generated",
|
||||
"System.ComponentModel;TypeConverter+StandardValuesCollection;get_SyncRoot;();generated",
|
||||
@@ -7511,14 +7482,9 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Data.Common;DbCommand;DbCommand;();generated",
|
||||
"System.Data.Common;DbCommand;DisposeAsync;();generated",
|
||||
"System.Data.Common;DbCommand;ExecuteDbDataReader;(System.Data.CommandBehavior);generated",
|
||||
"System.Data.Common;DbCommand;ExecuteDbDataReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);generated",
|
||||
"System.Data.Common;DbCommand;ExecuteNonQuery;();generated",
|
||||
"System.Data.Common;DbCommand;ExecuteNonQueryAsync;();generated",
|
||||
"System.Data.Common;DbCommand;ExecuteNonQueryAsync;(System.Threading.CancellationToken);generated",
|
||||
"System.Data.Common;DbCommand;ExecuteReaderAsync;();generated",
|
||||
"System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Data.CommandBehavior);generated",
|
||||
"System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);generated",
|
||||
"System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Threading.CancellationToken);generated",
|
||||
"System.Data.Common;DbCommand;ExecuteScalar;();generated",
|
||||
"System.Data.Common;DbCommand;ExecuteScalarAsync;();generated",
|
||||
"System.Data.Common;DbCommand;ExecuteScalarAsync;(System.Threading.CancellationToken);generated",
|
||||
@@ -7602,7 +7568,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Data.Common;DbConnectionStringBuilder;GetDefaultEvent;();generated",
|
||||
"System.Data.Common;DbConnectionStringBuilder;GetDefaultProperty;();generated",
|
||||
"System.Data.Common;DbConnectionStringBuilder;GetEditor;(System.Type);generated",
|
||||
"System.Data.Common;DbConnectionStringBuilder;GetEnumerator;();generated",
|
||||
"System.Data.Common;DbConnectionStringBuilder;GetEvents;();generated",
|
||||
"System.Data.Common;DbConnectionStringBuilder;GetEvents;(System.Attribute[]);generated",
|
||||
"System.Data.Common;DbConnectionStringBuilder;GetProperties;(System.Collections.Hashtable);generated",
|
||||
@@ -7670,8 +7635,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Data.Common;DbDataReader;GetDecimal;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetDouble;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetFieldType;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetFieldValueAsync<>;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetFieldValueAsync<>;(System.Int32,System.Threading.CancellationToken);generated",
|
||||
"System.Data.Common;DbDataReader;GetFloat;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetGuid;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetInt16;(System.Int32);generated",
|
||||
@@ -7681,7 +7644,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Data.Common;DbDataReader;GetOrdinal;(System.String);generated",
|
||||
"System.Data.Common;DbDataReader;GetProviderSpecificFieldType;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetSchemaTable;();generated",
|
||||
"System.Data.Common;DbDataReader;GetSchemaTableAsync;(System.Threading.CancellationToken);generated",
|
||||
"System.Data.Common;DbDataReader;GetStream;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetString;(System.Int32);generated",
|
||||
"System.Data.Common;DbDataReader;GetValue;(System.Int32);generated",
|
||||
@@ -8993,9 +8955,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Data;DataColumnChangeEventArgs;get_ProposedValue;();generated",
|
||||
"System.Data;DataColumnChangeEventArgs;get_Row;();generated",
|
||||
"System.Data;DataColumnChangeEventArgs;set_ProposedValue;(System.Object);generated",
|
||||
"System.Data;DataColumnCollection;Add;();generated",
|
||||
"System.Data;DataColumnCollection;Add;(System.String,System.Type);generated",
|
||||
"System.Data;DataColumnCollection;Add;(System.String,System.Type,System.String);generated",
|
||||
"System.Data;DataColumnCollection;CanRemove;(System.Data.DataColumn);generated",
|
||||
"System.Data;DataColumnCollection;Clear;();generated",
|
||||
"System.Data;DataColumnCollection;Contains;(System.String);generated",
|
||||
@@ -9018,7 +8977,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Data;DataReaderExtensions;GetDecimal;(System.Data.Common.DbDataReader,System.String);generated",
|
||||
"System.Data;DataReaderExtensions;GetDouble;(System.Data.Common.DbDataReader,System.String);generated",
|
||||
"System.Data;DataReaderExtensions;GetFieldType;(System.Data.Common.DbDataReader,System.String);generated",
|
||||
"System.Data;DataReaderExtensions;GetFieldValueAsync<>;(System.Data.Common.DbDataReader,System.String,System.Threading.CancellationToken);generated",
|
||||
"System.Data;DataReaderExtensions;GetFloat;(System.Data.Common.DbDataReader,System.String);generated",
|
||||
"System.Data;DataReaderExtensions;GetInt16;(System.Data.Common.DbDataReader,System.String);generated",
|
||||
"System.Data;DataReaderExtensions;GetInt32;(System.Data.Common.DbDataReader,System.String);generated",
|
||||
@@ -9036,10 +8994,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Data;DataRelation;get_Nested;();generated",
|
||||
"System.Data;DataRelation;get_ParentTable;();generated",
|
||||
"System.Data;DataRelation;set_Nested;(System.Boolean);generated",
|
||||
"System.Data;DataRelationCollection;Add;(System.Data.DataColumn,System.Data.DataColumn);generated",
|
||||
"System.Data;DataRelationCollection;Add;(System.Data.DataColumn[],System.Data.DataColumn[]);generated",
|
||||
"System.Data;DataRelationCollection;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn);generated",
|
||||
"System.Data;DataRelationCollection;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);generated",
|
||||
"System.Data;DataRelationCollection;AddCore;(System.Data.DataRelation);generated",
|
||||
"System.Data;DataRelationCollection;CanRemove;(System.Data.DataRelation);generated",
|
||||
"System.Data;DataRelationCollection;Clear;();generated",
|
||||
@@ -9286,7 +9240,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Data;DataTableClearEventArgs;get_Table;();generated",
|
||||
"System.Data;DataTableClearEventArgs;get_TableName;();generated",
|
||||
"System.Data;DataTableClearEventArgs;get_TableNamespace;();generated",
|
||||
"System.Data;DataTableCollection;Add;();generated",
|
||||
"System.Data;DataTableCollection;CanRemove;(System.Data.DataTable);generated",
|
||||
"System.Data;DataTableCollection;Clear;();generated",
|
||||
"System.Data;DataTableCollection;Contains;(System.String);generated",
|
||||
@@ -13442,19 +13395,15 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Drawing.Printing;PrinterResolution;set_X;(System.Int32);generated",
|
||||
"System.Drawing.Printing;PrinterResolution;set_Y;(System.Int32);generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PaperSizeCollection;CopyTo;(System.Drawing.Printing.PaperSize[],System.Int32);generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PaperSizeCollection;GetEnumerator;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PaperSizeCollection;get_Count;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PaperSizeCollection;get_IsSynchronized;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PaperSourceCollection;CopyTo;(System.Drawing.Printing.PaperSource[],System.Int32);generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PaperSourceCollection;GetEnumerator;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PaperSourceCollection;get_Count;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PaperSourceCollection;get_IsSynchronized;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;CopyTo;(System.Drawing.Printing.PrinterResolution[],System.Int32);generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;GetEnumerator;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;get_Count;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;get_IsSynchronized;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+StringCollection;CopyTo;(System.String[],System.Int32);generated",
|
||||
"System.Drawing.Printing;PrinterSettings+StringCollection;GetEnumerator;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+StringCollection;get_Count;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings+StringCollection;get_IsSynchronized;();generated",
|
||||
"System.Drawing.Printing;PrinterSettings;Clone;();generated",
|
||||
@@ -15785,12 +15734,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO.Compression;DeflateStream;EndWrite;(System.IAsyncResult);generated",
|
||||
"System.IO.Compression;DeflateStream;Flush;();generated",
|
||||
"System.IO.Compression;DeflateStream;Read;(System.Span<System.Byte>);generated",
|
||||
"System.IO.Compression;DeflateStream;ReadAsync;(System.Memory<System.Byte>,System.Threading.CancellationToken);generated",
|
||||
"System.IO.Compression;DeflateStream;ReadByte;();generated",
|
||||
"System.IO.Compression;DeflateStream;Seek;(System.Int64,System.IO.SeekOrigin);generated",
|
||||
"System.IO.Compression;DeflateStream;SetLength;(System.Int64);generated",
|
||||
"System.IO.Compression;DeflateStream;Write;(System.ReadOnlySpan<System.Byte>);generated",
|
||||
"System.IO.Compression;DeflateStream;WriteAsync;(System.ReadOnlyMemory<System.Byte>,System.Threading.CancellationToken);generated",
|
||||
"System.IO.Compression;DeflateStream;WriteByte;(System.Byte);generated",
|
||||
"System.IO.Compression;DeflateStream;get_CanRead;();generated",
|
||||
"System.IO.Compression;DeflateStream;get_CanSeek;();generated",
|
||||
@@ -15806,12 +15753,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO.Compression;GZipStream;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionLevel);generated",
|
||||
"System.IO.Compression;GZipStream;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionMode);generated",
|
||||
"System.IO.Compression;GZipStream;Read;(System.Span<System.Byte>);generated",
|
||||
"System.IO.Compression;GZipStream;ReadAsync;(System.Memory<System.Byte>,System.Threading.CancellationToken);generated",
|
||||
"System.IO.Compression;GZipStream;ReadByte;();generated",
|
||||
"System.IO.Compression;GZipStream;Seek;(System.Int64,System.IO.SeekOrigin);generated",
|
||||
"System.IO.Compression;GZipStream;SetLength;(System.Int64);generated",
|
||||
"System.IO.Compression;GZipStream;Write;(System.ReadOnlySpan<System.Byte>);generated",
|
||||
"System.IO.Compression;GZipStream;WriteAsync;(System.ReadOnlyMemory<System.Byte>,System.Threading.CancellationToken);generated",
|
||||
"System.IO.Compression;GZipStream;WriteByte;(System.Byte);generated",
|
||||
"System.IO.Compression;GZipStream;get_CanRead;();generated",
|
||||
"System.IO.Compression;GZipStream;get_CanSeek;();generated",
|
||||
@@ -16383,7 +16328,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO;BinaryWriter;BinaryWriter;(System.IO.Stream,System.Text.Encoding);generated",
|
||||
"System.IO;BinaryWriter;Close;();generated", "System.IO;BinaryWriter;Dispose;();generated",
|
||||
"System.IO;BinaryWriter;Dispose;(System.Boolean);generated",
|
||||
"System.IO;BinaryWriter;DisposeAsync;();generated",
|
||||
"System.IO;BinaryWriter;Flush;();generated",
|
||||
"System.IO;BinaryWriter;Seek;(System.Int32,System.IO.SeekOrigin);generated",
|
||||
"System.IO;BinaryWriter;Write7BitEncodedInt64;(System.Int64);generated",
|
||||
@@ -16774,18 +16718,14 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO;Stream;DisposeAsync;();generated",
|
||||
"System.IO;Stream;EndRead;(System.IAsyncResult);generated",
|
||||
"System.IO;Stream;EndWrite;(System.IAsyncResult);generated",
|
||||
"System.IO;Stream;Flush;();generated", "System.IO;Stream;FlushAsync;();generated",
|
||||
"System.IO;Stream;FlushAsync;(System.Threading.CancellationToken);generated",
|
||||
"System.IO;Stream;ObjectInvariant;();generated",
|
||||
"System.IO;Stream;Flush;();generated", "System.IO;Stream;ObjectInvariant;();generated",
|
||||
"System.IO;Stream;Read;(System.Span<System.Byte>);generated",
|
||||
"System.IO;Stream;ReadAsync;(System.Memory<System.Byte>,System.Threading.CancellationToken);generated",
|
||||
"System.IO;Stream;ReadByte;();generated",
|
||||
"System.IO;Stream;Seek;(System.Int64,System.IO.SeekOrigin);generated",
|
||||
"System.IO;Stream;SetLength;(System.Int64);generated",
|
||||
"System.IO;Stream;ValidateBufferArguments;(System.Byte[],System.Int32,System.Int32);generated",
|
||||
"System.IO;Stream;ValidateCopyToArguments;(System.IO.Stream,System.Int32);generated",
|
||||
"System.IO;Stream;Write;(System.ReadOnlySpan<System.Byte>);generated",
|
||||
"System.IO;Stream;WriteAsync;(System.ReadOnlyMemory<System.Byte>,System.Threading.CancellationToken);generated",
|
||||
"System.IO;Stream;WriteByte;(System.Byte);generated",
|
||||
"System.IO;Stream;get_CanRead;();generated", "System.IO;Stream;get_CanSeek;();generated",
|
||||
"System.IO;Stream;get_CanTimeout;();generated",
|
||||
@@ -16805,7 +16745,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO;StreamWriter;Dispose;(System.Boolean);generated",
|
||||
"System.IO;StreamWriter;DisposeAsync;();generated",
|
||||
"System.IO;StreamWriter;Flush;();generated",
|
||||
"System.IO;StreamWriter;FlushAsync;();generated",
|
||||
"System.IO;StreamWriter;StreamWriter;(System.IO.Stream);generated",
|
||||
"System.IO;StreamWriter;StreamWriter;(System.IO.Stream,System.Text.Encoding);generated",
|
||||
"System.IO;StreamWriter;StreamWriter;(System.IO.Stream,System.Text.Encoding,System.Int32);generated",
|
||||
@@ -16824,15 +16763,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO;StreamWriter;Write;(System.String,System.Object,System.Object);generated",
|
||||
"System.IO;StreamWriter;Write;(System.String,System.Object,System.Object,System.Object);generated",
|
||||
"System.IO;StreamWriter;Write;(System.String,System.Object[]);generated",
|
||||
"System.IO;StreamWriter;WriteAsync;(System.Char);generated",
|
||||
"System.IO;StreamWriter;WriteAsync;(System.Char[],System.Int32,System.Int32);generated",
|
||||
"System.IO;StreamWriter;WriteAsync;(System.String);generated",
|
||||
"System.IO;StreamWriter;WriteLine;(System.ReadOnlySpan<System.Char>);generated",
|
||||
"System.IO;StreamWriter;WriteLine;(System.String);generated",
|
||||
"System.IO;StreamWriter;WriteLineAsync;();generated",
|
||||
"System.IO;StreamWriter;WriteLineAsync;(System.Char);generated",
|
||||
"System.IO;StreamWriter;WriteLineAsync;(System.Char[],System.Int32,System.Int32);generated",
|
||||
"System.IO;StreamWriter;WriteLineAsync;(System.String);generated",
|
||||
"System.IO;StreamWriter;get_AutoFlush;();generated",
|
||||
"System.IO;StreamWriter;set_AutoFlush;(System.Boolean);generated",
|
||||
"System.IO;StringReader;Close;();generated",
|
||||
@@ -16845,10 +16777,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO;StringWriter;StringWriter;(System.Text.StringBuilder);generated",
|
||||
"System.IO;StringWriter;Write;(System.Char);generated",
|
||||
"System.IO;StringWriter;Write;(System.ReadOnlySpan<System.Char>);generated",
|
||||
"System.IO;StringWriter;Write;(System.Text.StringBuilder);generated",
|
||||
"System.IO;StringWriter;WriteAsync;(System.Char);generated",
|
||||
"System.IO;StringWriter;WriteLine;(System.ReadOnlySpan<System.Char>);generated",
|
||||
"System.IO;StringWriter;WriteLine;(System.Text.StringBuilder);generated",
|
||||
"System.IO;StringWriter;WriteLineAsync;(System.Char);generated",
|
||||
"System.IO;StringWriter;get_Encoding;();generated",
|
||||
"System.IO;TextReader;Close;();generated", "System.IO;TextReader;Dispose;();generated",
|
||||
@@ -16857,7 +16787,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO;TextWriter;Close;();generated", "System.IO;TextWriter;Dispose;();generated",
|
||||
"System.IO;TextWriter;Dispose;(System.Boolean);generated",
|
||||
"System.IO;TextWriter;DisposeAsync;();generated", "System.IO;TextWriter;Flush;();generated",
|
||||
"System.IO;TextWriter;FlushAsync;();generated",
|
||||
"System.IO;TextWriter;TextWriter;();generated",
|
||||
"System.IO;TextWriter;Write;(System.Boolean);generated",
|
||||
"System.IO;TextWriter;Write;(System.Char);generated",
|
||||
@@ -16872,9 +16801,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO;TextWriter;Write;(System.Text.StringBuilder);generated",
|
||||
"System.IO;TextWriter;Write;(System.UInt32);generated",
|
||||
"System.IO;TextWriter;Write;(System.UInt64);generated",
|
||||
"System.IO;TextWriter;WriteAsync;(System.Char);generated",
|
||||
"System.IO;TextWriter;WriteAsync;(System.Char[],System.Int32,System.Int32);generated",
|
||||
"System.IO;TextWriter;WriteAsync;(System.String);generated",
|
||||
"System.IO;TextWriter;WriteLine;();generated",
|
||||
"System.IO;TextWriter;WriteLine;(System.Boolean);generated",
|
||||
"System.IO;TextWriter;WriteLine;(System.Char);generated",
|
||||
@@ -16884,13 +16810,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.IO;TextWriter;WriteLine;(System.Int64);generated",
|
||||
"System.IO;TextWriter;WriteLine;(System.ReadOnlySpan<System.Char>);generated",
|
||||
"System.IO;TextWriter;WriteLine;(System.Single);generated",
|
||||
"System.IO;TextWriter;WriteLine;(System.Text.StringBuilder);generated",
|
||||
"System.IO;TextWriter;WriteLine;(System.UInt32);generated",
|
||||
"System.IO;TextWriter;WriteLine;(System.UInt64);generated",
|
||||
"System.IO;TextWriter;WriteLineAsync;();generated",
|
||||
"System.IO;TextWriter;WriteLineAsync;(System.Char);generated",
|
||||
"System.IO;TextWriter;WriteLineAsync;(System.Char[],System.Int32,System.Int32);generated",
|
||||
"System.IO;TextWriter;WriteLineAsync;(System.String);generated",
|
||||
"System.IO;TextWriter;get_Encoding;();generated",
|
||||
"System.IO;UnmanagedMemoryAccessor;Dispose;();generated",
|
||||
"System.IO;UnmanagedMemoryAccessor;Dispose;(System.Boolean);generated",
|
||||
@@ -18094,7 +18015,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Http.Headers;HttpHeadersNonValidated+Enumerator;Reset;();generated",
|
||||
"System.Net.Http.Headers;HttpHeadersNonValidated;Contains;(System.String);generated",
|
||||
"System.Net.Http.Headers;HttpHeadersNonValidated;ContainsKey;(System.String);generated",
|
||||
"System.Net.Http.Headers;HttpHeadersNonValidated;GetEnumerator;();generated",
|
||||
"System.Net.Http.Headers;HttpHeadersNonValidated;get_Count;();generated",
|
||||
"System.Net.Http.Headers;HttpRequestHeaders;get_Accept;();generated",
|
||||
"System.Net.Http.Headers;HttpRequestHeaders;get_AcceptCharset;();generated",
|
||||
@@ -18283,7 +18203,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Http.Json;JsonContent;TryComputeLength;(System.Int64);generated",
|
||||
"System.Net.Http.Json;JsonContent;get_ObjectType;();generated",
|
||||
"System.Net.Http.Json;JsonContent;get_Value;();generated",
|
||||
"System.Net.Http;ByteArrayContent;CreateContentReadStreamAsync;();generated",
|
||||
"System.Net.Http;ByteArrayContent;TryComputeLength;(System.Int64);generated",
|
||||
"System.Net.Http;DelegatingHandler;DelegatingHandler;();generated",
|
||||
"System.Net.Http;DelegatingHandler;Dispose;(System.Boolean);generated",
|
||||
@@ -18383,7 +18302,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Http;HttpClientHandler;set_UseDefaultCredentials;(System.Boolean);generated",
|
||||
"System.Net.Http;HttpClientHandler;set_UseProxy;(System.Boolean);generated",
|
||||
"System.Net.Http;HttpContent;CreateContentReadStreamAsync;();generated",
|
||||
"System.Net.Http;HttpContent;CreateContentReadStreamAsync;(System.Threading.CancellationToken);generated",
|
||||
"System.Net.Http;HttpContent;Dispose;();generated",
|
||||
"System.Net.Http;HttpContent;Dispose;(System.Boolean);generated",
|
||||
"System.Net.Http;HttpContent;HttpContent;();generated",
|
||||
@@ -18472,7 +18390,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Http;MultipartContent;get_HeaderEncodingSelector;();generated",
|
||||
"System.Net.Http;MultipartFormDataContent;MultipartFormDataContent;();generated",
|
||||
"System.Net.Http;MultipartFormDataContent;MultipartFormDataContent;(System.String);generated",
|
||||
"System.Net.Http;ReadOnlyMemoryContent;CreateContentReadStreamAsync;();generated",
|
||||
"System.Net.Http;ReadOnlyMemoryContent;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);generated",
|
||||
"System.Net.Http;ReadOnlyMemoryContent;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);generated",
|
||||
"System.Net.Http;ReadOnlyMemoryContent;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);generated",
|
||||
@@ -19103,7 +19020,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Quic;QuicStreamAbortedException;QuicStreamAbortedException;(System.String,System.Int64);generated",
|
||||
"System.Net.Quic;QuicStreamAbortedException;get_ErrorCode;();generated",
|
||||
"System.Net.Security;AuthenticatedStream;Dispose;(System.Boolean);generated",
|
||||
"System.Net.Security;AuthenticatedStream;DisposeAsync;();generated",
|
||||
"System.Net.Security;AuthenticatedStream;get_IsAuthenticated;();generated",
|
||||
"System.Net.Security;AuthenticatedStream;get_IsEncrypted;();generated",
|
||||
"System.Net.Security;AuthenticatedStream;get_IsMutuallyAuthenticated;();generated",
|
||||
@@ -19328,7 +19244,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Sockets;SendPacketsElement;set_MemoryBuffer;(System.Nullable<System.ReadOnlyMemory<System.Byte>>);generated",
|
||||
"System.Net.Sockets;SendPacketsElement;set_OffsetLong;(System.Int64);generated",
|
||||
"System.Net.Sockets;Socket;AcceptAsync;();generated",
|
||||
"System.Net.Sockets;Socket;AcceptAsync;(System.Net.Sockets.Socket);generated",
|
||||
"System.Net.Sockets;Socket;CancelConnectAsync;(System.Net.Sockets.SocketAsyncEventArgs);generated",
|
||||
"System.Net.Sockets;Socket;Close;();generated",
|
||||
"System.Net.Sockets;Socket;Close;(System.Int32);generated",
|
||||
@@ -19343,7 +19258,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Sockets;Socket;DuplicateAndClose;(System.Int32);generated",
|
||||
"System.Net.Sockets;Socket;EndAccept;(System.Byte[],System.IAsyncResult);generated",
|
||||
"System.Net.Sockets;Socket;EndAccept;(System.Byte[],System.Int32,System.IAsyncResult);generated",
|
||||
"System.Net.Sockets;Socket;EndAccept;(System.IAsyncResult);generated",
|
||||
"System.Net.Sockets;Socket;EndConnect;(System.IAsyncResult);generated",
|
||||
"System.Net.Sockets;Socket;EndDisconnect;(System.IAsyncResult);generated",
|
||||
"System.Net.Sockets;Socket;EndReceive;(System.IAsyncResult);generated",
|
||||
@@ -19378,10 +19292,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Sockets;Socket;ReceiveAsync;(System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags);generated",
|
||||
"System.Net.Sockets;Socket;ReceiveAsync;(System.Collections.Generic.IList<System.ArraySegment<System.Byte>>);generated",
|
||||
"System.Net.Sockets;Socket;ReceiveAsync;(System.Collections.Generic.IList<System.ArraySegment<System.Byte>>,System.Net.Sockets.SocketFlags);generated",
|
||||
"System.Net.Sockets;Socket;ReceiveFromAsync;(System.ArraySegment<System.Byte>,System.Net.EndPoint);generated",
|
||||
"System.Net.Sockets;Socket;ReceiveFromAsync;(System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated",
|
||||
"System.Net.Sockets;Socket;ReceiveMessageFromAsync;(System.ArraySegment<System.Byte>,System.Net.EndPoint);generated",
|
||||
"System.Net.Sockets;Socket;ReceiveMessageFromAsync;(System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated",
|
||||
"System.Net.Sockets;Socket;Select;(System.Collections.IList,System.Collections.IList,System.Collections.IList,System.Int32);generated",
|
||||
"System.Net.Sockets;Socket;Send;(System.Byte[]);generated",
|
||||
"System.Net.Sockets;Socket;Send;(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags);generated",
|
||||
@@ -19481,14 +19391,11 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Sockets;SocketInformation;set_Options;(System.Net.Sockets.SocketInformationOptions);generated",
|
||||
"System.Net.Sockets;SocketInformation;set_ProtocolInformation;(System.Byte[]);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;AcceptAsync;(System.Net.Sockets.Socket);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;AcceptAsync;(System.Net.Sockets.Socket,System.Net.Sockets.Socket);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.Net.IPAddress[],System.Int32);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.Net.IPAddress[],System.Int32,System.Threading.CancellationToken);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.String,System.Int32);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;ReceiveAsync;(System.Net.Sockets.Socket,System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;ReceiveAsync;(System.Net.Sockets.Socket,System.Collections.Generic.IList<System.ArraySegment<System.Byte>>,System.Net.Sockets.SocketFlags);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;ReceiveFromAsync;(System.Net.Sockets.Socket,System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;ReceiveMessageFromAsync;(System.Net.Sockets.Socket,System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;SendAsync;(System.Net.Sockets.Socket,System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags);generated",
|
||||
"System.Net.Sockets;SocketTaskExtensions;SendAsync;(System.Net.Sockets.Socket,System.Collections.Generic.IList<System.ArraySegment<System.Byte>>,System.Net.Sockets.SocketFlags);generated",
|
||||
"System.Net.Sockets;TcpClient;Close;();generated",
|
||||
@@ -19530,8 +19437,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net.Sockets;TcpListener;AcceptTcpClientAsync;(System.Threading.CancellationToken);generated",
|
||||
"System.Net.Sockets;TcpListener;AllowNatTraversal;(System.Boolean);generated",
|
||||
"System.Net.Sockets;TcpListener;Create;(System.Int32);generated",
|
||||
"System.Net.Sockets;TcpListener;EndAcceptSocket;(System.IAsyncResult);generated",
|
||||
"System.Net.Sockets;TcpListener;EndAcceptTcpClient;(System.IAsyncResult);generated",
|
||||
"System.Net.Sockets;TcpListener;Pending;();generated",
|
||||
"System.Net.Sockets;TcpListener;Start;();generated",
|
||||
"System.Net.Sockets;TcpListener;Start;(System.Int32);generated",
|
||||
@@ -19748,10 +19653,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net;CredentialCache;Remove;(System.Uri,System.String);generated",
|
||||
"System.Net;CredentialCache;get_DefaultCredentials;();generated",
|
||||
"System.Net;CredentialCache;get_DefaultNetworkCredentials;();generated",
|
||||
"System.Net;Dns;EndGetHostAddresses;(System.IAsyncResult);generated",
|
||||
"System.Net;Dns;EndGetHostByName;(System.IAsyncResult);generated",
|
||||
"System.Net;Dns;EndGetHostEntry;(System.IAsyncResult);generated",
|
||||
"System.Net;Dns;EndResolve;(System.IAsyncResult);generated",
|
||||
"System.Net;Dns;GetHostAddresses;(System.String);generated",
|
||||
"System.Net;Dns;GetHostAddresses;(System.String,System.Net.Sockets.AddressFamily);generated",
|
||||
"System.Net;Dns;GetHostAddressesAsync;(System.String);generated",
|
||||
@@ -19795,8 +19696,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net;EndpointPermission;get_Port;();generated",
|
||||
"System.Net;EndpointPermission;get_Transport;();generated",
|
||||
"System.Net;FileWebRequest;Abort;();generated",
|
||||
"System.Net;FileWebRequest;EndGetRequestStream;(System.IAsyncResult);generated",
|
||||
"System.Net;FileWebRequest;EndGetResponse;(System.IAsyncResult);generated",
|
||||
"System.Net;FileWebRequest;FileWebRequest;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
|
||||
"System.Net;FileWebRequest;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
|
||||
"System.Net;FileWebRequest;GetRequestStreamAsync;();generated",
|
||||
@@ -19951,9 +19850,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net;HttpWebRequest;AddRange;(System.String,System.Int32,System.Int32);generated",
|
||||
"System.Net;HttpWebRequest;AddRange;(System.String,System.Int64);generated",
|
||||
"System.Net;HttpWebRequest;AddRange;(System.String,System.Int64,System.Int64);generated",
|
||||
"System.Net;HttpWebRequest;EndGetRequestStream;(System.IAsyncResult);generated",
|
||||
"System.Net;HttpWebRequest;EndGetRequestStream;(System.IAsyncResult,System.Net.TransportContext);generated",
|
||||
"System.Net;HttpWebRequest;EndGetResponse;(System.IAsyncResult);generated",
|
||||
"System.Net;HttpWebRequest;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
|
||||
"System.Net;HttpWebRequest;HttpWebRequest;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
|
||||
"System.Net;HttpWebRequest;get_AllowAutoRedirect;();generated",
|
||||
@@ -20102,7 +19998,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Net;NetworkCredential;get_SecurePassword;();generated",
|
||||
"System.Net;NetworkCredential;set_SecurePassword;(System.Security.SecureString);generated",
|
||||
"System.Net;PathList;GetCookiesCount;();generated",
|
||||
"System.Net;PathList;get_Count;();generated", "System.Net;PathList;get_Values;();generated",
|
||||
"System.Net;PathList;get_Count;();generated",
|
||||
"System.Net;PathList;set_Item;(System.String,System.Object);generated",
|
||||
"System.Net;ProtocolViolationException;ProtocolViolationException;();generated",
|
||||
"System.Net;ProtocolViolationException;ProtocolViolationException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
|
||||
@@ -20488,6 +20384,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Numerics;BigInteger;Log;(System.Numerics.BigInteger,System.Double);generated",
|
||||
"System.Numerics;BigInteger;ModPow;(System.Numerics.BigInteger,System.Numerics.BigInteger,System.Numerics.BigInteger);generated",
|
||||
"System.Numerics;BigInteger;Multiply;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated",
|
||||
"System.Numerics;BigInteger;Negate;(System.Numerics.BigInteger);generated",
|
||||
"System.Numerics;BigInteger;Parse;(System.ReadOnlySpan<System.Char>,System.Globalization.NumberStyles,System.IFormatProvider);generated",
|
||||
"System.Numerics;BigInteger;Parse;(System.String);generated",
|
||||
"System.Numerics;BigInteger;Parse;(System.String,System.Globalization.NumberStyles);generated",
|
||||
@@ -20553,6 +20450,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Numerics;BigInteger;op_Multiply;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated",
|
||||
"System.Numerics;BigInteger;op_OnesComplement;(System.Numerics.BigInteger);generated",
|
||||
"System.Numerics;BigInteger;op_Subtraction;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated",
|
||||
"System.Numerics;BigInteger;op_UnaryNegation;(System.Numerics.BigInteger);generated",
|
||||
"System.Numerics;BitOperations;IsPow2;(System.Int32);generated",
|
||||
"System.Numerics;BitOperations;IsPow2;(System.Int64);generated",
|
||||
"System.Numerics;BitOperations;IsPow2;(System.IntPtr);generated",
|
||||
@@ -23476,7 +23374,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Resources;ResourceSet;Dispose;(System.Boolean);generated",
|
||||
"System.Resources;ResourceSet;GetDefaultReader;();generated",
|
||||
"System.Resources;ResourceSet;GetDefaultWriter;();generated",
|
||||
"System.Resources;ResourceSet;GetEnumerator;();generated",
|
||||
"System.Resources;ResourceSet;GetObject;(System.String);generated",
|
||||
"System.Resources;ResourceSet;GetObject;(System.String,System.Boolean);generated",
|
||||
"System.Resources;ResourceSet;GetString;(System.String);generated",
|
||||
@@ -23691,6 +23588,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Runtime.CompilerServices;DisablePrivateReflectionAttribute;DisablePrivateReflectionAttribute;();generated",
|
||||
"System.Runtime.CompilerServices;DiscardableAttribute;DiscardableAttribute;();generated",
|
||||
"System.Runtime.CompilerServices;DynamicAttribute;DynamicAttribute;();generated",
|
||||
"System.Runtime.CompilerServices;DynamicAttribute;DynamicAttribute;(System.Boolean[]);generated",
|
||||
"System.Runtime.CompilerServices;DynamicAttribute;get_TransformFlags;();generated",
|
||||
"System.Runtime.CompilerServices;EnumeratorCancellationAttribute;EnumeratorCancellationAttribute;();generated",
|
||||
"System.Runtime.CompilerServices;FixedAddressValueTypeAttribute;FixedAddressValueTypeAttribute;();generated",
|
||||
"System.Runtime.CompilerServices;FixedBufferAttribute;FixedBufferAttribute;(System.Type,System.Int32);generated",
|
||||
@@ -29676,7 +29575,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.ReadOnlySpan<System.Byte>);generated",
|
||||
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.ReadOnlySpan<System.Char>);generated",
|
||||
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.String);generated",
|
||||
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;GetBags;();generated",
|
||||
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Pkcs12SafeContents;();generated",
|
||||
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;get_ConfidentialityMode;();generated",
|
||||
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;get_IsReadOnly;();generated",
|
||||
@@ -29984,7 +29882,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Security.Cryptography.X509Certificates;X509Certificate;get_Handle;();generated",
|
||||
"System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;MoveNext;();generated",
|
||||
"System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;Reset;();generated",
|
||||
"System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;X509CertificateEnumerator;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);generated",
|
||||
"System.Security.Cryptography.X509Certificates;X509CertificateCollection;Contains;(System.Security.Cryptography.X509Certificates.X509Certificate);generated",
|
||||
"System.Security.Cryptography.X509Certificates;X509CertificateCollection;GetHashCode;();generated",
|
||||
"System.Security.Cryptography.X509Certificates;X509CertificateCollection;IndexOf;(System.Security.Cryptography.X509Certificates.X509Certificate);generated",
|
||||
@@ -30154,7 +30051,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Security.Cryptography.Xml;EncryptionPropertyCollection;get_IsReadOnly;();generated",
|
||||
"System.Security.Cryptography.Xml;EncryptionPropertyCollection;get_IsSynchronized;();generated",
|
||||
"System.Security.Cryptography.Xml;IRelDecryptor;Decrypt;(System.Security.Cryptography.Xml.EncryptionMethod,System.Security.Cryptography.Xml.KeyInfo,System.IO.Stream);generated",
|
||||
"System.Security.Cryptography.Xml;KeyInfo;GetEnumerator;(System.Type);generated",
|
||||
"System.Security.Cryptography.Xml;KeyInfo;GetXml;();generated",
|
||||
"System.Security.Cryptography.Xml;KeyInfo;KeyInfo;();generated",
|
||||
"System.Security.Cryptography.Xml;KeyInfo;get_Count;();generated",
|
||||
@@ -30221,7 +30117,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Security.Cryptography.Xml;Transform;Transform;();generated",
|
||||
"System.Security.Cryptography.Xml;Transform;get_InputTypes;();generated",
|
||||
"System.Security.Cryptography.Xml;Transform;get_OutputTypes;();generated",
|
||||
"System.Security.Cryptography.Xml;TransformChain;GetEnumerator;();generated",
|
||||
"System.Security.Cryptography.Xml;TransformChain;TransformChain;();generated",
|
||||
"System.Security.Cryptography.Xml;TransformChain;get_Count;();generated",
|
||||
"System.Security.Cryptography.Xml;X509IssuerSerial;get_IssuerName;();generated",
|
||||
@@ -34394,7 +34289,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Text.Json.Serialization;ReferenceResolver;GetReference;(System.Object,System.Boolean);generated",
|
||||
"System.Text.Json.Serialization;ReferenceResolver;ResolveReference;(System.String);generated",
|
||||
"System.Text.Json.SourceGeneration;JsonSourceGenerator;Execute;(Microsoft.CodeAnalysis.GeneratorExecutionContext);generated",
|
||||
"System.Text.Json.SourceGeneration;JsonSourceGenerator;GetSerializableTypes;();generated",
|
||||
"System.Text.Json.SourceGeneration;JsonSourceGenerator;Initialize;(Microsoft.CodeAnalysis.GeneratorInitializationContext);generated",
|
||||
"System.Text.Json.SourceGeneration;JsonSourceGenerator;Initialize;(Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext);generated",
|
||||
"System.Text.Json;JsonDocument;Dispose;();generated",
|
||||
@@ -35424,7 +35318,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Threading.RateLimiting;MetadataName<>;op_Inequality;(System.Threading.RateLimiting.MetadataName<>,System.Threading.RateLimiting.MetadataName<>);generated",
|
||||
"System.Threading.RateLimiting;RateLimitLease;Dispose;();generated",
|
||||
"System.Threading.RateLimiting;RateLimitLease;Dispose;(System.Boolean);generated",
|
||||
"System.Threading.RateLimiting;RateLimitLease;GetAllMetadata;();generated",
|
||||
"System.Threading.RateLimiting;RateLimitLease;TryGetMetadata;(System.String,System.Object);generated",
|
||||
"System.Threading.RateLimiting;RateLimitLease;get_IsAcquired;();generated",
|
||||
"System.Threading.RateLimiting;RateLimitLease;get_MetadataNames;();generated",
|
||||
@@ -35507,10 +35400,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlock;OutputAvailableAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>);generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlock;OutputAvailableAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>,System.Threading.CancellationToken);generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAllAsync<>;(System.Threading.Tasks.Dataflow.IReceivableSourceBlock<TOutput>,System.Threading.CancellationToken);generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>);generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>,System.Threading.CancellationToken);generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>,System.TimeSpan);generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>,System.TimeSpan,System.Threading.CancellationToken);generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlock;SendAsync<>;(System.Threading.Tasks.Dataflow.ITargetBlock<TInput>,TInput);generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlockOptions;DataflowBlockOptions;();generated",
|
||||
"System.Threading.Tasks.Dataflow;DataflowBlockOptions;get_BoundedCapacity;();generated",
|
||||
@@ -36723,13 +36612,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Xml.Schema;XmlSchemaParticle;set_MinOccursString;(System.String);generated",
|
||||
"System.Xml.Schema;XmlSchemaPatternFacet;XmlSchemaPatternFacet;();generated",
|
||||
"System.Xml.Schema;XmlSchemaRedefine;XmlSchemaRedefine;();generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;Add;(System.Xml.Schema.XmlSchemaSet);generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;Compile;();generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;Contains;(System.String);generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;Contains;(System.Xml.Schema.XmlSchema);generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;CopyTo;(System.Xml.Schema.XmlSchema[],System.Int32);generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;RemoveRecursive;(System.Xml.Schema.XmlSchema);generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;Schemas;();generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;Schemas;(System.String);generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;XmlSchemaSet;();generated",
|
||||
"System.Xml.Schema;XmlSchemaSet;get_Count;();generated",
|
||||
@@ -36982,7 +36868,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteEmptyTag;(System.String,System.String);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteEndElement;();generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteEndElement;(System.Object);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteId;(System.Object);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteNamespaceDeclarations;(System.Xml.Serialization.XmlSerializerNamespaces);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteNullTagEncoded;(System.String);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteNullTagEncoded;(System.String,System.String);generated",
|
||||
@@ -36991,8 +36876,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteNullableQualifiedNameEncoded;(System.String,System.String,System.Xml.XmlQualifiedName,System.Xml.XmlQualifiedName);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteNullableQualifiedNameLiteral;(System.String,System.String,System.Xml.XmlQualifiedName);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteReferencedElements;();generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteReferencingElement;(System.String,System.String,System.Object);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteReferencingElement;(System.String,System.String,System.Object,System.Boolean);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteStartDocument;();generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteStartElement;(System.String);generated",
|
||||
"System.Xml.Serialization;XmlSerializationWriter;WriteStartElement;(System.String,System.String);generated",
|
||||
@@ -41163,29 +41046,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
|
||||
"System;Tuple<>;Equals;(System.Object,System.Collections.IEqualityComparer);generated",
|
||||
"System;Tuple<>;GetHashCode;();generated",
|
||||
"System;Tuple<>;GetHashCode;(System.Collections.IEqualityComparer);generated",
|
||||
"System;Tuple<>;get_Length;();generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17,T18,T19,T20,T21>>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17,T18,T19,T20>>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17,T18,T19>>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17,T18>>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17>>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16>>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15>>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8>>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,,>;(System.ValueTuple<T1,T2,T3,T4>);generated",
|
||||
"System;TupleExtensions;ToTuple<,,>;(System.ValueTuple<T1,T2,T3>);generated",
|
||||
"System;TupleExtensions;ToTuple<,>;(System.ValueTuple<T1,T2>);generated",
|
||||
"System;TupleExtensions;ToTuple<>;(System.ValueTuple<T1>);generated",
|
||||
"System;Type;Equals;(System.Object);generated",
|
||||
"System;Tuple<>;get_Length;();generated", "System;Type;Equals;(System.Object);generated",
|
||||
"System;Type;Equals;(System.Type);generated", "System;Type;GetArrayRank;();generated",
|
||||
"System;Type;GetAttributeFlagsImpl;();generated",
|
||||
"System;Type;GetConstructorImpl;(System.Reflection.BindingFlags,System.Reflection.Binder,System.Reflection.CallingConventions,System.Type[],System.Reflection.ParameterModifier[]);generated",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ private class MicrosoftVisualBasicCollectionFlowModelCsv extends SummaryModelCsv
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"Microsoft.VisualBasic;Collection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"Microsoft.VisualBasic;Collection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual",
|
||||
"Microsoft.VisualBasic;Collection;false;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual",
|
||||
"Microsoft.VisualBasic;Collection;false;get_Item;(System.Object);;Argument[this].Element;ReturnValue;value;manual",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** The `System.CodeDome` namespace. */
|
||||
class SystemCodeDomNamespace extends Namespace {
|
||||
@@ -10,3 +11,11 @@ class SystemCodeDomNamespace extends Namespace {
|
||||
this.hasName("CodeDom")
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.CodeDom.CodeNamespaceImportCollection`. */
|
||||
private class SystemCodeDomCodeNamespaceImportCollectionFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.CodeDom;CodeNamespaceImportCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,20 +46,6 @@ private class SystemCollectionIEnumerableFlowModelCsv extends SummaryModelCsv {
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear content for Clear methods in all subtypes of `System.Collections.IEnumerable`. */
|
||||
private class SystemCollectionsIEnumerableClearFlow extends SummarizedCallable {
|
||||
SystemCollectionsIEnumerableClearFlow() {
|
||||
this.getDeclaringType().(RefType).getABaseType*() instanceof
|
||||
SystemCollectionsIEnumerableInterface and
|
||||
this.hasName("Clear")
|
||||
}
|
||||
|
||||
override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) {
|
||||
(if this.(Modifiable).isStatic() then pos.getPosition() = 0 else pos.isThisParameter()) and
|
||||
content instanceof DataFlow::ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
/** The `System.Collections.IEnumerator` interface. */
|
||||
class SystemCollectionsIEnumeratorInterface extends SystemCollectionsInterface {
|
||||
SystemCollectionsIEnumeratorInterface() { this.hasName("IEnumerator") }
|
||||
@@ -96,6 +82,7 @@ private class SystemCollectionsIListFlowModelCsv extends SummaryModelCsv {
|
||||
row =
|
||||
[
|
||||
"System.Collections;IList;true;Add;(System.Object);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Collections;IList;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections;IList;true;Insert;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual",
|
||||
"System.Collections;IList;true;get_Item;(System.Int32);;Argument[this].Element;ReturnValue;value;manual",
|
||||
"System.Collections;IList;true;set_Item;(System.Int32,System.Object);;Argument[1];Argument[this].Element;value;manual",
|
||||
@@ -115,6 +102,7 @@ private class SystemCollectionsIDictionaryFlowModelCsv extends SummaryModelCsv {
|
||||
[
|
||||
"System.Collections;IDictionary;true;Add;(System.Object,System.Object);;Argument[0];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual",
|
||||
"System.Collections;IDictionary;true;Add;(System.Object,System.Object);;Argument[1];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual",
|
||||
"System.Collections;IDictionary;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections;IDictionary;true;get_Item;(System.Object);;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue;value;manual",
|
||||
"System.Collections;IDictionary;true;get_Keys;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];ReturnValue.Element;value;manual",
|
||||
"System.Collections;IDictionary;true;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual",
|
||||
@@ -194,6 +182,7 @@ private class SystemCollectionsQueueFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"System.Collections;Queue;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections;Queue;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual",
|
||||
"System.Collections;Queue;false;Peek;();;Argument[this].Element;ReturnValue;value;manual",
|
||||
]
|
||||
@@ -205,6 +194,7 @@ private class SystemCollectionsStackFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"System.Collections;Stack;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections;Stack;false;Clone;();;Argument[0].Element;ReturnValue.Element;value;manual",
|
||||
"System.Collections;Stack;false;Peek;();;Argument[this].Element;ReturnValue;value;manual",
|
||||
"System.Collections;Stack;false;Pop;();;Argument[this].Element;ReturnValue;value;manual",
|
||||
|
||||
@@ -12,6 +12,7 @@ private class SystemComponentModelPropertyDescriptorCollectionFlowModelCsv exten
|
||||
"System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.ComponentModel.PropertyDescriptor);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual",
|
||||
"System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Key];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];value;manual",
|
||||
"System.ComponentModel;PropertyDescriptorCollection;false;Add;(System.Object);;Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual",
|
||||
"System.ComponentModel;PropertyDescriptorCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.ComponentModel;PropertyDescriptorCollection;false;Find;(System.String,System.Boolean);;Argument[this].Element;ReturnValue;value;manual",
|
||||
"System.ComponentModel;PropertyDescriptorCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual",
|
||||
"System.ComponentModel;PropertyDescriptorCollection;false;Insert;(System.Int32,System.ComponentModel.PropertyDescriptor);;Argument[1];Argument[this].Element;value;manual",
|
||||
@@ -37,6 +38,7 @@ private class SystemComponentModelEventDescriptorCollectionFlowModelCsv extends
|
||||
row =
|
||||
[
|
||||
"System.ComponentModel;EventDescriptorCollection;false;Add;(System.ComponentModel.EventDescriptor);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.ComponentModel;EventDescriptorCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.ComponentModel;EventDescriptorCollection;false;Find;(System.String,System.Boolean);;Argument[this].Element;ReturnValue;value;manual",
|
||||
"System.ComponentModel;EventDescriptorCollection;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.IEnumerator.Current];value;manual",
|
||||
"System.ComponentModel;EventDescriptorCollection;false;Insert;(System.Int32,System.ComponentModel.EventDescriptor);;Argument[1];Argument[this].Element;value;manual",
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/** Provides definitions related to the namespace `System.Configuration`. */
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** Data flow for some collection classes in `System.Configuration.*`. */
|
||||
private class SystemClearFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"System.Configuration;CommaDelimitedStringCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;ConfigurationLockCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;ConfigurationPropertyCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;ConfigurationSectionCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;ConfigurationSectionGroupCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;ConnectionStringSettingsCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;KeyValueConfigurationCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;NameValueConfigurationCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;ProviderSettingsCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;SettingElementCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;SettingsPropertyCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration;SettingsPropertyValueCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Configuration.Provider;ProviderCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -150,6 +150,7 @@ private class SystemDataConstraintCollectionFlowModelCsv extends SummaryModelCsv
|
||||
[
|
||||
"System.Data;ConstraintCollection;false;Add;(System.Data.Constraint);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Data;ConstraintCollection;false;AddRange;(System.Data.Constraint[]);;Argument[0].Element;Argument[this].Element;value;manual",
|
||||
"System.Data;ConstraintCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Data;ConstraintCollection;false;CopyTo;(System.Data.Constraint[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
]
|
||||
}
|
||||
@@ -163,6 +164,7 @@ private class SystemDataDataColumnCollectionFlowModelCsv extends SummaryModelCsv
|
||||
"System.Data;DataColumnCollection;false;Add;(System.Data.DataColumn);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Data;DataColumnCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Data;DataColumnCollection;false;AddRange;(System.Data.DataColumn[]);;Argument[0].Element;Argument[this].Element;value;manual",
|
||||
"System.Data;DataColumnCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Data;DataColumnCollection;false;CopyTo;(System.Data.DataColumn[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
]
|
||||
}
|
||||
@@ -174,6 +176,7 @@ private class SystemDataDataRelationCollectionFlowModelCsv extends SummaryModelC
|
||||
row =
|
||||
[
|
||||
"System.Data;DataRelationCollection;false;Add;(System.Data.DataRelation);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Data;DataRelationCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Data;DataRelationCollection;false;CopyTo;(System.Data.DataRelation[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
"System.Data;DataRelationCollection;true;AddRange;(System.Data.DataRelation[]);;Argument[0].Element;Argument[this].Element;value;manual",
|
||||
]
|
||||
@@ -187,6 +190,7 @@ private class SystemDataDataRawCollectionFlowModelCsv extends SummaryModelCsv {
|
||||
[
|
||||
"System.Data;DataRowCollection;false;Add;(System.Data.DataRow);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Data;DataRowCollection;false;Add;(System.Object[]);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Data;DataRowCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Data;DataRowCollection;false;CopyTo;(System.Data.DataRow[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
"System.Data;DataRowCollection;false;Find;(System.Object);;Argument[this].Element;ReturnValue;value;manual",
|
||||
"System.Data;DataRowCollection;false;Find;(System.Object[]);;Argument[this].Element;ReturnValue;value;manual",
|
||||
@@ -202,6 +206,7 @@ private class SystemDataDataTableCollectionFlowModelCsv extends SummaryModelCsv
|
||||
"System.Data;DataTableCollection;false;Add;(System.Data.DataTable);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Data;DataTableCollection;false;Add;(System.String);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Data;DataTableCollection;false;AddRange;(System.Data.DataTable[]);;Argument[0].Element;Argument[this].Element;value;manual",
|
||||
"System.Data;DataTableCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Data;DataTableCollection;false;CopyTo;(System.Data.DataTable[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Provides classes related to the namespace `System.Security`. */
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
|
||||
/** The `System.Security` namespace. */
|
||||
@@ -15,3 +16,15 @@ class SystemSecurityNamespace extends Namespace {
|
||||
class SystemSecurityClass extends Class {
|
||||
SystemSecurityClass() { this.getNamespace() instanceof SystemSecurityNamespace }
|
||||
}
|
||||
|
||||
/** Data flow for some collection like classes in `System.Security.*`. */
|
||||
private class SystemSecurityPolicyApplicationTrustCollectionFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"System.Security.Permissions;KeyContainerPermissionAccessEntryCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Security.Policy;ApplicationTrustCollection;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Security.Policy;Evidence;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,18 +26,6 @@ class SystemTextStringBuilderClass extends SystemTextClass {
|
||||
Method getAppendFormatMethod() { result = this.getAMethod("AppendFormat") }
|
||||
}
|
||||
|
||||
/** Clear content for `System.Text.StringBuilder.Clear`. */
|
||||
private class SystemTextStringBuilderClearFlow extends SummarizedCallable {
|
||||
SystemTextStringBuilderClearFlow() {
|
||||
this = any(SystemTextStringBuilderClass s).getAMethod("Clear")
|
||||
}
|
||||
|
||||
override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) {
|
||||
pos.isThisParameter() and
|
||||
content instanceof DataFlow::ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Text.StringBuilder`. */
|
||||
private class SystemTextStringBuilderFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
@@ -120,6 +108,7 @@ private class SystemTextStringBuilderFlowModelCsv extends SummaryModelCsv {
|
||||
"System.Text;StringBuilder;false;AppendLine;();;Argument[this];ReturnValue;value;manual",
|
||||
"System.Text;StringBuilder;false;AppendLine;(System.String);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Text;StringBuilder;false;AppendLine;(System.String);;Argument[this];ReturnValue;value;manual",
|
||||
"System.Text;StringBuilder;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Text;StringBuilder;false;StringBuilder;(System.String);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Text;StringBuilder;false;StringBuilder;(System.String,System.Int32);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Text;StringBuilder;false;StringBuilder;(System.String,System.Int32,System.Int32,System.Int32);;Argument[0];Argument[this].Element;value;manual",
|
||||
|
||||
@@ -44,6 +44,25 @@ private class SystemCollectionsConcurrentIProducerConsumerCollectionFlowModelCsv
|
||||
private class SystemCollectionsConcurrentConcurrentBagFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Collections.Concurrent;ConcurrentBag<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual"
|
||||
[
|
||||
"System.Collections.Concurrent;ConcurrentBag<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Collections.Concurrent;ConcurrentBag<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Collections.Concurrent.ConcurrentQueue<>`. */
|
||||
private class SystemCollectionsConcurrentConcurrentQueueFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Collections.Concurrent;ConcurrentQueue<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual"
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Collections.Concurrent.ConcurrentStack<>`. */
|
||||
private class SystemCollectionsConcurrentConcurrentStackFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Collections.Concurrent;ConcurrentStack<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ private class SystemCollectionsGenericICollectionFlowModelCsv extends SummaryMod
|
||||
row =
|
||||
[
|
||||
"System.Collections.Generic;ICollection<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Collections.Generic;ICollection<>;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections.Generic;ICollection<>;true;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
]
|
||||
}
|
||||
@@ -289,6 +290,8 @@ private class SystemCollectionsGenericSortedListFlowModelCsv extends SummaryMode
|
||||
"System.Collections.Generic;SortedList<,>;false;SortedList;(System.Collections.Generic.IDictionary<TKey,TValue>,System.Collections.Generic.IComparer<TKey>);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];value;manual",
|
||||
"System.Collections.Generic;SortedList<,>;false;get_Keys;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key];ReturnValue.Element;value;manual",
|
||||
"System.Collections.Generic;SortedList<,>;false;get_Values;();;Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Value];ReturnValue.Element;value;manual",
|
||||
"System.Collections.Generic;SortedList<,>+KeyList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections.Generic;SortedList<,>+ValueList;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -298,6 +301,7 @@ private class SystemCollectionsGenericQueueFlowModelCsv extends SummaryModelCsv
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"System.Collections.Generic;Queue<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections.Generic;Queue<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
"System.Collections.Generic;Queue<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.Queue<>+Enumerator.Current];value;manual",
|
||||
"System.Collections.Generic;Queue<>;false;Peek;();;Argument[this].Element;ReturnValue;value;manual",
|
||||
@@ -310,6 +314,7 @@ private class SystemCollectionsGenericStackFlowModelCsv extends SummaryModelCsv
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"System.Collections.Generic;Stack<>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections.Generic;Stack<>;false;CopyTo;(T[],System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
"System.Collections.Generic;Stack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Generic.Stack<>+Enumerator.Current];value;manual",
|
||||
"System.Collections.Generic;Stack<>;false;Peek;();;Argument[this].Element;ReturnValue;value;manual",
|
||||
|
||||
@@ -6,7 +6,10 @@ private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private class SystemCollectionsImmutableIImmutableDictionaryFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Collections.Immutable;IImmutableDictionary<,>;true;AddRange;(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);;Argument[0].Element;Argument[this].Element;value;manual"
|
||||
[
|
||||
"System.Collections.Immutable;IImmutableDictionary<,>;true;AddRange;(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);;Argument[0].Element;Argument[this].Element;value;manual",
|
||||
"System.Collections.Immutable;IImmutableDictionary<,>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +68,7 @@ private class SystemCollectionsImmutableIImmutableListFlowModelCsv extends Summa
|
||||
[
|
||||
"System.Collections.Immutable;IImmutableList<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Collections.Immutable;IImmutableList<>;true;AddRange;(System.Collections.Generic.IEnumerable<T>);;Argument[0].Element;Argument[this].Element;value;manual",
|
||||
"System.Collections.Immutable;IImmutableList<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -124,7 +128,10 @@ private class SystemCollectionsImmutableImmutableSortedSetFlowModelCsv extends S
|
||||
private class SystemCollectionsImmutableIImmutableSetFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Collections.Immutable;IImmutableSet<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual"
|
||||
[
|
||||
"System.Collections.Immutable;IImmutableSet<>;true;Add;(T);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Collections.Immutable;IImmutableSet<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +160,7 @@ private class SystemCollectionsImmutableImmutableHashSetFlowModelCsv extends Sum
|
||||
[
|
||||
"System.Collections.Immutable;ImmutableHashSet<>+Builder;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableHashSet<>+Enumerator.Current];value;manual",
|
||||
"System.Collections.Immutable;ImmutableHashSet<>;false;Add;(T);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Collections.Immutable;ImmutableHashSet<>;false;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual",
|
||||
"System.Collections.Immutable;ImmutableHashSet<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableHashSet<>+Enumerator.Current];value;manual",
|
||||
]
|
||||
}
|
||||
@@ -162,7 +170,10 @@ private class SystemCollectionsImmutableImmutableHashSetFlowModelCsv extends Sum
|
||||
private class SystemCollectionsImmutableImmutableQueueFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Collections.Immutable;ImmutableQueue<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableQueue<>+Enumerator.Current];value;manual"
|
||||
[
|
||||
"System.Collections.Immutable;IImmutableQueue<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual",
|
||||
"System.Collections.Immutable;ImmutableQueue<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableQueue<>+Enumerator.Current];value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +181,9 @@ private class SystemCollectionsImmutableImmutableQueueFlowModelCsv extends Summa
|
||||
private class SystemCollectionsImmutableImmutableStackFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Collections.Immutable;ImmutableStack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableStack<>+Enumerator.Current];value;manual"
|
||||
[
|
||||
"System.Collections.Immutable;IImmutableStack<>;true;Clear;();;Argument[this].WithoutElement;ReturnValue;value;manual",
|
||||
"System.Collections.Immutable;ImmutableStack<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.Property[System.Collections.Immutable.ImmutableStack<>+Enumerator.Current];value;manual",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ private class SystemCollectionsSpecializedNameValueCollectionFlowModelCsv extend
|
||||
row =
|
||||
[
|
||||
"System.Collections.Specialized;NameValueCollection;false;Add;(System.Collections.Specialized.NameValueCollection);;Argument[0];Argument[this].Element;value;manual",
|
||||
"System.Collections.Specialized;NameValueCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual",
|
||||
"System.Collections.Specialized;NameValueCollection;false;CopyTo;(System.Array,System.Int32);;Argument[this].Element;Argument[0].Element;value;manual",
|
||||
]
|
||||
}
|
||||
@@ -70,3 +71,11 @@ private class SystemCollectionsSpecializedStringCollectionFlowModelCsv extends S
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Collections.Specialized.StringDictionary`. */
|
||||
private class SystemCollectionsSpecializedStringDictionaryFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Collections.Specialized;StringDictionary;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,3 +95,11 @@ private class SystemDataCommonDbParameterCollectionFlowModelCsv extends External
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Data.Common.DbBatchCommandCollection`. */
|
||||
private class SystemDataCommonDbBatchCommandCollectionFlowModelCsv extends ExternalFlow::SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Data.Common;DbBatchCommandCollection;true;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,3 +28,11 @@ private class SystemNetHttpMultipartFormDataContentFlowModelCsv extends SummaryM
|
||||
"System.Net.Http;MultipartFormDataContent;false;Add;(System.Net.Http.HttpContent);;Argument[0];Argument[this].Element;value;manual"
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Net.Http.Headers.HttpHeaders`. */
|
||||
private class SystemNetHttpHeadersHttpHeadersFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Net.Http.Headers;HttpHeaders;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,3 +103,11 @@ private class SystemRuntimeCompilerServicesReadOnlyCollectionBuilderFlowModelCsv
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Runtime.CompilerServices.ConditionalWeakTable<,>`. */
|
||||
private class SystemRuntimeCompilerServicesConditionalWeakTableFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
"System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;Clear;();;Argument[this].WithoutElement;Argument[this];value;manual"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import csharp
|
||||
private import Email::Email
|
||||
private import ExternalLocationSink
|
||||
private import Html
|
||||
private import semmle.code.csharp.security.dataflow.XSSSinks as XSSSinks
|
||||
private import semmle.code.csharp.security.dataflow.XSSSinks as XssSinks
|
||||
private import semmle.code.csharp.frameworks.system.web.UI
|
||||
|
||||
/** A data flow sink of remote user output. */
|
||||
|
||||
@@ -36,10 +36,9 @@ compilations(
|
||||
* --- | ---
|
||||
* 0 | --compiler
|
||||
* 1 | *path to compiler*
|
||||
* 2 | --cil
|
||||
* 3 | f1.cs
|
||||
* 4 | f2.cs
|
||||
* 5 | f3.cs
|
||||
* 2 | f1.cs
|
||||
* 3 | f2.cs
|
||||
* 4 | f3.cs
|
||||
*/
|
||||
#keyset[id, num]
|
||||
compilation_args(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Remove '--cil' flag from the comments. This does not make any changes to the dbscheme.
|
||||
compatibility: full
|
||||
@@ -14,4 +14,4 @@ import csharp
|
||||
|
||||
from CommentLine c
|
||||
where c.getText().regexpMatch("(?s).*FIXME.*|.*TODO.*|.*(?<!=)\\s*XXX.*")
|
||||
select c, "TODO comment."
|
||||
select c, "TODO comments should be addressed."
|
||||
|
||||
@@ -72,5 +72,5 @@ where
|
||||
) and
|
||||
m1.fromSource()
|
||||
select m1,
|
||||
"confusing to have methods " + m1.getName() + " in " + m1.getDeclaringType().getName() + " and " +
|
||||
m2.getName() + " in " + m2.getDeclaringType().getName() + "."
|
||||
"It is confusing to have methods " + m1.getName() + " in " + m1.getDeclaringType().getName() +
|
||||
" and " + m2.getName() + " in " + m2.getDeclaringType().getName() + "."
|
||||
|
||||
@@ -64,6 +64,5 @@ where
|
||||
validGuard.controls(array, index) and
|
||||
validGuard.guards(indexAccess, _)
|
||||
)
|
||||
select incorrectGuard,
|
||||
"Off-by-one index comparison against length leads to possible out of bounds $@.", ea,
|
||||
ea.toString()
|
||||
select incorrectGuard, "Off-by-one index comparison against length may lead to out-of-bounds $@.",
|
||||
ea, ea.toString()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* @name Equality check on floating point values
|
||||
* @description Equality checks on floating point values can yield unexpected results.
|
||||
* @description Comparing results of floating-point computations with '==' or
|
||||
* '!=' is likely to yield surprising results since floating-point
|
||||
* computation does not follow the standard rules of algebra.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
|
||||
@@ -42,4 +42,4 @@ where
|
||||
(loopStmtWithEmptyBlock(s) or conditionalWithEmptyBlock(s)) and
|
||||
not exists(CommentBlock c | c.getParent() = s) and
|
||||
not exists(ForStmt fs | fs.getBody() = s and exists(fs.getAnUpdate()))
|
||||
select s, "Empty block."
|
||||
select s, "Empty block without comment."
|
||||
|
||||
@@ -35,4 +35,4 @@ where
|
||||
access = cast.getAChild() and
|
||||
access.getTarget().getDeclaringElement() = access.getEnclosingCallable() and
|
||||
nodeBeforeParameterAccess(access.getAControlFlowNode())
|
||||
select cast, "Missing type-check before casting parameter to 'Equals'."
|
||||
select cast, "Equals() method does not check argument type."
|
||||
|
||||
@@ -23,5 +23,5 @@ where
|
||||
c.hasFlowPath(source, sink) and
|
||||
// No global timeout set
|
||||
not exists(RegexGlobalTimeout r)
|
||||
select sink.getNode(), source, sink, "$@ flows to the construction of a regular expression.",
|
||||
source.getNode(), "User-provided value"
|
||||
select sink.getNode(), source, sink, "This regular expression is constructed from a $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -24,7 +24,7 @@ predicate incorrectUseOfRC2(Assignment e, string msg) {
|
||||
msg = "Key size should be at least 128 bits for RC2 encryption."
|
||||
}
|
||||
|
||||
predicate incorrectUseOfDSA(ObjectCreation e, string msg) {
|
||||
predicate incorrectUseOfDsa(ObjectCreation e, string msg) {
|
||||
e.getTarget()
|
||||
.getDeclaringType()
|
||||
.hasQualifiedName("System.Security.Cryptography", "DSACryptoServiceProvider") and
|
||||
@@ -32,7 +32,7 @@ predicate incorrectUseOfDSA(ObjectCreation e, string msg) {
|
||||
msg = "Key size should be at least 2048 bits for DSA encryption."
|
||||
}
|
||||
|
||||
predicate incorrectUseOfRSA(ObjectCreation e, string msg) {
|
||||
predicate incorrectUseOfRsa(ObjectCreation e, string msg) {
|
||||
e.getTarget()
|
||||
.getDeclaringType()
|
||||
.hasQualifiedName("System.Security.Cryptography", "RSACryptoServiceProvider") and
|
||||
@@ -43,6 +43,6 @@ predicate incorrectUseOfRSA(ObjectCreation e, string msg) {
|
||||
from Expr e, string msg
|
||||
where
|
||||
incorrectUseOfRC2(e, msg) or
|
||||
incorrectUseOfDSA(e, msg) or
|
||||
incorrectUseOfRSA(e, msg)
|
||||
incorrectUseOfDsa(e, msg) or
|
||||
incorrectUseOfRsa(e, msg)
|
||||
select e, msg
|
||||
|
||||
@@ -77,7 +77,7 @@ run_cmd(['dotnet', 'new', 'globaljson', '--force', '--sdk-version', sdk_version,
|
||||
|
||||
print("\n* Creating DB")
|
||||
run_cmd(['codeql', 'database', 'create', dbDir, '--language=csharp',
|
||||
'--command', 'dotnet build /t:rebuild /p:UseSharedCompilation=false ' + projectDirIn])
|
||||
'--command', 'dotnet build /t:rebuild ' + projectDirIn])
|
||||
|
||||
if not os.path.isdir(dbDir):
|
||||
print("Expected database directory " + dbDir + " not found.")
|
||||
|
||||
@@ -18,4 +18,4 @@ from MethodCall mc
|
||||
where
|
||||
mc instanceof ImplicitToStringExpr and
|
||||
mc.getTarget() instanceof ToStringMethod
|
||||
select mc, "Redundant call to 'ToString'."
|
||||
select mc, "Redundant call to 'ToString' on a String object."
|
||||
|
||||
4
csharp/ql/src/change-notes/2022-08-23-alert-messages.md
Normal file
4
csharp/ql/src/change-notes/2022-08-23-alert-messages.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The alert message of many queries have been changed to make the message consistent with other languages.
|
||||
4
csharp/ql/src/change-notes/2022-08-24-remove-cil-flag.md
Normal file
4
csharp/ql/src/change-notes/2022-08-24-remove-cil-flag.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* A new extractor option has been introduced for disabling CIL extraction. Either pass `-Ocil=false` to the `codeql` CLI or set the environment variable `CODEQL_EXTRACTOR_CSHARP_OPTION_CIL=false`.
|
||||
@@ -0,0 +1,259 @@
|
||||
import csharp
|
||||
import DataFlow
|
||||
|
||||
/**
|
||||
* A sensitive property for `TokenValidationParameters` that updates the underlying value.
|
||||
*/
|
||||
class TokenValidationParametersPropertySensitiveValidation extends Property {
|
||||
TokenValidationParametersPropertySensitiveValidation() {
|
||||
exists(Class c |
|
||||
c.hasQualifiedName("Microsoft.IdentityModel.Tokens.TokenValidationParameters")
|
||||
|
|
||||
c.getAProperty() = this and
|
||||
this.getName() in [
|
||||
"ValidateIssuer", "ValidateAudience", "ValidateLifetime", "RequireExpirationTime",
|
||||
"RequireAudience"
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow from a `false` value to a write sensitive property for `TokenValidationParameters`.
|
||||
*/
|
||||
class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation extends DataFlow::Configuration {
|
||||
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation() {
|
||||
this = "FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().getValue() = "false" and
|
||||
source.asExpr().getType() instanceof BoolType
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(TokenValidationParametersPropertySensitiveValidation p).getAnAssignedValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `assemblyName` is older than version `ver`
|
||||
*/
|
||||
bindingset[ver]
|
||||
predicate isAssemblyOlderVersion(string assemblyName, string ver) {
|
||||
exists(Assembly a |
|
||||
a.getName() = assemblyName and
|
||||
a.getVersion().isEarlierThan(ver)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A method `ValidateToken` for `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler` or other Token handler that shares the same behavior characteristics
|
||||
*/
|
||||
class JsonWebTokenHandlerValidateTokenMethod extends Method {
|
||||
JsonWebTokenHandlerValidateTokenMethod() {
|
||||
this.hasQualifiedName("Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken") or
|
||||
this.hasQualifiedName("Microsoft.AzureAD.DeviceIdentification.Common.Tokens.JwtValidator.ValidateEncryptedToken")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken`
|
||||
*/
|
||||
class JsonWebTokenHandlerValidateTokenCall extends MethodCall {
|
||||
JsonWebTokenHandlerValidateTokenCall() {
|
||||
this.getTarget() instanceof JsonWebTokenHandlerValidateTokenMethod
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A read access for properties `IsValid` or `Exception` for `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken`
|
||||
*/
|
||||
private class TokenValidationResultIsValidCall extends PropertyRead {
|
||||
TokenValidationResultIsValidCall() {
|
||||
exists(Property p | p.getAnAccess() = this |
|
||||
p.hasName("IsValid") or
|
||||
p.hasName("Exception")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dataflow from the output of `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken` call to access the `IsValid` or `Exception` property
|
||||
*/
|
||||
private class FlowsToTokenValidationResultIsValidCall extends DataFlow::Configuration {
|
||||
FlowsToTokenValidationResultIsValidCall() { this = "FlowsToTokenValidationResultIsValidCall" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof JsonWebTokenHandlerValidateTokenCall
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(TokenValidationResultIsValidCall call | sink.asExpr() = call.getQualifier())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A security-sensitive property for `Microsoft.IdentityModel.Tokens.TokenValidationParameters`
|
||||
*/
|
||||
class TokenValidationParametersProperty extends Property {
|
||||
TokenValidationParametersProperty() {
|
||||
exists(Class c |
|
||||
c.hasQualifiedName("Microsoft.IdentityModel.Tokens.TokenValidationParameters")
|
||||
|
|
||||
c.getAProperty() = this and
|
||||
this.getName() in [
|
||||
"SignatureValidator", "TokenReplayValidator", "AlgorithmValidator", "AudienceValidator",
|
||||
"IssuerSigningKeyValidator", "LifetimeValidator"
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the callable has a return statement and it always returns true for all such statements
|
||||
*/
|
||||
predicate callableHasAReturnStmtAndAlwaysReturnsTrue(Callable c) {
|
||||
c.getReturnType() instanceof BoolType and
|
||||
not callableMayThrowException(c) and
|
||||
forall(ReturnStmt rs | rs.getEnclosingCallable() = c |
|
||||
rs.getNumberOfChildren() = 1 and
|
||||
isExpressionAlwaysTrue(rs.getChildExpr(0))
|
||||
) and
|
||||
exists(ReturnStmt rs | rs.getEnclosingCallable() = c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the lambda expression `le` always returns true
|
||||
*/
|
||||
predicate lambdaExprReturnsOnlyLiteralTrue(AnonymousFunctionExpr le) {
|
||||
le.getExpressionBody().(BoolLiteral).getBoolValue() = true
|
||||
or
|
||||
// special scenarios where the expression is not a `BoolLiteral`, but it will evaluatue to `true`
|
||||
exists(Expr e | le.getExpressionBody() = e |
|
||||
not e instanceof Call and
|
||||
not e instanceof Literal and
|
||||
e.getType() instanceof BoolType and
|
||||
e.getValue() = "true"
|
||||
)
|
||||
}
|
||||
|
||||
class CallableAlwaysReturnsTrue extends Callable {
|
||||
CallableAlwaysReturnsTrue() {
|
||||
callableHasAReturnStmtAndAlwaysReturnsTrue(this)
|
||||
or
|
||||
lambdaExprReturnsOnlyLiteralTrue(this)
|
||||
or
|
||||
exists(AnonymousFunctionExpr le, Call call, Callable callable | this = le |
|
||||
callable.getACall() = call and
|
||||
call = le.getExpressionBody() and
|
||||
callableHasAReturnStmtAndAlwaysReturnsTrue(callable)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any exception being thrown by the callable is of type `System.ArgumentNullException`
|
||||
* It will also hold if no exceptions are thrown by the callable
|
||||
*/
|
||||
predicate callableOnlyThrowsArgumentNullException(Callable c) {
|
||||
forall(ThrowElement thre | c = thre.getEnclosingCallable() |
|
||||
thre.getThrownExceptionType().hasQualifiedName("System.ArgumentNullException")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A specialization of `CallableAlwaysReturnsTrue` that takes into consideration exceptions being thrown for higher precision.
|
||||
*/
|
||||
class CallableAlwaysReturnsTrueHigherPrecision extends CallableAlwaysReturnsTrue {
|
||||
CallableAlwaysReturnsTrueHigherPrecision() {
|
||||
callableOnlyThrowsArgumentNullException(this) and
|
||||
(
|
||||
forall(Call call, Callable callable | call.getEnclosingCallable() = this |
|
||||
callable.getACall() = call and
|
||||
callable instanceof CallableAlwaysReturnsTrueHigherPrecision
|
||||
)
|
||||
or
|
||||
exists(AnonymousFunctionExpr le, Call call, CallableAlwaysReturnsTrueHigherPrecision cat |
|
||||
this = le
|
||||
|
|
||||
le.canReturn(call) and
|
||||
cat.getACall() = call
|
||||
)
|
||||
or
|
||||
exists(LambdaExpr le | le = this |
|
||||
le.getBody() instanceof CallableAlwaysReturnsTrueHigherPrecision
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable that returns a `string` and has a `string` as 1st argument
|
||||
*/
|
||||
private class CallableReturnsStringAndArg0IsString extends Callable {
|
||||
CallableReturnsStringAndArg0IsString() {
|
||||
this.getReturnType() instanceof StringType and
|
||||
this.getParameter(0).getType() instanceof StringType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Callable that always return the 1st argument, both of `string` type
|
||||
*/
|
||||
class CallableAlwaysReturnsParameter0 extends CallableReturnsStringAndArg0IsString {
|
||||
CallableAlwaysReturnsParameter0() {
|
||||
forex(Expr ret | this.canReturn(ret) |
|
||||
ret = this.getParameter(0).getAnAccess()
|
||||
or
|
||||
exists(CallableAlwaysReturnsParameter0 c |
|
||||
ret = c.getACall() and
|
||||
ret.(Call).getArgument(0) = this.getParameter(0).getAnAccess()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Callable that always return the 1st argument, both of `string` type. Higher precision
|
||||
*/
|
||||
class CallableAlwaysReturnsParameter0MayThrowExceptions extends CallableReturnsStringAndArg0IsString {
|
||||
CallableAlwaysReturnsParameter0MayThrowExceptions() {
|
||||
forex(Expr ret | this.canReturn(ret) |
|
||||
ret = this.getParameter(0).getAnAccess()
|
||||
or
|
||||
exists(CallableAlwaysReturnsParameter0MayThrowExceptions c |
|
||||
ret = c.getACall() and
|
||||
ret.(Call).getArgument(0) = this.getParameter(0).getAnAccess()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hold if the `Expr` e is a `BoolLiteral` with value true,
|
||||
* the expression has a predictable value == `true`,
|
||||
* or if it is a `ConditionalExpr` where the `then` and `else` expressions meet `isExpressionAlwaysTrue` criteria
|
||||
*/
|
||||
predicate isExpressionAlwaysTrue(Expr e) {
|
||||
e.(BoolLiteral).getBoolValue() = true
|
||||
or
|
||||
e.getValue() = "true"
|
||||
or
|
||||
e instanceof ConditionalExpr and
|
||||
isExpressionAlwaysTrue(e.(ConditionalExpr).getThen()) and
|
||||
isExpressionAlwaysTrue(e.(ConditionalExpr).getElse())
|
||||
or
|
||||
exists(Callable callable |
|
||||
callableHasAReturnStmtAndAlwaysReturnsTrue(callable) and
|
||||
callable.getACall() = e
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `Callable` c throws any exception other than `ThrowsArgumentNullException`
|
||||
*/
|
||||
predicate callableMayThrowException(Callable c) {
|
||||
exists(ThrowStmt thre | c = thre.getEnclosingCallable()) and
|
||||
not callableOnlyThrowsArgumentNullException(c)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
class TestClass
|
||||
{
|
||||
public void TestMethod()
|
||||
{
|
||||
TokenValidationParameters parameters = new TokenValidationParameters();
|
||||
parameters.AudienceValidator = (audiences, token, tvp) => { return true; };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
class TestClass
|
||||
{
|
||||
public void TestMethod()
|
||||
{
|
||||
TokenValidationParameters parameters = new TokenValidationParameters();
|
||||
parameters.AudienceValidator = (audiences, token, tvp) =>
|
||||
{
|
||||
// Implement your own custom audience validation
|
||||
if (PerformCustomAudienceValidation(audiences, token))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>By setting critical <code>TokenValidationParameter</code> validation delegates to always return <code>true</code>, important authentication safeguards are disabled. Disabling safeguards can lead to incorrect validation of tokens from any issuer or expired tokens.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Improve the logic of the delegate so not all code paths return <code>true</code>, which effectively disables that type of validation; or throw <code>SecurityTokenInvalidAudienceException</code> or <code>SecurityTokenInvalidLifetimeException</code> in failure cases when you want to fail validation and have other cases pass by returning <code>true</code>.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>This example delegates <code>AudienceValidator</code> to a callable that always returns true.</p>
|
||||
<sample src="delegated-security-validations-always-return-true-bad.cs" />
|
||||
|
||||
<p>To fix it, use a callable that performs a validation, and fails when appropriate.</p>
|
||||
<sample src="delegated-security-validations-always-return-true-good.cs" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
<li><a href="https://aka.ms/wilson/tokenvalidation">azure-activedirectory-identitymodel-extensions-for-dotnet ValidatingTokens wiki</a></li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @name Delegated security sensitive validations for JsonWebTokenHandler always return true, medium precision
|
||||
* @description Security sensitive validations for `JsonWebTokenHandler` are being delegated to a function that seems to always return true.
|
||||
* Higher precision version checks for exception throws, so less false positives are expected.
|
||||
* @kind problem
|
||||
* @tags security
|
||||
* JsonWebTokenHandler
|
||||
* manual-verification-required
|
||||
* @id cs/json-webtoken-handler/delegated-security-validations-always-return-true
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataFlow
|
||||
import JsonWebTokenHandlerLib
|
||||
|
||||
from TokenValidationParametersProperty p, CallableAlwaysReturnsTrueHigherPrecision e
|
||||
where e = p.getAnAssignedValue()
|
||||
select e, "JsonWebTokenHandler security-sensitive property $@ is being delegated to $@.", p,
|
||||
p.getQualifiedName().toString(), e, "a callable that always returns \"true\""
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
class TestClass
|
||||
{
|
||||
public void TestMethod()
|
||||
{
|
||||
TokenValidationParameters parameters = new TokenValidationParameters();
|
||||
parameters.RequireExpirationTime = false;
|
||||
parameters.ValidateAudience = false;
|
||||
parameters.ValidateIssuer = false;
|
||||
parameters.ValidateLifetime = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
class TestClass
|
||||
{
|
||||
public void TestMethod()
|
||||
{
|
||||
TokenValidationParameters parameters = new TokenValidationParameters();
|
||||
parameters.RequireExpirationTime = true;
|
||||
parameters.ValidateAudience = true;
|
||||
parameters.ValidateIssuer = true;
|
||||
parameters.ValidateLifetime = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Token validation checks ensure that while validating tokens, all aspects are analyzed and verified. Turning off validation can lead to security holes by allowing untrusted tokens to make it through validation.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Set <code>Microsoft.IdentityModel.Tokens.TokenValidationParameters</code> properties <code>RequireExpirationTime</code>, <code>ValidateAudience</code>, <code>ValidateIssuer</code>, or <code>ValidateLifetime</code> to <code>true</code>. Or, remove the assignment to <code>false</code> because the default value is <code>true</code>.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>This example disabled the validation.</p>
|
||||
<sample src="security-validation-disabled-bad.cs" />
|
||||
|
||||
<p>To fix it, do not disable the validations or use the default value.</p>
|
||||
<sample src="security-validation-disabled-good.cs" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
<li><a href="https://aka.ms/wilson/tokenvalidation">azure-activedirectory-identitymodel-extensions-for-dotnet ValidatingTokens wiki</a></li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @name Security sensitive JsonWebTokenHandler validations are disabled
|
||||
* @description Check if secruity sensitive token validations for `JsonWebTokenHandler` are being disabled.
|
||||
* @kind problem
|
||||
* @tags security
|
||||
* JsonWebTokenHandler
|
||||
* manual-verification-required
|
||||
* @id cs/json-webtoken-handler/security-validations-disabled
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import JsonWebTokenHandlerLib
|
||||
|
||||
from
|
||||
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation config,
|
||||
DataFlow::Node source, DataFlow::Node sink,
|
||||
TokenValidationParametersPropertySensitiveValidation pw
|
||||
where
|
||||
config.hasFlow(source, sink) and
|
||||
sink.asExpr() = pw.getAnAssignedValue()
|
||||
select sink, "The security sensitive property $@ is being disabled by the following value: $@.", pw,
|
||||
pw.getQualifiedName().toString(), source, "false"
|
||||
@@ -6,7 +6,7 @@
|
||||
private import IRFunctionBase
|
||||
private import TInstruction
|
||||
|
||||
module SSA {
|
||||
module Ssa {
|
||||
class MemoryLocation = boolean;
|
||||
|
||||
predicate hasPhiInstruction(TRawInstruction blockStartInstr, MemoryLocation memoryLocation) {
|
||||
@@ -17,3 +17,6 @@ module SSA {
|
||||
|
||||
predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Ssa */
|
||||
deprecated module SSA = Ssa;
|
||||
|
||||
@@ -20,24 +20,24 @@ newtype TInstruction =
|
||||
IRConstruction::Raw::hasInstruction(tag1, tag2)
|
||||
} or
|
||||
TUnaliasedSsaPhiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation
|
||||
TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation
|
||||
) {
|
||||
UnaliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
UnaliasedSsa::Ssa::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TUnaliasedSsaChiInstruction(TRawInstruction primaryInstruction) { none() } or
|
||||
TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
||||
UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TAliasedSsaPhiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
|
||||
TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation
|
||||
) {
|
||||
AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
AliasedSsa::Ssa::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
|
||||
AliasedSsa::SSA::hasChiInstruction(primaryInstruction)
|
||||
AliasedSsa::Ssa::hasChiInstruction(primaryInstruction)
|
||||
} or
|
||||
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
AliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
||||
AliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,7 +50,7 @@ module UnaliasedSsaInstructions {
|
||||
class TPhiInstruction = TUnaliasedSsaPhiInstruction;
|
||||
|
||||
TPhiInstruction phiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation
|
||||
TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation
|
||||
) {
|
||||
result = TUnaliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ module AliasedSsaInstructions {
|
||||
class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction;
|
||||
|
||||
TPhiInstruction phiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
|
||||
TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation
|
||||
) {
|
||||
result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ newtype TInstructionTag =
|
||||
PointerAddTag(int index) { index in [0 .. 255] } or
|
||||
ElementsAddressTag(int index) { index in [0 .. 255] } or
|
||||
ConvertTag() or
|
||||
GeneratedNEQTag() or
|
||||
GeneratedNeqTag() or
|
||||
GeneratedConstantTag() or
|
||||
GeneratedBranchTag()
|
||||
|
||||
@@ -181,7 +181,7 @@ string getInstructionTagId(TInstructionTag tag) {
|
||||
or
|
||||
tag = ConvertTag() and result = "Convert"
|
||||
or
|
||||
tag = GeneratedNEQTag() and result = "GeneratedNEQTag"
|
||||
tag = GeneratedNeqTag() and result = "GeneratedNEQTag"
|
||||
or
|
||||
tag = GeneratedConstantTag() and result = "GeneratedConstantTag"
|
||||
or
|
||||
|
||||
@@ -1710,7 +1710,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
or
|
||||
(
|
||||
tag = GeneratedNEQTag() and
|
||||
tag = GeneratedNeqTag() and
|
||||
kind instanceof GotoEdge and
|
||||
if this.hasVar()
|
||||
then result = this.getInstruction(GeneratedBranchTag())
|
||||
@@ -1733,7 +1733,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
|
||||
kind instanceof GotoEdge and
|
||||
if this.hasVar()
|
||||
then result = this.getPatternVarDecl().getFirstInstruction()
|
||||
else result = this.getInstruction(GeneratedNEQTag())
|
||||
else result = this.getInstruction(GeneratedNeqTag())
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
@@ -1742,7 +1742,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
|
||||
or
|
||||
this.hasVar() and
|
||||
child = this.getPatternVarDecl() and
|
||||
result = this.getInstruction(GeneratedNEQTag())
|
||||
result = this.getInstruction(GeneratedNeqTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) {
|
||||
@@ -1755,7 +1755,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
|
||||
opcode instanceof Opcode::CheckedConvertOrNull and
|
||||
resultType = getTypeForPRValue(expr.getPattern().getType())
|
||||
or
|
||||
tag = GeneratedNEQTag() and
|
||||
tag = GeneratedNeqTag() and
|
||||
opcode instanceof Opcode::CompareNE and
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
or
|
||||
@@ -1775,7 +1775,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
|
||||
result = "0"
|
||||
}
|
||||
|
||||
override Instruction getResult() { result = this.getInstruction(GeneratedNEQTag()) }
|
||||
override Instruction getResult() { result = this.getInstruction(GeneratedNeqTag()) }
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = ConvertTag() and
|
||||
@@ -1792,7 +1792,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
|
||||
result = this.getPatternVarDecl().getTargetAddress()
|
||||
)
|
||||
or
|
||||
tag = GeneratedNEQTag() and
|
||||
tag = GeneratedNeqTag() and
|
||||
(
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = this.getInstruction(ConvertTag())
|
||||
@@ -1804,7 +1804,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
|
||||
this.hasVar() and
|
||||
tag = GeneratedBranchTag() and
|
||||
operandTag instanceof ConditionOperandTag and
|
||||
result = this.getInstruction(GeneratedNEQTag())
|
||||
result = this.getInstruction(GeneratedNeqTag())
|
||||
}
|
||||
|
||||
private TranslatedExpr getIsExpr() { result = getTranslatedExpr(expr.getExpr()) }
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
private import SSAConstruction as SSA
|
||||
import SSA::SsaConsistency
|
||||
private import SSAConstruction as Ssa
|
||||
import Ssa::SsaConsistency
|
||||
|
||||
@@ -1135,7 +1135,7 @@ deprecated module SSAConsistency = SsaConsistency;
|
||||
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
|
||||
* that all of SSA construction will be evaluated in the same stage.
|
||||
*/
|
||||
module SSA {
|
||||
module Ssa {
|
||||
class MemoryLocation = Alias::MemoryLocation;
|
||||
|
||||
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2;
|
||||
@@ -1144,3 +1144,6 @@ module SSA {
|
||||
|
||||
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Ssa */
|
||||
deprecated module SSA = Ssa;
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* @id csharp/utils/model-generator/discarded-summary-models
|
||||
*/
|
||||
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import internal.CaptureModels
|
||||
private import internal.CaptureSummaryFlow
|
||||
import semmle.code.csharp.dataflow.ExternalFlow
|
||||
import internal.CaptureModels
|
||||
import internal.CaptureSummaryFlow
|
||||
|
||||
from TargetApi api, string flow
|
||||
from DataFlowTargetApi api, string flow
|
||||
where flow = captureFlow(api) and hasSummary(api, false)
|
||||
select flow order by flow
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user