mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge branch 'main' into more-shell-taint
This commit is contained in:
111
.github/actions/cache-query-compilation/action.yml
vendored
111
.github/actions/cache-query-compilation/action.yml
vendored
@@ -9,7 +9,7 @@ inputs:
|
||||
outputs:
|
||||
cache-dir:
|
||||
description: "The directory where the cache was stored"
|
||||
value: ${{ steps.fill-compilation-dir.outputs.compdir }}
|
||||
value: ${{ steps.output-compilation-dir.outputs.compdir }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
@@ -27,7 +27,9 @@ runs:
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: '**/.cache'
|
||||
path: |
|
||||
**/.cache
|
||||
~/.codeql/compile-cache
|
||||
key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }}
|
||||
restore-keys: |
|
||||
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }}
|
||||
@@ -37,18 +39,111 @@ runs:
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '**/.cache'
|
||||
path: |
|
||||
**/.cache
|
||||
~/.codeql/compile-cache
|
||||
key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main
|
||||
restore-keys: | # restore the latest cache if the exact cache is unavailable, to speed up compilation.
|
||||
codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-
|
||||
codeql-compile-${{ inputs.key }}-main-
|
||||
- name: Fill compilation cache directory
|
||||
id: fill-compilation-dir
|
||||
- name: Output-compilationdir
|
||||
id: output-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:
|
||||
COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir
|
||||
- name: Fill compilation cache directory
|
||||
id: fill-compilation-dir
|
||||
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");
|
||||
const os = require("os");
|
||||
|
||||
// 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}`);
|
||||
}
|
||||
|
||||
const globalCacheDir = path.join(os.homedir(), ".codeql", "compile-cache");
|
||||
if (fs.existsSync(globalCacheDir)) {
|
||||
console.log("Found global home dir: " + globalCacheDir);
|
||||
cacheDirs.push(globalCacheDir);
|
||||
}
|
||||
|
||||
if (cacheDirs.length === 0) {
|
||||
console.log("No cache dirs found");
|
||||
return;
|
||||
}
|
||||
|
||||
// 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();
|
||||
6
.github/workflows/compile-queries.yml
vendored
6
.github/workflows/compile-queries.yml
vendored
@@ -24,14 +24,14 @@ jobs:
|
||||
with:
|
||||
key: all-queries
|
||||
- name: check formatting
|
||||
run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 codeql query format --check-only
|
||||
run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
|
||||
- name: compile queries - check-only
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
- name: compile queries - full
|
||||
# do full compile if running on main - this populates the cache
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
|
||||
15
.github/workflows/ql-for-ql-build.yml
vendored
15
.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
|
||||
@@ -22,6 +15,8 @@ jobs:
|
||||
steps:
|
||||
### Build the queries ###
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@v2
|
||||
@@ -34,7 +29,9 @@ jobs:
|
||||
id: cache-extractor
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ql/extractor-pack/
|
||||
path: |
|
||||
ql/extractor-pack/
|
||||
ql/target/release/buramu
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||
- name: Cache cargo
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
@@ -57,6 +54,7 @@ jobs:
|
||||
key: run-ql-for-ql
|
||||
- name: Make database and analyze
|
||||
run: |
|
||||
./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse.
|
||||
${CODEQL} database create -l=ql --search-path ql/extractor-pack ${DB}
|
||||
${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
@@ -65,6 +63,7 @@ jobs:
|
||||
LGTM_INDEX_FILTERS: |
|
||||
exclude:ql/ql/test
|
||||
exclude:*/ql/lib/upgrades/
|
||||
exclude:java/ql/integration-tests
|
||||
- name: Upload sarif to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
|
||||
2
.github/workflows/swift.yml
vendored
2
.github/workflows/swift.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "misc/codegen/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift.yml
|
||||
- .github/actions/**
|
||||
@@ -19,6 +20,7 @@ on:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "misc/codegen/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift.yml
|
||||
- .github/actions/**
|
||||
|
||||
@@ -53,5 +53,5 @@ repos:
|
||||
name: Run Swift code generation unit tests
|
||||
files: ^swift/codegen/.*\.py$
|
||||
language: system
|
||||
entry: bazel test //swift/codegen/test
|
||||
entry: bazel test //misc/codegen/test
|
||||
pass_filenames: false
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
/csharp/ @github/codeql-csharp
|
||||
/go/ @github/codeql-go
|
||||
/java/ @github/codeql-java
|
||||
/javascript/ @github/codeql-javascript
|
||||
/python/ @github/codeql-python
|
||||
/ruby/ @github/codeql-ruby
|
||||
/javascript/ @github/codeql-dynamic
|
||||
/python/ @github/codeql-dynamic
|
||||
/ruby/ @github/codeql-dynamic
|
||||
/swift/ @github/codeql-swift
|
||||
/misc/codegen/ @github/codeql-swift
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
/java/kotlin-explorer/ @github/codeql-kotlin
|
||||
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
cpp/ql/lib/change-notes/released/0.5.3.md
Normal file
3
cpp/ql/lib/change-notes/released/0.5.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.2
|
||||
lastReleaseVersion: 0.5.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.5.3-dev
|
||||
version: 0.5.4-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
cpp/ql/src/change-notes/released/0.5.3.md
Normal file
3
cpp/ql/src/change-notes/released/0.5.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.2
|
||||
lastReleaseVersion: 0.5.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.5.3-dev
|
||||
version: 0.5.4-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -77,12 +77,8 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <summary>
|
||||
/// Gets the source-level modifiers belonging to this symbol, if any.
|
||||
/// </summary>
|
||||
public static IEnumerable<string> GetSourceLevelModifiers(this ISymbol symbol)
|
||||
{
|
||||
var methodModifiers = symbol.GetModifiers<Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax>(md => md.Modifiers);
|
||||
var typeModifiers = symbol.GetModifiers<Microsoft.CodeAnalysis.CSharp.Syntax.TypeDeclarationSyntax>(cd => cd.Modifiers);
|
||||
return methodModifiers.Concat(typeModifiers).Select(m => m.Text);
|
||||
}
|
||||
public static IEnumerable<string> GetSourceLevelModifiers(this ISymbol symbol) =>
|
||||
symbol.GetModifiers<Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax>(md => md.Modifiers).Select(m => m.Text);
|
||||
|
||||
/// <summary>
|
||||
/// Holds if the ID generated for `dependant` will contain a reference to
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.4.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.4.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.4.2
|
||||
lastReleaseVersion: 1.4.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.4.3-dev
|
||||
version: 1.4.4-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.4.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.4.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.4.2
|
||||
lastReleaseVersion: 1.4.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.4.3-dev
|
||||
version: 1.4.4-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
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' })
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.5.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables.
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables.
|
||||
@@ -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.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The extraction of member modifiers has been generalised, which could lead to the extraction of more modifiers.
|
||||
5
csharp/ql/lib/change-notes/released/0.5.3.md
Normal file
5
csharp/ql/lib/change-notes/released/0.5.3.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.5.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.2
|
||||
lastReleaseVersion: 0.5.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.5.3-dev
|
||||
version: 0.5.4-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
@@ -8,6 +8,7 @@ upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
dataExtensions:
|
||||
- ext/*.model.yml
|
||||
- ext/generated/*.model.yml
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,184 +3,34 @@
|
||||
*/
|
||||
|
||||
private import Comments
|
||||
private import codeql.util.FileSystem
|
||||
|
||||
/** A file or folder. */
|
||||
class Container extends @container {
|
||||
/**
|
||||
* Gets the absolute, canonical path of this container, using forward slashes
|
||||
* as path separator.
|
||||
*
|
||||
* The path starts with a _root prefix_ followed by zero or more _path
|
||||
* segments_ separated by forward slashes.
|
||||
*
|
||||
* The root prefix is of one of the following forms:
|
||||
*
|
||||
* 1. A single forward slash `/` (Unix-style)
|
||||
* 2. An upper-case drive letter followed by a colon and a forward slash,
|
||||
* such as `C:/` (Windows-style)
|
||||
* 3. Two forward slashes, a computer name, and then another forward slash,
|
||||
* such as `//FileServer/` (UNC-style)
|
||||
*
|
||||
* Path segments are never empty (that is, absolute paths never contain two
|
||||
* contiguous slashes, except as part of a UNC-style root prefix). Also, path
|
||||
* segments never contain forward slashes, and no path segment is of the
|
||||
* form `.` (one dot) or `..` (two dots).
|
||||
*
|
||||
* Note that an absolute path never ends with a forward slash, except if it is
|
||||
* a bare root prefix, that is, the path has no path segments. A container
|
||||
* whose absolute path has no segments is always a `Folder`, not a `File`.
|
||||
*/
|
||||
string getAbsolutePath() { none() }
|
||||
private module Input implements InputSig {
|
||||
abstract class ContainerBase extends @container {
|
||||
abstract string getAbsolutePath();
|
||||
|
||||
/**
|
||||
* Gets a URL representing the location of this container.
|
||||
*
|
||||
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
|
||||
*/
|
||||
string getURL() { none() }
|
||||
ContainerBase getParentContainer() { containerparent(result, this) }
|
||||
|
||||
/**
|
||||
* Gets the relative path of this file or folder from the root folder of the
|
||||
* analyzed source location. The relative path of the root folder itself is
|
||||
* the empty string.
|
||||
*
|
||||
* This has no result if the container is outside the source root, that is,
|
||||
* if the root folder is not a reflexive, transitive parent of this container.
|
||||
*/
|
||||
string getRelativePath() {
|
||||
exists(string absPath, string pref |
|
||||
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
|
||||
|
|
||||
absPath = pref and result = ""
|
||||
or
|
||||
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
|
||||
not result.matches("/%")
|
||||
)
|
||||
string toString() { result = this.getAbsolutePath() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base name of this container including extension, that is, the last
|
||||
* segment of its absolute path, or the empty string if it has no segments.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding base names
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Base name</th></tr>
|
||||
* <tr><td>"/tmp/tst.cs"</td><td>"tst.cs"</td></tr>
|
||||
* <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr>
|
||||
* <tr><td>"/"</td><td>""</td></tr>
|
||||
* <tr><td>"C:/"</td><td>""</td></tr>
|
||||
* <tr><td>"D:/"</td><td>""</td></tr>
|
||||
* <tr><td>"//FileServer/"</td><td>""</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getBaseName() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
|
||||
class FolderBase extends ContainerBase, @folder {
|
||||
override string getAbsolutePath() { folders(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extension of this container, that is, the suffix of its base name
|
||||
* after the last dot character, if any.
|
||||
*
|
||||
* In particular,
|
||||
*
|
||||
* - if the name does not include a dot, there is no extension, so this
|
||||
* predicate has no result;
|
||||
* - if the name ends in a dot, the extension is the empty string;
|
||||
* - if the name contains multiple dots, the extension follows the last dot.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding extensions
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Extension</th></tr>
|
||||
* <tr><td>"/tmp/tst.cs"</td><td>"cs"</td></tr>
|
||||
* <tr><td>"/tmp/.classpath"</td><td>"classpath"</td></tr>
|
||||
* <tr><td>"/bin/bash"</td><td>not defined</td></tr>
|
||||
* <tr><td>"/tmp/tst2."</td><td>""</td></tr>
|
||||
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getExtension() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
|
||||
class FileBase extends ContainerBase, @file {
|
||||
override string getAbsolutePath() { files(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stem of this container, that is, the prefix of its base name up to
|
||||
* (but not including) the last dot character if there is one, or the entire
|
||||
* base name if there is not.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding stems
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Stem</th></tr>
|
||||
* <tr><td>"/tmp/tst.cs"</td><td>"tst"</td></tr>
|
||||
* <tr><td>"/tmp/.classpath"</td><td>""</td></tr>
|
||||
* <tr><td>"/bin/bash"</td><td>"bash"</td></tr>
|
||||
* <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr>
|
||||
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getStem() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
|
||||
}
|
||||
|
||||
/** Gets the parent container of this file or folder, if any. */
|
||||
Container getParentContainer() { containerparent(result, this) }
|
||||
|
||||
/** Gets a file or sub-folder in this container. */
|
||||
Container getAChildContainer() { this = result.getParentContainer() }
|
||||
|
||||
/** Gets a file in this container. */
|
||||
File getAFile() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the file in this container that has the given `baseName`, if any. */
|
||||
File getFile(string baseName) {
|
||||
result = this.getAFile() and
|
||||
result.getBaseName() = baseName
|
||||
}
|
||||
|
||||
/** Gets a sub-folder in this container. */
|
||||
Folder getAFolder() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
|
||||
Folder getFolder(string baseName) {
|
||||
result = this.getAFolder() and
|
||||
result.getBaseName() = baseName
|
||||
}
|
||||
|
||||
/** Gets the file or sub-folder in this container that has the given `name`, if any. */
|
||||
Container getChildContainer(string name) {
|
||||
result = this.getAChildContainer() and
|
||||
result.getBaseName() = name
|
||||
}
|
||||
|
||||
/** Gets the file in this container that has the given `stem` and `extension`, if any. */
|
||||
File getFile(string stem, string extension) {
|
||||
result = this.getAChildContainer() and
|
||||
result.getStem() = stem and
|
||||
result.getExtension() = extension
|
||||
}
|
||||
|
||||
/** Gets a sub-folder contained in this container. */
|
||||
Folder getASubFolder() { result = this.getAChildContainer() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of the path of this container.
|
||||
*
|
||||
* This is the absolute path of the container.
|
||||
*/
|
||||
string toString() { result = this.getAbsolutePath() }
|
||||
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
|
||||
}
|
||||
|
||||
private module Impl = Make<Input>;
|
||||
|
||||
class Container = Impl::Container;
|
||||
|
||||
/** A folder. */
|
||||
class Folder extends Container, @folder {
|
||||
override string getAbsolutePath() { folders(this, result) }
|
||||
|
||||
override string getURL() { result = "folder://" + this.getAbsolutePath() }
|
||||
}
|
||||
class Folder extends Container, Impl::Folder { }
|
||||
|
||||
bindingset[flag]
|
||||
private predicate fileHasExtractionFlag(File f, int flag) {
|
||||
@@ -191,9 +41,7 @@ private predicate fileHasExtractionFlag(File f, int flag) {
|
||||
}
|
||||
|
||||
/** A file. */
|
||||
class File extends Container, @file {
|
||||
override string getAbsolutePath() { files(this, result) }
|
||||
|
||||
class File extends Container, Impl::File {
|
||||
/** Gets the number of lines in this file. */
|
||||
int getNumberOfLines() { numlines(this, result, _, _) }
|
||||
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -8,6 +8,7 @@ private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||
|
||||
@@ -104,8 +105,17 @@ class ExternalApi extends DotNet::Callable {
|
||||
pragma[nomagic]
|
||||
predicate isSink() { sinkNode(this.getAnInput(), _) }
|
||||
|
||||
/** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */
|
||||
predicate isSupported() { this.hasSummary() or this.isSource() or this.isSink() }
|
||||
/** Holds if this API is a known neutral. */
|
||||
pragma[nomagic]
|
||||
predicate isNeutral() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
|
||||
|
||||
/**
|
||||
* Holds if this API is supported by existing CodeQL libraries, that is, it is either a
|
||||
* recognized source, sink or neutral or it has a flow summary.
|
||||
*/
|
||||
predicate isSupported() {
|
||||
this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,13 +8,9 @@
|
||||
|
||||
private import csharp
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import ExternalApi
|
||||
|
||||
private predicate relevant(ExternalApi api) {
|
||||
api.isSupported() or
|
||||
api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||
}
|
||||
private predicate relevant(ExternalApi api) { api.isSupported() }
|
||||
|
||||
from string info, int usages
|
||||
where Results<relevant/1>::restrict(info, usages)
|
||||
|
||||
@@ -7,14 +7,9 @@
|
||||
*/
|
||||
|
||||
private import csharp
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import ExternalApi
|
||||
|
||||
private predicate relevant(ExternalApi api) {
|
||||
not api.isSupported() and
|
||||
not api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||
}
|
||||
private predicate relevant(ExternalApi api) { not api.isSupported() }
|
||||
|
||||
from string info, int usages
|
||||
where Results<relevant/1>::restrict(info, usages)
|
||||
|
||||
3
csharp/ql/src/change-notes/released/0.5.3.md
Normal file
3
csharp/ql/src/change-notes/released/0.5.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.2
|
||||
lastReleaseVersion: 0.5.3
|
||||
|
||||
@@ -9,13 +9,10 @@
|
||||
*/
|
||||
|
||||
private import csharp
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import Telemetry.ExternalApi
|
||||
|
||||
from Call c, ExternalApi api
|
||||
where
|
||||
c.getTarget().getUnboundDeclaration() = api and
|
||||
not api.isSupported() and
|
||||
not api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||
not api.isSupported()
|
||||
select c, "Call to unsupported external API $@.", api, api.toString()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 0.5.3-dev
|
||||
version: 0.5.4-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
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
|
||||
|
||||
@@ -204,6 +204,7 @@ The completed query will now identify cases where the result of ``strlen`` is st
|
||||
.. code-block:: ql
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.SSA
|
||||
|
||||
class MallocCall extends FunctionCall
|
||||
{
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
.NET Core up to 3.1
|
||||
|
||||
.NET 5, .NET 6","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
|
||||
Go (aka Golang), "Go up to 1.19", "Go 1.11 or more recent", ``.go``
|
||||
Java,"Java 7 to 19 [4]_","javac (OpenJDK and Oracle JDK),
|
||||
Go (aka Golang), "Go up to 1.20", "Go 1.11 or more recent", ``.go``
|
||||
Java,"Java 7 to 20 [4]_","javac (OpenJDK and Oracle JDK),
|
||||
|
||||
Eclipse compiler for Java (ECJ) [5]_",``.java``
|
||||
Kotlin [6]_,"Kotlin 1.5.0 to 1.8.20","kotlinc",``.kt``
|
||||
@@ -31,7 +31,7 @@
|
||||
.. [1] C++20 support is currently in beta. Supported for GCC on Linux only. Modules are *not* supported.
|
||||
.. [2] Support for the clang-cl compiler is preliminary.
|
||||
.. [3] Support for the Arm Compiler (armcc) is preliminary.
|
||||
.. [4] Builds that execute on Java 7 to 19 can be analyzed. The analysis understands Java 19 standard language features.
|
||||
.. [4] Builds that execute on Java 7 to 20 can be analyzed. The analysis understands Java 20 standard language features.
|
||||
.. [5] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin.
|
||||
.. [6] Kotlin support is currently in beta.
|
||||
.. [7] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.4.3
|
||||
|
||||
### New Features
|
||||
|
||||
* Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed; the definition of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules; and taint flow models have been added for relevant, new standard-library functions.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Support for the Twirp framework has been added.
|
||||
|
||||
## 0.4.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
lgtm,codescanning
|
||||
* Support for the Twirp framework has been added.
|
||||
9
go/ql/lib/change-notes/released/0.4.3.md
Normal file
9
go/ql/lib/change-notes/released/0.4.3.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 0.4.3
|
||||
|
||||
### New Features
|
||||
|
||||
* Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed; the definition of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules; and taint flow models have been added for relevant, new standard-library functions.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Support for the Twirp framework has been added.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.2
|
||||
lastReleaseVersion: 0.4.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-all
|
||||
version: 0.4.3-dev
|
||||
version: 0.4.4-dev
|
||||
groups: go
|
||||
dbscheme: go.dbscheme
|
||||
extractor: go
|
||||
|
||||
@@ -112,22 +112,10 @@ class Type extends @type {
|
||||
or
|
||||
u instanceof ArrayType and u.(ArrayType).getElementType().implementsComparable()
|
||||
or
|
||||
exists(InterfaceType uif | uif = u |
|
||||
not uif instanceof BasicInterfaceType and
|
||||
if exists(uif.getAnEmbeddedTypeSetLiteral())
|
||||
then
|
||||
// All types in the intersection of all the embedded type set
|
||||
// literals must implement comparable.
|
||||
forall(Type intersectionType |
|
||||
intersectionType = uif.getAnEmbeddedTypeSetLiteral().getATerm().getType() and
|
||||
forall(TypeSetLiteralType tslit | tslit = uif.getAnEmbeddedTypeSetLiteral() |
|
||||
intersectionType = tslit.getATerm().getType()
|
||||
)
|
||||
|
|
||||
intersectionType.implementsComparable()
|
||||
)
|
||||
else uif.isOrEmbedsComparable()
|
||||
)
|
||||
// As of Go 1.20, any interface type satisfies the `comparable` constraint, even though comparison
|
||||
// may panic at runtime depending on the actual object's concrete type.
|
||||
// Look at git history here if you need the old definition.
|
||||
u instanceof InterfaceType
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ import semmle.go.frameworks.stdlib.Syscall
|
||||
import semmle.go.frameworks.stdlib.TextScanner
|
||||
import semmle.go.frameworks.stdlib.TextTabwriter
|
||||
import semmle.go.frameworks.stdlib.TextTemplate
|
||||
import semmle.go.frameworks.stdlib.Unsafe
|
||||
|
||||
/** A `String()` method. */
|
||||
class StringMethod extends TaintTracking::FunctionModel, Method {
|
||||
|
||||
@@ -11,6 +11,15 @@ module Bytes {
|
||||
FunctionOutput outp;
|
||||
|
||||
FunctionModels() {
|
||||
hasQualifiedName("bytes", "Clone") and
|
||||
(inp.isParameter(0) and outp.isResult())
|
||||
or
|
||||
hasQualifiedName("bytes", "Cut") and
|
||||
(inp.isParameter(0) and outp.isResult([0, 1]))
|
||||
or
|
||||
hasQualifiedName("bytes", ["CutPrefix", "CutSuffix"]) and
|
||||
(inp.isParameter(0) and outp.isResult(0))
|
||||
or
|
||||
// signature: func Fields(s []byte) [][]byte
|
||||
hasQualifiedName("bytes", "Fields") and
|
||||
(inp.isParameter(0) and outp.isResult())
|
||||
|
||||
@@ -22,6 +22,10 @@ module Errors {
|
||||
// signature: func Unwrap(err error) error
|
||||
hasQualifiedName("errors", "Unwrap") and
|
||||
(inp.isParameter(0) and outp.isResult())
|
||||
or
|
||||
// signature: func Join(errs ...error) error
|
||||
hasQualifiedName("errors", "Join") and
|
||||
(inp.isParameter(_) and outp.isResult())
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
|
||||
@@ -11,6 +11,9 @@ module Sync {
|
||||
FunctionOutput outp;
|
||||
|
||||
MethodModels() {
|
||||
hasQualifiedName("sync", "Map", "CompareAndSwap") and
|
||||
(inp.isParameter(2) and outp.isReceiver())
|
||||
or
|
||||
// signature: func (*Map) Load(key interface{}) (value interface{}, ok bool)
|
||||
hasQualifiedName("sync", "Map", "Load") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
@@ -28,6 +31,13 @@ module Sync {
|
||||
hasQualifiedName("sync", "Map", "Store") and
|
||||
(inp.isParameter(_) and outp.isReceiver())
|
||||
or
|
||||
hasQualifiedName("sync", "Map", "Swap") and
|
||||
(
|
||||
inp.isReceiver() and outp.isResult(0)
|
||||
or
|
||||
inp.isParameter(_) and outp.isReceiver()
|
||||
)
|
||||
or
|
||||
// signature: func (*Pool) Get() interface{}
|
||||
hasQualifiedName("sync", "Pool", "Get") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
|
||||
22
go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll
Normal file
22
go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `unsafe` package.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/** Provides models of commonly used functions in the `unsafe` package. */
|
||||
module Unsafe {
|
||||
private class FunctionModels extends TaintTracking::FunctionModel {
|
||||
FunctionInput inp;
|
||||
FunctionOutput outp;
|
||||
|
||||
FunctionModels() {
|
||||
hasQualifiedName("unsafe", ["String", "StringData", "Slice", "SliceData"]) and
|
||||
(inp.isParameter(0) and outp.isResult())
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = inp and output = outp
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,14 +56,14 @@ private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSiz
|
||||
* integer types, which could cause unexpected values.
|
||||
*/
|
||||
class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
|
||||
boolean sourceIsSigned;
|
||||
boolean sinkIsSigned;
|
||||
int sourceBitSize;
|
||||
int sinkBitSize;
|
||||
|
||||
ConversionWithoutBoundsCheckConfig() {
|
||||
sourceIsSigned in [true, false] and
|
||||
sinkIsSigned in [true, false] and
|
||||
isIncorrectIntegerConversion(sourceBitSize, sinkBitSize) and
|
||||
this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sourceIsSigned + sinkBitSize
|
||||
this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sinkIsSigned + sinkBitSize
|
||||
}
|
||||
|
||||
/** Gets the bit size of the source. */
|
||||
@@ -75,11 +75,6 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
|
||||
|
|
||||
c.getTarget() = ip and source = c.getResult(0)
|
||||
|
|
||||
(
|
||||
if ip.getResultType(0) instanceof SignedIntegerType
|
||||
then sourceIsSigned = true
|
||||
else sourceIsSigned = false
|
||||
) and
|
||||
(
|
||||
apparentBitSize = ip.getTargetBitSize()
|
||||
or
|
||||
@@ -112,10 +107,13 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
|
||||
predicate isSinkWithBitSize(DataFlow::TypeCastNode sink, int bitSize) {
|
||||
sink.asExpr() instanceof ConversionExpr and
|
||||
exists(IntegerType integerType | sink.getResultType().getUnderlyingType() = integerType |
|
||||
bitSize = integerType.getSize()
|
||||
or
|
||||
not exists(integerType.getSize()) and
|
||||
bitSize = getIntTypeBitSize(sink.getFile())
|
||||
(
|
||||
bitSize = integerType.getSize()
|
||||
or
|
||||
not exists(integerType.getSize()) and
|
||||
bitSize = getIntTypeBitSize(sink.getFile())
|
||||
) and
|
||||
if integerType instanceof SignedIntegerType then sinkIsSigned = true else sinkIsSigned = false
|
||||
) and
|
||||
not exists(ShrExpr shrExpr |
|
||||
shrExpr.getLeftOperand().getGlobalValueNumber() =
|
||||
@@ -134,7 +132,7 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
|
||||
if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32
|
||||
|
|
||||
node = DataFlow::BarrierGuard<upperBoundCheckGuard/3>::getABarrierNodeForGuard(g) and
|
||||
g.isBoundFor(bitSize, sourceIsSigned)
|
||||
g.isBoundFor(bitSize, sinkIsSigned)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.4.3
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `go/unhandled-writable-file-close`, to detect instances where writable file handles are closed without appropriate checks for errors.
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The precision of the `go/log-injection` query was decreased from `high` to `medium`, since it may not be able to identify every way in which log data may be sanitized. This also aligns it with the precision of comparable queries for other languages.
|
||||
|
||||
## 0.4.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `go/unhandled-writable-file-close`, to detect instances where writable file handles are closed without appropriate checks for errors.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `go/incorrect-integer-conversion` now correctly recognises guards of the form `if val <= x` to protect a conversion `uintX(val)` when `x` is in the range `(math.MaxIntX, math.MaxUintX]`.
|
||||
@@ -1,4 +1,9 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
## 0.4.3
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `go/unhandled-writable-file-close`, to detect instances where writable file handles are closed without appropriate checks for errors.
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The precision of the `go/log-injection` query was decreased from `high` to `medium`, since it may not be able to identify every way in which log data may be sanitized. This also aligns it with the precision of comparable queries for other languages.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.2
|
||||
lastReleaseVersion: 0.4.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-queries
|
||||
version: 0.4.3-dev
|
||||
version: 0.4.4-dev
|
||||
groups:
|
||||
- go
|
||||
- queries
|
||||
|
||||
@@ -51,31 +51,31 @@
|
||||
| interface.go:95:6:95:8 | i18 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.i18 |
|
||||
| interface.go:101:6:101:8 | i19 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.i19 |
|
||||
| interface.go:105:6:105:8 | i20 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.i20 |
|
||||
| interface.go:110:6:110:19 | testComparable | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable |
|
||||
| interface.go:111:6:111:20 | testComparable0 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable0 |
|
||||
| interface.go:112:6:112:20 | testComparable1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable1 |
|
||||
| interface.go:113:6:113:20 | testComparable2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable2 |
|
||||
| interface.go:114:6:114:20 | testComparable3 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable3 |
|
||||
| interface.go:115:6:115:20 | testComparable4 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable4 |
|
||||
| interface.go:116:6:116:20 | testComparable5 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable5 |
|
||||
| interface.go:117:6:117:20 | testComparable6 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable6 |
|
||||
| interface.go:118:6:118:20 | testComparable7 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable7 |
|
||||
| interface.go:119:6:119:20 | testComparable8 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable8 |
|
||||
| interface.go:120:6:120:20 | testComparable9 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable9 |
|
||||
| interface.go:121:6:121:21 | testComparable10 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable10 |
|
||||
| interface.go:122:6:122:21 | testComparable11 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable11 |
|
||||
| interface.go:123:6:123:21 | testComparable12 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable12 |
|
||||
| interface.go:124:6:124:21 | testComparable13 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable13 |
|
||||
| interface.go:125:6:125:21 | testComparable14 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable14 |
|
||||
| interface.go:126:6:126:21 | testComparable15 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable15 |
|
||||
| interface.go:127:6:127:21 | testComparable16 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable16 |
|
||||
| interface.go:128:6:128:21 | testComparable17 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable17 |
|
||||
| interface.go:129:6:129:21 | testComparable18 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable18 |
|
||||
| interface.go:130:6:130:21 | testComparable19 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable19 |
|
||||
| interface.go:131:6:131:21 | testComparable20 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable20 |
|
||||
| interface.go:132:6:132:21 | testComparable21 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable21 |
|
||||
| interface.go:133:6:133:21 | testComparable22 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable22 |
|
||||
| interface.go:134:6:134:21 | testComparable23 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable23 |
|
||||
| interface.go:114:6:114:19 | testComparable | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable |
|
||||
| interface.go:115:6:115:20 | testComparable0 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable0 |
|
||||
| interface.go:116:6:116:20 | testComparable1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable1 |
|
||||
| interface.go:117:6:117:20 | testComparable2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable2 |
|
||||
| interface.go:118:6:118:20 | testComparable3 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable3 |
|
||||
| interface.go:119:6:119:20 | testComparable4 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable4 |
|
||||
| interface.go:120:6:120:20 | testComparable5 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable5 |
|
||||
| interface.go:121:6:121:20 | testComparable6 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable6 |
|
||||
| interface.go:122:6:122:20 | testComparable7 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable7 |
|
||||
| interface.go:123:6:123:20 | testComparable8 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable8 |
|
||||
| interface.go:124:6:124:20 | testComparable9 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable9 |
|
||||
| interface.go:125:6:125:21 | testComparable10 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable10 |
|
||||
| interface.go:126:6:126:21 | testComparable11 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable11 |
|
||||
| interface.go:127:6:127:21 | testComparable12 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable12 |
|
||||
| interface.go:128:6:128:21 | testComparable13 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable13 |
|
||||
| interface.go:129:6:129:21 | testComparable14 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable14 |
|
||||
| interface.go:130:6:130:21 | testComparable15 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable15 |
|
||||
| interface.go:131:6:131:21 | testComparable16 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable16 |
|
||||
| interface.go:132:6:132:21 | testComparable17 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable17 |
|
||||
| interface.go:133:6:133:21 | testComparable18 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable18 |
|
||||
| interface.go:134:6:134:21 | testComparable19 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable19 |
|
||||
| interface.go:135:6:135:21 | testComparable20 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable20 |
|
||||
| interface.go:136:6:136:21 | testComparable21 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable21 |
|
||||
| interface.go:137:6:137:21 | testComparable22 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable22 |
|
||||
| interface.go:138:6:138:21 | testComparable23 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable23 |
|
||||
| pkg1/embedding.go:8:6:8:9 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.base |
|
||||
| pkg1/embedding.go:19:6:19:13 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder |
|
||||
| pkg1/embedding.go:22:6:22:16 | ptrembedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.ptrembedder |
|
||||
|
||||
@@ -51,31 +51,31 @@
|
||||
| interface.go:95:6:95:8 | i18 | i18 |
|
||||
| interface.go:101:6:101:8 | i19 | i19 |
|
||||
| interface.go:105:6:105:8 | i20 | i20 |
|
||||
| interface.go:110:6:110:19 | testComparable | testComparable |
|
||||
| interface.go:111:6:111:20 | testComparable0 | testComparable0 |
|
||||
| interface.go:112:6:112:20 | testComparable1 | testComparable1 |
|
||||
| interface.go:113:6:113:20 | testComparable2 | testComparable2 |
|
||||
| interface.go:114:6:114:20 | testComparable3 | testComparable3 |
|
||||
| interface.go:115:6:115:20 | testComparable4 | testComparable4 |
|
||||
| interface.go:116:6:116:20 | testComparable5 | testComparable5 |
|
||||
| interface.go:117:6:117:20 | testComparable6 | testComparable6 |
|
||||
| interface.go:118:6:118:20 | testComparable7 | testComparable7 |
|
||||
| interface.go:119:6:119:20 | testComparable8 | testComparable8 |
|
||||
| interface.go:120:6:120:20 | testComparable9 | testComparable9 |
|
||||
| interface.go:121:6:121:21 | testComparable10 | testComparable10 |
|
||||
| interface.go:122:6:122:21 | testComparable11 | testComparable11 |
|
||||
| interface.go:123:6:123:21 | testComparable12 | testComparable12 |
|
||||
| interface.go:124:6:124:21 | testComparable13 | testComparable13 |
|
||||
| interface.go:125:6:125:21 | testComparable14 | testComparable14 |
|
||||
| interface.go:126:6:126:21 | testComparable15 | testComparable15 |
|
||||
| interface.go:127:6:127:21 | testComparable16 | testComparable16 |
|
||||
| interface.go:128:6:128:21 | testComparable17 | testComparable17 |
|
||||
| interface.go:129:6:129:21 | testComparable18 | testComparable18 |
|
||||
| interface.go:130:6:130:21 | testComparable19 | testComparable19 |
|
||||
| interface.go:131:6:131:21 | testComparable20 | testComparable20 |
|
||||
| interface.go:132:6:132:21 | testComparable21 | testComparable21 |
|
||||
| interface.go:133:6:133:21 | testComparable22 | testComparable22 |
|
||||
| interface.go:134:6:134:21 | testComparable23 | testComparable23 |
|
||||
| interface.go:114:6:114:19 | testComparable | testComparable |
|
||||
| interface.go:115:6:115:20 | testComparable0 | testComparable0 |
|
||||
| interface.go:116:6:116:20 | testComparable1 | testComparable1 |
|
||||
| interface.go:117:6:117:20 | testComparable2 | testComparable2 |
|
||||
| interface.go:118:6:118:20 | testComparable3 | testComparable3 |
|
||||
| interface.go:119:6:119:20 | testComparable4 | testComparable4 |
|
||||
| interface.go:120:6:120:20 | testComparable5 | testComparable5 |
|
||||
| interface.go:121:6:121:20 | testComparable6 | testComparable6 |
|
||||
| interface.go:122:6:122:20 | testComparable7 | testComparable7 |
|
||||
| interface.go:123:6:123:20 | testComparable8 | testComparable8 |
|
||||
| interface.go:124:6:124:20 | testComparable9 | testComparable9 |
|
||||
| interface.go:125:6:125:21 | testComparable10 | testComparable10 |
|
||||
| interface.go:126:6:126:21 | testComparable11 | testComparable11 |
|
||||
| interface.go:127:6:127:21 | testComparable12 | testComparable12 |
|
||||
| interface.go:128:6:128:21 | testComparable13 | testComparable13 |
|
||||
| interface.go:129:6:129:21 | testComparable14 | testComparable14 |
|
||||
| interface.go:130:6:130:21 | testComparable15 | testComparable15 |
|
||||
| interface.go:131:6:131:21 | testComparable16 | testComparable16 |
|
||||
| interface.go:132:6:132:21 | testComparable17 | testComparable17 |
|
||||
| interface.go:133:6:133:21 | testComparable18 | testComparable18 |
|
||||
| interface.go:134:6:134:21 | testComparable19 | testComparable19 |
|
||||
| interface.go:135:6:135:21 | testComparable20 | testComparable20 |
|
||||
| interface.go:136:6:136:21 | testComparable21 | testComparable21 |
|
||||
| interface.go:137:6:137:21 | testComparable22 | testComparable22 |
|
||||
| interface.go:138:6:138:21 | testComparable23 | testComparable23 |
|
||||
| pkg1/embedding.go:8:6:8:9 | base | base |
|
||||
| pkg1/embedding.go:19:6:19:13 | embedder | embedder |
|
||||
| pkg1/embedding.go:22:6:22:16 | ptrembedder | ptrembedder |
|
||||
|
||||
@@ -107,28 +107,32 @@ type i20 interface {
|
||||
StringB() string
|
||||
}
|
||||
|
||||
type testComparable[T comparable] struct{} // $ implementsComparable
|
||||
type testComparable0[T0 i0] struct{} // $ implementsComparable
|
||||
type testComparable1[T1 i1] struct{} // $ implementsComparable
|
||||
type testComparable2[T2 i2] struct{} // $ implementsComparable
|
||||
type testComparable3[T3 i3] struct{} // $ implementsComparable
|
||||
type testComparable4[T4 i4] struct{} // $ implementsComparable
|
||||
type testComparable5[T5 i5] struct{} // does not implement comparable
|
||||
type testComparable6[T6 i6] struct{} // does not implement comparable
|
||||
type testComparable7[T7 i7] struct{} // $ implementsComparable
|
||||
type testComparable8[T8 i8] struct{} // does not implement comparable
|
||||
type testComparable9[T9 i9] struct{} // does not implement comparable
|
||||
type testComparable10[T10 i10] struct{} // $ implementsComparable
|
||||
type testComparable11[T11 i11] struct{} // $ implementsComparable
|
||||
type testComparable12[T12 i12] struct{} // does not implement comparable
|
||||
type testComparable13[T13 i13] struct{} // does not implement comparable
|
||||
type testComparable14[T14 i14] struct{} // $ implementsComparable
|
||||
type testComparable15[T15 i15] struct{} // $ implementsComparable
|
||||
type testComparable16[T16 i16] struct{} // does not implement comparable
|
||||
type testComparable17[T17 i17] struct{} // does not implement comparable
|
||||
type testComparable18[T18 i18] struct{} // $ implementsComparable
|
||||
type testComparable19[T19 i19] struct{} // does not implement comparable
|
||||
type testComparable20[T20 i20] struct{} // $ implementsComparable
|
||||
type testComparable21[T21 ~[]byte | string] struct{} // does not implement comparable
|
||||
type testComparable22[T22 any] struct{} // does not implement comparable
|
||||
type testComparable23[T23 ~[5]byte | string] struct{} // $ implementsComparable
|
||||
// These used to distinguish strictly-comparable interfaces (i.e. those which will not panic at runtime on attempting a comparison),
|
||||
// which were required to satisfy the `comparable` type constraint in Go <1.20. Now they all match `comparable` as all interfaces
|
||||
// are accepted. I mark those which are also strictly comparable for the future in case we want to expose that concept in QL.
|
||||
|
||||
type testComparable[T comparable] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable0[T0 i0] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable1[T1 i1] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable2[T2 i2] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable3[T3 i3] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable4[T4 i4] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable5[T5 i5] struct{} // $ implementsComparable
|
||||
type testComparable6[T6 i6] struct{} // $ implementsComparable
|
||||
type testComparable7[T7 i7] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable8[T8 i8] struct{} // $ implementsComparable
|
||||
type testComparable9[T9 i9] struct{} // $ implementsComparable
|
||||
type testComparable10[T10 i10] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable11[T11 i11] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable12[T12 i12] struct{} // $ implementsComparable
|
||||
type testComparable13[T13 i13] struct{} // $ implementsComparable
|
||||
type testComparable14[T14 i14] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable15[T15 i15] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable16[T16 i16] struct{} // $ implementsComparable
|
||||
type testComparable17[T17 i17] struct{} // $ implementsComparable
|
||||
type testComparable18[T18 i18] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable19[T19 i19] struct{} // $ implementsComparable
|
||||
type testComparable20[T20 i20] struct{} // $ implementsComparable isStrictlyComparable
|
||||
type testComparable21[T21 ~[]byte | string] struct{} // $ implementsComparable
|
||||
type testComparable22[T22 any] struct{} // $ implementsComparable
|
||||
type testComparable23[T23 ~[5]byte | string] struct{} // $ implementsComparable isStrictlyComparable
|
||||
|
||||
@@ -7,7 +7,7 @@ func testing() {
|
||||
nonvariadicDeclaredFunction([]int{})
|
||||
}
|
||||
|
||||
func variadicDeclaredFunction(x ...int) int { // $ isVariadic
|
||||
func variadicDeclaredFunction(x ...int) int {
|
||||
a := make([]int, 0, 10)
|
||||
y := append(x, a...)
|
||||
print(x[0], x[1])
|
||||
@@ -15,7 +15,7 @@ func variadicDeclaredFunction(x ...int) int { // $ isVariadic
|
||||
fmt.Fprint(nil, nil, nil)
|
||||
variadicFunctionLiteral := func(z ...int) int { return z[1] } // $ isVariadic
|
||||
return variadicFunctionLiteral(y...)
|
||||
}
|
||||
} // $ isVariadic
|
||||
|
||||
func nonvariadicDeclaredFunction(x []int) int {
|
||||
return 0
|
||||
|
||||
@@ -59,7 +59,7 @@ func main() {
|
||||
|
||||
http.HandleFunc("/foo", handler) // $ handler="/foo"
|
||||
|
||||
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { // $ handler="/bar"
|
||||
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
|
||||
})
|
||||
}) // $ handler="/bar"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class DataConfiguration extends DataFlow::Configuration {
|
||||
DataConfiguration() { this = "data-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(DataFlow::CallNode c | c.getCalleeName() = "source").getResult(0)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
class DataFlowTest extends InlineExpectationsTest {
|
||||
DataFlowTest() { this = "DataFlowTest" }
|
||||
|
||||
override string getARelevantTag() { result = "dataflow" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "dataflow" and
|
||||
exists(DataFlow::Node sink | any(DataConfiguration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TaintConfiguration extends TaintTracking::Configuration {
|
||||
TaintConfiguration() { this = "taint-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(DataFlow::CallNode c | c.getCalleeName() = "source").getResult(0)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
class TaintFlowTest extends InlineExpectationsTest {
|
||||
TaintFlowTest() { this = "TaintFlowTest" }
|
||||
|
||||
override string getARelevantTag() { result = "taintflow" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "taintflow" and
|
||||
exists(DataFlow::Node sink | any(TaintConfiguration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
func source() string {
|
||||
return "untrusted data"
|
||||
}
|
||||
|
||||
func sink(string) {
|
||||
}
|
||||
|
||||
func sliceToArray(p []string) [1]string {
|
||||
return [1]string(p)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Test the new slice->array conversion permitted in Go 1.20
|
||||
var a [4]string
|
||||
a[0] = source()
|
||||
alias := sliceToArray(a[:])
|
||||
sink(alias[0]) // $ taintflow
|
||||
|
||||
// Compare with the standard dataflow support for arrays
|
||||
var b [4]string
|
||||
b[0] = source()
|
||||
sink(b[0]) // $ taintflow
|
||||
}
|
||||
@@ -316,6 +316,39 @@ func TaintStepTest_BytesReaderWriteTo_B0I0O0(sourceCQL interface{}) interface{}
|
||||
return intoWriter197
|
||||
}
|
||||
|
||||
func TaintStepTest_Clone(sourceCQL interface{}) interface{} {
|
||||
fromReader628 := sourceCQL.([]byte)
|
||||
return bytes.Clone(fromReader628)
|
||||
}
|
||||
|
||||
func TaintStepTest_Cutleft(sourceCQL interface{}) interface{} {
|
||||
fromReader628 := sourceCQL.([]byte)
|
||||
sep := []byte{}
|
||||
left, _, _ := bytes.Cut(fromReader628, sep)
|
||||
return left
|
||||
}
|
||||
|
||||
func TaintStepTest_Cutright(sourceCQL interface{}) interface{} {
|
||||
fromReader628 := sourceCQL.([]byte)
|
||||
sep := []byte{}
|
||||
_, right, _ := bytes.Cut(fromReader628, sep)
|
||||
return right
|
||||
}
|
||||
|
||||
func TaintStepTest_CutPrefix(sourceCQL interface{}) interface{} {
|
||||
fromReader628 := sourceCQL.([]byte)
|
||||
sep := []byte{}
|
||||
result, _ := bytes.CutPrefix(fromReader628, sep)
|
||||
return result
|
||||
}
|
||||
|
||||
func TaintStepTest_CutSuffix(sourceCQL interface{}) interface{} {
|
||||
fromReader628 := sourceCQL.([]byte)
|
||||
sep := []byte{}
|
||||
result, _ := bytes.CutSuffix(fromReader628, sep)
|
||||
return result
|
||||
}
|
||||
|
||||
func RunAllTaints_Bytes() {
|
||||
{
|
||||
source := newSource(0)
|
||||
@@ -567,4 +600,29 @@ func RunAllTaints_Bytes() {
|
||||
out := TaintStepTest_BytesReaderWriteTo_B0I0O0(source)
|
||||
sink(49, out)
|
||||
}
|
||||
{
|
||||
source := newSource(50)
|
||||
out := TaintStepTest_Cutleft(source)
|
||||
sink(50, out)
|
||||
}
|
||||
{
|
||||
source := newSource(51)
|
||||
out := TaintStepTest_Cutright(source)
|
||||
sink(51, out)
|
||||
}
|
||||
{
|
||||
source := newSource(52)
|
||||
out := TaintStepTest_CutPrefix(source)
|
||||
sink(52, out)
|
||||
}
|
||||
{
|
||||
source := newSource(53)
|
||||
out := TaintStepTest_CutSuffix(source)
|
||||
sink(53, out)
|
||||
}
|
||||
{
|
||||
source := newSource(54)
|
||||
out := TaintStepTest_Clone(source)
|
||||
sink(54, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,18 @@ func TaintStepTest_ErrorsUnwrap_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
return intoError957
|
||||
}
|
||||
|
||||
func TaintStepTest_ErrorsJoin1(sourceCQL interface{}) interface{} {
|
||||
fromError784 := sourceCQL.(error)
|
||||
intoError957 := errors.Join(fromError784, errors.New(""))
|
||||
return intoError957
|
||||
}
|
||||
|
||||
func TaintStepTest_ErrorsJoin2(sourceCQL interface{}) interface{} {
|
||||
fromError784 := sourceCQL.(error)
|
||||
intoError957 := errors.Join(errors.New(""), fromError784)
|
||||
return intoError957
|
||||
}
|
||||
|
||||
func RunAllTaints_Errors() {
|
||||
{
|
||||
source := newSource(0)
|
||||
@@ -39,4 +51,14 @@ func RunAllTaints_Errors() {
|
||||
out := TaintStepTest_ErrorsUnwrap_B0I0O0(source)
|
||||
sink(2, out)
|
||||
}
|
||||
{
|
||||
source := newSource(3)
|
||||
out := TaintStepTest_ErrorsJoin1(source)
|
||||
sink(3, out)
|
||||
}
|
||||
{
|
||||
source := newSource(4)
|
||||
out := TaintStepTest_ErrorsJoin2(source)
|
||||
sink(4, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,30 @@ func TaintStepTest_SyncMapStore_B0I1O0(sourceCQL interface{}) interface{} {
|
||||
return intoMap881
|
||||
}
|
||||
|
||||
func TaintStepTest_SyncMapSwapinkey(sourceCQL interface{}) interface{} {
|
||||
var m sync.Map
|
||||
m.Swap(sourceCQL, "value")
|
||||
return m
|
||||
}
|
||||
|
||||
func TaintStepTest_SyncMapSwapinvalue(sourceCQL interface{}) interface{} {
|
||||
var m sync.Map
|
||||
m.Swap("key", sourceCQL)
|
||||
return m
|
||||
}
|
||||
|
||||
func TaintStepTest_SyncMapSwapout(sourceCQL interface{}) interface{} {
|
||||
m := sourceCQL.(sync.Map)
|
||||
oldVal, _ := m.Swap("key", "value")
|
||||
return oldVal
|
||||
}
|
||||
|
||||
func TaintStepTest_SyncMapCompareAndSwap(sourceCQL interface{}) interface{} {
|
||||
var m sync.Map
|
||||
m.CompareAndSwap("key", "compareTo", sourceCQL)
|
||||
return m
|
||||
}
|
||||
|
||||
func TaintStepTest_SyncPoolGet_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromPool186 := sourceCQL.(sync.Pool)
|
||||
intoInterface284 := fromPool186.Get()
|
||||
@@ -122,4 +146,24 @@ func RunAllTaints_Sync() {
|
||||
out := TaintStepTest_SyncPoolPut_B0I0O0(source)
|
||||
sink(9, out)
|
||||
}
|
||||
{
|
||||
source := newSource(10)
|
||||
out := TaintStepTest_SyncMapSwapinkey(source)
|
||||
sink(10, out)
|
||||
}
|
||||
{
|
||||
source := newSource(11)
|
||||
out := TaintStepTest_SyncMapSwapinvalue(source)
|
||||
sink(11, out)
|
||||
}
|
||||
{
|
||||
source := newSource(12)
|
||||
out := TaintStepTest_SyncMapSwapout(source)
|
||||
sink(12, out)
|
||||
}
|
||||
{
|
||||
source := newSource(13)
|
||||
out := TaintStepTest_SyncMapCompareAndSwap(source)
|
||||
sink(13, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func TaintStepTest_UnsafeSlice(sourceCQL interface{}) interface{} {
|
||||
s := sourceCQL.(*byte)
|
||||
return unsafe.Slice(s, 1)
|
||||
}
|
||||
|
||||
func TaintStepTest_UnsafeSliceData(sourceCQL interface{}) interface{} {
|
||||
s := sourceCQL.([]byte)
|
||||
return unsafe.SliceData(s)
|
||||
}
|
||||
|
||||
func TaintStepTest_UnsafeString(sourceCQL interface{}) interface{} {
|
||||
s := sourceCQL.(*byte)
|
||||
return unsafe.String(s, 1)
|
||||
}
|
||||
|
||||
func TaintStepTest_UnsafeStringData(sourceCQL interface{}) interface{} {
|
||||
s := sourceCQL.(string)
|
||||
return unsafe.StringData(s)
|
||||
}
|
||||
|
||||
func RunAllTaints_Unsafe() {
|
||||
{
|
||||
source := newSource(0)
|
||||
out := TaintStepTest_UnsafeSlice(source)
|
||||
sink(0, out)
|
||||
}
|
||||
{
|
||||
source := newSource(1)
|
||||
out := TaintStepTest_UnsafeSliceData(source)
|
||||
sink(1, out)
|
||||
}
|
||||
{
|
||||
source := newSource(2)
|
||||
out := TaintStepTest_UnsafeString(source)
|
||||
sink(2, out)
|
||||
}
|
||||
{
|
||||
source := newSource(3)
|
||||
out := TaintStepTest_UnsafeStringData(source)
|
||||
sink(3, out)
|
||||
}
|
||||
}
|
||||
@@ -264,6 +264,9 @@ func testBoundsChecking(input string) {
|
||||
_ = int16(parsed)
|
||||
}
|
||||
}
|
||||
if parsed <= math.MaxUint16 {
|
||||
_ = uint16(parsed)
|
||||
}
|
||||
}
|
||||
{
|
||||
parsed, err := strconv.ParseUint(input, 10, 32)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
|
||||
/**
|
||||
* Use `apply false` in the top-level build.gradle file to add a Gradle
|
||||
* plugin as a build dependency but not apply it to the current (root)
|
||||
* project. Don't use `apply false` in sub-projects. For more information,
|
||||
* see Applying external plugins with same version to subprojects.
|
||||
*/
|
||||
|
||||
id 'com.android.application' version '7.3.1' apply false
|
||||
id 'com.android.library' version '7.3.1' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user