Compare commits

..

24 Commits

Author SHA1 Message Date
Anders Fugmann
a139a6f5bb Swift: disable stack protection in extractor to fix Linux crash
The FunctionStackProtection SIL pass crashes on Linux when processing
standard library functions like withUnsafePointer(to:_:). This is a
known upstream Swift compiler bug (swiftlang/swift#69768).

The extractor does not need stack protection since it only extracts
semantic information from the AST and never produces executable code.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-12 13:31:47 +01:00
Jeroen Ketema
759c0f5b3d Test 2026-03-12 11:42:51 +01:00
Jeroen Ketema
c9bd100aaf Swift: Disable stack protector pass 2026-03-12 11:37:44 +01:00
Ian Lynagh
bbd02b855b Merge pull request #21424 from github/idrissrio/cpp/overlay/discard
C/C++ overlay: update discard mechanism
2026-03-11 13:45:52 +00:00
Idriss Riouak
48a03e2a04 Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-11 14:25:53 +01:00
idrissrio
a92d97744f C/C++ overlay: address review comment 2026-03-11 14:25:52 +01:00
idrissrio
ef6c1a9968 C/C++ overlay: fix failing header_dependency test 2026-03-11 14:25:50 +01:00
idrissrio
72142b51f7 C/C++ overlay: switch to updated discard strategy 2026-03-11 14:25:49 +01:00
Tom Hvitved
c06d4d2647 Merge pull request #21422 from hvitved/rust/type-mention-refactor
Rust: Small refactor in `TypeMention.qll`
2026-03-11 14:01:03 +01:00
Ian Lynagh
68dfa5c83b Merge pull request #21451 from igfoo/igfoo/fix-build
Revert "Bump rules_android from 0.6.4 to 0.7.1"
2026-03-11 12:27:20 +00:00
Ian Lynagh
25a20f74f0 Revert "Bump rules_android from 0.6.4 to 0.7.1"
This reverts commit c7349740f0.

It was making the build fail
2026-03-11 11:54:18 +00:00
Taus
5a65282241 Merge pull request #21429 from github/tausbn/fix-bad-join-in-method-call-order
Python: Fix bad join in method call order computation
2026-03-10 18:17:35 +01:00
Paolo Tranquilli
79499c240a Merge pull request #21444 from github/dependabot/bazel/googletest-1.17.0.bcr.2
Bump googletest from 1.14.0.bcr.1 to 1.17.0.bcr.2
2026-03-10 16:41:38 +01:00
Paolo Tranquilli
267a46d01b Merge pull request #21445 from github/dependabot/bazel/rules_shell-0.6.1
Bump rules_shell from 0.5.0 to 0.6.1
2026-03-10 16:41:24 +01:00
Ian Lynagh
341059d2d0 Merge pull request #21437 from igfoo/igfoo/onemk
C++: Small simplification
2026-03-10 15:36:38 +00:00
Paolo Tranquilli
3c3c58b0a9 Merge pull request #21443 from github/dependabot/bazel/rules_android-0.7.1
Bump rules_android from 0.6.4 to 0.7.1
2026-03-10 16:06:40 +01:00
Paolo Tranquilli
9bf1072a01 Merge pull request #21447 from github/revert-21414-redsun82/rerun-slash-command
Revert "Add `/rerun` slash command for failed internal checks"
2026-03-10 15:55:45 +01:00
Paolo Tranquilli
a5f23ade8c Revert "Add /rerun slash command for failed internal checks" 2026-03-10 14:43:59 +01:00
dependabot[bot]
b631138b63 Bump rules_shell from 0.5.0 to 0.6.1
Bumps [rules_shell](https://github.com/bazelbuild/rules_shell) from 0.5.0 to 0.6.1.
- [Release notes](https://github.com/bazelbuild/rules_shell/releases)
- [Commits](https://github.com/bazelbuild/rules_shell/compare/v0.5.0...v0.6.1)

---
updated-dependencies:
- dependency-name: rules_shell
  dependency-version: 0.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 11:21:40 +00:00
dependabot[bot]
093d36ebe6 Bump googletest from 1.14.0.bcr.1 to 1.17.0.bcr.2
Bumps [googletest](https://github.com/google/googletest) from 1.14.0.bcr.1 to 1.17.0.bcr.2.
- [Release notes](https://github.com/google/googletest/releases)
- [Commits](https://github.com/google/googletest/commits)

---
updated-dependencies:
- dependency-name: googletest
  dependency-version: 1.17.0.bcr.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 11:21:37 +00:00
dependabot[bot]
c7349740f0 Bump rules_android from 0.6.4 to 0.7.1
Bumps [rules_android](https://github.com/bazelbuild/rules_android) from 0.6.4 to 0.7.1.
- [Release notes](https://github.com/bazelbuild/rules_android/releases)
- [Commits](https://github.com/bazelbuild/rules_android/compare/v0.6.4...v0.7.1)

---
updated-dependencies:
- dependency-name: rules_android
  dependency-version: 0.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 11:21:34 +00:00
Ian Lynagh
dbb8bb86ba C++: Small simplification 2026-03-09 17:45:38 +00:00
Taus
c5360ba46c Python: Fix bad join in method call order computation
This join had badness 1127 on the project FiacreT/M-moire, producing ~31
million tuples in order to end up with only ~27k tuples later in the
pipeline. With the fix, we reduce this by roughly the full 31 million
(the new materialised helper predicate accounting for roughly 130k
tuples on its own).

Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2026-03-09 13:09:29 +00:00
Tom Hvitved
4dca9aa958 Rust: Small refactor in TypeMention.qll 2026-03-06 15:33:11 +01:00
40 changed files with 108 additions and 872 deletions

View File

@@ -1,14 +0,0 @@
---
trigger: rerun
title: Rerun failed internal checks
surfaces:
- pull_request
description: >
Finds all failed internal CI checks for this PR and reruns their failed jobs.
steps:
- type: repository_dispatch
eventType: rerun-workflow
- type: fill
submit_form: true
template: "Rerun has been triggered."

View File

@@ -21,7 +21,7 @@ bazel_dep(name = "rules_java", version = "9.0.3")
bazel_dep(name = "rules_pkg", version = "1.0.1")
bazel_dep(name = "rules_nodejs", version = "6.7.3")
bazel_dep(name = "rules_python", version = "1.9.0")
bazel_dep(name = "rules_shell", version = "0.5.0")
bazel_dep(name = "rules_shell", version = "0.6.1")
bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
@@ -29,7 +29,7 @@ bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
bazel_dep(name = "rules_kotlin", version = "2.2.2-codeql.1")
bazel_dep(name = "gazelle", version = "0.47.0")
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "googletest", version = "1.17.0.bcr.2")
bazel_dep(name = "rules_rust", version = "0.68.1.codeql.1")
bazel_dep(name = "zstd", version = "1.5.7.bcr.1")

View File

@@ -1663,7 +1663,7 @@ private module Cached {
private predicate compares_ge(
ValueNumber test, Operand left, Operand right, int k, boolean isGe, GuardValue value
) {
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, value))
compares_lt(test, right, left, 1 - k, isGe, value)
}
/** Rearrange various simple comparisons into `left < right + k` form. */

View File

@@ -6,117 +6,67 @@ private import OverlayXml
/**
* Holds always for the overlay variant and never for the base variant.
* This local predicate is used to define local predicates that behave
* differently for the base and overlay variant.
*/
overlay[local]
predicate isOverlay() { databaseMetadata("isOverlay", "true") }
overlay[local]
private string getLocationFilePath(@location_default loc) {
exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result))
}
/**
* Gets the file path for an element with a single location.
* Holds if the TRAP file or tag `t` is reachable from source file `sourceFile`
* in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
*/
overlay[local]
private string getSingleLocationFilePath(@element e) {
exists(@location_default loc |
var_decls(e, _, _, _, loc)
or
fun_decls(e, _, _, _, loc)
or
type_decls(e, _, loc)
or
namespace_decls(e, _, loc, _)
or
macroinvocations(e, _, loc, _)
or
preprocdirects(e, _, loc)
or
diagnostics(e, _, _, _, _, loc)
or
usings(e, _, loc, _)
or
static_asserts(e, _, _, loc, _)
or
derivations(e, _, _, _, loc)
or
frienddecls(e, _, _, loc)
or
comments(e, _, loc)
or
exprs(e, _, loc)
or
stmts(e, _, loc)
or
initialisers(e, _, _, loc)
or
attributes(e, _, _, _, loc)
or
attribute_args(e, _, _, _, loc)
or
namequalifiers(e, _, _, loc)
or
enumconstants(e, _, _, _, _, loc)
or
type_mentions(e, _, loc, _)
or
lambda_capture(e, _, _, _, _, _, loc)
or
concept_templates(e, _, loc)
|
result = getLocationFilePath(loc)
private predicate locallyReachableTrapOrTag(
boolean isOverlayVariant, string sourceFile, @trap_or_tag t
) {
exists(@source_file sf, @trap trap |
(if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
source_file_uses_trap(sf, trap) and
source_file_name(sf, sourceFile) and
(t = trap or trap_uses_tag(trap, t))
)
}
/**
* Gets the file path for an element with potentially multiple locations.
* Holds if element `e` is in TRAP file or tag `t`
* in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
*/
overlay[local]
private string getMultiLocationFilePath(@element e) {
exists(@location_default loc |
var_decls(_, e, _, _, loc)
or
fun_decls(_, e, _, _, loc)
or
type_decls(_, e, loc)
or
namespace_decls(_, e, loc, _)
|
result = getLocationFilePath(loc)
)
}
/**
* A local helper predicate that holds in the base variant and never in the
* overlay variant.
*/
overlay[local]
private predicate isBase() { not isOverlay() }
/**
* Holds if `path` was extracted in the overlay database.
*/
overlay[local]
private predicate overlayHasFile(string path) {
isOverlay() and
files(_, path) and
path != ""
private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap_or_tag t) {
(if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
in_trap_or_tag(e, t)
}
/**
* Discards an element from the base variant if:
* - It has a single location in a file extracted in the overlay, or
* - All of its locations are in files extracted in the overlay.
* - We have knowledge about what TRAP file or tag it is in (in the base).
* - It is not in any overlay TRAP file or tag that is reachable from an overlay source file.
* - For every base TRAP file or tag that contains it and is reachable from a base source file,
* either the source file has changed, or the overlay has redefined the TRAP file or tag,
* or the overlay runner has re-extracted the same source file.
*/
overlay[discard_entity]
private predicate discardElement(@element e) {
isBase() and
(
overlayHasFile(getSingleLocationFilePath(e))
or
forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path))
// If we don't have any knowledge about what TRAP file something
// is in, then we don't want to discard it, so we only consider
// entities that are known to be in a base TRAP file or tag.
locallyInTrapOrTag(false, e, _) and
// Anything that is reachable from an overlay source file should
// not be discarded.
not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) |
locallyReachableTrapOrTag(true, _, t)
) and
// Finally, we have to make sure the base variant does not retain it.
// If it is reachable from a base source file, then that is
// sufficient unless either the base source file has changed (in
// particular, been deleted), or the overlay has redefined the TRAP
// file or tag it is in, or the overlay runner has re-extracted the same
// source file (e.g. because a header it includes has changed).
forall(@trap_or_tag t, string sourceFile |
locallyInTrapOrTag(false, e, t) and
locallyReachableTrapOrTag(false, sourceFile, t)
|
overlayChangedFiles(sourceFile) or
locallyReachableTrapOrTag(true, _, t) or
locallyReachableTrapOrTag(true, sourceFile, _)
)
}

View File

@@ -1,3 +0,0 @@
import '../lib.just'
build: (_build_dist "java")

View File

@@ -1,6 +0,0 @@
import "../../lib.just"
[no-cd]
format *ARGS=".": (_format_ql ARGS)
consistency_queries := source_dir() / "consistency-queries"

View File

@@ -1,15 +0,0 @@
import "../justfile"
base_flags := """\
CODEQL_EXTRACTOR_KOTLIN_DIAGNOSTIC_LIMIT= \
"""
all_checks := default_db_checks + """\
--check-undefined-labels \
--check-repeated-labels \
--check-redefined-labels \
--check-use-before-definition \
--consistency-queries=""" + consistency_queries
[no-cd]
test *ARGS=".": (_codeql_test "java" base_flags all_checks ARGS)

View File

@@ -1,16 +0,0 @@
import "../justfile"
base_flags := """\
CODEQL_EXTRACTOR_KOTLIN_DIAGNOSTIC_LIMIT= \
CODEQL_KOTLIN_LEGACY_TEST_EXTRACTION_KOTLIN2=true \
"""
all_checks := default_db_checks + """\
--check-undefined-labels \
--check-repeated-labels \
--check-redefined-labels \
--check-use-before-definition \
--consistency-queries=""" + consistency_queries
[no-cd]
test *ARGS=".": (_codeql_test "java" base_flags all_checks ARGS)

View File

@@ -1,16 +0,0 @@
import "../justfile"
base_flags := """\
CODEQL_EXTRACTOR_KOTLIN_DIAGNOSTIC_LIMIT="\\ " \
"""
all_checks := default_db_checks + """\
--check-undefined-labels \
--check-repeated-labels \
--check-redefined-labels \
--check-use-before-definition \
--consistency-queries=""" + consistency_queries
[no-cd]
test *ARGS=".": (_codeql_test "java" base_flags all_checks ARGS)

View File

@@ -1,4 +0,0 @@
# see misc/just/README.md for an overview
import 'lib.just'
import 'misc/just/forward.just'

View File

@@ -1 +0,0 @@
import "misc/just/lib.just"

View File

@@ -1,5 +0,0 @@
import '../just/lib.just'
[no-cd, positional-arguments, no-exit-message]
hello +ARGS:
@echo "hello from bzl" "$@"

View File

@@ -43,7 +43,7 @@ use_repo(apphost_packs_extension, "dotnet.apphost_packs")
bazel_dep(name = "bazel_skylib", version = "1.7.1")
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "bazel_lib", version = "3.0.0")
bazel_dep(name = "rules_shell", version = "0.5.0")
bazel_dep(name = "rules_shell", version = "0.6.1")
# Dev dependencies
bazel_dep(name = "rules_pkg", version = "1.1.0", dev_dependency = True)

View File

@@ -1,5 +0,0 @@
import "../just/lib.just"
test *ARGS="": (_bazel "test" "@codeql//misc/codegen/...")
format *ARGS=".": (_format_py ARGS)

View File

@@ -1,44 +0,0 @@
This directory contains an infrastructure for [`just`](https://github.com/casey/just)
recipes that can be used throughout this and the internal repository. In particular we
have common verbs (`build`, `test`, `format`, `lint`, `generate`) that individual parts
of the project can implement, and some common functionality that can be used to that
effect.
# Forwarding
The core of the functionality is given by forwarding. The idea is that:
- if you are in the directory where a verb is implemented, you will get that as per
standard `just` behaviour (possibly using fallback).
- if on the other hand you are beneath it, and you run something like
`just test ql/rust/ql/test/{a,b}`, then a forwarder script finds a common justfile
implementing the verb for all the positional arguments passed there, and then retries
calling `just test` from there. So if `test` is implemented beneath that (in that case,
it is in `rust/ql/test`), it uses that recipe.
- even if there isn't a recipe that is common to all the positional arguments, the
forwarder will still group the arguments in batches using the same recipe. So
`just build ql/rust ql/java`, or
`just test ql/rust/ql/test/some/language/test ql/rust/ql/integration-test/some/integration/test`
will also work, with corresponding recipes run sequentially.
Another point is how launching QL tests can be tweaked:
- by default, the corresponding CLI is built from the internal repo (nothing is done if
working in `codeql` standalone), and no additional database or consistency checks are
made
- `--codeql=built` can be passed to skip the build step (if no changes were made to the
CLI/extractors). This is consistent with the same pytest option
- you can add the additional checks that CI does with `--all-checks` or the `+`
abbreviation. These additional checks are configured in justfiles per language, and
correspond to all the additional checks that CI adds (but that a dev might not want to
run by default).
Some caveats:
- passing arguments with spaces generally doesn't work, although setting arguments with
spaces in `justfile`s (for the base arguments) is supported using escaping as in `\\`.
This is a known limitation of just (see
<https://github.com/casey/just/issues/1988>)
- when running different recipes for the same verb, non-positional arguments need to be
supported by all recipes involved. For example, this will work ok for `--learn` or
`--codeql` options in language and integration tests

View File

@@ -1,19 +0,0 @@
# Helper build recipes
import "defs.just"
# Build the given language-specific CLI distribution
_build_dist LANGUAGE: _require_semmle_code (_maybe_build_dist LANGUAGE)
# Build the language-specific distribution if we are in an internal repository checkout
# Otherwise, do nothing
[no-exit-message]
_maybe_build_dist LANGUAGE: (_if_in_semmle_code ('cd "$SEMMLE_CODE"; tools/bazel test //language-packs:intree-' + LANGUAGE + '-as-test --test_output=all') '# using codeql from PATH, if any')
# Call bazel. Uses our official bazel wrapper if we are in an internal repository checkout
[no-cd, no-exit-message]
_bazel COMMAND *ARGS: (_if_in_semmle_code 'cd "$SEMMLE_CODE"; tools/bazel' 'bazel' COMMAND ARGS)
# Call sembuild (requires an internal repository checkout)
[no-cd, no-exit-message]
_sembuild *ARGS: (_run_in_semmle_code "./build" ARGS)

View File

@@ -1,159 +0,0 @@
import * as child_process from "child_process";
import * as path from "path";
import * as os from "os";
import * as fs from "fs";
const vars = {
just: process.env["JUST_EXECUTABLE"] || "just",
error: process.env["JUST_ERROR"] || "error",
cmd_begin: process.env["CMD_BEGIN"] || "",
cmd_end: process.env["CMD_END"] || "",
semmle_code: process.env["SEMMLE_CODE"],
};
function invoke(
invocation: string[],
options: { cwd?: string; log_prefix?: string } = {},
): number {
const log_prefix =
options.log_prefix && options.log_prefix !== ""
? `${options.log_prefix} `
: "";
console.log(
`${vars.cmd_begin}${log_prefix}${invocation.join(" ")}${vars.cmd_end}`,
);
try {
child_process.execFileSync(invocation[0], invocation.slice(1), {
stdio: "inherit",
cwd: options.cwd,
});
} catch (error) {
return 1;
}
return 0;
}
type Args = {
tests: string[];
flags: string[];
env: string[];
codeql: string;
all: boolean;
};
const old_console_error = console.error;
console.error = (message: string) => {
old_console_error(vars.error + message);
};
function parseArgs(args: Args, argv: string) {
argv.split(/(?<!\\) /)
.map((arg) => arg.replace("\\ ", " "))
.forEach((arg) => {
if (arg.startsWith("--codeql=")) {
args.codeql = arg.split("=")[1];
} else if (arg === "+" || arg === "--all-checks") {
args.all = true;
} else if (arg.startsWith("-")) {
args.flags.push(arg);
} else if (/^[A-Z_][A-Z_0-9]*=.*$/.test(arg)) {
args.env.push(arg);
} else if (arg !== "") {
args.tests.push(arg);
}
});
}
function codeqlTestRun(argv: string[]): number {
const [language, base_args, all_args, extra_args] = argv;
const ram_per_thread = process.platform === "linux" ? 3000 : 2048;
const cpus = os.cpus().length;
let args: Args = {
tests: [],
flags: [`--ram=${ram_per_thread * cpus}`, `-j${cpus}`],
env: [],
codeql: vars.semmle_code ? "build" : "host",
all: false,
};
parseArgs(args, base_args);
parseArgs(args, extra_args);
if (args.all) {
parseArgs(args, all_args);
}
if (
!vars.semmle_code &&
(args.codeql === "build" || args.codeql === "built")
) {
console.error(
"Using `--codeql=build` or `--codeql=built` requires working with the internal repository",
);
return 1;
}
if (args.tests.length === 0) {
args.tests.push(".");
}
if (args.codeql === "build") {
if (
invoke([vars.just, language, "build"], {
cwd: vars.semmle_code,
}) !== 0
) {
return 1;
}
}
if (args.codeql !== "host") {
// disable the default implicit config file, but keep an explicit one
// this is the same behavior wrt to `--codeql` as the integration test runner
process.env["CODEQL_CONFIG_FILE"] ||= ".";
}
// Set and unset environment variables
args.env.forEach((envVar) => {
const [key, value] = envVar.split("=", 2);
if (key) {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
} else {
console.error(`Invalid environment variable assignment: ${envVar}`);
process.exit(1);
}
});
let codeql;
function check_codeql() {
if (!fs.existsSync(codeql)) {
console.error(`CodeQL executable not found: ${codeql}`);
process.exit(1);
}
}
if (args.codeql === "built" || args.codeql === "build") {
codeql = path.join(
vars.semmle_code!,
"target",
"intree",
`codeql-${language}`,
"codeql",
);
check_codeql();
} else if (args.codeql === "host") {
codeql = "codeql";
} else {
codeql = args.codeql;
check_codeql();
}
if (fs.lstatSync(codeql).isDirectory()) {
codeql = path.join(codeql, "codeql");
if (process.platform === "win32") {
codeql += ".exe";
}
check_codeql();
}
return invoke([codeql, "test", "run", ...args.flags, "--", ...args.tests], {
log_prefix: args.env.join(" "),
});
}
process.exit(codeqlTestRun(process.argv.slice(2)));

View File

@@ -1,58 +0,0 @@
import? '../../../semmle-code.just' # internal repo just file, if present
import 'semmle-code-stub.just'
set fallback
set allow-duplicate-recipes
set allow-duplicate-variables
set unstable
export PATH_SEP := if os() == "windows" { ";" } else { ":" }
export JUST_EXECUTABLE := just_executable()
error := style("error") + "error" + NORMAL + ": "
cmd_sep := "\n#--------------------------------------------------------\n"
export CMD_BEGIN := style("command") + cmd_sep
export CMD_END := cmd_sep + NORMAL
export JUST_ERROR := error
tsx := "npx tsx@4.19.0"
default_db_checks := """\
--check-databases \
--check-diff-informed \
--fail-on-trap-errors \
"""
[no-exit-message]
@_require_semmle_code:
{{ if SEMMLE_CODE == "" { '''
echo "''' + error + ''' running this recipe requires doing so from an internal repository checkout" >&2
exit 1
''' } else { "" } }}
[no-cd]
_run +ARGS:
{{ cmd_sep }}{{ ARGS }}{{ cmd_sep }}
[no-cd]
_run_in DIR +ARGS:
{{ cmd_sep }}cd "{{ DIR }}"; {{ ARGS }}{{ cmd_sep }}
[no-cd]
_run_in_semmle_code +ARGS: _require_semmle_code (_run_in "$SEMMLE_CODE" ARGS)
[no-cd, positional-arguments, no-exit-message]
@_just +ARGS:
echo "-> just $@"
"{{ JUST_EXECUTABLE }}" "$@"
[no-cd, positional-arguments]
@_if_not_on_ci_just +ARGS:
if [ "${GITHUB_ACTIONS:-}" != "true" ]; then \
echo "-> just $@"; \
"$JUST_EXECUTABLE" "$@"; \
fi
[no-cd, no-exit-message]
_if_in_semmle_code THEN ELSE *ARGS:
{{ cmd_sep }}{{ if SEMMLE_CODE != "" { THEN } else { ELSE } }} {{ ARGS }}{{ cmd_sep }}

View File

@@ -1,20 +0,0 @@
import "build.just"
[no-cd, no-exit-message]
_format_ql +ARGS: (_maybe_build_dist "nolang") (
_if_in_semmle_code
'"$SEMMLE_CODE/target/intree/codeql-nolang/codeql"'
'codeql'
("query format --in-place -v $(find " + ARGS + " -type f -name '*.ql' -or -name '*.qll')")
)
[no-cd, no-exit-message]
_format_py *ARGS=".": (_if_in_semmle_code "uv run black" "black" ARGS)
[no-cd, no-exit-message]
_format_cpp *ARGS=".": (
_if_in_semmle_code
"uv run clang-format"
"clang-format"
"-i --verbose $(find " + ARGS + " -type f -name '*.h' -or -name '*.cpp')"
)

View File

@@ -1,131 +0,0 @@
import * as child_process from "child_process";
import * as path from "path";
import * as fs from "fs";
const vars = {
just: process.env["JUST_EXECUTABLE"] || "just",
error: process.env["JUST_ERROR"] || "",
};
console.debug = (...args: any[]) => {}; // comment out to debug script
const old_console_error = console.error;
console.error = (message: string) => {
old_console_error(vars.error + message);
};
function checkJustCommand(
justfile: string,
command: string,
postitionalArgs: string[],
): boolean {
if (!fs.existsSync(justfile)) {
return false;
}
let { cwd, args } = getJustContext(justfile, command, [], postitionalArgs);
console.debug(
`Checking: ${cwd ? `cd ${cwd}; ` : ""}just ${args.join(", ")}`,
);
const res = child_process.spawnSync(vars.just, ["--dry-run", ...args], {
stdio: ["ignore", "ignore", "pipe"],
encoding: "utf8",
cwd,
});
console.debug("result:", res);
// avoid having the forwarder find itself
return (
res.status === 0 &&
!res.stderr.includes(`forward-command.ts" ${command} "$@"`)
);
}
function findJustfile(command: string, arg: string): string | undefined {
for (let p = arg; ; p = path.dirname(p)) {
const candidate = path.join(p, "justfile");
if (checkJustCommand(candidate, command, [arg])) {
return candidate;
}
if (p === "/" || p === ".") {
return undefined;
}
}
}
function forwardCommand(args: string[]): number {
if (args.length == 0) {
console.error("No command provided");
return 1;
}
return forward(args[0], args.slice(1));
}
function forward(cmd: string, args: string[]): number {
// non-positional arguments are flags, + (used by language tests) or environment variable settings
const is_non_positional = /^(-.*|\+|[A-Z_][A-Z_0-9]*=.*)$/;
const flags = args.filter((arg) => is_non_positional.test(arg));
const positionalArgs = args.filter((arg) => !is_non_positional.test(arg));
let justfiles: Map<string, string[]> = new Map();
for (const arg of positionalArgs.length > 0 ? positionalArgs : ["."]) {
const justfile = findJustfile(cmd, arg);
if (!justfile) {
console.error(`No justfile found for ${cmd} on ${arg}`);
return 1;
}
justfiles.set(justfile, [...(justfiles.get(justfile) || []), arg]);
}
const invocations = Array.from(justfiles.entries()).map(
([justfile, positionalArgs]) => {
const { cwd, args } = getJustContext(
justfile,
cmd,
flags,
positionalArgs,
);
console.log(`-> ${cwd ? `cd ${cwd}; ` : ""}just ${args.join(" ")}`);
return { cwd, args };
},
);
for (const { cwd, args } of invocations) {
if (invokeJust(cwd, args) !== 0) {
return 1;
}
}
return 0;
}
function getJustContext(
justfile: string,
cmd: string,
flags: string[],
positionalArgs: string[],
): { args: string[]; cwd?: string } {
if (
positionalArgs.length === 1 &&
justfile == path.join(positionalArgs[0], "justfile")
) {
// If there's only one positional argument and it matches the justfile path, suppress arguments
// so for example `just build ql/rust` becomes `just build` in the `ql/rust` directory
return {
cwd: positionalArgs[0],
args: [cmd, ...flags],
};
} else {
return {
cwd: undefined,
args: ["--justfile", justfile, cmd, ...flags, ...positionalArgs],
};
}
}
function invokeJust(cwd: string | undefined, args: string[]): number {
try {
child_process.execFileSync(vars.just, args, {
stdio: "inherit",
cwd,
});
} catch (error) {
return 1;
}
return 0;
}
process.exit(forwardCommand(process.argv.slice(2)));

View File

@@ -1,38 +0,0 @@
# Common verbs
# See README.md in this directory for an overview.
import "lib.just"
# copy&paste necessary for each command until proper forwarding of multiple args is implemented
# see https://github.com/casey/just/issues/1988
_forward := tsx + ' "' + source_dir() + '/forward-command.ts"'
alias t := test
alias b := build
alias g := generate
alias gen := generate
alias f := format
alias l := lint
[no-cd, positional-arguments, no-exit-message]
@test *ARGS:
{{ _forward }} test "$@"
[no-cd, positional-arguments, no-exit-message]
@build *ARGS:
{{ _forward }} build "$@"
[no-cd, positional-arguments, no-exit-message]
@generate *ARGS:
{{ _forward }} generate "$@"
[no-cd, positional-arguments, no-exit-message]
@lint *ARGS:
{{ _forward }} lint "$@"
[no-cd, positional-arguments, no-exit-message]
@format *ARGS:
{{ _forward }} format "$@"

View File

@@ -1,2 +0,0 @@
format *ARGS=".":
npx prettier --write {{ ARGS }}

View File

@@ -1,33 +0,0 @@
import * as path from "path";
import * as process from "process";
import * as child_process from "child_process";
function languageTests(argv: string[]): number {
const [extra_args, dir, ...relativeRoots] = argv;
const semmle_code = process.env["SEMMLE_CODE"]!;
let roots = relativeRoots.map((root) =>
path.relative(semmle_code, path.join(dir, root)),
);
const invocation = [
process.env["JUST_EXECUTABLE"] || "just",
"--justfile",
path.join(roots[0], "justfile"),
"test",
"--all-checks",
"--codeql=built",
...extra_args.split(" "),
...roots,
];
console.log(`-> just ${invocation.slice(1).join(" ")}`);
try {
child_process.execFileSync(invocation[0], invocation.slice(1), {
stdio: "inherit",
cwd: semmle_code,
});
} catch (error) {
return 1;
}
return 0;
}
process.exit(languageTests(process.argv.slice(2)));

View File

@@ -1,47 +0,0 @@
# Helper recipes
import "build.just"
import "format.just"
# Run language tests. `BASE_FLAGS` are used by default, `ALL_CHECK_FLAGS` are used if
# `--all-checks` or `+` is passed along in `EXTRA_ARGS`
[no-cd, positional-arguments, no-exit-message]
@_codeql_test LANGUAGE BASE_FLAGS ALL_CHECKS_FLAGS EXTRA_ARGS:
{{ tsx }} "{{ source_dir() }}/codeql-test-run.ts" "$@"
# Run all language tests in ROOTS for a language. This is intended to be called by CI
[no-cd, positional-arguments, no-exit-message]
@_language_tests EXTRA_ARGS SOURCE_DIR +ROOTS: _require_semmle_code
{{ tsx }} "{{ source_dir() }}/language-tests.ts" "$@"
# Run integration tests. Requires an internal repository checkout
[no-cd, no-exit-message]
_integration_test *ARGS: _require_semmle_code (_run "$SEMMLE_CODE/tools/pytest" "--codeql=build-as-test" ARGS)
# Generic run command recipe that can be used by other recipes, with nice rendering
[no-cd]
_run +ARGS:
{{ cmd_sep }}{{ ARGS }}{{ cmd_sep }}
# Run a command in a specific directory
[no-cd]
_run_in DIR +ARGS:
{{ cmd_sep }}cd "{{ DIR }}"; {{ ARGS }}{{ cmd_sep }}
# Run a command in the internal repository checkout
[no-cd]
_run_in_semmle_code +ARGS: _require_semmle_code (_run_in "$SEMMLE_CODE" ARGS)
# Run a just recipe
[no-cd, positional-arguments, no-exit-message]
@_just +ARGS:
echo "-> just $@"
"{{ JUST_EXECUTABLE }}" "$@"
# Run a just recipe, but only if we are not on CI
[no-cd, positional-arguments]
@_if_not_on_ci_just +ARGS:
if [ "${GITHUB_ACTIONS:-}" != "true" ]; then \
echo "-> just $@"; \
"$JUST_EXECUTABLE" "$@"; \
fi

View File

@@ -1 +0,0 @@
export SEMMLE_CODE := ""

View File

@@ -152,11 +152,7 @@ predicate missingCallToSuperclassMethod(Class base, Function shouldCall, string
*/
predicate missingCallToSuperclassMethodRestricted(Class base, Function shouldCall, string name) {
missingCallToSuperclassMethod(base, shouldCall, name) and
not exists(Class superBase |
// Alert only on the highest base class that has the issue
superBase = getADirectSuperclass+(base) and
missingCallToSuperclassMethod(superBase, shouldCall, name)
) and
not superclassAlsoMissesCall(base, shouldCall, name) and
not exists(Function subShouldCall |
// Mention in the alert only the lowest method we're missing the call to
subShouldCall.getScope() = getADirectSubclass+(shouldCall.getScope()) and
@@ -164,6 +160,15 @@ predicate missingCallToSuperclassMethodRestricted(Class base, Function shouldCal
)
}
/**
* Holds if a strict superclass of `base` is also missing a call to `shouldCall` named `name`,
* indicating that `base` is not the highest class in the hierarchy with this issue.
*/
pragma[nomagic]
private predicate superclassAlsoMissesCall(Class base, Function shouldCall, string name) {
missingCallToSuperclassMethod(getADirectSuperclass+(base), shouldCall, name)
}
/**
* If `base` contains a `super()` call, gets a method in the inheritance hierarchy of `name` in the MRO of `base`
* that does not contain a `super()` call, but would call `shouldCall` if it did, which does not otherwise get called

View File

@@ -2,7 +2,7 @@
set -eu
source misc/bazel/runfiles.sh 2>/dev/null || source ../ql+/misc/bazel/runfiles.sh
source misc/bazel/runfiles.sh 2>/dev/null || source external/ql+/misc/bazel/runfiles.sh
ast_generator="$(rlocation "$1")"
grammar_file="$(rlocation "$2")"

View File

@@ -1,14 +0,0 @@
import '../lib.just'
install: (_bazel "run" "@codeql//rust:install")
build: (_if_not_on_ci_just "generate" source_dir()) (_build_dist "rust")
generate: (_bazel "run" "@codeql//rust/codegen")
lint: (_run_in source_dir() "python3" "lint.py")
format: (_run_in source_dir() "python3" "lint.py" "--format-only")
[group('test')]
language-tests *EXTRA_ARGS: (_language_tests EXTRA_ARGS source_dir() 'ql/test')

View File

@@ -4,14 +4,6 @@ import subprocess
import pathlib
import shutil
import sys
import argparse
def options():
parser = argparse.ArgumentParser(description="lint rust language pack code")
parser.add_argument("--format-only", action="store_true", help="Only apply formatting")
return parser.parse_args()
def tool(name):
@@ -20,35 +12,27 @@ def tool(name):
return ret
def main():
args = options()
this_dir = pathlib.Path(__file__).resolve().parent
this_dir = pathlib.Path(__file__).resolve().parent
cargo = tool("cargo")
bazel = tool("bazel")
runs = []
cargo = tool("cargo")
bazel = tool("bazel")
runs = []
def run(tool, args, *, cwd=this_dir):
print("+", tool, args)
runs.append(subprocess.run([tool] + args.split(), cwd=cwd))
def run(tool, args, *, cwd=this_dir):
print("+", tool, args)
runs.append(subprocess.run([tool] + args.split(), cwd=cwd))
# make sure bazel-provided sources are put in tree for `cargo` to work with them
run(bazel, "run ast-generator:inject-sources")
run(cargo, "fmt --all --quiet")
for manifest in this_dir.rglob("Cargo.toml"):
if not manifest.is_relative_to(this_dir / "ql") and not manifest.is_relative_to(this_dir / "integration-tests"):
run(cargo,
"clippy --fix --allow-dirty --allow-staged --quiet -- -D warnings",
cwd=manifest.parent)
# make sure bazel-provided sources are put in tree for `cargo` to work with them
run(bazel, "run ast-generator:inject-sources")
run(cargo, "fmt --all --quiet")
if not args.format_only:
for manifest in this_dir.rglob("Cargo.toml"):
if not manifest.is_relative_to(this_dir / "ql") and not manifest.is_relative_to(this_dir / "integration-tests"):
run(cargo,
"clippy --fix --allow-dirty --allow-staged --quiet -- -D warnings",
cwd=manifest.parent)
return max(r.returncode for r in runs)
if __name__ == "__main__":
sys.exit(main())
sys.exit(max(r.returncode for r in runs))

View File

@@ -1,10 +0,0 @@
import "../../../lib.just"
[no-cd]
test *ARGS=".": (_if_not_on_ci_just "generate" source_dir()) (_integration_test ARGS)
# TODO in separate PR
# [no-cd]
# format *ARGS=".": (_format_ql ARGS) (_format_py ARGS)

View File

@@ -1,6 +0,0 @@
import "../../lib.just"
[no-cd]
format *ARGS=".": (_format_ql ARGS)
consistency_queries := source_dir() / "consistency-queries"

View File

@@ -39,8 +39,8 @@ predicate pathTypeAsTraitAssoc(
/**
* Holds if `assoc` is accessed on `tp` in `path`.
*
* That is, this is the case when `path` is of the form `<tp as
* Trait>::AssocType` or `tp::AssocType`; and `AssocType` resolves to `assoc`.
* That is, this is the case when `path` is of the form `<tp as Trait>::AssocType`
* or `tp::AssocType`; and `AssocType` resolves to `assoc`.
*/
predicate tpAssociatedType(TypeParam tp, AssocType assoc, Path path) {
resolvePath(path.getQualifier()) = tp and

View File

@@ -699,9 +699,13 @@ class PreTypeMention = PreTypeMention::TypeMention;
/**
* Holds if `path` accesses an associated type `alias` from `trait` on a
* concrete type given by `tm`.
*
* `implOrTmTrait` is either the mention that resolves to `trait` when `path`
* is of the form `<Type as Trait>::AssocType`, or the enclosing `impl` block
* when `path` is of the form `Self::AssocType`.
*/
private predicate pathConcreteTypeAssocType(
Path path, PreTypeMention tm, TraitItemNode trait, PreTypeMention tmTrait, TypeAlias alias
Path path, PreTypeMention tm, TraitItemNode trait, AstNode implOrTmTrait, TypeAlias alias
) {
exists(Path qualifier |
qualifier = path.getQualifier() and
@@ -710,19 +714,19 @@ private predicate pathConcreteTypeAssocType(
// path of the form `<Type as Trait>::AssocType`
// ^^^ tm ^^^^^^^^^ name
exists(string name |
pathTypeAsTraitAssoc(path, tm, tmTrait, trait, name) and
pathTypeAsTraitAssoc(path, tm, implOrTmTrait, trait, name) and
getTraitAssocType(trait, name) = alias
)
or
// path of the form `Self::AssocType` within an `impl` block
// tm ^^^^ ^^^^^^^^^ name
exists(ImplItemNode impl |
alias = resolvePath(path) and
qualifier = impl.getASelfPath() and
tm = impl.(Impl).getSelfTy() and
trait.getAnAssocItem() = alias and
tmTrait = impl.getTraitPath()
)
implOrTmTrait =
any(ImplItemNode impl |
alias = resolvePath(path) and
qualifier = impl.getASelfPath() and
tm = impl.(Impl).getSelfTy() and
trait.getAnAssocItem() = alias
)
)
}
@@ -741,21 +745,26 @@ private module PathSatisfiesConstraint =
*/
private Type getPathConcreteAssocTypeAt(Path path, TypePath typePath) {
exists(
PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, PreTypeMention tmTrait,
PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, AstNode implOrTmTrait,
TypeAlias alias, TypePath path0
|
pathConcreteTypeAssocType(path, tm, trait, tmTrait, alias) and
pathConcreteTypeAssocType(path, tm, trait, implOrTmTrait, alias) and
t = TTrait(trait) and
PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, t, path0, result) and
path0.isCons(TAssociatedTypeTypeParameter(trait, alias), typePath)
|
tmTrait.getTypeAt(TypePath::nil()) != t
implOrTmTrait instanceof Impl
or
not exists(TypePath path1, Type t1 |
t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and
not t1 instanceof TypeParameter and
t1 != tmTrait.getTypeAt(path1)
)
// When `path` is of the form `<Type as Trait>::AssocType` we need to check
// that `impl` is not more specific than the mentioned trait
implOrTmTrait =
any(PreTypeMention tmTrait |
not exists(TypePath path1, Type t1 |
t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and
not t1 instanceof TypeParameter and
t1 != tmTrait.getTypeAt(path1)
)
)
)
}

View File

@@ -1,7 +0,0 @@
import "../justfile"
all_checks := default_db_checks + """\
--consistency-queries=""" + consistency_queries
[no-cd]
test *ARGS=".": (_codeql_test "rust" "" all_checks ARGS)

View File

@@ -81,6 +81,9 @@ static void turnOffSilVerifications(swift::SILOptions& options) {
options.VerifyExclusivity = false;
options.VerifyNone = true;
options.VerifySILOwnership = false;
// Stack protection is not needed for extraction and causes a crash on Linux
// (https://github.com/swiftlang/swift/issues/69768)
options.EnableStackProtection = false;
}
codeql::TrapDomain invocationTrapDomain(codeql::SwiftExtractorState& state);

View File

@@ -1,17 +0,0 @@
import '../lib.just'
import "../../ql/swift/ql/justfile"
install: (_bazel "run" "@codeql//swift:install")
[group('build')]
build: (_build_dist "swift")
generate: (_bazel "run" "@codeql//swift/codegen")
format ARGS=".": (_format_cpp ARGS)
[group('test')]
language-tests *EXTRA_ARGS: (_language_tests EXTRA_ARGS source_dir() 'ql/test')
[group('test')]
extra-tests: (_sembuild "target/test/check-queries-swift") (_sembuild "target/test/check-db-upgrades-swift") (_sembuild "target/test/check-db-downgrades-swift")

View File

@@ -1,9 +0,0 @@
import "../../../lib.just"
[no-cd]
test *ARGS=".": (_just "generate") (_integration_test ARGS)
# TODO in separate PR
# [no-cd]
# format *ARGS=".": (_format_ql ARGS) (_format_py ARGS)

View File

@@ -1,6 +0,0 @@
import "../../lib.just"
[no-cd]
format *ARGS=".": (_format_ql ARGS)
consistency_queries := source_dir() / "consistency-queries"

View File

@@ -187,3 +187,5 @@ func makeTuple<each T>(_ t: repeat each T) -> (repeat each T) {
}
let _ = makeTuple("A", 2)
//codeql-extractor-options: -disable-stack-protector

View File

@@ -1,11 +0,0 @@
import "../justfile"
all_checks := default_db_checks + """\
--check-repeated-labels \
--check-redefined-labels \
--check-use-before-definition \
--consistency-queries=""" + consistency_queries
[no-cd]
test *ARGS=".": (_codeql_test "swift" "" all_checks ARGS)