mirror of
https://github.com/github/codeql.git
synced 2026-03-17 04:56:58 +01:00
Merge branch 'main' into post-release-prep/codeql-cli-2.12.3
This commit is contained in:
@@ -43,12 +43,83 @@ runs:
|
||||
codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-
|
||||
codeql-compile-${{ inputs.key }}-main-
|
||||
- name: Fill compilation cache directory
|
||||
id: fill-compilation-dir
|
||||
shell: bash
|
||||
run: |
|
||||
# Move all the existing cache into another folder, so we only preserve the cache for the current queries.
|
||||
node $GITHUB_WORKSPACE/.github/actions/cache-query-compilation/move-caches.js ${COMBINED_CACHE_DIR}
|
||||
|
||||
echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir
|
||||
with:
|
||||
script: |
|
||||
// # Move all the existing cache into another folder, so we only preserve the cache for the current queries.
|
||||
// mkdir -p ${COMBINED_CACHE_DIR}
|
||||
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||
// # copy the contents of the .cache folders into the combined cache folder.
|
||||
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||
// # clean up the .cache folders
|
||||
// rm -rf **/.cache/*
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// the first argv is the cache folder to create.
|
||||
const COMBINED_CACHE_DIR = process.env.COMBINED_CACHE_DIR;
|
||||
|
||||
function* walkCaches(dir) {
|
||||
const files = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const file of files) {
|
||||
if (file.isDirectory()) {
|
||||
const filePath = path.join(dir, file.name);
|
||||
yield* walkCaches(filePath);
|
||||
if (file.name === ".cache") {
|
||||
yield filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyDir(src, dest) {
|
||||
for await (const file of await fs.promises.readdir(src, { withFileTypes: true })) {
|
||||
const srcPath = path.join(src, file.name);
|
||||
const destPath = path.join(dest, file.name);
|
||||
if (file.isDirectory()) {
|
||||
if (!fs.existsSync(destPath)) {
|
||||
fs.mkdirSync(destPath);
|
||||
}
|
||||
await copyDir(srcPath, destPath);
|
||||
} else {
|
||||
await fs.promises.copyFile(srcPath, destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const cacheDirs = [...walkCaches(".")];
|
||||
|
||||
for (const dir of cacheDirs) {
|
||||
console.log(`Found .cache dir at ${dir}`);
|
||||
}
|
||||
|
||||
// mkdir -p ${COMBINED_CACHE_DIR}
|
||||
fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true });
|
||||
|
||||
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) =>
|
||||
(async function () {
|
||||
await fs.promises.rm(path.join(cacheDir, "lock"), { force: true });
|
||||
await fs.promises.rm(path.join(cacheDir, "size"), { force: true });
|
||||
})()
|
||||
)
|
||||
);
|
||||
|
||||
// # copy the contents of the .cache folders into the combined cache folder.
|
||||
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) => copyDir(cacheDir, COMBINED_CACHE_DIR))
|
||||
);
|
||||
|
||||
// # clean up the .cache folders
|
||||
// rm -rf **/.cache/*
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) => fs.promises.rm(cacheDir, { recursive: true }))
|
||||
);
|
||||
}
|
||||
main();
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
// # Move all the existing cache into another folder, so we only preserve the cache for the current queries.
|
||||
// mkdir -p ${COMBINED_CACHE_DIR}
|
||||
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||
// # copy the contents of the .cache folders into the combined cache folder.
|
||||
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||
// # clean up the .cache folders
|
||||
// rm -rf **/.cache/*
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// the first argv is the cache folder to create.
|
||||
const COMBINED_CACHE_DIR = process.argv[2];
|
||||
|
||||
function* walkCaches(dir) {
|
||||
const files = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const file of files) {
|
||||
if (file.isDirectory()) {
|
||||
const filePath = path.join(dir, file.name);
|
||||
yield* walkCaches(filePath);
|
||||
if (file.name === ".cache") {
|
||||
yield filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyDir(src, dest) {
|
||||
for await (const file of await fs.promises.readdir(src, { withFileTypes: true })) {
|
||||
const srcPath = path.join(src, file.name);
|
||||
const destPath = path.join(dest, file.name);
|
||||
if (file.isDirectory()) {
|
||||
if (!fs.existsSync(destPath)) {
|
||||
fs.mkdirSync(destPath);
|
||||
}
|
||||
await copyDir(srcPath, destPath);
|
||||
} else {
|
||||
await fs.promises.copyFile(srcPath, destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const cacheDirs = [...walkCaches(".")];
|
||||
|
||||
for (const dir of cacheDirs) {
|
||||
console.log(`Found .cache dir at ${dir}`);
|
||||
}
|
||||
|
||||
// mkdir -p ${COMBINED_CACHE_DIR}
|
||||
fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true });
|
||||
|
||||
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) =>
|
||||
(async function () {
|
||||
await fs.promises.rm(path.join(cacheDir, "lock"), { force: true });
|
||||
await fs.promises.rm(path.join(cacheDir, "size"), { force: true });
|
||||
})()
|
||||
)
|
||||
);
|
||||
|
||||
// # copy the contents of the .cache folders into the combined cache folder.
|
||||
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) => copyDir(cacheDir, COMBINED_CACHE_DIR))
|
||||
);
|
||||
|
||||
// # clean up the .cache folders
|
||||
// rm -rf **/.cache/*
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) => fs.promises.rm(cacheDir, { recursive: true }))
|
||||
);
|
||||
}
|
||||
main();
|
||||
7
.github/workflows/ql-for-ql-build.yml
vendored
7
.github/workflows/ql-for-ql-build.yml
vendored
@@ -5,13 +5,6 @@ on:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "ql/**"
|
||||
- "**.qll"
|
||||
- "**.ql"
|
||||
- "**.dbscheme"
|
||||
- "**/qlpack.yml"
|
||||
- ".github/workflows/ql-for-ql-build.yml"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
@@ -131,6 +131,14 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
|
||||
bool IBuildActions.IsWindows() => IsWindows;
|
||||
|
||||
public bool IsMacOs { get; set; }
|
||||
|
||||
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||
|
||||
public bool IsArm { get; set; }
|
||||
|
||||
bool IBuildActions.IsArm() => IsArm;
|
||||
|
||||
string IBuildActions.PathCombine(params string[] parts)
|
||||
{
|
||||
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||||
|
||||
@@ -145,6 +145,14 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
|
||||
bool IBuildActions.IsWindows() => IsWindows;
|
||||
|
||||
public bool IsMacOs { get; set; }
|
||||
|
||||
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||
|
||||
public bool IsArm { get; set; }
|
||||
|
||||
bool IBuildActions.IsArm() => IsArm;
|
||||
|
||||
public string PathCombine(params string[] parts)
|
||||
{
|
||||
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Xml;
|
||||
using System.Net.Http;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Semmle.Autobuild.Shared
|
||||
{
|
||||
@@ -98,6 +99,18 @@ namespace Semmle.Autobuild.Shared
|
||||
/// </summary>
|
||||
bool IsWindows();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether we are running on macOS.
|
||||
/// </summary>
|
||||
/// <returns>True if we are running on macOS.</returns>
|
||||
bool IsMacOs();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether we are running on arm.
|
||||
/// </summary>
|
||||
/// <returns>True if we are running on arm.</returns>
|
||||
bool IsArm();
|
||||
|
||||
/// <summary>
|
||||
/// Combine path segments, Path.Combine().
|
||||
/// </summary>
|
||||
@@ -203,6 +216,12 @@ namespace Semmle.Autobuild.Shared
|
||||
|
||||
bool IBuildActions.IsWindows() => Win32.IsWindows();
|
||||
|
||||
bool IBuildActions.IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
|
||||
bool IBuildActions.IsArm() =>
|
||||
RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ||
|
||||
RuntimeInformation.ProcessArchitecture == Architecture.Arm;
|
||||
|
||||
string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);
|
||||
|
||||
void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents);
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
using Semmle.Util.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Semmle.Autobuild.Shared
|
||||
{
|
||||
internal static class MsBuildCommandExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Appends a call to msbuild.
|
||||
/// </summary>
|
||||
/// <param name="cmdBuilder"></param>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static CommandBuilder MsBuildCommand(this CommandBuilder cmdBuilder, IAutobuilder<AutobuildOptionsShared> builder)
|
||||
{
|
||||
var isArmMac = builder.Actions.IsMacOs() && builder.Actions.IsArm();
|
||||
|
||||
// mono doesn't ship with `msbuild` on Arm-based Macs, but we can fall back to
|
||||
// msbuild that ships with `dotnet` which can be invoked with `dotnet msbuild`
|
||||
// perhaps we should do this on all platforms?
|
||||
return isArmMac ?
|
||||
cmdBuilder.RunCommand("dotnet").Argument("msbuild") :
|
||||
cmdBuilder.RunCommand("msbuild");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A build rule using msbuild.
|
||||
/// </summary>
|
||||
public class MsBuildRule : IBuildRule<AutobuildOptionsShared>
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the msbuild command.
|
||||
/// </summary>
|
||||
private const string msBuild = "msbuild";
|
||||
|
||||
public BuildScript Analyse(IAutobuilder<AutobuildOptionsShared> builder, bool auto)
|
||||
{
|
||||
if (!builder.ProjectsOrSolutionsToBuild.Any())
|
||||
@@ -57,7 +75,7 @@ namespace Semmle.Autobuild.Shared
|
||||
Script;
|
||||
var nugetRestore = GetNugetRestoreScript();
|
||||
var msbuildRestoreCommand = new CommandBuilder(builder.Actions).
|
||||
RunCommand(msBuild).
|
||||
MsBuildCommand(builder).
|
||||
Argument("/t:restore").
|
||||
QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
@@ -95,7 +113,7 @@ namespace Semmle.Autobuild.Shared
|
||||
command.RunCommand("set Platform=&& type NUL", quoteExe: false);
|
||||
}
|
||||
|
||||
command.RunCommand(msBuild);
|
||||
command.MsBuildCommand(builder);
|
||||
command.QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
var target = builder.Options.MsBuildTarget ?? "rebuild";
|
||||
|
||||
@@ -65,6 +65,15 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.has_modifiers(target, Modifier.Create(cx, modifier));
|
||||
}
|
||||
|
||||
private static void ExtractFieldModifiers(Context cx, TextWriter trapFile, IEntity key, IFieldSymbol symbol)
|
||||
{
|
||||
if (symbol.IsReadOnly)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Readonly);
|
||||
|
||||
if (symbol.IsRequired)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Required);
|
||||
}
|
||||
|
||||
private static void ExtractNamedTypeModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol)
|
||||
{
|
||||
if (symbol.Kind != SymbolKind.NamedType)
|
||||
@@ -106,8 +115,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
if (symbol.IsVirtual)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Virtual);
|
||||
|
||||
if (symbol.Kind == SymbolKind.Field && ((IFieldSymbol)symbol).IsReadOnly)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Readonly);
|
||||
if (symbol is IFieldSymbol field)
|
||||
ExtractFieldModifiers(cx, trapFile, key, field);
|
||||
|
||||
if (symbol.Kind == SymbolKind.Property && ((IPropertySymbol)symbol).IsRequired)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Required);
|
||||
|
||||
if (symbol.IsOverride)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Override);
|
||||
|
||||
@@ -13,6 +13,7 @@ internal static class Modifiers
|
||||
public const string Public = "public";
|
||||
public const string Readonly = "readonly";
|
||||
public const string Record = "record";
|
||||
public const string Required = "required";
|
||||
public const string Ref = "ref";
|
||||
public const string Sealed = "sealed";
|
||||
public const string Static = "static";
|
||||
|
||||
13
csharp/ql/integration-tests/all-platforms/msbuild/Program.cs
Normal file
13
csharp/ql/integration-tests/all-platforms/msbuild/Program.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello world!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net4.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
from create_database_utils import *
|
||||
|
||||
# force CodeQL to use MSBuild by setting `LGTM_INDEX_MSBUILD_TARGET`
|
||||
run_codeql_database_create([], test_db="default-db", db=None, lang="csharp", extra_env={ 'LGTM_INDEX_MSBUILD_TARGET': 'Build' })
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 11: Added library support for `checked` operators.
|
||||
4
csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md
Normal file
4
csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 11: Added extractor support for `required` fields and properties.
|
||||
@@ -435,8 +435,12 @@ class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @de
|
||||
* (`BinaryOperator`), or a conversion operator (`ConversionOperator`).
|
||||
*/
|
||||
class Operator extends Callable, Member, Attributable, @operator {
|
||||
/** Gets the assembly name of this operator. */
|
||||
string getAssemblyName() { operators(this, result, _, _, _, _) }
|
||||
/**
|
||||
* DEPRECATED: use `getFunctionName()` instead.
|
||||
*
|
||||
* Gets the assembly name of this operator.
|
||||
*/
|
||||
deprecated string getAssemblyName() { result = this.getFunctionName() }
|
||||
|
||||
override string getName() { operators(this, _, result, _, _, _) }
|
||||
|
||||
@@ -445,7 +449,7 @@ class Operator extends Callable, Member, Attributable, @operator {
|
||||
/**
|
||||
* Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`.
|
||||
*/
|
||||
string getFunctionName() { none() }
|
||||
string getFunctionName() { operators(this, result, _, _, _, _) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) }
|
||||
|
||||
@@ -481,10 +485,11 @@ class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
|
||||
* A user-defined unary operator - an operator taking one operand.
|
||||
*
|
||||
* Either a plus operator (`PlusOperator`), minus operator (`MinusOperator`),
|
||||
* not operator (`NotOperator`), complement operator (`ComplementOperator`),
|
||||
* true operator (`TrueOperator`), false operator (`FalseOperator`),
|
||||
* increment operator (`IncrementOperator`), or decrement operator
|
||||
* (`DecrementOperator`).
|
||||
* checked minus operator (`CheckedMinusOperator`), not operator (`NotOperator`),
|
||||
* complement operator (`ComplementOperator`), true operator (`TrueOperator`),
|
||||
* false operator (`FalseOperator`), increment operator (`IncrementOperator`),
|
||||
* checked increment operator (`CheckedIncrementOperator`), decrement operator
|
||||
* (`DecrementOperator`) or checked decrement operator (`CheckedDecrementOperator`).
|
||||
*/
|
||||
class UnaryOperator extends Operator {
|
||||
UnaryOperator() {
|
||||
@@ -505,8 +510,6 @@ class UnaryOperator extends Operator {
|
||||
class PlusOperator extends UnaryOperator {
|
||||
PlusOperator() { this.getName() = "+" }
|
||||
|
||||
override string getFunctionName() { result = "op_UnaryPlus" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PlusOperator" }
|
||||
}
|
||||
|
||||
@@ -522,11 +525,24 @@ class PlusOperator extends UnaryOperator {
|
||||
class MinusOperator extends UnaryOperator {
|
||||
MinusOperator() { this.getName() = "-" }
|
||||
|
||||
override string getFunctionName() { result = "op_UnaryNegation" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MinusOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked minus operator (`-`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked -(Widget w) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedMinusOperator extends UnaryOperator {
|
||||
CheckedMinusOperator() { this.getName() = "checked -" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedMinusOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined not operator (`!`), for example
|
||||
*
|
||||
@@ -539,8 +555,6 @@ class MinusOperator extends UnaryOperator {
|
||||
class NotOperator extends UnaryOperator {
|
||||
NotOperator() { this.getName() = "!" }
|
||||
|
||||
override string getFunctionName() { result = "op_LogicalNot" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NotOperator" }
|
||||
}
|
||||
|
||||
@@ -556,8 +570,6 @@ class NotOperator extends UnaryOperator {
|
||||
class ComplementOperator extends UnaryOperator {
|
||||
ComplementOperator() { this.getName() = "~" }
|
||||
|
||||
override string getFunctionName() { result = "op_OnesComplement" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ComplementOperator" }
|
||||
}
|
||||
|
||||
@@ -573,11 +585,24 @@ class ComplementOperator extends UnaryOperator {
|
||||
class IncrementOperator extends UnaryOperator {
|
||||
IncrementOperator() { this.getName() = "++" }
|
||||
|
||||
override string getFunctionName() { result = "op_Increment" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "IncrementOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked increment operator (`++`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked ++(Widget w) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedIncrementOperator extends UnaryOperator {
|
||||
CheckedIncrementOperator() { this.getName() = "checked ++" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedIncrementOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined decrement operator (`--`), for example
|
||||
*
|
||||
@@ -590,11 +615,24 @@ class IncrementOperator extends UnaryOperator {
|
||||
class DecrementOperator extends UnaryOperator {
|
||||
DecrementOperator() { this.getName() = "--" }
|
||||
|
||||
override string getFunctionName() { result = "op_Decrement" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DecrementOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked decrement operator (`--`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked --(Widget w) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedDecrementOperator extends UnaryOperator {
|
||||
CheckedDecrementOperator() { this.getName() = "checked --" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedDecrementOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined false operator (`false`), for example
|
||||
*
|
||||
@@ -607,8 +645,6 @@ class DecrementOperator extends UnaryOperator {
|
||||
class FalseOperator extends UnaryOperator {
|
||||
FalseOperator() { this.getName() = "false" }
|
||||
|
||||
override string getFunctionName() { result = "op_False" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FalseOperator" }
|
||||
}
|
||||
|
||||
@@ -624,17 +660,18 @@ class FalseOperator extends UnaryOperator {
|
||||
class TrueOperator extends UnaryOperator {
|
||||
TrueOperator() { this.getName() = "true" }
|
||||
|
||||
override string getFunctionName() { result = "op_True" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TrueOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined binary operator.
|
||||
*
|
||||
* Either an addition operator (`AddOperator`), a subtraction operator
|
||||
* (`SubOperator`), a multiplication operator (`MulOperator`), a division
|
||||
* operator (`DivOperator`), a remainder operator (`RemOperator`), an and
|
||||
* Either an addition operator (`AddOperator`), a checked addition operator
|
||||
* (`CheckedAddOperator`) a subtraction operator (`SubOperator`), a checked
|
||||
* substraction operator (`CheckedSubOperator`), a multiplication operator
|
||||
* (`MulOperator`), a checked multiplication operator (`CheckedMulOperator`),
|
||||
* a division operator (`DivOperator`), a checked division operator
|
||||
* (`CheckedDivOperator`), a remainder operator (`RemOperator`), an and
|
||||
* operator (`AndOperator`), an or operator (`OrOperator`), an xor
|
||||
* operator (`XorOperator`), a left shift operator (`LeftShiftOperator`),
|
||||
* a right shift operator (`RightShiftOperator`), an unsigned right shift
|
||||
@@ -659,11 +696,24 @@ class BinaryOperator extends Operator {
|
||||
class AddOperator extends BinaryOperator {
|
||||
AddOperator() { this.getName() = "+" }
|
||||
|
||||
override string getFunctionName() { result = "op_Addition" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AddOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked addition operator (`+`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked +(Widget lhs, Widget rhs) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedAddOperator extends BinaryOperator {
|
||||
CheckedAddOperator() { this.getName() = "checked +" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedAddOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined subtraction operator (`-`), for example
|
||||
*
|
||||
@@ -676,11 +726,24 @@ class AddOperator extends BinaryOperator {
|
||||
class SubOperator extends BinaryOperator {
|
||||
SubOperator() { this.getName() = "-" }
|
||||
|
||||
override string getFunctionName() { result = "op_Subtraction" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SubOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked subtraction operator (`-`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked -(Widget lhs, Widget rhs) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedSubOperator extends BinaryOperator {
|
||||
CheckedSubOperator() { this.getName() = "checked -" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedSubOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined multiplication operator (`*`), for example
|
||||
*
|
||||
@@ -693,11 +756,24 @@ class SubOperator extends BinaryOperator {
|
||||
class MulOperator extends BinaryOperator {
|
||||
MulOperator() { this.getName() = "*" }
|
||||
|
||||
override string getFunctionName() { result = "op_Multiply" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MulOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked multiplication operator (`*`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked *(Widget lhs, Widget rhs) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedMulOperator extends BinaryOperator {
|
||||
CheckedMulOperator() { this.getName() = "checked *" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedMulOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined division operator (`/`), for example
|
||||
*
|
||||
@@ -710,11 +786,24 @@ class MulOperator extends BinaryOperator {
|
||||
class DivOperator extends BinaryOperator {
|
||||
DivOperator() { this.getName() = "/" }
|
||||
|
||||
override string getFunctionName() { result = "op_Division" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DivOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked division operator (`/`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked /(Widget lhs, Widget rhs) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedDivOperator extends BinaryOperator {
|
||||
CheckedDivOperator() { this.getName() = "checked /" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedDivOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined remainder operator (`%`), for example
|
||||
*
|
||||
@@ -727,8 +816,6 @@ class DivOperator extends BinaryOperator {
|
||||
class RemOperator extends BinaryOperator {
|
||||
RemOperator() { this.getName() = "%" }
|
||||
|
||||
override string getFunctionName() { result = "op_Modulus" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RemOperator" }
|
||||
}
|
||||
|
||||
@@ -744,8 +831,6 @@ class RemOperator extends BinaryOperator {
|
||||
class AndOperator extends BinaryOperator {
|
||||
AndOperator() { this.getName() = "&" }
|
||||
|
||||
override string getFunctionName() { result = "op_BitwiseAnd" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AndOperator" }
|
||||
}
|
||||
|
||||
@@ -761,8 +846,6 @@ class AndOperator extends BinaryOperator {
|
||||
class OrOperator extends BinaryOperator {
|
||||
OrOperator() { this.getName() = "|" }
|
||||
|
||||
override string getFunctionName() { result = "op_BitwiseOr" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OrOperator" }
|
||||
}
|
||||
|
||||
@@ -778,8 +861,6 @@ class OrOperator extends BinaryOperator {
|
||||
class XorOperator extends BinaryOperator {
|
||||
XorOperator() { this.getName() = "^" }
|
||||
|
||||
override string getFunctionName() { result = "op_ExclusiveOr" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "XorOperator" }
|
||||
}
|
||||
|
||||
@@ -795,8 +876,6 @@ class XorOperator extends BinaryOperator {
|
||||
class LeftShiftOperator extends BinaryOperator {
|
||||
LeftShiftOperator() { this.getName() = "<<" }
|
||||
|
||||
override string getFunctionName() { result = "op_LeftShift" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LeftShiftOperator" }
|
||||
}
|
||||
|
||||
@@ -815,8 +894,6 @@ deprecated class LShiftOperator = LeftShiftOperator;
|
||||
class RightShiftOperator extends BinaryOperator {
|
||||
RightShiftOperator() { this.getName() = ">>" }
|
||||
|
||||
override string getFunctionName() { result = "op_RightShift" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RightShiftOperator" }
|
||||
}
|
||||
|
||||
@@ -835,8 +912,6 @@ deprecated class RShiftOperator = RightShiftOperator;
|
||||
class UnsignedRightShiftOperator extends BinaryOperator {
|
||||
UnsignedRightShiftOperator() { this.getName() = ">>>" }
|
||||
|
||||
override string getFunctionName() { result = "op_UnsignedRightShift" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnsignedRightShiftOperator" }
|
||||
}
|
||||
|
||||
@@ -852,8 +927,6 @@ class UnsignedRightShiftOperator extends BinaryOperator {
|
||||
class EQOperator extends BinaryOperator {
|
||||
EQOperator() { this.getName() = "==" }
|
||||
|
||||
override string getFunctionName() { result = "op_Equality" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "EQOperator" }
|
||||
}
|
||||
|
||||
@@ -869,8 +942,6 @@ class EQOperator extends BinaryOperator {
|
||||
class NEOperator extends BinaryOperator {
|
||||
NEOperator() { this.getName() = "!=" }
|
||||
|
||||
override string getFunctionName() { result = "op_Inequality" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NEOperator" }
|
||||
}
|
||||
|
||||
@@ -886,8 +957,6 @@ class NEOperator extends BinaryOperator {
|
||||
class LTOperator extends BinaryOperator {
|
||||
LTOperator() { this.getName() = "<" }
|
||||
|
||||
override string getFunctionName() { result = "op_LessThan" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LTOperator" }
|
||||
}
|
||||
|
||||
@@ -903,8 +972,6 @@ class LTOperator extends BinaryOperator {
|
||||
class GTOperator extends BinaryOperator {
|
||||
GTOperator() { this.getName() = ">" }
|
||||
|
||||
override string getFunctionName() { result = "op_GreaterThan" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "GTOperator" }
|
||||
}
|
||||
|
||||
@@ -920,8 +987,6 @@ class GTOperator extends BinaryOperator {
|
||||
class LEOperator extends BinaryOperator {
|
||||
LEOperator() { this.getName() = "<=" }
|
||||
|
||||
override string getFunctionName() { result = "op_LessThanOrEqual" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LEOperator" }
|
||||
}
|
||||
|
||||
@@ -937,8 +1002,6 @@ class LEOperator extends BinaryOperator {
|
||||
class GEOperator extends BinaryOperator {
|
||||
GEOperator() { this.getName() = ">=" }
|
||||
|
||||
override string getFunctionName() { result = "op_GreaterThanOrEqual" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "GEOperator" }
|
||||
}
|
||||
|
||||
@@ -954,7 +1017,8 @@ class GEOperator extends BinaryOperator {
|
||||
class ConversionOperator extends Operator {
|
||||
ConversionOperator() {
|
||||
this.getName() = "implicit conversion" or
|
||||
this.getName() = "explicit conversion"
|
||||
this.getName() = "explicit conversion" or
|
||||
this.getName() = "checked explicit conversion"
|
||||
}
|
||||
|
||||
/** Gets the source type of the conversion. */
|
||||
@@ -976,8 +1040,6 @@ class ConversionOperator extends Operator {
|
||||
class ImplicitConversionOperator extends ConversionOperator {
|
||||
ImplicitConversionOperator() { this.getName() = "implicit conversion" }
|
||||
|
||||
override string getFunctionName() { result = "op_Implicit" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImplicitConversionOperator" }
|
||||
}
|
||||
|
||||
@@ -993,11 +1055,24 @@ class ImplicitConversionOperator extends ConversionOperator {
|
||||
class ExplicitConversionOperator extends ConversionOperator {
|
||||
ExplicitConversionOperator() { this.getName() = "explicit conversion" }
|
||||
|
||||
override string getFunctionName() { result = "op_Explicit" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ExplicitConversionOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked explicit conversion operator, for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static explicit operator checked int(BigInteger i) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedExplicitConversionOperator extends ConversionOperator {
|
||||
CheckedExplicitConversionOperator() { this.getName() = "checked explicit conversion" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedExplicitConversionOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A local function, defined within the scope of another callable.
|
||||
* For example, `Fac` on lines 2--4 in
|
||||
|
||||
@@ -90,6 +90,9 @@ class Modifiable extends Declaration, @modifiable {
|
||||
/** Holds if this declaration is `const`. */
|
||||
predicate isConst() { this.hasModifier("const") }
|
||||
|
||||
/** Holds if this declaration has the modifier `required`. */
|
||||
predicate isRequired() { this.hasModifier("required") }
|
||||
|
||||
/** Holds if this declaration is `unsafe`. */
|
||||
predicate isUnsafe() {
|
||||
this.hasModifier("unsafe") or
|
||||
@@ -178,6 +181,8 @@ class Member extends DotNet::Member, Modifiable, @member {
|
||||
override predicate isAbstract() { Modifiable.super.isAbstract() }
|
||||
|
||||
override predicate isStatic() { Modifiable.super.isStatic() }
|
||||
|
||||
override predicate isRequired() { Modifiable.super.isRequired() }
|
||||
}
|
||||
|
||||
private class TOverridable = @virtualizable or @callable_accessor;
|
||||
|
||||
@@ -80,6 +80,9 @@ class Member extends Declaration, @dotnet_member {
|
||||
/** Holds if this member is `static`. */
|
||||
predicate isStatic() { none() }
|
||||
|
||||
/** Holds if this member is declared `required`. */
|
||||
predicate isRequired() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this member has name `name` and is defined in type `type`
|
||||
* with namespace `namespace`.
|
||||
|
||||
56
csharp/ql/test/library-tests/csharp11/CheckedOperators.cs
Normal file
56
csharp/ql/test/library-tests/csharp11/CheckedOperators.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
namespace CheckedOperators;
|
||||
|
||||
public class Number
|
||||
{
|
||||
public int Value { get; }
|
||||
|
||||
public Number(int n) => this.Value = n;
|
||||
|
||||
public static Number operator checked +(Number n1, Number n2) =>
|
||||
new Number(checked(n1.Value + n2.Value));
|
||||
|
||||
public static Number operator +(Number n1, Number n2) =>
|
||||
new Number(n1.Value + n2.Value);
|
||||
|
||||
public static Number operator checked -(Number n1, Number n2) =>
|
||||
new Number(checked(n1.Value - n2.Value));
|
||||
|
||||
public static Number operator -(Number n1, Number n2) =>
|
||||
new Number(n1.Value - n2.Value);
|
||||
|
||||
public static Number operator checked *(Number n1, Number n2) =>
|
||||
new Number(checked(n1.Value * n2.Value));
|
||||
|
||||
public static Number operator *(Number n1, Number n2) =>
|
||||
new Number(n1.Value * n2.Value);
|
||||
|
||||
public static Number operator checked /(Number n1, Number n2) =>
|
||||
new Number(checked(n1.Value / n2.Value));
|
||||
|
||||
public static Number operator /(Number n1, Number n2) =>
|
||||
new Number(n1.Value / n2.Value);
|
||||
|
||||
public static Number operator checked -(Number n) =>
|
||||
new Number(checked(-n.Value));
|
||||
|
||||
public static Number operator -(Number n) =>
|
||||
new Number(-n.Value);
|
||||
|
||||
public static Number operator checked ++(Number n) =>
|
||||
new Number(checked(n.Value + 1));
|
||||
|
||||
public static Number operator ++(Number n) =>
|
||||
new Number(n.Value + 1);
|
||||
|
||||
public static Number operator checked --(Number n) =>
|
||||
new Number(checked(n.Value - 1));
|
||||
|
||||
public static Number operator --(Number n) =>
|
||||
new Number(n.Value - 1);
|
||||
|
||||
public static explicit operator short(Number n) =>
|
||||
(short)n.Value;
|
||||
|
||||
public static explicit operator checked short(Number n) =>
|
||||
checked((short)n.Value);
|
||||
}
|
||||
@@ -1,3 +1,221 @@
|
||||
CheckedOperators.cs:
|
||||
# 1| [NamespaceDeclaration] namespace ... { ... }
|
||||
# 3| 1: [Class] Number
|
||||
# 5| 4: [Property] Value
|
||||
# 5| -1: [TypeMention] int
|
||||
# 5| 3: [Getter] get_Value
|
||||
# 7| 5: [InstanceConstructor] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 7| 0: [Parameter] n
|
||||
# 7| -1: [TypeMention] int
|
||||
# 7| 4: [AssignExpr] ... = ...
|
||||
# 7| 0: [PropertyCall] access to property Value
|
||||
# 7| -1: [ThisAccess] this access
|
||||
# 7| 1: [ParameterAccess] access to parameter n
|
||||
# 9| 6: [CheckedAddOperator] checked +
|
||||
# 9| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 9| 0: [Parameter] n1
|
||||
# 9| -1: [TypeMention] Number
|
||||
# 9| 1: [Parameter] n2
|
||||
# 9| -1: [TypeMention] Number
|
||||
# 10| 4: [ObjectCreation] object creation of type Number
|
||||
# 10| -1: [TypeMention] Number
|
||||
# 10| 0: [CheckedExpr] checked (...)
|
||||
# 10| 0: [AddExpr] ... + ...
|
||||
# 10| 0: [PropertyCall] access to property Value
|
||||
# 10| -1: [ParameterAccess] access to parameter n1
|
||||
# 10| 1: [PropertyCall] access to property Value
|
||||
# 10| -1: [ParameterAccess] access to parameter n2
|
||||
# 12| 7: [AddOperator] +
|
||||
# 12| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 12| 0: [Parameter] n1
|
||||
# 12| -1: [TypeMention] Number
|
||||
# 12| 1: [Parameter] n2
|
||||
# 12| -1: [TypeMention] Number
|
||||
# 13| 4: [ObjectCreation] object creation of type Number
|
||||
# 13| -1: [TypeMention] Number
|
||||
# 13| 0: [AddExpr] ... + ...
|
||||
# 13| 0: [PropertyCall] access to property Value
|
||||
# 13| -1: [ParameterAccess] access to parameter n1
|
||||
# 13| 1: [PropertyCall] access to property Value
|
||||
# 13| -1: [ParameterAccess] access to parameter n2
|
||||
# 15| 8: [CheckedSubOperator] checked -
|
||||
# 15| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 15| 0: [Parameter] n1
|
||||
# 15| -1: [TypeMention] Number
|
||||
# 15| 1: [Parameter] n2
|
||||
# 15| -1: [TypeMention] Number
|
||||
# 16| 4: [ObjectCreation] object creation of type Number
|
||||
# 16| -1: [TypeMention] Number
|
||||
# 16| 0: [CheckedExpr] checked (...)
|
||||
# 16| 0: [SubExpr] ... - ...
|
||||
# 16| 0: [PropertyCall] access to property Value
|
||||
# 16| -1: [ParameterAccess] access to parameter n1
|
||||
# 16| 1: [PropertyCall] access to property Value
|
||||
# 16| -1: [ParameterAccess] access to parameter n2
|
||||
# 18| 9: [SubOperator] -
|
||||
# 18| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 18| 0: [Parameter] n1
|
||||
# 18| -1: [TypeMention] Number
|
||||
# 18| 1: [Parameter] n2
|
||||
# 18| -1: [TypeMention] Number
|
||||
# 19| 4: [ObjectCreation] object creation of type Number
|
||||
# 19| -1: [TypeMention] Number
|
||||
# 19| 0: [SubExpr] ... - ...
|
||||
# 19| 0: [PropertyCall] access to property Value
|
||||
# 19| -1: [ParameterAccess] access to parameter n1
|
||||
# 19| 1: [PropertyCall] access to property Value
|
||||
# 19| -1: [ParameterAccess] access to parameter n2
|
||||
# 21| 10: [CheckedMulOperator] checked *
|
||||
# 21| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 21| 0: [Parameter] n1
|
||||
# 21| -1: [TypeMention] Number
|
||||
# 21| 1: [Parameter] n2
|
||||
# 21| -1: [TypeMention] Number
|
||||
# 22| 4: [ObjectCreation] object creation of type Number
|
||||
# 22| -1: [TypeMention] Number
|
||||
# 22| 0: [CheckedExpr] checked (...)
|
||||
# 22| 0: [MulExpr] ... * ...
|
||||
# 22| 0: [PropertyCall] access to property Value
|
||||
# 22| -1: [ParameterAccess] access to parameter n1
|
||||
# 22| 1: [PropertyCall] access to property Value
|
||||
# 22| -1: [ParameterAccess] access to parameter n2
|
||||
# 24| 11: [MulOperator] *
|
||||
# 24| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 24| 0: [Parameter] n1
|
||||
# 24| -1: [TypeMention] Number
|
||||
# 24| 1: [Parameter] n2
|
||||
# 24| -1: [TypeMention] Number
|
||||
# 25| 4: [ObjectCreation] object creation of type Number
|
||||
# 25| -1: [TypeMention] Number
|
||||
# 25| 0: [MulExpr] ... * ...
|
||||
# 25| 0: [PropertyCall] access to property Value
|
||||
# 25| -1: [ParameterAccess] access to parameter n1
|
||||
# 25| 1: [PropertyCall] access to property Value
|
||||
# 25| -1: [ParameterAccess] access to parameter n2
|
||||
# 27| 12: [CheckedDivOperator] checked /
|
||||
# 27| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 27| 0: [Parameter] n1
|
||||
# 27| -1: [TypeMention] Number
|
||||
# 27| 1: [Parameter] n2
|
||||
# 27| -1: [TypeMention] Number
|
||||
# 28| 4: [ObjectCreation] object creation of type Number
|
||||
# 28| -1: [TypeMention] Number
|
||||
# 28| 0: [CheckedExpr] checked (...)
|
||||
# 28| 0: [DivExpr] ... / ...
|
||||
# 28| 0: [PropertyCall] access to property Value
|
||||
# 28| -1: [ParameterAccess] access to parameter n1
|
||||
# 28| 1: [PropertyCall] access to property Value
|
||||
# 28| -1: [ParameterAccess] access to parameter n2
|
||||
# 30| 13: [DivOperator] /
|
||||
# 30| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 30| 0: [Parameter] n1
|
||||
# 30| -1: [TypeMention] Number
|
||||
# 30| 1: [Parameter] n2
|
||||
# 30| -1: [TypeMention] Number
|
||||
# 31| 4: [ObjectCreation] object creation of type Number
|
||||
# 31| -1: [TypeMention] Number
|
||||
# 31| 0: [DivExpr] ... / ...
|
||||
# 31| 0: [PropertyCall] access to property Value
|
||||
# 31| -1: [ParameterAccess] access to parameter n1
|
||||
# 31| 1: [PropertyCall] access to property Value
|
||||
# 31| -1: [ParameterAccess] access to parameter n2
|
||||
# 33| 14: [CheckedMinusOperator] checked -
|
||||
# 33| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 33| 0: [Parameter] n
|
||||
# 33| -1: [TypeMention] Number
|
||||
# 34| 4: [ObjectCreation] object creation of type Number
|
||||
# 34| -1: [TypeMention] Number
|
||||
# 34| 0: [CheckedExpr] checked (...)
|
||||
# 34| 0: [UnaryMinusExpr] -...
|
||||
# 34| 0: [PropertyCall] access to property Value
|
||||
# 34| -1: [ParameterAccess] access to parameter n
|
||||
# 36| 15: [MinusOperator] -
|
||||
# 36| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 36| 0: [Parameter] n
|
||||
# 36| -1: [TypeMention] Number
|
||||
# 37| 4: [ObjectCreation] object creation of type Number
|
||||
# 37| -1: [TypeMention] Number
|
||||
# 37| 0: [UnaryMinusExpr] -...
|
||||
# 37| 0: [PropertyCall] access to property Value
|
||||
# 37| -1: [ParameterAccess] access to parameter n
|
||||
# 39| 16: [CheckedIncrementOperator] checked ++
|
||||
# 39| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 39| 0: [Parameter] n
|
||||
# 39| -1: [TypeMention] Number
|
||||
# 40| 4: [ObjectCreation] object creation of type Number
|
||||
# 40| -1: [TypeMention] Number
|
||||
# 40| 0: [CheckedExpr] checked (...)
|
||||
# 40| 0: [AddExpr] ... + ...
|
||||
# 40| 0: [PropertyCall] access to property Value
|
||||
# 40| -1: [ParameterAccess] access to parameter n
|
||||
# 40| 1: [IntLiteral] 1
|
||||
# 42| 17: [IncrementOperator] ++
|
||||
# 42| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 42| 0: [Parameter] n
|
||||
# 42| -1: [TypeMention] Number
|
||||
# 43| 4: [ObjectCreation] object creation of type Number
|
||||
# 43| -1: [TypeMention] Number
|
||||
# 43| 0: [AddExpr] ... + ...
|
||||
# 43| 0: [PropertyCall] access to property Value
|
||||
# 43| -1: [ParameterAccess] access to parameter n
|
||||
# 43| 1: [IntLiteral] 1
|
||||
# 45| 18: [CheckedDecrementOperator] checked --
|
||||
# 45| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 45| 0: [Parameter] n
|
||||
# 45| -1: [TypeMention] Number
|
||||
# 46| 4: [ObjectCreation] object creation of type Number
|
||||
# 46| -1: [TypeMention] Number
|
||||
# 46| 0: [CheckedExpr] checked (...)
|
||||
# 46| 0: [SubExpr] ... - ...
|
||||
# 46| 0: [PropertyCall] access to property Value
|
||||
# 46| -1: [ParameterAccess] access to parameter n
|
||||
# 46| 1: [IntLiteral] 1
|
||||
# 48| 19: [DecrementOperator] --
|
||||
# 48| -1: [TypeMention] Number
|
||||
#-----| 2: (Parameters)
|
||||
# 48| 0: [Parameter] n
|
||||
# 48| -1: [TypeMention] Number
|
||||
# 49| 4: [ObjectCreation] object creation of type Number
|
||||
# 49| -1: [TypeMention] Number
|
||||
# 49| 0: [SubExpr] ... - ...
|
||||
# 49| 0: [PropertyCall] access to property Value
|
||||
# 49| -1: [ParameterAccess] access to parameter n
|
||||
# 49| 1: [IntLiteral] 1
|
||||
# 51| 20: [ExplicitConversionOperator] explicit conversion
|
||||
# 51| -1: [TypeMention] short
|
||||
#-----| 2: (Parameters)
|
||||
# 51| 0: [Parameter] n
|
||||
# 51| -1: [TypeMention] Number
|
||||
# 52| 4: [CastExpr] (...) ...
|
||||
# 52| 0: [TypeAccess] access to type Int16
|
||||
# 52| 0: [TypeMention] short
|
||||
# 52| 1: [PropertyCall] access to property Value
|
||||
# 52| -1: [ParameterAccess] access to parameter n
|
||||
# 54| 21: [CheckedExplicitConversionOperator] checked explicit conversion
|
||||
# 54| -1: [TypeMention] short
|
||||
#-----| 2: (Parameters)
|
||||
# 54| 0: [Parameter] n
|
||||
# 54| -1: [TypeMention] Number
|
||||
# 55| 4: [CheckedExpr] checked (...)
|
||||
# 55| 0: [CastExpr] (...) ...
|
||||
# 55| 0: [TypeAccess] access to type Int16
|
||||
# 55| 0: [TypeMention] short
|
||||
# 55| 1: [PropertyCall] access to property Value
|
||||
# 55| -1: [ParameterAccess] access to parameter n
|
||||
GenericAttribute.cs:
|
||||
# 3| [GenericAssemblyAttribute] [assembly: MyGeneric<Int32>(...)]
|
||||
# 3| 0: [TypeMention] MyGenericAttribute<int>
|
||||
@@ -439,6 +657,97 @@ RelaxedShift.cs:
|
||||
# 30| 1: [OperatorCall] call to operator >>>
|
||||
# 30| 0: [LocalVariableAccess] access to local variable n31
|
||||
# 30| 1: [StringLiteralUtf16] "3"
|
||||
RequiredMembers.cs:
|
||||
# 4| [Class] ClassRequiredMembers
|
||||
# 6| 4: [Field] RequiredField
|
||||
# 6| -1: [TypeMention] object
|
||||
# 7| 5: [Property] RequiredProperty
|
||||
# 7| -1: [TypeMention] string
|
||||
# 7| 3: [Getter] get_RequiredProperty
|
||||
# 7| 4: [Setter] set_RequiredProperty
|
||||
#-----| 2: (Parameters)
|
||||
# 7| 0: [Parameter] value
|
||||
# 8| 6: [Property] VirtualProperty
|
||||
# 8| -1: [TypeMention] object
|
||||
# 8| 3: [Getter] get_VirtualProperty
|
||||
# 8| 4: [Setter] set_VirtualProperty
|
||||
#-----| 2: (Parameters)
|
||||
# 8| 0: [Parameter] value
|
||||
# 10| 7: [InstanceConstructor] ClassRequiredMembers
|
||||
# 10| 4: [BlockStmt] {...}
|
||||
# 13| 8: [InstanceConstructor] ClassRequiredMembers
|
||||
#-----| 0: (Attributes)
|
||||
# 12| 1: [DefaultAttribute] [SetsRequiredMembers(...)]
|
||||
# 12| 0: [TypeMention] SetsRequiredMembersAttribute
|
||||
#-----| 2: (Parameters)
|
||||
# 13| 0: [Parameter] requiredField
|
||||
# 13| -1: [TypeMention] object
|
||||
# 13| 1: [Parameter] requiredProperty
|
||||
# 13| -1: [TypeMention] string
|
||||
# 14| 4: [BlockStmt] {...}
|
||||
# 15| 0: [ExprStmt] ...;
|
||||
# 15| 0: [AssignExpr] ... = ...
|
||||
# 15| 0: [FieldAccess] access to field RequiredField
|
||||
# 15| 1: [ParameterAccess] access to parameter requiredField
|
||||
# 16| 1: [ExprStmt] ...;
|
||||
# 16| 0: [AssignExpr] ... = ...
|
||||
# 16| 0: [PropertyCall] access to property RequiredProperty
|
||||
# 16| 1: [ParameterAccess] access to parameter requiredProperty
|
||||
# 20| [Class] ClassRequiredMembersSub
|
||||
#-----| 3: (Base types)
|
||||
# 20| 0: [TypeMention] ClassRequiredMembers
|
||||
# 22| 4: [Property] VirtualProperty
|
||||
# 22| -1: [TypeMention] object
|
||||
# 22| 3: [Getter] get_VirtualProperty
|
||||
# 22| 4: [Setter] set_VirtualProperty
|
||||
#-----| 2: (Parameters)
|
||||
# 22| 0: [Parameter] value
|
||||
# 24| 5: [InstanceConstructor] ClassRequiredMembersSub
|
||||
# 24| 3: [ConstructorInitializer] call to constructor ClassRequiredMembers
|
||||
# 24| 4: [BlockStmt] {...}
|
||||
# 27| 6: [InstanceConstructor] ClassRequiredMembersSub
|
||||
#-----| 0: (Attributes)
|
||||
# 26| 1: [DefaultAttribute] [SetsRequiredMembers(...)]
|
||||
# 26| 0: [TypeMention] SetsRequiredMembersAttribute
|
||||
#-----| 2: (Parameters)
|
||||
# 27| 0: [Parameter] requiredField
|
||||
# 27| -1: [TypeMention] object
|
||||
# 27| 1: [Parameter] requiredProperty
|
||||
# 27| -1: [TypeMention] string
|
||||
# 27| 2: [Parameter] virtualProperty
|
||||
# 27| -1: [TypeMention] object
|
||||
# 27| 3: [ConstructorInitializer] call to constructor ClassRequiredMembers
|
||||
# 27| 0: [ParameterAccess] access to parameter requiredField
|
||||
# 27| 1: [ParameterAccess] access to parameter requiredProperty
|
||||
# 28| 4: [BlockStmt] {...}
|
||||
# 29| 0: [ExprStmt] ...;
|
||||
# 29| 0: [AssignExpr] ... = ...
|
||||
# 29| 0: [PropertyCall] access to property VirtualProperty
|
||||
# 29| 1: [ParameterAccess] access to parameter virtualProperty
|
||||
# 33| [RecordClass] RecordRequiredMembers
|
||||
# 33| 12: [NEOperator] !=
|
||||
#-----| 2: (Parameters)
|
||||
# 33| 0: [Parameter] left
|
||||
# 33| 1: [Parameter] right
|
||||
# 33| 13: [EQOperator] ==
|
||||
#-----| 2: (Parameters)
|
||||
# 33| 0: [Parameter] left
|
||||
# 33| 1: [Parameter] right
|
||||
# 33| 14: [Property] EqualityContract
|
||||
# 33| 3: [Getter] get_EqualityContract
|
||||
# 35| 15: [Property] X
|
||||
# 35| -1: [TypeMention] object
|
||||
# 35| 3: [Getter] get_X
|
||||
# 35| 4: [Setter] set_X
|
||||
#-----| 2: (Parameters)
|
||||
# 35| 0: [Parameter] value
|
||||
# 38| [Struct] StructRequiredMembers
|
||||
# 40| 5: [Property] Y
|
||||
# 40| -1: [TypeMention] string
|
||||
# 40| 3: [Getter] get_Y
|
||||
# 40| 4: [Setter] set_Y
|
||||
#-----| 2: (Parameters)
|
||||
# 40| 0: [Parameter] value
|
||||
Scoped.cs:
|
||||
# 1| [Struct] S1
|
||||
# 2| [Struct] S2
|
||||
|
||||
42
csharp/ql/test/library-tests/csharp11/RequiredMembers.cs
Normal file
42
csharp/ql/test/library-tests/csharp11/RequiredMembers.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
public class ClassRequiredMembers
|
||||
{
|
||||
public required object? RequiredField;
|
||||
public required string? RequiredProperty { get; init; }
|
||||
public virtual object? VirtualProperty { get; init; }
|
||||
|
||||
public ClassRequiredMembers() { }
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ClassRequiredMembers(object requiredField, string requiredProperty)
|
||||
{
|
||||
RequiredField = requiredField;
|
||||
RequiredProperty = requiredProperty;
|
||||
}
|
||||
}
|
||||
|
||||
public class ClassRequiredMembersSub : ClassRequiredMembers
|
||||
{
|
||||
public override required object? VirtualProperty { get; init; }
|
||||
|
||||
public ClassRequiredMembersSub() : base() { }
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ClassRequiredMembersSub(object requiredField, string requiredProperty, object virtualProperty) : base(requiredField, requiredProperty)
|
||||
{
|
||||
VirtualProperty = virtualProperty;
|
||||
}
|
||||
}
|
||||
|
||||
public record RecordRequiredMembers
|
||||
{
|
||||
public required object? X { get; init; }
|
||||
}
|
||||
|
||||
public struct StructRequiredMembers
|
||||
{
|
||||
public required string? Y { get; init; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
| CheckedOperators.cs:9:43:9:43 | checked + | op_CheckedAddition | CheckedAddOperator |
|
||||
| CheckedOperators.cs:12:35:12:35 | + | op_Addition | AddOperator |
|
||||
| CheckedOperators.cs:15:43:15:43 | checked - | op_CheckedSubtraction | CheckedSubOperator |
|
||||
| CheckedOperators.cs:18:35:18:35 | - | op_Subtraction | SubOperator |
|
||||
| CheckedOperators.cs:21:43:21:43 | checked * | op_CheckedMultiply | CheckedMulOperator |
|
||||
| CheckedOperators.cs:24:35:24:35 | * | op_Multiply | MulOperator |
|
||||
| CheckedOperators.cs:27:43:27:43 | checked / | op_CheckedDivision | CheckedDivOperator |
|
||||
| CheckedOperators.cs:30:35:30:35 | / | op_Division | DivOperator |
|
||||
| CheckedOperators.cs:33:43:33:43 | checked - | op_CheckedUnaryNegation | CheckedMinusOperator |
|
||||
| CheckedOperators.cs:36:35:36:35 | - | op_UnaryNegation | MinusOperator |
|
||||
| CheckedOperators.cs:39:43:39:44 | checked ++ | op_CheckedIncrement | CheckedIncrementOperator |
|
||||
| CheckedOperators.cs:42:35:42:36 | ++ | op_Increment | IncrementOperator |
|
||||
| CheckedOperators.cs:45:43:45:44 | checked -- | op_CheckedDecrement | CheckedDecrementOperator |
|
||||
| CheckedOperators.cs:48:35:48:36 | -- | op_Decrement | DecrementOperator |
|
||||
| CheckedOperators.cs:51:28:51:35 | explicit conversion | op_Explicit | ExplicitConversionOperator |
|
||||
| CheckedOperators.cs:54:28:54:35 | checked explicit conversion | op_CheckedExplicit | CheckedExplicitConversionOperator |
|
||||
@@ -0,0 +1,5 @@
|
||||
import csharp
|
||||
|
||||
from Operator o
|
||||
where o.getFile().getStem() = "CheckedOperators"
|
||||
select o, o.getFunctionName(), o.getAPrimaryQlClass()
|
||||
@@ -0,0 +1,5 @@
|
||||
| RequiredMembers.cs:6:29:6:41 | RequiredField | ClassRequiredMembers | Field |
|
||||
| RequiredMembers.cs:7:29:7:44 | RequiredProperty | ClassRequiredMembers | Property |
|
||||
| RequiredMembers.cs:22:38:22:52 | VirtualProperty | ClassRequiredMembersSub | Property |
|
||||
| RequiredMembers.cs:35:29:35:29 | X | RecordRequiredMembers | Property |
|
||||
| RequiredMembers.cs:40:29:40:29 | Y | StructRequiredMembers | Property |
|
||||
8
csharp/ql/test/library-tests/csharp11/requiredMembers.ql
Normal file
8
csharp/ql/test/library-tests/csharp11/requiredMembers.ql
Normal file
@@ -0,0 +1,8 @@
|
||||
import csharp
|
||||
|
||||
query predicate requiredmembers(Member m, string type, string qlclass) {
|
||||
m.getFile().getStem() = "RequiredMembers" and
|
||||
m.isRequired() and
|
||||
type = m.getDeclaringType().getName() and
|
||||
qlclass = m.getAPrimaryQlClass()
|
||||
}
|
||||
@@ -238,3 +238,7 @@
|
||||
| ViableCallable.cs:458:10:458:14 | M5<> | ViableCallable.cs:444:23:444:27 | M2<> |
|
||||
| ViableCallable.cs:475:10:475:12 | Run | ViableCallable.cs:468:10:468:11 | M2 |
|
||||
| ViableCallable.cs:475:10:475:12 | Run | ViableCallable.cs:473:17:473:18 | M1 |
|
||||
| ViableCallable.cs:492:10:492:12 | Run | ViableCallable.cs:487:32:487:32 | + |
|
||||
| ViableCallable.cs:492:10:492:12 | Run | ViableCallable.cs:488:40:488:40 | checked + |
|
||||
| ViableCallable.cs:492:10:492:12 | Run | ViableCallable.cs:489:28:489:35 | explicit conversion |
|
||||
| ViableCallable.cs:492:10:492:12 | Run | ViableCallable.cs:490:28:490:35 | checked explicit conversion |
|
||||
|
||||
@@ -471,3 +471,7 @@
|
||||
| ViableCallable.cs:461:9:461:30 | call to method M2<T> | C17.M2<T>(Func<T>) |
|
||||
| ViableCallable.cs:478:9:478:14 | call to method M1 | C18.M1() |
|
||||
| ViableCallable.cs:481:9:481:14 | call to method M2 | I2.M2() |
|
||||
| ViableCallable.cs:495:18:495:22 | call to operator + | C19.+(C19, C19) |
|
||||
| ViableCallable.cs:498:26:498:30 | call to operator checked + | C19.checked +(C19, C19) |
|
||||
| ViableCallable.cs:501:18:501:23 | call to operator explicit conversion | C19.explicit conversion(C19) |
|
||||
| ViableCallable.cs:504:26:504:31 | call to operator checked explicit conversion | C19.checked explicit conversion(C19) |
|
||||
|
||||
@@ -480,4 +480,27 @@ class C18 : I2
|
||||
// Viable callables: I2.M2()
|
||||
i.M2();
|
||||
}
|
||||
}
|
||||
|
||||
class C19
|
||||
{
|
||||
public static C19 operator +(C19 x, C19 y) => throw null;
|
||||
public static C19 operator checked +(C19 x, C19 y) => throw null;
|
||||
public static explicit operator int(C19 x) => throw null;
|
||||
public static explicit operator checked int(C19 x) => throw null;
|
||||
|
||||
void Run(C19 c)
|
||||
{
|
||||
// Viable callables: C19.op_Addition()
|
||||
var c1 = c + c;
|
||||
|
||||
// Viable callables: C19.op_CheckedAddition()
|
||||
var c2 = checked(c + c);
|
||||
|
||||
// Viable callables: C19.op_Explicit()
|
||||
var n1 = (int)c;
|
||||
|
||||
// Viable callables: C19.op_CheckedExplicit()
|
||||
var n2 = checked((int)c);
|
||||
}
|
||||
}
|
||||
@@ -268,3 +268,7 @@
|
||||
| ViableCallable.cs:423:9:423:21 | call to method M<String> | M<> | A5 |
|
||||
| ViableCallable.cs:478:9:478:14 | call to method M1 | M1 | C18 |
|
||||
| ViableCallable.cs:481:9:481:14 | call to method M2 | M2 | I2 |
|
||||
| ViableCallable.cs:495:18:495:22 | call to operator + | + | C19 |
|
||||
| ViableCallable.cs:498:26:498:30 | call to operator checked + | checked + | C19 |
|
||||
| ViableCallable.cs:501:18:501:23 | call to operator explicit conversion | explicit conversion | C19 |
|
||||
| ViableCallable.cs:504:26:504:31 | call to operator checked explicit conversion | checked explicit conversion | C19 |
|
||||
|
||||
@@ -6,7 +6,11 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
dotnet_platform="linux-x64"
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
platform="osx64"
|
||||
dotnet_platform="osx-x64"
|
||||
if [[ $(uname -m) == 'arm64' ]]; then
|
||||
dotnet_platform="osx-arm64"
|
||||
else
|
||||
dotnet_platform="osx-x64"
|
||||
fi
|
||||
else
|
||||
echo "Unknown OS"
|
||||
exit 1
|
||||
|
||||
6
java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes
vendored
Normal file
6
java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
BIN
java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
244
java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew
vendored
Executable file
244
java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew
vendored
Executable file
@@ -0,0 +1,244 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
92
java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat
vendored
Normal file
92
java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -1,5 +1,7 @@
|
||||
import platform
|
||||
from create_database_utils import *
|
||||
|
||||
gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew"
|
||||
|
||||
run_codeql_database_create(
|
||||
["gradle build --no-daemon --no-build-cache"], lang="java")
|
||||
runSuccessfully([get_cmd("gradle"), "clean"])
|
||||
["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java")
|
||||
|
||||
6
java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/.gitattributes
vendored
Normal file
6
java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
BIN
java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
244
java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew
vendored
Executable file
244
java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew
vendored
Executable file
@@ -0,0 +1,244 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
92
java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew.bat
vendored
Normal file
92
java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -1,4 +1,7 @@
|
||||
import platform
|
||||
from create_database_utils import *
|
||||
|
||||
run_codeql_database_create(["gradle build --no-daemon --no-build-cache"], lang="java")
|
||||
runSuccessfully([get_cmd("gradle"), "clean"])
|
||||
gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew"
|
||||
|
||||
run_codeql_database_create(
|
||||
["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java")
|
||||
|
||||
6
java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/.gitattributes
vendored
Normal file
6
java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
244
java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew
vendored
Executable file
244
java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew
vendored
Executable file
@@ -0,0 +1,244 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
92
java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew.bat
vendored
Normal file
92
java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -1,4 +1,7 @@
|
||||
import platform
|
||||
from create_database_utils import *
|
||||
|
||||
run_codeql_database_create(["gradle build --no-daemon --no-build-cache"], lang="java")
|
||||
runSuccessfully([get_cmd("gradle"), "clean"])
|
||||
gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew"
|
||||
|
||||
run_codeql_database_create(
|
||||
["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java")
|
||||
|
||||
6
java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes
vendored
Normal file
6
java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
BIN
java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
244
java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew
vendored
Executable file
244
java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew
vendored
Executable file
@@ -0,0 +1,244 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
92
java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat
vendored
Normal file
92
java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -1,5 +1,7 @@
|
||||
import platform
|
||||
from create_database_utils import *
|
||||
|
||||
gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew"
|
||||
|
||||
run_codeql_database_create(
|
||||
["gradle build --no-daemon --no-build-cache --rerun-tasks"], lang="java")
|
||||
runSuccessfully([get_cmd("gradle"), "clean"])
|
||||
["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java")
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `java/hardcoded-credential-api-call` now recognizes methods that accept user and password from the SQLServerDataSource class of the Microsoft JDBC Driver for SQL Server.
|
||||
@@ -485,6 +485,10 @@ private predicate otherApiCallableCredentialParam(string s) {
|
||||
"com.mongodb.MongoCredential;createCredential(String, String, char[]);2",
|
||||
"com.mongodb.MongoCredential;createMongoCRCredential(String, String, char[]);2",
|
||||
"com.mongodb.MongoCredential;createPlainCredential(String, String, char[]);2",
|
||||
"com.mongodb.MongoCredential;createScramSha1Credential(String, String, char[]);2"
|
||||
"com.mongodb.MongoCredential;createScramSha1Credential(String, String, char[]);2",
|
||||
"com.microsoft.sqlserver.jdbc.SQLServerDataSource;setUser(String);0",
|
||||
"com.microsoft.sqlserver.jdbc.SQLServerDataSource;setPassword(String);0",
|
||||
"com.microsoft.sqlserver.jdbc.SQLServerDataSource;getConnection(String, String);0",
|
||||
"com.microsoft.sqlserver.jdbc.SQLServerDataSource;getConnection(String, String);1",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ class TestCase extends TTestCase {
|
||||
*/
|
||||
Type getOutputType() {
|
||||
if baseOutput = SummaryComponentStack::return()
|
||||
then result = callable.getReturnType()
|
||||
then result = getReturnType(callable)
|
||||
else
|
||||
exists(int i |
|
||||
baseOutput = SummaryComponentStack::argument(i) and
|
||||
|
||||
@@ -16,6 +16,11 @@ Type getRootSourceDeclaration(Type t) {
|
||||
else result = t
|
||||
}
|
||||
|
||||
/** Gets the return type of the callable c, or the constructed tpe if it's a constructor */
|
||||
Type getReturnType(Callable c) {
|
||||
if c instanceof Constructor then result = c.getDeclaringType() else result = c.getReturnType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if type `t` does not clash with another type we want to import that has the same base name.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python3
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import errno
|
||||
import json
|
||||
@@ -13,11 +13,14 @@ import tempfile
|
||||
|
||||
if any(s == "--help" for s in sys.argv):
|
||||
print("""Usage:
|
||||
GenerateFlowTestCase.py specsToTest.csv projectPom.xml outdir [--force]
|
||||
GenerateFlowTestCase.py specsToTest projectPom.xml outdir [--force]
|
||||
|
||||
This generates test cases exercising function model specifications found in specsToTest.csv
|
||||
This generates test cases exercising function model specifications found in specsToTest
|
||||
producing files Test.java, test.ql, test.ext.yml and test.expected in outdir.
|
||||
|
||||
specsToTest should either be a .csv file, a .yml file, or a directory of .yml files, containing the
|
||||
model specifications to test.
|
||||
|
||||
projectPom.xml should be a Maven pom sufficient to resolve the classes named in specsToTest.csv.
|
||||
Typically this means supplying a skeleton POM <dependencies> section that retrieves whatever jars
|
||||
contain the needed classes.
|
||||
@@ -40,14 +43,15 @@ if "--force" in sys.argv:
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print(
|
||||
"Usage: GenerateFlowTestCase.py specsToTest.csv projectPom.xml outdir [--force]", file=sys.stderr)
|
||||
print("specsToTest.csv should contain CSV rows describing method taint-propagation specifications to test", file=sys.stderr)
|
||||
print("projectPom.xml should import dependencies sufficient to resolve the types used in specsToTest.csv", file=sys.stderr)
|
||||
"Usage: GenerateFlowTestCase.py specsToTest projectPom.xml outdir [--force]", file=sys.stderr)
|
||||
print("specsToTest should contain CSV rows or YAML models describing method taint-propagation specifications to test", file=sys.stderr)
|
||||
print("projectPom.xml should import dependencies sufficient to resolve the types used in specsToTest", file=sys.stderr)
|
||||
print("\nRun with --help for more details.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
os.makedirs(sys.argv[3])
|
||||
except Exception as e:
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
print("Failed to create output directory %s: %s" % (sys.argv[3], e))
|
||||
sys.exit(1)
|
||||
@@ -75,38 +79,86 @@ except Exception as e:
|
||||
(sys.argv[2], e), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
commentRegex = re.compile("^\s*(//|#)")
|
||||
commentRegex = re.compile(r"^\s*(//|#)")
|
||||
|
||||
|
||||
def isComment(s):
|
||||
return commentRegex.match(s) is not None
|
||||
|
||||
|
||||
try:
|
||||
with open(sys.argv[1], "r") as f:
|
||||
specs = [l for l in f if not isComment(l)]
|
||||
except Exception as e:
|
||||
print("Failed to open %s: %s\n" % (sys.argv[1], e))
|
||||
def readCsv(file):
|
||||
try:
|
||||
with open(file, "r") as f:
|
||||
specs = [l.strip() for l in f if not isComment(l)]
|
||||
except Exception as e:
|
||||
print("Failed to open %s: %s\n" % (file, e))
|
||||
sys.exit(1)
|
||||
|
||||
specs = [row.split(";") for row in specs]
|
||||
return specs
|
||||
|
||||
|
||||
def readYml(file):
|
||||
try:
|
||||
import yaml
|
||||
with open(file, "r") as f:
|
||||
doc = yaml.load(f.read(), yaml.Loader)
|
||||
specs = []
|
||||
for ext in doc['extensions']:
|
||||
if ext['addsTo']['extensible'] == 'summaryModel':
|
||||
for row in ext['data']:
|
||||
if isinstance(row[2], bool):
|
||||
row[2] = str(row[2]).lower()
|
||||
specs.append(row)
|
||||
return specs
|
||||
except ImportError:
|
||||
print("PyYAML not found - try \n pip install pyyaml")
|
||||
sys.exit(1)
|
||||
except ValueError as e:
|
||||
print("Invalid yaml model in %s: %s\n" % (file, e))
|
||||
sys.exit(1)
|
||||
except OSError as e:
|
||||
print("Failed to open %s: %s\n" % (file, e))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def readYmlDir(dirname):
|
||||
specs = []
|
||||
for f in os.listdir(dirname):
|
||||
if f.endswith('.yml'):
|
||||
specs += readYml(f"{dirname}/{f}")
|
||||
return specs
|
||||
|
||||
|
||||
specsFile = sys.argv[1]
|
||||
if os.path.isdir(specsFile):
|
||||
specs = readYmlDir(specsFile)
|
||||
elif specsFile.endswith(".yml") or specsFile.endswith(".yaml"):
|
||||
specs = readYml(specsFile)
|
||||
elif specsFile.endswith(".csv"):
|
||||
specs = readCsv(specsFile)
|
||||
else:
|
||||
print(f"Invalid specs {specsFile}. Must be a csv file, a yml file, or a directory of yml files.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
projectTestPkgDir = os.path.join(projectDir, "src", "main", "java", "test")
|
||||
projectTestFile = os.path.join(projectTestPkgDir, "Test.java")
|
||||
|
||||
os.makedirs(projectTestPkgDir)
|
||||
|
||||
|
||||
def qualifiedOuterNameFromCsvRow(row):
|
||||
cells = row.split(";")
|
||||
if len(cells) < 2:
|
||||
def qualifiedOuterNameFromRow(row):
|
||||
if len(row) < 2:
|
||||
return None
|
||||
return cells[0] + "." + cells[1].replace("$", ".")
|
||||
return row[0] + "." + row[1].replace("$", ".")
|
||||
|
||||
|
||||
with open(projectTestFile, "w") as testJava:
|
||||
testJava.write("package test;\n\npublic class Test {\n\n")
|
||||
|
||||
for i, spec in enumerate(specs):
|
||||
outerName = qualifiedOuterNameFromCsvRow(spec)
|
||||
outerName = qualifiedOuterNameFromRow(spec)
|
||||
if outerName is None:
|
||||
print("A taint specification has the wrong format: should be 'package;classname;methodname....'", file=sys.stderr)
|
||||
print("Mis-formatted row: " + spec, file=sys.stderr)
|
||||
@@ -140,7 +192,7 @@ dependencies:
|
||||
with open(qlFile, "w") as f:
|
||||
f.write(
|
||||
"import java\nimport utils.flowtestcasegenerator.GenerateFlowTestCase\n\nclass GenRow extends TargetSummaryModelCsv {\n\n\toverride predicate row(string r) {\n\t\tr = [\n")
|
||||
f.write(",\n".join('\t\t\t"%s"' % spec.strip() for spec in specs))
|
||||
f.write(",\n".join('\t\t\t"%s"' % ';'.join(spec) for spec in specs))
|
||||
f.write("\n\t\t]\n\t}\n}\n")
|
||||
|
||||
print("Generating tests")
|
||||
@@ -221,7 +273,7 @@ if len(supportModelRows) != 0:
|
||||
# Make a test extension file
|
||||
with open(resultYml, "w") as f:
|
||||
models = "\n".join(' - [%s]' %
|
||||
modelSpecRow[0].strip() for modelSpecRow in supportModelRows)
|
||||
modelSpecRow[0].strip() for modelSpecRow in supportModelRows)
|
||||
dataextensions = f"""extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-tests
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
|
||||
|
||||
public class HardcodedMSSQLCredentials {
|
||||
public static void main(SQLServerDataSource ds) throws Exception {
|
||||
ds.setUser("Username"); // $ HardcodedCredentialsApiCall
|
||||
ds.setPassword("password"); // $ HardcodedCredentialsApiCall
|
||||
ds.getConnection("Username", null); // $ HardcodedCredentialsApiCall
|
||||
ds.getConnection(null, "password"); // $ HardcodedCredentialsApiCall
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700:${testdir}/../../../../../stubs/azure-sdk-for-java:${testdir}/../../../../../stubs/shiro-core-1.4.0:${testdir}/../../../../../stubs/jsch-0.1.55:${testdir}/../../../../../stubs/ganymed-ssh-2-260:${testdir}/../../../../../stubs/apache-mina-sshd-2.8.0:${testdir}/../../../../../stubs/sshj-0.33.0:${testdir}/../../../../../stubs/j2ssh-1.5.5:${testdir}/../../../../../stubs/trilead-ssh2-212:${testdir}/../../../../../stubs/apache-commons-net-3.8.0:${testdir}/../../../../../stubs/mongodbClient
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700:${testdir}/../../../../../stubs/azure-sdk-for-java:${testdir}/../../../../../stubs/shiro-core-1.4.0:${testdir}/../../../../../stubs/jsch-0.1.55:${testdir}/../../../../../stubs/ganymed-ssh-2-260:${testdir}/../../../../../stubs/apache-mina-sshd-2.8.0:${testdir}/../../../../../stubs/sshj-0.33.0:${testdir}/../../../../../stubs/j2ssh-1.5.5:${testdir}/../../../../../stubs/trilead-ssh2-212:${testdir}/../../../../../stubs/apache-commons-net-3.8.0:${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/mssql-jdbc-12.2.0
|
||||
|
||||
166
java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java
generated
Normal file
166
java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java
generated
Normal file
@@ -0,0 +1,166 @@
|
||||
// Generated automatically from com.microsoft.sqlserver.jdbc.ISQLServerDataSource for testing purposes
|
||||
|
||||
package com.microsoft.sqlserver.jdbc;
|
||||
|
||||
import com.microsoft.sqlserver.jdbc.SQLServerAccessTokenCallback;
|
||||
import javax.sql.CommonDataSource;
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
|
||||
public interface ISQLServerDataSource extends CommonDataSource
|
||||
{
|
||||
GSSCredential getGSSCredentials();
|
||||
SQLServerAccessTokenCallback getAccessTokenCallback();
|
||||
String getAADSecurePrincipalId();
|
||||
String getAccessToken();
|
||||
String getApplicationIntent();
|
||||
String getApplicationName();
|
||||
String getAuthentication();
|
||||
String getClientCertificate();
|
||||
String getClientKey();
|
||||
String getColumnEncryptionSetting();
|
||||
String getDatabaseName();
|
||||
String getDatetimeParameterType();
|
||||
String getDescription();
|
||||
String getDomain();
|
||||
String getEnclaveAttestationProtocol();
|
||||
String getEnclaveAttestationUrl();
|
||||
String getEncrypt();
|
||||
String getFailoverPartner();
|
||||
String getHostNameInCertificate();
|
||||
String getIPAddressPreference();
|
||||
String getInstanceName();
|
||||
String getJAASConfigurationName();
|
||||
String getJASSConfigurationName();
|
||||
String getKeyStoreAuthentication();
|
||||
String getKeyStoreLocation();
|
||||
String getKeyStorePrincipalId();
|
||||
String getKeyVaultProviderClientId();
|
||||
String getMSIClientId();
|
||||
String getMaxResultBuffer();
|
||||
String getPrepareMethod();
|
||||
String getRealm();
|
||||
String getResponseBuffering();
|
||||
String getSSLProtocol();
|
||||
String getSelectMethod();
|
||||
String getServerCertificate();
|
||||
String getServerName();
|
||||
String getServerSpn();
|
||||
String getSocketFactoryClass();
|
||||
String getSocketFactoryConstructorArg();
|
||||
String getTrustManagerClass();
|
||||
String getTrustManagerConstructorArg();
|
||||
String getTrustStore();
|
||||
String getTrustStoreType();
|
||||
String getURL();
|
||||
String getUser();
|
||||
String getWorkstationID();
|
||||
boolean getDelayLoadingLobs();
|
||||
boolean getDisableStatementPooling();
|
||||
boolean getEnablePrepareOnFirstPreparedStatementCall();
|
||||
boolean getFIPS();
|
||||
boolean getLastUpdateCount();
|
||||
boolean getMultiSubnetFailover();
|
||||
boolean getReplication();
|
||||
boolean getSendStringParametersAsUnicode();
|
||||
boolean getSendTemporalDataTypesAsStringForBulkCopy();
|
||||
boolean getSendTimeAsDatetime();
|
||||
boolean getServerNameAsACE();
|
||||
boolean getTransparentNetworkIPResolution();
|
||||
boolean getTrustServerCertificate();
|
||||
boolean getUseBulkCopyForBatchInsert();
|
||||
boolean getUseFmtOnly();
|
||||
boolean getXopenStates();
|
||||
int getCancelQueryTimeout();
|
||||
int getConnectRetryCount();
|
||||
int getConnectRetryInterval();
|
||||
int getLockTimeout();
|
||||
int getMsiTokenCacheTtl();
|
||||
int getPacketSize();
|
||||
int getPortNumber();
|
||||
int getQueryTimeout();
|
||||
int getServerPreparedStatementDiscardThreshold();
|
||||
int getSocketTimeout();
|
||||
int getStatementPoolingCacheSize();
|
||||
void setAADSecurePrincipalId(String p0);
|
||||
void setAADSecurePrincipalSecret(String p0);
|
||||
void setAccessToken(String p0);
|
||||
void setAccessTokenCallback(SQLServerAccessTokenCallback p0);
|
||||
void setApplicationIntent(String p0);
|
||||
void setApplicationName(String p0);
|
||||
void setAuthentication(String p0);
|
||||
void setAuthenticationScheme(String p0);
|
||||
void setCancelQueryTimeout(int p0);
|
||||
void setClientCertificate(String p0);
|
||||
void setClientKey(String p0);
|
||||
void setClientKeyPassword(String p0);
|
||||
void setColumnEncryptionSetting(String p0);
|
||||
void setConnectRetryCount(int p0);
|
||||
void setConnectRetryInterval(int p0);
|
||||
void setDatabaseName(String p0);
|
||||
void setDatetimeParameterType(String p0);
|
||||
void setDelayLoadingLobs(boolean p0);
|
||||
void setDescription(String p0);
|
||||
void setDisableStatementPooling(boolean p0);
|
||||
void setDomain(String p0);
|
||||
void setEnablePrepareOnFirstPreparedStatementCall(boolean p0);
|
||||
void setEnclaveAttestationProtocol(String p0);
|
||||
void setEnclaveAttestationUrl(String p0);
|
||||
void setEncrypt(String p0);
|
||||
void setEncrypt(boolean p0);
|
||||
void setFIPS(boolean p0);
|
||||
void setFailoverPartner(String p0);
|
||||
void setGSSCredentials(GSSCredential p0);
|
||||
void setHostNameInCertificate(String p0);
|
||||
void setIPAddressPreference(String p0);
|
||||
void setInstanceName(String p0);
|
||||
void setIntegratedSecurity(boolean p0);
|
||||
void setJAASConfigurationName(String p0);
|
||||
void setJASSConfigurationName(String p0);
|
||||
void setKeyStoreAuthentication(String p0);
|
||||
void setKeyStoreLocation(String p0);
|
||||
void setKeyStorePrincipalId(String p0);
|
||||
void setKeyStoreSecret(String p0);
|
||||
void setKeyVaultProviderClientId(String p0);
|
||||
void setKeyVaultProviderClientKey(String p0);
|
||||
void setLastUpdateCount(boolean p0);
|
||||
void setLockTimeout(int p0);
|
||||
void setMSIClientId(String p0);
|
||||
void setMaxResultBuffer(String p0);
|
||||
void setMsiTokenCacheTtl(int p0);
|
||||
void setMultiSubnetFailover(boolean p0);
|
||||
void setPacketSize(int p0);
|
||||
void setPassword(String p0);
|
||||
void setPortNumber(int p0);
|
||||
void setPrepareMethod(String p0);
|
||||
void setQueryTimeout(int p0);
|
||||
void setRealm(String p0);
|
||||
void setReplication(boolean p0);
|
||||
void setResponseBuffering(String p0);
|
||||
void setSSLProtocol(String p0);
|
||||
void setSelectMethod(String p0);
|
||||
void setSendStringParametersAsUnicode(boolean p0);
|
||||
void setSendTemporalDataTypesAsStringForBulkCopy(boolean p0);
|
||||
void setSendTimeAsDatetime(boolean p0);
|
||||
void setServerCertificate(String p0);
|
||||
void setServerName(String p0);
|
||||
void setServerNameAsACE(boolean p0);
|
||||
void setServerPreparedStatementDiscardThreshold(int p0);
|
||||
void setServerSpn(String p0);
|
||||
void setSocketFactoryClass(String p0);
|
||||
void setSocketFactoryConstructorArg(String p0);
|
||||
void setSocketTimeout(int p0);
|
||||
void setStatementPoolingCacheSize(int p0);
|
||||
void setTransparentNetworkIPResolution(boolean p0);
|
||||
void setTrustManagerClass(String p0);
|
||||
void setTrustManagerConstructorArg(String p0);
|
||||
void setTrustServerCertificate(boolean p0);
|
||||
void setTrustStore(String p0);
|
||||
void setTrustStorePassword(String p0);
|
||||
void setTrustStoreType(String p0);
|
||||
void setURL(String p0);
|
||||
void setUseBulkCopyForBatchInsert(boolean p0);
|
||||
void setUseFmtOnly(boolean p0);
|
||||
void setUser(String p0);
|
||||
void setWorkstationID(String p0);
|
||||
void setXopenStates(boolean p0);
|
||||
}
|
||||
10
java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerAccessTokenCallback.java
generated
Normal file
10
java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerAccessTokenCallback.java
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
// Generated automatically from com.microsoft.sqlserver.jdbc.SQLServerAccessTokenCallback for testing purposes
|
||||
|
||||
package com.microsoft.sqlserver.jdbc;
|
||||
|
||||
import com.microsoft.sqlserver.jdbc.SqlAuthenticationToken;
|
||||
|
||||
public interface SQLServerAccessTokenCallback
|
||||
{
|
||||
SqlAuthenticationToken getAccessToken(String p0, String p1);
|
||||
}
|
||||
185
java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java
generated
Normal file
185
java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java
generated
Normal file
@@ -0,0 +1,185 @@
|
||||
// Generated automatically from com.microsoft.sqlserver.jdbc.SQLServerDataSource for testing purposes
|
||||
|
||||
package com.microsoft.sqlserver.jdbc;
|
||||
|
||||
import com.microsoft.sqlserver.jdbc.ISQLServerDataSource;
|
||||
import com.microsoft.sqlserver.jdbc.SQLServerAccessTokenCallback;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.util.logging.Logger;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.sql.DataSource;
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
|
||||
public class SQLServerDataSource implements DataSource, ISQLServerDataSource, Referenceable, Serializable
|
||||
{
|
||||
public <T> T unwrap(Class<T> p0){ return null; }
|
||||
public Connection getConnection(){ return null; }
|
||||
public Connection getConnection(String p0, String p1){ return null; }
|
||||
public GSSCredential getGSSCredentials(){ return null; }
|
||||
public Logger getParentLogger(){ return null; }
|
||||
public PrintWriter getLogWriter(){ return null; }
|
||||
public Reference getReference(){ return null; }
|
||||
public SQLServerAccessTokenCallback getAccessTokenCallback(){ return null; }
|
||||
public SQLServerDataSource(){}
|
||||
public String getAADSecurePrincipalId(){ return null; }
|
||||
public String getAccessToken(){ return null; }
|
||||
public String getApplicationIntent(){ return null; }
|
||||
public String getApplicationName(){ return null; }
|
||||
public String getAuthentication(){ return null; }
|
||||
public String getClientCertificate(){ return null; }
|
||||
public String getClientKey(){ return null; }
|
||||
public String getColumnEncryptionSetting(){ return null; }
|
||||
public String getDatabaseName(){ return null; }
|
||||
public String getDatetimeParameterType(){ return null; }
|
||||
public String getDescription(){ return null; }
|
||||
public String getDomain(){ return null; }
|
||||
public String getEnclaveAttestationProtocol(){ return null; }
|
||||
public String getEnclaveAttestationUrl(){ return null; }
|
||||
public String getEncrypt(){ return null; }
|
||||
public String getFailoverPartner(){ return null; }
|
||||
public String getHostNameInCertificate(){ return null; }
|
||||
public String getIPAddressPreference(){ return null; }
|
||||
public String getInstanceName(){ return null; }
|
||||
public String getJAASConfigurationName(){ return null; }
|
||||
public String getJASSConfigurationName(){ return null; }
|
||||
public String getKeyStoreAuthentication(){ return null; }
|
||||
public String getKeyStoreLocation(){ return null; }
|
||||
public String getKeyStorePrincipalId(){ return null; }
|
||||
public String getKeyVaultProviderClientId(){ return null; }
|
||||
public String getMSIClientId(){ return null; }
|
||||
public String getMaxResultBuffer(){ return null; }
|
||||
public String getPrepareMethod(){ return null; }
|
||||
public String getRealm(){ return null; }
|
||||
public String getResponseBuffering(){ return null; }
|
||||
public String getSSLProtocol(){ return null; }
|
||||
public String getSelectMethod(){ return null; }
|
||||
public String getServerCertificate(){ return null; }
|
||||
public String getServerName(){ return null; }
|
||||
public String getServerSpn(){ return null; }
|
||||
public String getSocketFactoryClass(){ return null; }
|
||||
public String getSocketFactoryConstructorArg(){ return null; }
|
||||
public String getTrustManagerClass(){ return null; }
|
||||
public String getTrustManagerConstructorArg(){ return null; }
|
||||
public String getTrustStore(){ return null; }
|
||||
public String getTrustStoreType(){ return null; }
|
||||
public String getURL(){ return null; }
|
||||
public String getUser(){ return null; }
|
||||
public String getWorkstationID(){ return null; }
|
||||
public String toString(){ return null; }
|
||||
public boolean getDelayLoadingLobs(){ return false; }
|
||||
public boolean getDisableStatementPooling(){ return false; }
|
||||
public boolean getEnablePrepareOnFirstPreparedStatementCall(){ return false; }
|
||||
public boolean getFIPS(){ return false; }
|
||||
public boolean getLastUpdateCount(){ return false; }
|
||||
public boolean getMultiSubnetFailover(){ return false; }
|
||||
public boolean getReplication(){ return false; }
|
||||
public boolean getSendStringParametersAsUnicode(){ return false; }
|
||||
public boolean getSendTemporalDataTypesAsStringForBulkCopy(){ return false; }
|
||||
public boolean getSendTimeAsDatetime(){ return false; }
|
||||
public boolean getServerNameAsACE(){ return false; }
|
||||
public boolean getTransparentNetworkIPResolution(){ return false; }
|
||||
public boolean getTrustServerCertificate(){ return false; }
|
||||
public boolean getUseBulkCopyForBatchInsert(){ return false; }
|
||||
public boolean getUseFmtOnly(){ return false; }
|
||||
public boolean getXopenStates(){ return false; }
|
||||
public boolean isWrapperFor(Class<? extends Object> p0){ return false; }
|
||||
public int getCancelQueryTimeout(){ return 0; }
|
||||
public int getConnectRetryCount(){ return 0; }
|
||||
public int getConnectRetryInterval(){ return 0; }
|
||||
public int getLockTimeout(){ return 0; }
|
||||
public int getLoginTimeout(){ return 0; }
|
||||
public int getMsiTokenCacheTtl(){ return 0; }
|
||||
public int getPacketSize(){ return 0; }
|
||||
public int getPortNumber(){ return 0; }
|
||||
public int getQueryTimeout(){ return 0; }
|
||||
public int getServerPreparedStatementDiscardThreshold(){ return 0; }
|
||||
public int getSocketTimeout(){ return 0; }
|
||||
public int getStatementPoolingCacheSize(){ return 0; }
|
||||
public void setAADSecurePrincipalId(String p0){}
|
||||
public void setAADSecurePrincipalSecret(String p0){}
|
||||
public void setAccessToken(String p0){}
|
||||
public void setAccessTokenCallback(SQLServerAccessTokenCallback p0){}
|
||||
public void setApplicationIntent(String p0){}
|
||||
public void setApplicationName(String p0){}
|
||||
public void setAuthentication(String p0){}
|
||||
public void setAuthenticationScheme(String p0){}
|
||||
public void setCancelQueryTimeout(int p0){}
|
||||
public void setClientCertificate(String p0){}
|
||||
public void setClientKey(String p0){}
|
||||
public void setClientKeyPassword(String p0){}
|
||||
public void setColumnEncryptionSetting(String p0){}
|
||||
public void setConnectRetryCount(int p0){}
|
||||
public void setConnectRetryInterval(int p0){}
|
||||
public void setDatabaseName(String p0){}
|
||||
public void setDatetimeParameterType(String p0){}
|
||||
public void setDelayLoadingLobs(boolean p0){}
|
||||
public void setDescription(String p0){}
|
||||
public void setDisableStatementPooling(boolean p0){}
|
||||
public void setDomain(String p0){}
|
||||
public void setEnablePrepareOnFirstPreparedStatementCall(boolean p0){}
|
||||
public void setEnclaveAttestationProtocol(String p0){}
|
||||
public void setEnclaveAttestationUrl(String p0){}
|
||||
public void setEncrypt(String p0){}
|
||||
public void setEncrypt(boolean p0){}
|
||||
public void setFIPS(boolean p0){}
|
||||
public void setFailoverPartner(String p0){}
|
||||
public void setGSSCredentials(GSSCredential p0){}
|
||||
public void setHostNameInCertificate(String p0){}
|
||||
public void setIPAddressPreference(String p0){}
|
||||
public void setInstanceName(String p0){}
|
||||
public void setIntegratedSecurity(boolean p0){}
|
||||
public void setJAASConfigurationName(String p0){}
|
||||
public void setJASSConfigurationName(String p0){}
|
||||
public void setKeyStoreAuthentication(String p0){}
|
||||
public void setKeyStoreLocation(String p0){}
|
||||
public void setKeyStorePrincipalId(String p0){}
|
||||
public void setKeyStoreSecret(String p0){}
|
||||
public void setKeyVaultProviderClientId(String p0){}
|
||||
public void setKeyVaultProviderClientKey(String p0){}
|
||||
public void setLastUpdateCount(boolean p0){}
|
||||
public void setLockTimeout(int p0){}
|
||||
public void setLogWriter(PrintWriter p0){}
|
||||
public void setLoginTimeout(int p0){}
|
||||
public void setMSIClientId(String p0){}
|
||||
public void setMaxResultBuffer(String p0){}
|
||||
public void setMsiTokenCacheTtl(int p0){}
|
||||
public void setMultiSubnetFailover(boolean p0){}
|
||||
public void setPacketSize(int p0){}
|
||||
public void setPassword(String p0){}
|
||||
public void setPortNumber(int p0){}
|
||||
public void setPrepareMethod(String p0){}
|
||||
public void setQueryTimeout(int p0){}
|
||||
public void setRealm(String p0){}
|
||||
public void setReplication(boolean p0){}
|
||||
public void setResponseBuffering(String p0){}
|
||||
public void setSSLProtocol(String p0){}
|
||||
public void setSelectMethod(String p0){}
|
||||
public void setSendStringParametersAsUnicode(boolean p0){}
|
||||
public void setSendTemporalDataTypesAsStringForBulkCopy(boolean p0){}
|
||||
public void setSendTimeAsDatetime(boolean p0){}
|
||||
public void setServerCertificate(String p0){}
|
||||
public void setServerName(String p0){}
|
||||
public void setServerNameAsACE(boolean p0){}
|
||||
public void setServerPreparedStatementDiscardThreshold(int p0){}
|
||||
public void setServerSpn(String p0){}
|
||||
public void setSocketFactoryClass(String p0){}
|
||||
public void setSocketFactoryConstructorArg(String p0){}
|
||||
public void setSocketTimeout(int p0){}
|
||||
public void setStatementPoolingCacheSize(int p0){}
|
||||
public void setTransparentNetworkIPResolution(boolean p0){}
|
||||
public void setTrustManagerClass(String p0){}
|
||||
public void setTrustManagerConstructorArg(String p0){}
|
||||
public void setTrustServerCertificate(boolean p0){}
|
||||
public void setTrustStore(String p0){}
|
||||
public void setTrustStorePassword(String p0){}
|
||||
public void setTrustStoreType(String p0){}
|
||||
public void setURL(String p0){}
|
||||
public void setUseBulkCopyForBatchInsert(boolean p0){}
|
||||
public void setUseFmtOnly(boolean p0){}
|
||||
public void setUser(String p0){}
|
||||
public void setWorkstationID(String p0){}
|
||||
public void setXopenStates(boolean p0){}
|
||||
}
|
||||
16
java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SqlAuthenticationToken.java
generated
Normal file
16
java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SqlAuthenticationToken.java
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
// Generated automatically from com.microsoft.sqlserver.jdbc.SqlAuthenticationToken for testing purposes
|
||||
|
||||
package com.microsoft.sqlserver.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
public class SqlAuthenticationToken implements Serializable
|
||||
{
|
||||
protected SqlAuthenticationToken() {}
|
||||
public Date getExpiresOn(){ return null; }
|
||||
public SqlAuthenticationToken(String p0, Date p1){}
|
||||
public SqlAuthenticationToken(String p0, long p1){}
|
||||
public String getAccessToken(){ return null; }
|
||||
public String toString(){ return null; }
|
||||
}
|
||||
11
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/SecretKey.java
generated
Normal file
11
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/SecretKey.java
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
// Generated automatically from javax.crypto.SecretKey for testing purposes
|
||||
|
||||
package javax.crypto;
|
||||
|
||||
import java.security.Key;
|
||||
import javax.security.auth.Destroyable;
|
||||
|
||||
public interface SecretKey extends Destroyable, Key
|
||||
{
|
||||
static long serialVersionUID = 0;
|
||||
}
|
||||
18
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/spec/SecretKeySpec.java
generated
Normal file
18
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/spec/SecretKeySpec.java
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
// Generated automatically from javax.crypto.spec.SecretKeySpec for testing purposes
|
||||
|
||||
package javax.crypto.spec;
|
||||
|
||||
import java.security.spec.KeySpec;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class SecretKeySpec implements KeySpec, SecretKey
|
||||
{
|
||||
protected SecretKeySpec() {}
|
||||
public SecretKeySpec(byte[] p0, String p1){}
|
||||
public SecretKeySpec(byte[] p0, int p1, int p2, String p3){}
|
||||
public String getAlgorithm(){ return null; }
|
||||
public String getFormat(){ return null; }
|
||||
public boolean equals(Object p0){ return false; }
|
||||
public byte[] getEncoded(){ return null; }
|
||||
public int hashCode(){ return 0; }
|
||||
}
|
||||
17
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/RefAddr.java
generated
Normal file
17
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/RefAddr.java
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
// Generated automatically from javax.naming.RefAddr for testing purposes
|
||||
|
||||
package javax.naming;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
abstract public class RefAddr implements Serializable
|
||||
{
|
||||
protected RefAddr() {}
|
||||
protected RefAddr(String p0){}
|
||||
protected String addrType = null;
|
||||
public String getType(){ return null; }
|
||||
public String toString(){ return null; }
|
||||
public abstract Object getContent();
|
||||
public boolean equals(Object p0){ return false; }
|
||||
public int hashCode(){ return 0; }
|
||||
}
|
||||
36
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Reference.java
generated
Normal file
36
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Reference.java
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
// Generated automatically from javax.naming.Reference for testing purposes
|
||||
|
||||
package javax.naming;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
import javax.naming.RefAddr;
|
||||
|
||||
public class Reference implements Cloneable, Serializable
|
||||
{
|
||||
protected Reference() {}
|
||||
protected String classFactory = null;
|
||||
protected String classFactoryLocation = null;
|
||||
protected String className = null;
|
||||
protected Vector<RefAddr> addrs = null;
|
||||
public Enumeration<RefAddr> getAll(){ return null; }
|
||||
public Object clone(){ return null; }
|
||||
public Object remove(int p0){ return null; }
|
||||
public RefAddr get(String p0){ return null; }
|
||||
public RefAddr get(int p0){ return null; }
|
||||
public Reference(String p0){}
|
||||
public Reference(String p0, RefAddr p1){}
|
||||
public Reference(String p0, RefAddr p1, String p2, String p3){}
|
||||
public Reference(String p0, String p1, String p2){}
|
||||
public String getClassName(){ return null; }
|
||||
public String getFactoryClassLocation(){ return null; }
|
||||
public String getFactoryClassName(){ return null; }
|
||||
public String toString(){ return null; }
|
||||
public boolean equals(Object p0){ return false; }
|
||||
public int hashCode(){ return 0; }
|
||||
public int size(){ return 0; }
|
||||
public void add(RefAddr p0){}
|
||||
public void add(int p0, RefAddr p1){}
|
||||
public void clear(){}
|
||||
}
|
||||
10
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Referenceable.java
generated
Normal file
10
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Referenceable.java
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
// Generated automatically from javax.naming.Referenceable for testing purposes
|
||||
|
||||
package javax.naming;
|
||||
|
||||
import javax.naming.Reference;
|
||||
|
||||
public interface Referenceable
|
||||
{
|
||||
Reference getReference();
|
||||
}
|
||||
10
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/security/auth/Destroyable.java
generated
Normal file
10
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/security/auth/Destroyable.java
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
// Generated automatically from javax.security.auth.Destroyable for testing purposes
|
||||
|
||||
package javax.security.auth;
|
||||
|
||||
|
||||
public interface Destroyable
|
||||
{
|
||||
default boolean isDestroyed(){ return false; }
|
||||
default void destroy(){}
|
||||
}
|
||||
17
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/CommonDataSource.java
generated
Normal file
17
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/CommonDataSource.java
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
// Generated automatically from javax.sql.CommonDataSource for testing purposes
|
||||
|
||||
package javax.sql;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.ShardingKeyBuilder;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public interface CommonDataSource
|
||||
{
|
||||
Logger getParentLogger();
|
||||
PrintWriter getLogWriter();
|
||||
default ShardingKeyBuilder createShardingKeyBuilder(){ return null; }
|
||||
int getLoginTimeout();
|
||||
void setLogWriter(PrintWriter p0);
|
||||
void setLoginTimeout(int p0);
|
||||
}
|
||||
20
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/DataSource.java
generated
Normal file
20
java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/DataSource.java
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
// Generated automatically from javax.sql.DataSource for testing purposes
|
||||
|
||||
package javax.sql;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ConnectionBuilder;
|
||||
import java.sql.Wrapper;
|
||||
import javax.sql.CommonDataSource;
|
||||
|
||||
public interface DataSource extends CommonDataSource, Wrapper
|
||||
{
|
||||
Connection getConnection();
|
||||
Connection getConnection(String p0, String p1);
|
||||
PrintWriter getLogWriter();
|
||||
default ConnectionBuilder createConnectionBuilder(){ return null; }
|
||||
int getLoginTimeout();
|
||||
void setLogWriter(PrintWriter p0);
|
||||
void setLoginTimeout(int p0);
|
||||
}
|
||||
27
java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSCredential.java
generated
Normal file
27
java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSCredential.java
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
// Generated automatically from org.ietf.jgss.GSSCredential for testing purposes
|
||||
|
||||
package org.ietf.jgss;
|
||||
|
||||
import org.ietf.jgss.GSSName;
|
||||
import org.ietf.jgss.Oid;
|
||||
|
||||
public interface GSSCredential extends Cloneable
|
||||
{
|
||||
GSSName getName();
|
||||
GSSName getName(Oid p0);
|
||||
Oid[] getMechs();
|
||||
boolean equals(Object p0);
|
||||
int getRemainingAcceptLifetime(Oid p0);
|
||||
int getRemainingInitLifetime(Oid p0);
|
||||
int getRemainingLifetime();
|
||||
int getUsage();
|
||||
int getUsage(Oid p0);
|
||||
int hashCode();
|
||||
static int ACCEPT_ONLY = 0;
|
||||
static int DEFAULT_LIFETIME = 0;
|
||||
static int INDEFINITE_LIFETIME = 0;
|
||||
static int INITIATE_AND_ACCEPT = 0;
|
||||
static int INITIATE_ONLY = 0;
|
||||
void add(GSSName p0, int p1, int p2, Oid p3, int p4);
|
||||
void dispose();
|
||||
}
|
||||
24
java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSName.java
generated
Normal file
24
java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSName.java
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
// Generated automatically from org.ietf.jgss.GSSName for testing purposes
|
||||
|
||||
package org.ietf.jgss;
|
||||
|
||||
import org.ietf.jgss.Oid;
|
||||
|
||||
public interface GSSName
|
||||
{
|
||||
GSSName canonicalize(Oid p0);
|
||||
Oid getStringNameType();
|
||||
String toString();
|
||||
boolean equals(GSSName p0);
|
||||
boolean equals(Object p0);
|
||||
boolean isAnonymous();
|
||||
boolean isMN();
|
||||
byte[] export();
|
||||
int hashCode();
|
||||
static Oid NT_ANONYMOUS = null;
|
||||
static Oid NT_EXPORT_NAME = null;
|
||||
static Oid NT_HOSTBASED_SERVICE = null;
|
||||
static Oid NT_MACHINE_UID_NAME = null;
|
||||
static Oid NT_STRING_UID_NAME = null;
|
||||
static Oid NT_USER_NAME = null;
|
||||
}
|
||||
18
java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/Oid.java
generated
Normal file
18
java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/Oid.java
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
// Generated automatically from org.ietf.jgss.Oid for testing purposes
|
||||
|
||||
package org.ietf.jgss;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Oid
|
||||
{
|
||||
protected Oid() {}
|
||||
public Oid(InputStream p0){}
|
||||
public Oid(String p0){}
|
||||
public Oid(byte[] p0){}
|
||||
public String toString(){ return null; }
|
||||
public boolean containedIn(Oid[] p0){ return false; }
|
||||
public boolean equals(Object p0){ return false; }
|
||||
public byte[] getDER(){ return null; }
|
||||
public int hashCode(){ return 0; }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Fixed module resolution so we properly recognize definitions made within if-then-else statements.
|
||||
@@ -71,13 +71,19 @@ module ImportResolution {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate module_export(Module m, string name, DataFlow::CfgNode defn) {
|
||||
exists(EssaVariable v |
|
||||
exists(EssaVariable v, EssaDefinition essaDef |
|
||||
v.getName() = name and
|
||||
v.getAUse() = ImportStar::getStarImported*(m).getANormalExit()
|
||||
v.getAUse() = ImportStar::getStarImported*(m).getANormalExit() and
|
||||
(
|
||||
essaDef = v.getDefinition()
|
||||
or
|
||||
// to handle definitions guarded by if-then-else
|
||||
essaDef = v.getDefinition().(PhiFunction).getAnInput()
|
||||
)
|
||||
|
|
||||
defn.getNode() = v.getDefinition().(AssignmentDefinition).getValue()
|
||||
defn.getNode() = essaDef.(AssignmentDefinition).getValue()
|
||||
or
|
||||
defn.getNode() = v.getDefinition().(ArgumentRefinement).getArgument()
|
||||
defn.getNode() = essaDef.(ArgumentRefinement).getArgument()
|
||||
)
|
||||
or
|
||||
exists(Alias a |
|
||||
|
||||
@@ -1,36 +1,30 @@
|
||||
import os.path
|
||||
from flask import Flask, request, abort
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
urlpatterns = [
|
||||
# Route to user_picture
|
||||
url(r'^user-pic1$', user_picture1, name='user-picture1'),
|
||||
url(r'^user-pic2$', user_picture2, name='user-picture2'),
|
||||
url(r'^user-pic3$', user_picture3, name='user-picture3')
|
||||
]
|
||||
|
||||
|
||||
def user_picture1(request):
|
||||
"""A view that is vulnerable to malicious file access."""
|
||||
filename = request.GET.get('p')
|
||||
@app.route("/user_picture1")
|
||||
def user_picture1():
|
||||
filename = request.args.get('p')
|
||||
# BAD: This could read any file on the file system
|
||||
data = open(filename, 'rb').read()
|
||||
return HttpResponse(data)
|
||||
return data
|
||||
|
||||
def user_picture2(request):
|
||||
"""A view that is vulnerable to malicious file access."""
|
||||
@app.route("/user_picture2")
|
||||
def user_picture2():
|
||||
base_path = '/server/static/images'
|
||||
filename = request.GET.get('p')
|
||||
filename = request.args.get('p')
|
||||
# BAD: This could still read any file on the file system
|
||||
data = open(os.path.join(base_path, filename), 'rb').read()
|
||||
return HttpResponse(data)
|
||||
return data
|
||||
|
||||
def user_picture3(request):
|
||||
"""A view that is not vulnerable to malicious file access."""
|
||||
@app.route("/user_picture3")
|
||||
def user_picture3():
|
||||
base_path = '/server/static/images'
|
||||
filename = request.GET.get('p')
|
||||
filename = request.args.get('p')
|
||||
#GOOD -- Verify with normalised version of path
|
||||
fullpath = os.path.normpath(os.path.join(base_path, filename))
|
||||
if not fullpath.startswith(base_path):
|
||||
raise SecurityException()
|
||||
raise Exception("not allowed")
|
||||
data = open(fullpath, 'rb').read()
|
||||
return HttpResponse(data)
|
||||
return data
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
import sys
|
||||
import tarfile
|
||||
|
||||
with tarfile.open('archive.zip') as tar:
|
||||
with tarfile.open(sys.argv[1]) as tar:
|
||||
#BAD : This could write any file on the filesystem.
|
||||
for entry in tar:
|
||||
tar.extract(entry, "/tmp/unpack/")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
import sys
|
||||
import tarfile
|
||||
import os.path
|
||||
|
||||
with tarfile.open('archive.zip') as tar:
|
||||
with tarfile.open(sys.argv[1]) as tar:
|
||||
for entry in tar:
|
||||
#GOOD: Check that entry is safe
|
||||
if os.path.isabs(entry.name) or ".." in entry.name:
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Extracting files from a malicious tarball without validating that the destination file path
|
||||
is within the destination directory using <code>shutil.unpack_archive()</code> can cause files outside the
|
||||
destination directory to be overwritten, due to the possible presence of directory traversal elements
|
||||
(<code>..</code>) in archive path names.</p>
|
||||
|
||||
<p>Tarball contain archive entries representing each file in the archive. These entries
|
||||
include a file path for the entry, but these file paths are not restricted and may contain
|
||||
unexpected special elements such as the directory traversal element (<code>..</code>). If these
|
||||
file paths are used to determine an output file to write the contents of the archive item to, then
|
||||
the file may be written to an unexpected location. This can result in sensitive information being
|
||||
revealed or deleted, or an attacker being able to influence behavior by modifying unexpected
|
||||
files.</p>
|
||||
|
||||
<p>For example, if a tarball contains a file entry <code>../sneaky-file.txt</code>, and the tarball
|
||||
is extracted to the directory <code>/tmp/tmp123</code>, then naively combining the paths would result
|
||||
in an output file path of <code>/tmp/tmp123/../sneaky-file.txt</code>, which would cause the file to be
|
||||
written to <code>/tmp/</code>.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Ensure that output paths constructed from tarball entries are validated
|
||||
to prevent writing files to unexpected locations.</p>
|
||||
|
||||
<p>Consider using a safer module, such as: <code>zipfile</code></p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
In this example an archive is extracted without validating file paths.
|
||||
</p>
|
||||
|
||||
<sample src="examples/HIT_UnsafeUnpack.py" />
|
||||
|
||||
<p>To fix this vulnerability, we need to call the function <code>tarfile.extract()</code>
|
||||
on each <code>member</code> after verifying that it does not contain either <code>..</code> or startswith <code>/</code>.
|
||||
</p>
|
||||
|
||||
<sample src="examples/NoHIT_UnsafeUnpack.py" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
Shutil official documentation
|
||||
<a href="https://docs.python.org/3/library/shutil.html?highlight=unpack_archive#shutil.unpack_archive">shutil.unpack_archive() warning.</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @name Arbitrary file write during a tarball extraction from a user controlled source
|
||||
* @description Extracting files from a potentially malicious tarball using `shutil.unpack_archive()` without validating
|
||||
* that the destination file path is within the destination directory can cause files outside
|
||||
* the destination directory to be overwritten. More precisely, if the tarball comes from a user controlled
|
||||
* location either a remote one or cli argument.
|
||||
* @kind path-problem
|
||||
* @id py/unsafe-unpacking
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision high
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-022
|
||||
*/
|
||||
|
||||
import python
|
||||
import experimental.Security.UnsafeUnpackQuery
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from UnsafeUnpackingConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Unsafe extraction from a malicious tarball retrieved from a remote location."
|
||||
@@ -0,0 +1,12 @@
|
||||
import requests
|
||||
import shutil
|
||||
|
||||
url = "https://www.someremote.location/tarball.tar.gz"
|
||||
response = requests.get(url, stream=True)
|
||||
|
||||
tarpath = "/tmp/tmp456/tarball.tar.gz"
|
||||
with open(tarpath, "wb") as f:
|
||||
f.write(response.raw.read())
|
||||
|
||||
untarredpath = "/tmp/tmp123"
|
||||
shutil.unpack_archive(tarpath, untarredpath)
|
||||
@@ -0,0 +1,17 @@
|
||||
import requests
|
||||
import tarfile
|
||||
|
||||
url = "https://www.someremote.location/tarball.tar.gz"
|
||||
response = requests.get(url, stream=True)
|
||||
|
||||
tarpath = "/tmp/tmp456/tarball.tar.gz"
|
||||
with open(tarpath, "wb") as f:
|
||||
f.write(response.raw.read())
|
||||
|
||||
untarredpath = "/tmp/tmp123"
|
||||
with tarfile.open(tarpath) as tar:
|
||||
for member in tar.getmembers():
|
||||
if member.name.startswith("/") or ".." in member.name:
|
||||
raise Exception("Path traversal identified in tarball")
|
||||
|
||||
tar.extract(untarredpath, member)
|
||||
213
python/ql/src/experimental/Security/UnsafeUnpackQuery.qll
Normal file
213
python/ql/src/experimental/Security/UnsafeUnpackQuery.qll
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting "UnsafeUnpacking" vulnerabilities.
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.Concepts
|
||||
import semmle.python.dataflow.new.internal.DataFlowPublic
|
||||
import semmle.python.ApiGraphs
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import semmle.python.frameworks.Stdlib
|
||||
import semmle.python.dataflow.new.RemoteFlowSources
|
||||
|
||||
/**
|
||||
* Handle those three cases of Tarfile opens:
|
||||
* - `tarfile.open()`
|
||||
* - `tarfile.TarFile()`
|
||||
* - `MKtarfile.Tarfile.open()`
|
||||
*/
|
||||
API::Node tarfileOpen() {
|
||||
result in [
|
||||
API::moduleImport("tarfile").getMember(["open", "TarFile"]),
|
||||
API::moduleImport("tarfile").getMember("TarFile").getASubclass().getMember("open")
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for handling the previous three cases, plus the use of `closing` in with the previous cases
|
||||
*/
|
||||
class AllTarfileOpens extends API::CallNode {
|
||||
AllTarfileOpens() {
|
||||
this = tarfileOpen().getACall()
|
||||
or
|
||||
exists(API::Node closing, Node arg |
|
||||
closing = API::moduleImport("contextlib").getMember("closing") and
|
||||
this = closing.getACall() and
|
||||
arg = this.getArg(0) and
|
||||
arg = tarfileOpen().getACall()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class UnsafeUnpackingConfig extends TaintTracking::Configuration {
|
||||
UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
// A source coming from a remote location
|
||||
source instanceof RemoteFlowSource
|
||||
or
|
||||
// A source coming from a CLI argparse module
|
||||
// see argparse: https://docs.python.org/3/library/argparse.html
|
||||
exists(MethodCallNode args |
|
||||
args = source.(AttrRead).getObject().getALocalSource() and
|
||||
args =
|
||||
API::moduleImport("argparse")
|
||||
.getMember("ArgumentParser")
|
||||
.getReturn()
|
||||
.getMember("parse_args")
|
||||
.getACall()
|
||||
)
|
||||
or
|
||||
// A source catching an S3 file download
|
||||
// see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file
|
||||
source =
|
||||
API::moduleImport("boto3")
|
||||
.getMember("client")
|
||||
.getReturn()
|
||||
.getMember(["download_file", "download_fileobj"])
|
||||
.getACall()
|
||||
.getArg(2)
|
||||
or
|
||||
// A source catching an S3 file download
|
||||
// see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html
|
||||
source =
|
||||
API::moduleImport("boto3")
|
||||
.getMember("Session")
|
||||
.getReturn()
|
||||
.getMember("client")
|
||||
.getReturn()
|
||||
.getMember(["download_file", "download_fileobj"])
|
||||
.getACall()
|
||||
.getArg(2)
|
||||
or
|
||||
// A source download a file using wget
|
||||
// see wget: https://pypi.org/project/wget/
|
||||
exists(API::CallNode mcn |
|
||||
mcn = API::moduleImport("wget").getMember("download").getACall() and
|
||||
if exists(mcn.getArg(1)) then source = mcn.getArg(1) else source = mcn.getReturn().asSource()
|
||||
)
|
||||
or
|
||||
// catch the Django uploaded files as a source
|
||||
// see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES
|
||||
source.(AttrRead).getAttributeName() = "FILES"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
(
|
||||
// A sink capturing method calls to `unpack_archive`.
|
||||
sink = API::moduleImport("shutil").getMember("unpack_archive").getACall().getArg(0)
|
||||
or
|
||||
// A sink capturing method calls to `extractall` without `members` argument.
|
||||
// For a call to `file.extractall` without `members` argument, `file` is considered a sink.
|
||||
exists(MethodCallNode call, AllTarfileOpens atfo |
|
||||
call = atfo.getReturn().getMember("extractall").getACall() and
|
||||
not exists(call.getArgByName("members")) and
|
||||
sink = call.getObject()
|
||||
)
|
||||
or
|
||||
// A sink capturing method calls to `extractall` with `members` argument.
|
||||
// For a call to `file.extractall` with `members` argument, `file` is considered a sink if not
|
||||
// a the `members` argument contains a NameConstant as None, a List or call to the method `getmembers`.
|
||||
// Otherwise, the argument of `members` is considered a sink.
|
||||
exists(MethodCallNode call, Node arg, AllTarfileOpens atfo |
|
||||
call = atfo.getReturn().getMember("extractall").getACall() and
|
||||
arg = call.getArgByName("members") and
|
||||
if
|
||||
arg.asCfgNode() instanceof NameConstantNode or
|
||||
arg.asCfgNode() instanceof ListNode
|
||||
then sink = call.getObject()
|
||||
else
|
||||
if arg.(MethodCallNode).getMethodName() = "getmembers"
|
||||
then sink = arg.(MethodCallNode).getObject()
|
||||
else sink = call.getArgByName("members")
|
||||
)
|
||||
or
|
||||
// An argument to `extract` is considered a sink.
|
||||
exists(AllTarfileOpens atfo |
|
||||
sink = atfo.getReturn().getMember("extract").getACall().getArg(0)
|
||||
)
|
||||
or
|
||||
//An argument to `_extract_member` is considered a sink.
|
||||
exists(MethodCallNode call, AllTarfileOpens atfo |
|
||||
call = atfo.getReturn().getMember("_extract_member").getACall() and
|
||||
call.getArg(1).(AttrRead).accesses(sink, "name")
|
||||
)
|
||||
) and
|
||||
not sink.getScope().getLocation().getFile().inStdlib()
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// Reading the response
|
||||
nodeTo.(MethodCallNode).calls(nodeFrom, "read")
|
||||
or
|
||||
// Open a file for access
|
||||
exists(MethodCallNode cn |
|
||||
cn.calls(nodeTo, "open") and
|
||||
cn.flowsTo(nodeFrom)
|
||||
)
|
||||
or
|
||||
// Open a file for access using builtin
|
||||
exists(API::CallNode cn |
|
||||
cn = API::builtin("open").getACall() and
|
||||
nodeTo = cn.getArg(0) and
|
||||
cn.flowsTo(nodeFrom)
|
||||
)
|
||||
or
|
||||
// Write access
|
||||
exists(MethodCallNode cn |
|
||||
cn.calls(nodeTo, "write") and
|
||||
nodeFrom = cn.getArg(0)
|
||||
)
|
||||
or
|
||||
// Retrieve Django uploaded files
|
||||
// see getlist(): https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.QueryDict.getlist
|
||||
// see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks
|
||||
nodeTo.(MethodCallNode).calls(nodeFrom, ["getlist", "get", "chunks"])
|
||||
or
|
||||
// Considering the use of "fs"
|
||||
// see fs: https://docs.djangoproject.com/en/4.1/ref/files/storage/#the-filesystemstorage-class
|
||||
nodeTo =
|
||||
API::moduleImport("django")
|
||||
.getMember("core")
|
||||
.getMember("files")
|
||||
.getMember("storage")
|
||||
.getMember("FileSystemStorage")
|
||||
.getReturn()
|
||||
.getMember(["save", "path"])
|
||||
.getACall() and
|
||||
nodeFrom = nodeTo.(MethodCallNode).getArg(0)
|
||||
or
|
||||
// Accessing the name or raw content
|
||||
nodeTo.(AttrRead).accesses(nodeFrom, ["name", "raw"])
|
||||
or
|
||||
// Join the base_dir to the filename
|
||||
nodeTo = API::moduleImport("os").getMember("path").getMember("join").getACall() and
|
||||
nodeFrom = nodeTo.(API::CallNode).getArg(1)
|
||||
or
|
||||
// Go through an Open for a Tarfile
|
||||
nodeTo = tarfileOpen().getACall() and nodeFrom = nodeTo.(MethodCallNode).getArg(0)
|
||||
or
|
||||
// Handle the case where the getmembers is used.
|
||||
nodeTo.(MethodCallNode).calls(nodeFrom, "getmembers") and
|
||||
nodeFrom instanceof AllTarfileOpens
|
||||
or
|
||||
// To handle the case of `with closing(tarfile.open()) as file:`
|
||||
// we add a step from the first argument of `closing` to the call to `closing`,
|
||||
// whenever that first argument is a return of `tarfile.open()`.
|
||||
nodeTo = API::moduleImport("contextlib").getMember("closing").getACall() and
|
||||
nodeFrom = nodeTo.(API::CallNode).getArg(0) and
|
||||
nodeFrom = tarfileOpen().getReturn().getAValueReachableFromSource()
|
||||
or
|
||||
// see Path : https://docs.python.org/3/library/pathlib.html#pathlib.Path
|
||||
nodeTo = API::moduleImport("pathlib").getMember("Path").getACall() and
|
||||
nodeFrom = nodeTo.(API::CallNode).getArg(0)
|
||||
or
|
||||
// Use of absolutepath
|
||||
// see absolute : https://docs.python.org/3/library/pathlib.html#pathlib.Path.absolute
|
||||
exists(API::CallNode mcn |
|
||||
mcn = API::moduleImport("pathlib").getMember("Path").getACall() and
|
||||
nodeTo = mcn.getAMethodCall("absolute") and
|
||||
nodeFrom = mcn.getArg(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
from trace import *
|
||||
enter(__file__)
|
||||
|
||||
# definition based on "random" choice in this case it will always go the the if-branch,
|
||||
# but our analysis is not able to figure this out
|
||||
if eval("True"):
|
||||
if_then_else_defined = "if_defined"
|
||||
else:
|
||||
# we also check that nested if-then-else works, it would be easy to accidentally
|
||||
# only support _one_ level of nesting.
|
||||
if eval("True"):
|
||||
if_then_else_defined = "else_defined_1"
|
||||
else:
|
||||
if_then_else_defined = "else_defined_2"
|
||||
|
||||
exit(__file__)
|
||||
@@ -89,6 +89,9 @@ check("non_clashing_submodule", non_clashing_submodule, "<module attr_clash.non_
|
||||
from package.subpackage2 import *
|
||||
check("subpackage2_attr", subpackage2_attr, "subpackage2_attr", globals()) #$ prints=subpackage2_attr
|
||||
|
||||
# check that definitions from within if-then-else are found
|
||||
from if_then_else import if_then_else_defined
|
||||
check("if_then_else_defined", if_then_else_defined, "if_defined", globals()) #$ prints=if_defined prints=else_defined_1 prints=else_defined_2
|
||||
|
||||
exit(__file__)
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
missingAnnotationOnSink
|
||||
failures
|
||||
@@ -0,0 +1,3 @@
|
||||
import python
|
||||
import experimental.dataflow.TestUtil.DataflowQueryTest
|
||||
import experimental.Security.UnsafeUnpackQuery
|
||||
@@ -0,0 +1,83 @@
|
||||
edges
|
||||
| UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:5:26:5:32 | GSSA Variable request |
|
||||
| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request |
|
||||
| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath |
|
||||
| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path |
|
||||
| UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file |
|
||||
| UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file |
|
||||
| UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file |
|
||||
| UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath |
|
||||
| UnsafeUnpack.py:103:23:103:27 | SSA variable chunk | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath |
|
||||
| UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript |
|
||||
| UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | UnsafeUnpack.py:103:23:103:27 | SSA variable chunk |
|
||||
| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path |
|
||||
| UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:116:17:116:21 | SSA variable ufile |
|
||||
| UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path |
|
||||
| UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar |
|
||||
| UnsafeUnpack.py:158:23:158:27 | SSA variable chunk | UnsafeUnpack.py:163:23:163:28 | SSA variable member |
|
||||
| UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript |
|
||||
| UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript | UnsafeUnpack.py:158:23:158:27 | SSA variable chunk |
|
||||
| UnsafeUnpack.py:163:23:163:28 | SSA variable member | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result |
|
||||
| UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() |
|
||||
| UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute |
|
||||
nodes
|
||||
| UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | semmle.label | ModuleVariableNode for UnsafeUnpack.request |
|
||||
| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember |
|
||||
| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | semmle.label | GSSA Variable request |
|
||||
| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath |
|
||||
| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path |
|
||||
| UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path |
|
||||
| UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file |
|
||||
| UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file |
|
||||
| UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file |
|
||||
| UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file |
|
||||
| UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath |
|
||||
| UnsafeUnpack.py:103:23:103:27 | SSA variable chunk | semmle.label | SSA variable chunk |
|
||||
| UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | semmle.label | ControlFlowNode for savepath |
|
||||
| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path |
|
||||
| UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | semmle.label | SSA variable ufile |
|
||||
| UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | semmle.label | ControlFlowNode for uploaded_file_path |
|
||||
| UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar |
|
||||
| UnsafeUnpack.py:158:23:158:27 | SSA variable chunk | semmle.label | SSA variable chunk |
|
||||
| UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| UnsafeUnpack.py:163:23:163:28 | SSA variable member | semmle.label | SSA variable member |
|
||||
| UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | semmle.label | ControlFlowNode for result |
|
||||
| UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | semmle.label | ControlFlowNode for tmp |
|
||||
| UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
subpaths
|
||||
#select
|
||||
| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
| UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | Unsafe extraction from a malicious tarball retrieved from a remote location. |
|
||||
@@ -0,0 +1,201 @@
|
||||
import requests
|
||||
import shutil
|
||||
import os
|
||||
|
||||
from flask import Flask, request
|
||||
app = Flask(__name__)
|
||||
|
||||
# Consider any RemoteFlowSource as a source
|
||||
@app.route("/download_from_url")
|
||||
def download_from_url():
|
||||
filename = request.args.get('filename', '')
|
||||
if not filename:
|
||||
response = requests.get(filename, stream=True)
|
||||
|
||||
tarpath = "/tmp/tmp456/tarball.tar.gz"
|
||||
with open(tarpath, "wb") as f:
|
||||
f.write(response.raw.read())
|
||||
untarredpath = "/tmp/tmp123"
|
||||
shutil.unpack_archive(tarpath, untarredpath) # $result=BAD
|
||||
|
||||
|
||||
# A source catching an S3 filename download
|
||||
# see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file
|
||||
import boto3
|
||||
import os
|
||||
|
||||
remote_ziped_name = "remote_name.tar.gz"
|
||||
base_dir = "/tmp/basedir"
|
||||
local_ziped_path = os.path.join(base_dir, remote_ziped_name)
|
||||
bucket_name = "mybucket"
|
||||
|
||||
s3 = boto3.client('s3')
|
||||
s3.download_file(bucket_name, remote_ziped_name, local_ziped_path)
|
||||
shutil.unpack_archive(local_ziped_path, base_dir) # $result=BAD
|
||||
|
||||
|
||||
# wget
|
||||
# see wget: https://pypi.org/project/wget/
|
||||
import wget
|
||||
import os
|
||||
|
||||
url = "https://some.remote/location/remote_name.tar.xz"
|
||||
compressed_file = "/tmp/basedir/local_name.tar.xz"
|
||||
base_dir = "/tmp/basedir"
|
||||
|
||||
# download(url, out, bar) contains out parameter
|
||||
wget.download(url, compressed_file)
|
||||
shutil.unpack_archive(compressed_file, base_dir) # $result=BAD
|
||||
|
||||
# download(url) returns filename
|
||||
compressed_file = wget.download(url)
|
||||
shutil.unpack_archive(compressed_file, base_dir) # $result=BAD
|
||||
|
||||
|
||||
# A source coming from a CLI argparse module
|
||||
# see argparse: https://docs.python.org/3/library/argparse.html
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||
parser.add_argument('integers', metavar='N', type=int, nargs='+',
|
||||
help='an integer for the accumulator')
|
||||
parser.add_argument('filename', help='filename to be provided')
|
||||
|
||||
args = parser.parse_args()
|
||||
compressed_file = args.filename
|
||||
shutil.unpack_archive(compressed_file, base_dir) # $result=BAD
|
||||
|
||||
|
||||
# A source coming from a CLI and downloaded
|
||||
import argparse
|
||||
import requests
|
||||
|
||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||
parser.add_argument('integers', metavar='N', type=int, nargs='+',
|
||||
help='an integer for the accumulator')
|
||||
parser.add_argument('filename', help='url to filename to be provided')
|
||||
|
||||
args = parser.parse_args()
|
||||
url_filename = args.filename
|
||||
|
||||
response = requests.get(url_filename, stream=True)
|
||||
|
||||
tarpath = "/tmp/tmp456/tarball.tar.gz"
|
||||
with open(tarpath, "wb") as f:
|
||||
f.write(response.raw.read())
|
||||
|
||||
shutil.unpack_archive(tarpath, base_dir) # $result=BAD
|
||||
|
||||
# the django upload functionality
|
||||
# see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES
|
||||
from django.shortcuts import render
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
import shutil
|
||||
|
||||
def simple_upload(request):
|
||||
|
||||
base_dir = "/tmp/baase_dir"
|
||||
if request.method == 'POST':
|
||||
# Read uploaded files by chunks of data
|
||||
# see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks
|
||||
savepath = os.path.join(base_dir, "tarball_compressed.tar.gz")
|
||||
with open(savepath, 'wb+') as wfile:
|
||||
for chunk in request.FILES["ufile1"].chunks():
|
||||
wfile.write(chunk)
|
||||
shutil.unpack_archive(savepath, base_dir) # $result=BAD
|
||||
|
||||
# Write in binary the uploaded tarball
|
||||
myfile = request.FILES.get("ufile1")
|
||||
file_path = os.path.join(base_dir, "tarball.tar")
|
||||
with file_path.open('wb') as f:
|
||||
f.write(myfile.read())
|
||||
shutil.unpack_archive(file_path, base_dir) # $result=BAD
|
||||
|
||||
# Save uploaded files using FileSystemStorage Django API
|
||||
# see FileSystemStorage: https://docs.djangoproject.com/en/4.1/ref/files/storage/#django.core.files.storage.FileSystemStorage
|
||||
for ufile in request.FILES.getlist():
|
||||
fs = FileSystemStorage()
|
||||
filename = fs.save(ufile.name, ufile)
|
||||
uploaded_file_path = fs.path(filename)
|
||||
shutil.unpack_archive(uploaded_file_path, base_dir) # $result=BAD
|
||||
|
||||
return render(request, 'simple_upload.html')
|
||||
|
||||
elif request.method == 'GET':
|
||||
return render(request, 'simple_upload.html')
|
||||
|
||||
|
||||
import shutil
|
||||
import os
|
||||
import tarfile
|
||||
import tempfile
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||
parser.add_argument('integers', metavar='N', type=int, nargs='+',
|
||||
help='an integer for the accumulator')
|
||||
parser.add_argument('filename', help='filename to be provided')
|
||||
|
||||
args = parser.parse_args()
|
||||
unsafe_filename_tar = args.filename
|
||||
with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar:
|
||||
tar.extractall(path="/tmp/unpack/", members=tar) # $result=BAD
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
import shutil
|
||||
|
||||
def simple_upload(request):
|
||||
|
||||
base_dir = "/tmp/baase_dir"
|
||||
if request.method == 'POST':
|
||||
# Read uploaded files by chunks of data
|
||||
# see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks
|
||||
savepath = os.path.join(base_dir, "tarball_compressed.tar.gz")
|
||||
with open(savepath, 'wb+') as wfile:
|
||||
for chunk in request.FILES["ufile1"].chunks():
|
||||
wfile.write(chunk)
|
||||
|
||||
tar = tarfile.open(savepath)
|
||||
result = []
|
||||
for member in tar:
|
||||
if member.issym():
|
||||
raise ValueError("But it is a symlink")
|
||||
result.append(member)
|
||||
tar.extractall(path=tempfile.mkdtemp(), members=result) # $result=BAD
|
||||
tar.close()
|
||||
|
||||
|
||||
response = requests.get(url_filename, stream=True)
|
||||
tarpath = "/tmp/tmp456/tarball.tar.gz"
|
||||
with open(tarpath, "wb") as f:
|
||||
f.write(response.raw.read())
|
||||
target_dir = "/tmp/unpack"
|
||||
tarfile.TarFile(tarpath, mode="r").extractall(path=target_dir) # $result=BAD
|
||||
|
||||
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import boto3
|
||||
|
||||
def default_session() -> boto3.Session:
|
||||
_SESSION = None
|
||||
if _SESSION is None:
|
||||
_SESSION = boto3.Session()
|
||||
return _SESSION
|
||||
|
||||
cache = False
|
||||
cache_dir = "/tmp/artifacts"
|
||||
object_path = "/objects/obj1"
|
||||
s3 = default_session().client("s3")
|
||||
with tempfile.NamedTemporaryFile(suffix=".tar.gz") as tmp:
|
||||
s3.download_fileobj(bucket_name, object_path, tmp)
|
||||
tmp.seek(0)
|
||||
if cache:
|
||||
cache_dir.mkdir(exist_ok=True, parents=True)
|
||||
target = cache_dir
|
||||
else:
|
||||
target = Path(tempfile.mkdtemp())
|
||||
shutil.unpack_archive(tmp.name, target) # $result=BAD
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-022bis/UnsafeUnpack.ql
|
||||
@@ -2,5 +2,6 @@
|
||||
| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
|
||||
| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
|
||||
| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. |
|
||||
| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
|
||||
| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
|
||||
| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user