Compare commits

...

837 Commits

Author SHA1 Message Date
Michael B. Gale
21710fa597 Add diagnostics rule for arbitrary build messages 2023-03-08 14:27:23 +00:00
yoff
a45a0ee50d Merge pull request #12425 from RasmusWL/arg-passing-problem
Python: Add test of keyword argument with same name as positional-only parameter
2023-03-08 12:01:26 +01:00
Paolo Tranquilli
a4c0a0353f Merge pull request #12426 from github/redsun82/cpp-file-permissions-example
C++: fix example code for `FilePermissions.qll`
2023-03-07 19:55:46 +01:00
AlexDenisov
6a985a3df9 Merge pull request #12392 from github/alexdenisov/mangle-builtin-types
Swift: mangle builtin types
2023-03-07 18:22:13 +01:00
Alex Denisov
1283bcb860 Swift: mangle builtin types 2023-03-07 17:45:08 +01:00
AlexDenisov
d469b9711d Merge pull request #12388 from github/alexdenisov/introduce-type-mangling
Swift: introduce type mangling
2023-03-07 17:44:30 +01:00
Geoffrey White
72d6f56df1 Merge pull request #12413 from geoffw0/ptrout2
Swift: Permit data flow from all generic arguments
2023-03-07 16:27:12 +00:00
Paolo Tranquilli
c4fd39ec3f C++: fix example code for FilePermissions.qll 2023-03-07 13:50:20 +01:00
Paolo Tranquilli
bdad847584 Merge pull request #12422 from github/redsun82/cpp-scanf-fp
C++: add false positives to `MissingCheckScanf` test
2023-03-07 13:29:22 +01:00
Rasmus Wriedt Larsen
dda29e99b2 Python: Add test of keyword argument with same name as positional-only parameter
This is a bit of an edge case, but allowed. Since we currently don't
provide information on positional only arguments, we can't do much to
solve it right now.
2023-03-07 13:28:48 +01:00
Michael B. Gale
7627a53c49 Merge pull request #12371 from github/mbg/csharp/increase-diagnostic-visibility
C#: Make diagnostics visible everywhere
2023-03-07 12:13:09 +00:00
Michael B. Gale
974fdd305e Merge pull request #12372 from github/mbg/csharp/check-integration-test-diagnostics
C#: Add diagnostic checks to all remaining integration tests
2023-03-07 12:11:47 +00:00
Michael B. Gale
b75f138507 Merge pull request #12385 from github/mbg/csharp/readd-tsp-support
C#: Add support for the tool status page
2023-03-07 12:10:52 +00:00
Paolo Tranquilli
429518bcea C++: add further FP to test 2023-03-07 12:03:34 +01:00
Paolo Tranquilli
311cf4e7fd C++: add false positives to MissingCheckScanf test
See https://github.com/github/codeql/issues/12412 for the initial
report.
2023-03-07 11:56:05 +01:00
Michael Nebel
40d31120d9 Merge pull request #12264 from michaelnebel/csharp/nugetnet7
C#: Stub generator improvements.
2023-03-07 11:30:57 +01:00
Jeroen Ketema
3a4c0a2aae Merge pull request #12389 from jketema/more-deprecated
C++: Add `deprecated` to predicates that are deprecated according to the QLDoc
2023-03-07 11:21:43 +01:00
Michael Nebel
676c352819 C#: Update expected test output. 2023-03-07 10:19:26 +01:00
Michael Nebel
e85b2ebd20 C#: Replace stub member comment with file level comment. 2023-03-07 10:19:26 +01:00
Michael Nebel
c8f7304d9b C#: Address review comments. 2023-03-07 10:19:25 +01:00
Michael Nebel
e797b5c226 C#: Narrow the set of declarations where we make explicit interface implementations. 2023-03-07 10:19:25 +01:00
Michael Nebel
d8acc7cd17 C#: Stub generator support for explicit interface implementations of explicit conversion operators including test cases. 2023-03-07 10:19:25 +01:00
Michael Nebel
59349ed7c7 C#: Add test cases for static and virtual operators in interfaces and overlapping interface declarations. 2023-03-07 10:19:25 +01:00
Michael Nebel
50570dc3ee C#: Only add explicit interface implementation to the generated stub if it is unique. 2023-03-07 10:19:25 +01:00
Michael Nebel
5ba59fc9a8 C#: Stub generator support for operators in interfaces and interface implementations. 2023-03-07 10:19:25 +01:00
Michael Nebel
b68e78d908 C#: Stub generator support for static virtual and static abstract interface members. 2023-03-07 10:19:25 +01:00
Michael Nebel
aa4b98bbd5 C#: The stub generator should just format whitespaces. 2023-03-07 10:19:25 +01:00
Tom Hvitved
9b02eb729f Merge pull request #12419 from hvitved/ruby/stored-xss-config-rewrite
Ruby: Rewrite Stored XSS query to use new data flow interface
2023-03-07 09:46:08 +01:00
Jeroen Ketema
c9bccd9b43 C++: Fix more tests that used deprecated function 2023-03-07 09:01:13 +01:00
Tom Hvitved
b6a709df50 Ruby: Rewrite Stored XSS query to use new data flow interface 2023-03-07 07:23:27 +01:00
Geoffrey White
2ed140c696 Swift: Update the pointertypes test. 2023-03-06 17:14:14 +00:00
Mathias Vorreiter Pedersen
ff53e53e8c Merge pull request #12236 from MathiasVP/language-specific-field-flow-branch-limit-term
Dataflow: Add a language specific term to `join` and `branch`
2023-03-06 16:59:09 +00:00
Geoffrey White
4d327dbf4f Swift: The PointerType class isn't used any d any more. 2023-03-06 16:36:41 +00:00
Geoffrey White
61340c4b20 Swift: Permit data flow from generic arguments, rather than just pointers. 2023-03-06 16:34:12 +00:00
Geoffrey White
1e5b904514 Swift: Add test cases for mutating pointers inside containers. 2023-03-06 16:17:39 +00:00
Mathias Vorreiter Pedersen
92ad099c1b DataFlow: Remove bindingsets, remove the call column, and swap parameter and argument columns. 2023-03-06 13:47:59 +00:00
Mathias Vorreiter Pedersen
3bf28cc752 DataFlow: Sync identical files. 2023-03-06 13:46:21 +00:00
Mathias Vorreiter Pedersen
9647b6a3f5 Swift: Add stub. 2023-03-06 13:45:04 +00:00
Mathias Vorreiter Pedersen
e6b6369a21 Ruby: Add stub. 2023-03-06 13:44:59 +00:00
Mathias Vorreiter Pedersen
5ebd50044f Python: Add stub. 2023-03-06 13:44:24 +00:00
Mathias Vorreiter Pedersen
4720e2a30a Java: Add stub. 2023-03-06 13:44:24 +00:00
Mathias Vorreiter Pedersen
067abacbb8 Go: Add stub. 2023-03-06 13:44:23 +00:00
Mathias Vorreiter Pedersen
b667e0136f C#: Add stub. 2023-03-06 13:44:23 +00:00
Mathias Vorreiter Pedersen
05314b48e8 C++: Add stub. 2023-03-06 13:44:23 +00:00
Mathias Vorreiter Pedersen
6e8a2a6375 DataFlow: Add a language-specific predicate for modifying 'branch' and 'join'. 2023-03-06 13:44:19 +00:00
Geoffrey White
56b6441ef5 Merge pull request #12391 from geoffw0/ptrout
Swift: Permit data flow out through pointer arguments
2023-03-06 13:37:22 +00:00
Anders Schack-Mulligen
5c7f2ac7f7 Merge pull request #12186 from aschackmull/dataflow/refactor-configuration
Data flow: Refactor configuration
2023-03-06 13:38:59 +01:00
dependabot[bot]
3538cf89b9 Merge pull request #12404 from github/dependabot/cargo/ql/serde_json-1.0.94 2023-03-06 09:55:33 +00:00
Arthur Baars
d2ab40c184 Merge pull request #12208 from gregxsunday/main
Add ZipSlip and TarSlip query to ruby
2023-03-06 10:40:06 +01:00
dependabot[bot]
ce5e76a3a0 Bump serde_json from 1.0.93 to 1.0.94 in /ql
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.93 to 1.0.94.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.93...v1.0.94)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 09:32:26 +00:00
Anders Schack-Mulligen
557cb17f4d Dataflow: Minor perf fix for single config wrapper. 2023-03-06 10:24:33 +01:00
Calum Grant
b8e123dc08 Merge pull request #12402 from github/dependabot/cargo/ruby/serde_json-1.0.94
Bump serde_json from 1.0.93 to 1.0.94 in /ruby
2023-03-06 09:24:21 +00:00
Anders Schack-Mulligen
d4c5877484 Merge pull request #3 from MathiasVP/fix-exec-tainted
C++: Use refactored dataflow library in `cpp/command-line-injection`
2023-03-06 09:32:34 +01:00
Jeroen Ketema
72d03e4060 C++: Fix test that used deprecated function 2023-03-06 09:07:52 +01:00
dependabot[bot]
f93b304578 Bump serde_json from 1.0.93 to 1.0.94 in /ruby
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.93 to 1.0.94.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.93...v1.0.94)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 04:15:01 +00:00
Geoffrey White
6f120a66d0 Merge pull request #12368 from geoffw0/taintarith3
Swift: Fill some gaps in arithmetic / bitwise operations modelling
2023-03-03 18:20:54 +00:00
Geoffrey White
9aaf30691c Merge pull request #12307 from geoffw0/stringconflationtaint
Swift: Update swift/string-length-conflation to taint tracking
2023-03-03 17:27:15 +00:00
Geoffrey White
c29dcefcf2 Swift: Fix .expected file. Locations had changed after the formatting fix. 2023-03-03 17:24:07 +00:00
Geoffrey White
395bf675fe Swift: Make the test work on Linux. 2023-03-03 17:14:57 +00:00
Jeroen Ketema
aa00424b75 C++: Fix experimental query that uses the deprecated freeCall predicate 2023-03-03 17:53:49 +01:00
Geoffrey White
2d889304bb Swift: Some cases in the SqlInjection test are fixed by this. 2023-03-03 16:49:13 +00:00
Geoffrey White
b2bcb2d378 Swift: Fix formatting. 2023-03-03 16:32:21 +00:00
Chris Smowton
d4e02eb846 Merge pull request #12384 from smowton/smowton/admin/java-tsp-message-cleanup
Java TSP: test changes re: formatting improvements
2023-03-03 16:24:35 +00:00
Geoffrey White
6e3040987a Swift: Autoformat. 2023-03-03 16:24:28 +00:00
Geoffrey White
234f17b578 Swift: Use PointerType in data flow's 'modifiable' predicate. 2023-03-03 16:23:49 +00:00
Geoffrey White
3249cee1c9 Swift: Add an overall PointerType. 2023-03-03 16:23:46 +00:00
Geoffrey White
589e0af20a Swift: Test for pointer types. 2023-03-03 16:23:29 +00:00
Geoffrey White
9423c21d46 Swift: Add simple model for pointer types. 2023-03-03 16:23:27 +00:00
Jeroen Ketema
391d9bed5b C++: Add deprecated to predicates that are deprecated according to the QLDoc 2023-03-03 17:15:47 +01:00
Jeroen Ketema
2ee8344e92 Merge pull request #12387 from jketema/qualified-deprecation
C++: Properly deprecate `hasQualifiedName` by using the `deprecated` keyword
2023-03-03 17:11:56 +01:00
Alex Denisov
7f3e7224df Swift: introduce type mangling 2023-03-03 16:28:41 +01:00
AlexDenisov
4aeff0f8dc Merge pull request #12335 from github/alexdenisov/extract-lazy-declarations
Swift: extract lazy declarations
2023-03-03 16:06:20 +01:00
Geoffrey White
9f86bcb1b8 Swift: Proof of concept fix. 2023-03-03 15:04:47 +00:00
Geoffrey White
15227d3c09 Swift: Add tests where a user-defined (non-modelled) function taints the pointee of a pointer argument. 2023-03-03 15:00:22 +00:00
Jeroen Ketema
6495f1911f C++: Properly deprecate hasQualifiedName by using the deprecated keyword 2023-03-03 15:57:59 +01:00
Chris Smowton
b234bbd119 Accept test changes 2023-03-03 14:46:21 +00:00
Mathias Vorreiter Pedersen
907e6299a4 C++: Convert 'ExecTainted' to use the new refactored dataflow library. 2023-03-03 14:41:29 +00:00
Michael B. Gale
9dc9925f59 Abstract over DiagnosticsStream for tests 2023-03-03 13:05:43 +00:00
Michael Nebel
df6f5d52b9 C#: Use dependency injection in the auto builder for Diagnostic classifier. 2023-03-03 13:05:28 +00:00
Michael B. Gale
85751e7ddd Simplify DiagnosticClassifier in CSharpAutobuilder 2023-03-03 13:05:28 +00:00
Michael B. Gale
fe3066da56 Apply ql-for-ql suggestion 2023-03-03 13:05:28 +00:00
Michael B. Gale
a5f7913af3 Fix expected test output for Windows tests 2023-03-03 13:05:28 +00:00
Michael B. Gale
c2049c22a3 Refactor to avoid public setters 2023-03-03 13:05:27 +00:00
Michael B. Gale
4f0a93295a Move Language class to Semmle.Util 2023-03-03 13:05:27 +00:00
Michael B. Gale
6f3b5c01d5 Fix IDisposable contract violation 2023-03-03 13:05:27 +00:00
Michael B. Gale
be2d64a9d4 Simplify Xamarin query to be platform-independent 2023-03-03 13:05:27 +00:00
Michael B. Gale
92359de363 Add test for missing Xamarin SDKs 2023-03-03 13:05:27 +00:00
Michael B. Gale
1638f8edc5 Add test for missing project files 2023-03-03 13:05:26 +00:00
Michael B. Gale
40bda03180 Add test for dotnet incompatible projects 2023-03-03 13:05:26 +00:00
Michael B. Gale
5c641362bc Show .NET core error only if files exist 2023-03-03 13:05:26 +00:00
Michael B. Gale
04aaccb186 Fix C++ test missing env var 2023-03-03 13:05:26 +00:00
Michael B. Gale
6eda71b659 Add tests for build script diagnostics 2023-03-03 13:05:26 +00:00
Michael B. Gale
b26f9d0ff1 Use relative paths 2023-03-03 13:05:25 +00:00
Michael B. Gale
b2d1cfe3d1 Add diagnostic for missing project files 2023-03-03 13:05:25 +00:00
Michael B. Gale
b97c885c8d Add helper for markdown lists of projects 2023-03-03 13:05:25 +00:00
Michael B. Gale
5b6444d32d Refactor autobuild logic into an IBuildRule 2023-03-03 13:05:25 +00:00
Michael B. Gale
65608d7900 Fix: drop please 2023-03-03 13:05:24 +00:00
Michael B. Gale
95f9d0761a Add docs link for missing Xamarin SDKs 2023-03-03 13:05:24 +00:00
Michael B. Gale
0d5c5a7e92 Link to docs for autobuild failures 2023-03-03 13:05:24 +00:00
Michael B. Gale
9d19752c2e Make improvements based on PR feedback 2023-03-03 13:05:24 +00:00
Michael B. Gale
62cd8ca26f Update C/C++ autobuilder 2023-03-03 13:05:24 +00:00
Michael B. Gale
abf3f9f232 Use TryGetValue 2023-03-03 13:05:23 +00:00
Michael B. Gale
6471889fa6 Detect missing Xamarin SDKs 2023-03-03 13:05:23 +00:00
Michael B. Gale
b1f9a3d22a Fixup: better error message for no-projects-or-solutions 2023-03-03 13:05:23 +00:00
Michael B. Gale
9165ec92c5 Report .NET Core & MSBuild failures 2023-03-03 13:05:23 +00:00
Michael B. Gale
62b59747d1 Track which projects/solutions fail to build 2023-03-03 13:05:23 +00:00
Michael B. Gale
43df6397bb Report projects incompatible with .NET Core 2023-03-03 13:05:22 +00:00
Michael B. Gale
802e2319b5 Set DiagnosticMessage defaults
Refactor `GetDiagnosticSource` into `MakeDiagnostic`
which sets the defaults.
2023-03-03 13:05:22 +00:00
Michael B. Gale
28b350ee95 Change logic for autobuild failures
This is to account for multiple attempted rules that failed
2023-03-03 13:05:22 +00:00
Michael B. Gale
dfcc57ba83 Support asynchronous stdout/stderr processing 2023-03-03 13:05:22 +00:00
Michael B. Gale
ec2deb0889 Fixup: We => CodeQL 2023-03-03 13:05:22 +00:00
Michael B. Gale
dc7cf272db Add no projects/solutions diagnostic 2023-03-03 13:05:21 +00:00
Michael B. Gale
55d7b74489 Add diagnostics for BuildCommandAutoRule 2023-03-03 13:05:21 +00:00
Michael B. Gale
b88382e3e7 BuildCommandAutoRule: expose more information
We expose the list of candidate script paths and the chosen script path
so that we can inspect them for diagnostics purposes.
2023-03-03 13:05:21 +00:00
Michael B. Gale
60afa6e9f0 Add basic reporting of a general autobuild failure 2023-03-03 13:05:21 +00:00
Michael B. Gale
38a3a5ebfa Add initial code for diagnostic messages 2023-03-03 13:05:21 +00:00
Michael B. Gale
e029b1f0a8 Read ..._DIAGNOSTIC_DIR variable 2023-03-03 13:05:20 +00:00
Michael B. Gale
467429c23e Refactor env var code in Autobuilder class 2023-03-03 13:05:19 +00:00
Kasper Svendsen
fe65fb8743 Merge pull request #12360 from kaspersv/kaspersv/actioncontroller-prevent-bad-join
ActionController: Prevent bad join
2023-03-03 13:38:33 +01:00
Asger F
f2f972567d Merge pull request #12379 from github/revert-12217-mbg/csharp/tsp-support
Revert "C#: Tool status page support"
2023-03-03 13:29:13 +01:00
Erik Krogh Kristensen
d94e51aaf6 Merge pull request #12377 from erik-krogh/jHtml
JS: add the html argument to the jQuery functions as an XSS sink
2023-03-03 13:19:38 +01:00
Nick Fyson
48c30771da Merge pull request #12374 from github/codeql-ci/atm/update-model-pack/ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5
ATM: Update model pack to version 0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5
2023-03-03 11:42:57 +00:00
Anders Schack-Mulligen
0addcfa7c5 Dataflow: Fix some perf issues. 2023-03-03 11:45:32 +01:00
Asger F
8f0b77d54f Revert "C#: Tool status page support" 2023-03-03 11:44:42 +01:00
Geoffrey White
7b596f4928 Merge pull request #10431 from ihsinme/ihsinme-patch-111
CPP: Add query for CWE-369: Divide By Zero.
2023-03-03 10:42:04 +00:00
erik-krogh
a6c9af4182 add the html argument to the jQuery functions as an XSS sink 2023-03-03 11:09:53 +01:00
erik-krogh
94870b838f add failing test 2023-03-03 11:08:33 +01:00
Nick Fyson
5869c36366 Merge branch 'main' into codeql-ci/atm/update-model-pack/ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5 2023-03-03 10:03:22 +00:00
Alex Denisov
ae7a0c517c Swift: do not allocate mangler statically 2023-03-03 10:28:08 +01:00
Alex Denisov
60c1505097 Swift: address review comments 2023-03-03 10:26:44 +01:00
Paolo Tranquilli
1a19909abf Merge pull request #12373 from github/redsun82/swift-qldoc
Swift: turn on QLdoc check
2023-03-03 08:26:39 +01:00
Alex Denisov
ffcb382705 Swift: only consider Builting and __ObjC declarations as lazy 2023-03-02 20:00:23 +01:00
github-actions[bot]
50c90bbc5c ATM: Update model pack dependency of ML-powered model building and query packs 2023-03-02 17:31:03 +00:00
Geoffrey White
764a52354e Merge pull request #12367 from geoffw0/nsstring2
Swift: Additional NSString taint test cases
2023-03-02 15:56:15 +00:00
Michael B. Gale
75b4a0e8ea Add diagnostic checks to all integration tests 2023-03-02 15:25:49 +00:00
Paolo Tranquilli
162b995428 Swift: turn on QLdoc check 2023-03-02 16:16:12 +01:00
Anders Schack-Mulligen
b34f99f716 Dataflow: Add change notes. 2023-03-02 16:01:29 +01:00
Michael B. Gale
6c501d15b6 Make diagnostics visible everywhere 2023-03-02 14:53:53 +00:00
Anders Schack-Mulligen
a498ab241b Go: Fix query. 2023-03-02 13:53:37 +01:00
Mathias Vorreiter Pedersen
a1a2d7c469 Merge pull request #12355 from geoffw0/splittest
Swift: Split the taint flow test.
2023-03-02 12:53:07 +00:00
Geoffrey White
27ec36298f Swift: Understand binary pointwise operations. 2023-03-02 12:42:34 +00:00
Geoffrey White
ec2c58b416 Swift: Understand overflow binary bitwise operations. 2023-03-02 12:11:25 +00:00
Geoffrey White
1206b73d87 Swift: Understand overflow binary arithmetic operations. 2023-03-02 12:11:15 +00:00
Michael B. Gale
fd9b279ef9 Merge pull request #12217 from github/mbg/csharp/tsp-support 2023-03-02 11:47:30 +00:00
Geoffrey White
53f52df809 Swift: Add taint test cases for overflow, bitwise and pointwise arithmetic operations. 2023-03-02 11:41:31 +00:00
Geoffrey White
c42add2191 Swift: Add test cases for overflow and pointwise binary arithmetic operations. 2023-03-02 11:28:59 +00:00
Geoffrey White
730532f96a Swift: Add some (limited) test coverage for NSString <-> Data conversion. 2023-03-02 10:33:57 +00:00
Geoffrey White
1332309f59 Swift: Add some (limited) test coverage for String <-> NSString conversions. 2023-03-02 10:33:57 +00:00
Arthur Baars
9e5ef9cf9d Merge pull request #12216 from aibaars/diagnostics-2
Ruby: improve diagnostic messages
2023-03-02 10:30:58 +01:00
Kasper Svendsen
9cac4bbe0f ActionController: Prevent bad join 2023-03-02 10:02:08 +01:00
Tony Torralba
7705d5f513 Merge pull request #12357 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-03-02 09:30:38 +01:00
Michael Nebel
2525ac3dd2 C#: Use dependency injection in the auto builder for Diagnostic classifier. 2023-03-02 09:18:56 +01:00
github-actions[bot]
3b9de22af9 Add changed framework coverage reports 2023-03-02 00:18:47 +00:00
Geoffrey White
8e069b7686 Swift: Split the taint flow test. 2023-03-01 20:45:46 +00:00
yoff
65acf16ecc Merge pull request #12320 from yoff/python/document-api-call-node
Python: Document `API::CallNode`
2023-03-01 20:19:30 +01:00
Geoffrey White
bf6f6eec34 Merge pull request #12225 from geoffw0/nsstring
Swift: Taint models for NSString
2023-03-01 16:30:06 +00:00
Tony Torralba
59bd1e5ab1 Merge pull request #12228 from github/java/mad-decls-triage-request-2276
Java: Update MaD sink decls after triage
2023-03-01 17:08:38 +01:00
Geoffrey White
f8079056ec Swift: Fix test on Linux. 2023-03-01 15:47:30 +00:00
Michael B. Gale
93a45fce5e Simplify DiagnosticClassifier in CSharpAutobuilder 2023-03-01 14:58:49 +00:00
Alex Denisov
276fec39fc Swift: consider lazy declaration emitted if the process lost in the race 2023-03-01 15:42:44 +01:00
Alex Denisov
ded0e570b0 Swift: extract lazy declarations 2023-03-01 15:22:22 +01:00
AlexDenisov
fed504c1d0 Merge pull request #12348 from github/alexdenisov/extract-emission-body-decisions
Swift: move decision making out of dispatcher. NFC
2023-03-01 15:18:44 +01:00
Alex Denisov
8194fe3743 Swift: do not make module depend on itself for linkage awareness 2023-03-01 14:30:06 +01:00
Paolo Tranquilli
37438599de Merge branch 'main' into alexdenisov/extract-emission-body-decisions 2023-03-01 13:47:12 +01:00
Paolo Tranquilli
c0f9b111a0 Merge pull request #12347 from github/alexdenisov/move-location-extraction
Swift: move location extraction logic into a separate class. NFC
2023-03-01 13:46:52 +01:00
Anders Schack-Mulligen
34cc93846b Python: Adjust InsecureProtocol query. 2023-03-01 13:36:10 +01:00
Arthur Baars
2c611d3fef Address review comments 2023-03-01 13:30:02 +01:00
Michael Nebel
2db588f72e Merge pull request #12322 from michaelnebel/csharp/operatorexplicitinterface
C# 11: Support for explicit interface implementations of operators.
2023-03-01 12:55:21 +01:00
Erik Krogh Kristensen
64dad3db8a Merge pull request #12333 from kaspersv/kaspersv/fix-join-order
ReflectedXss: Prevent bad join order
2023-03-01 12:48:30 +01:00
AlexDenisov
5701798f1c Merge branch 'main' into alexdenisov/move-location-extraction 2023-03-01 12:24:41 +01:00
AlexDenisov
bb8d195607 Merge pull request #12337 from github/alexdenisov/extract-mangler
Swift: extract mangler into a separate class. NFC
2023-03-01 12:23:24 +01:00
Alex Denisov
def9831180 Swift: move decision making out of dispatcher 2023-03-01 12:02:58 +01:00
Alex Denisov
b1aef82117 Swift: move location extraction logic into a separate class 2023-03-01 11:32:50 +01:00
Tom Hvitved
16fa8b2914 Merge pull request #12051 from hmac/actioncontroller-filter-flow-steps
Ruby: flow steps for ActionController filters
2023-03-01 10:51:09 +01:00
Michael Nebel
ad5a45e465 C#: Add change note. 2023-03-01 10:42:29 +01:00
Michael Nebel
477b4566ed C#: Update expected test output. 2023-03-01 10:42:29 +01:00
Michael Nebel
f209eed91c C#: Extractor- and library support for explicit interface implementations for operators. 2023-03-01 10:42:28 +01:00
Michael Nebel
51be175111 C#: Add public members testcase and expected output. 2023-03-01 10:42:28 +01:00
Michael Nebel
363dd49a3c C#: Add explicit interface implementation examples and update expected test output. 2023-03-01 10:42:28 +01:00
Michael Nebel
0dc6ada616 Merge pull request #12234 from michaelnebel/csharp/filescopedtypes
C# 11: Support for `file` scoped types.
2023-03-01 10:39:46 +01:00
Geoffrey White
b6db0de437 Swift: Add inline expectation results. 2023-03-01 09:26:30 +00:00
Geoffrey White
228c0e221d Merge branch 'main' into nsstring 2023-03-01 09:12:36 +00:00
Geoffrey White
11e0efee68 Merge pull request #12308 from geoffw0/taintplusequals2
Swift: Model assignment operators (+= etc)
2023-03-01 09:02:29 +00:00
Tony Torralba
0439eb640d Add tests 2023-03-01 09:49:28 +01:00
Tony Torralba
4e7dbbf5f0 Add stubs 2023-03-01 09:48:33 +01:00
Tom Hvitved
92359e539b Fix another bad join
Before
```
[2023-03-01 08:19:51] Evaluated non-recursive predicate Filters#b57b2328::Filters::selfPostUpdate#2#ff@6718c917 in 6751ms (size: 83265).
Evaluated relational algebra for predicate Filters#b57b2328::Filters::selfPostUpdate#2#ff@6718c917 with tuple counts:
         3872025  ~3%    {2} r1 = JOIN _CfgNodes#ace8e412::ExprCfgNode::getExpr#0#dispred#ff_DataFlowPrivate#462ff392::Cached::TExprNode#ff#shared WITH Statement#f35022d0::Stmt::getCfgScope#0#dispred#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1
         3637917  ~0%    {2} r2 = JOIN r1 WITH Method#8b49e67f::Callable#f ON FIRST 1 OUTPUT Lhs.0, Lhs.1
          679799  ~0%    {2} r3 = JOIN r2 WITH Method#8b49e67f::Method#ff ON FIRST 1 OUTPUT Lhs.0, Lhs.1
         3069328  ~0%    {3} r4 = JOIN r3 WITH Variable#1965ffe5::Variable::getDeclaringScope#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0
        22039083  ~0%    {3} r5 = JOIN r4 WITH Variable#1965ffe5::VariableAccess::getVariable#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2
        10051483  ~0%    {3} r6 = JOIN r5 WITH Variable#9f7d933a::SelfVariableAccessImpl#class#f ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2
        10057538  ~5%    {3} r7 = JOIN r6 WITH CfgNodes#ace8e412::ExprCfgNode::getExpr#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2
        10057538  ~5%    {3} r8 = JOIN r7 WITH CfgNodes#ace8e412::ExprNodes::SelfVariableAccessCfgNode#ff ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2
        10057538  ~0%    {3} r9 = JOIN r8 WITH DataFlowPrivate#462ff392::Cached::TExprNode#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2
        10033937  ~1%    {3} r10 = JOIN r9 WITH DataFlowPublic#e1781e31::PostUpdateNode::getPreUpdateNode#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2
           83281  ~2%    {2} r11 = JOIN r10 WITH DataFlowPublic#e1781e31::PostUpdateNode::getPreUpdateNode#0#dispred#ff ON FIRST 2 OUTPUT Lhs.0, Lhs.2
                         return r11
```

After
```
[2023-03-01 08:31:20] Evaluated non-recursive predicate Filters#b57b2328::Filters::selfPostUpdate#2#ff@06d73c6q in 161ms (size: 83265).
Evaluated relational algebra for predicate Filters#b57b2328::Filters::selfPostUpdate#2#ff@06d73c6q with tuple counts:
         23680  ~2%    {1} r1 = SCAN Method#8b49e67f::Method#ff OUTPUT In.0
         23680  ~2%    {1} r2 = STREAM DEDUP r1
         23680  ~0%    {2} r3 = JOIN r2 WITH Method#8b49e67f::Callable#f ON FIRST 1 OUTPUT Lhs.0, Lhs.0
         54790  ~4%    {3} r4 = JOIN r3 WITH Variable#1965ffe5::Variable::getDeclaringScope#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0
        202490  ~0%    {3} r5 = JOIN r4 WITH Variable#1965ffe5::VariableAccess::getVariable#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2
         98332  ~5%    {3} r6 = JOIN r5 WITH Variable#9f7d933a::SelfVariableAccessImpl#class#f ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2
         83491  ~1%    {2} r7 = JOIN r6 WITH Statement#f35022d0::Stmt::getCfgScope#0#dispred#ff ON FIRST 2 OUTPUT Lhs.0, Lhs.2
         83584  ~0%    {2} r8 = JOIN r7 WITH CfgNodes#ace8e412::ExprCfgNode::getExpr#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1
         83584  ~0%    {2} r9 = JOIN r8 WITH DataFlowPrivate#462ff392::Cached::TExprNode#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1
         83265  ~2%    {2} r10 = JOIN r9 WITH DataFlowPublic#e1781e31::PostUpdateNode::getPreUpdateNode#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1
                       return r10
```
2023-03-01 08:34:07 +01:00
Aditya Sharad
aa6c60abfc Merge pull request #12342 from github/codeql-cli-2.12.3-mergeback
Mergeback: codeql-cli-2.12.3 into main
2023-02-28 10:30:51 -08:00
Felicity Chapman
6224d6ce31 Merge branch 'codeql-cli-2.12.3' into codeql-cli-2.12.3-mergeback 2023-02-28 17:08:49 +00:00
Michael B. Gale
49039246e1 Apply ql-for-ql suggestion 2023-02-28 15:55:50 +00:00
Michael B. Gale
f22c86442e Fix expected test output for Windows tests 2023-02-28 15:53:52 +00:00
Michael B. Gale
fea29d5172 Refactor to avoid public setters 2023-02-28 15:22:36 +00:00
Erik Krogh Kristensen
f3f5f6eacf Merge pull request #12190 from erik-krogh/fix-erb
JS: Actually extract `.html.erb` files.
2023-02-28 16:11:32 +01:00
Felicity Chapman
770326e770 Merge pull request #12321 from github/fc-7775-docs-update
CodeQL extension for VS Code docs update
2023-02-28 14:59:46 +00:00
Alex Denisov
97d5401118 Swift: extract mangler into a separate class 2023-02-28 15:29:44 +01:00
Michael B. Gale
e3762c7f93 Move Language class to Semmle.Util 2023-02-28 14:16:33 +00:00
Felicity Chapman
a7d221cdab Update docs/codeql/reusables/beta-note-mrva.rst 2023-02-28 14:12:57 +00:00
Michael B. Gale
e60676fbde Fix IDisposable contract violation 2023-02-28 13:56:06 +00:00
Anders Schack-Mulligen
5469a82efb Go,Java,Python: Fix some tests. 2023-02-28 14:31:00 +01:00
Michael Nebel
734001b7c4 Merge pull request #12334 from michaelnebel/csharp/staticinitialisers
C#: Update query to handle static field writes from properties.
2023-02-28 14:10:46 +01:00
Geoffrey White
d5952a174e Merge pull request #12329 from geoffw0/network
Swift: Modernize the cleartext-* queries
2023-02-28 13:04:10 +00:00
Michael Nebel
51746627d2 C#: Address review comments. 2023-02-28 13:38:34 +01:00
Felicity Chapman
aba7440293 Update docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst
Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com>
2023-02-28 12:29:16 +00:00
Felicity Chapman
832dc27b08 Update docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst
Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com>
2023-02-28 12:22:26 +00:00
Michael Nebel
4ef866b3a3 C#: Add change note. 2023-02-28 13:21:31 +01:00
Michael Nebel
baea74fa1b C#: Add new testexamples and update expected testoutput. 2023-02-28 13:21:31 +01:00
Michael Nebel
621674e82e C#: Update cs/static/field-written-by-instance to handle properties. 2023-02-28 13:21:30 +01:00
Chris Smowton
687f3c6b2e Merge pull request #12330 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-02-28 11:27:00 +00:00
Felicity Chapman
0af529ed7b Apply suggestions from code review
Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com>
2023-02-28 11:12:29 +00:00
Kasper Svendsen
86925646f3 ReflectedXss: Prevent bad join order 2023-02-28 12:06:27 +01:00
Michael Nebel
2db3694015 C#: Add code comment explaining the exclusion of the declared accessibility extraction for file scoped types. 2023-02-28 11:02:38 +01:00
Felicity Chapman
b21253732b Update for review feedback 2023-02-28 09:58:51 +00:00
Anders Schack-Mulligen
64c60d59b1 Go: Fix compilation. 2023-02-28 09:57:22 +01:00
github-actions[bot]
b6f81fc938 Add changed framework coverage reports 2023-02-28 00:17:14 +00:00
Geoffrey White
5110cf1e02 Swift: Convert some fiddly GRDB database sinks to CSV. 2023-02-27 23:31:48 +00:00
Geoffrey White
f289811473 Swift: Fix and autoformat. 2023-02-27 23:01:05 +00:00
Geoffrey White
ea4c2e4321 Swift: Add CSV extension points. 2023-02-27 23:01:05 +00:00
Geoffrey White
c533334470 Swift: Implementation classes should be private. 2023-02-27 23:01:04 +00:00
Geoffrey White
c21ec1c3f5 Swift: Standardize the taint sources, sinks, sanitizers. 2023-02-27 23:01:04 +00:00
Geoffrey White
6928e62d8b Swift: Split the three sensitive exprs queries into separate QL and QLL files. 2023-02-27 23:01:04 +00:00
Geoffrey White
59a2aa817c Merge branch 'main' into nsstring 2023-02-27 22:34:04 +00:00
Geoffrey White
bb55456885 Merge branch 'main' into taintplusequals2 2023-02-27 22:33:26 +00:00
Arthur Baars
6c57823232 Merge branch 'main' into diagnostics-2 2023-02-27 19:00:03 +01:00
Geoffrey White
36a33bc718 Swift: Delete file that was resurrected by the merge. 2023-02-27 17:33:21 +00:00
Nick Rolfe
0f4df0da99 Merge pull request #12326 from RasmusWL/python-fix-expected
Python: Fix expected of call-graph after merge
2023-02-27 17:30:10 +00:00
Geoffrey White
296093ded6 Merge branch 'main' into nsstring 2023-02-27 17:26:57 +00:00
Erik Krogh Kristensen
50aa5e072a Merge pull request #12177 from erik-krogh/alias-html
JS: More precise type-test sanitizer guards in unsafe-html-construction
2023-02-27 18:16:11 +01:00
Felicity Chapman
1d13811e46 Revise troubleshooting article 2023-02-27 16:42:07 +00:00
Rasmus Wriedt Larsen
d198b91c82 Python: Fix expected of call-graph after merge
Since the import resolution was fixed, but tests not rerun, these
expectations were not updated to reflect that we now handle them
properly 💪
2023-02-27 17:38:28 +01:00
Edward Minnix III
7f607fb46b Merge pull request #12032 from egregius313/egregius313/promote-hardcoded-jwt-credential
Java: Promote Hardcoded JWT credential query
2023-02-27 11:33:53 -05:00
Felicity Chapman
8e4eb9ad46 Tweaks to mention variant analysis in related articles 2023-02-27 16:21:09 +00:00
erik-krogh
505168f24b fix upper-case .html.erb files 2023-02-27 17:19:43 +01:00
Felicity Chapman
49ec539b60 Updates following initial PM review 2023-02-27 16:07:28 +00:00
Felicity Chapman
29802af647 Fix typo in heading 2023-02-27 15:06:19 +00:00
Felicity Chapman
9bee9c003a Apply suggestions from code review
Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com>
2023-02-27 14:58:17 +00:00
Erik Krogh Kristensen
927c322b7b Merge pull request #11769 from erik-krogh/moreSan
JS: Sanitizer for `sanitizer(x) === true`
2023-02-27 15:48:34 +01:00
Mathias Vorreiter Pedersen
332b759873 Merge pull request #12275 from jketema/uniform-ssa
Make "Detecting a potential buffer overflow" example more uniform
2023-02-27 14:38:11 +00:00
Mathias Vorreiter Pedersen
1dd95a61c1 Merge pull request #12292 from github/calumgrant/aggregate-domain
Query and tests for sum without domain
2023-02-27 14:19:20 +00:00
Tony Torralba
db6cb1ffe3 Remove dubious model after investigating it 2023-02-27 14:57:56 +01:00
yoff
335be21943 Update docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst
Co-authored-by: Taus <tausbn@github.com>
2023-02-27 14:53:31 +01:00
Taus
25043f51a4 Merge pull request #11376 from RasmusWL/call-graph-code
Python: New type-tracking based call-graph
2023-02-27 14:51:21 +01:00
Anders Schack-Mulligen
9671c8824c C#: Remove reference to stageStats. 2023-02-27 14:30:05 +01:00
Anders Schack-Mulligen
7e3e10c34b C/C++: Remove reference to Partial Flow. 2023-02-27 14:30:05 +01:00
Anders Schack-Mulligen
bf650c755c Dataflow: Sync changes to all languages. 2023-02-27 14:30:05 +01:00
Paolo Tranquilli
5cb3279816 Merge pull request #12319 from github/redsun82/swift-codegen
Codegen: make Swift codegen language agnostic
2023-02-27 14:06:20 +01:00
Felicity Chapman
70ed029d0e More updates 2023-02-27 12:41:53 +00:00
Alex Ford
7c85448cba Merge pull request #12080 from alexrford/js-use-shared-cryptography
JS: Use shared `CryptographicOperation` concept
2023-02-27 12:26:38 +00:00
Tony Torralba
0e3f4f6c7c Merge pull request #12305 from pwntester/new_java_net_URL_toURI_taintstep
Java: Add new java.net.URI taintsteps
2023-02-27 13:09:46 +01:00
Geoffrey White
8ef6521cc9 Swift: Undo toString changes. 2023-02-27 12:01:02 +00:00
Ed Minnix
ed1aac1aa5 Remove unneeded example file 2023-02-27 12:16:14 +01:00
Ed Minnix
06a1368e7c Additional test cases 2023-02-27 12:16:14 +01:00
Ed Minnix
4aec708fac Add change note 2023-02-27 12:16:14 +01:00
Ed Minnix
6de946ef00 Remove experimental files 2023-02-27 12:16:14 +01:00
Ed Minnix
3ff1a97e38 Add byte[] signatures 2023-02-27 12:16:14 +01:00
Ed Minnix
d71386e001 Add example file for documentation 2023-02-27 12:16:14 +01:00
Ed Minnix
fa6ac063d1 Add com.auth0.jwt.algorithm.Algorithm sinks
The HMAC* constructors of the com.auth0.jwt.algorithm.Algorithm class
take a secret as a parameter. Therefore, the arguments should be added
to be checked for hardcoded credentials.
2023-02-27 12:16:14 +01:00
AlexDenisov
85bf10ee0f Merge pull request #12227 from github/redsun82/swift-5.7.3
Swift: update to 5.7.3
2023-02-27 10:24:07 +01:00
Rasmus Lerchedahl Petersen
1447c2348a python: describe API::CallNode 2023-02-27 10:06:23 +01:00
Paolo Tranquilli
1218145259 Codegen: update README.md files 2023-02-27 10:01:50 +01:00
Paolo Tranquilli
06a6450be4 Codegen: make --qltest-output optional 2023-02-27 09:46:48 +01:00
Paolo Tranquilli
cdd4e8021b Move swift/codegen to misc/codegen 2023-02-27 09:46:48 +01:00
Paolo Tranquilli
6d192cdcc1 Swift: make C++ code generation language agnostic 2023-02-27 09:46:48 +01:00
Paolo Tranquilli
feb4e60c4b Swift: make all ql generation language agnostic 2023-02-27 09:46:48 +01:00
Paolo Tranquilli
aca18f5da8 Swift: make codegen use a config file 2023-02-27 09:46:48 +01:00
Paolo Tranquilli
e4627cb702 Swift: make codegen a bit more language-agnostic 2023-02-27 09:46:48 +01:00
Tony Torralba
c027e10ef7 Add java.net tests 2023-02-27 09:33:16 +01:00
Tony Torralba
4a9f63ea1a Fix toASCIIString casing 2023-02-27 09:32:42 +01:00
erik-krogh
0e60fc5512 Merge branch 'main' into alias-html 2023-02-27 09:16:25 +01:00
Erik Krogh Kristensen
f8f926ad50 Merge pull request #12175 from erik-krogh/reg-input
JS: add process.env and process.argv etc. as source for `js/regex-injection`
2023-02-27 09:12:02 +01:00
Rasmus Lerchedahl Petersen
9b08b06de4 python: update deprecated predicate names 2023-02-27 09:07:07 +01:00
Erik Krogh Kristensen
4ffe20ae75 Merge pull request #12189 from erik-krogh/more-export
JS: also consider relative exports when finding library inputs
2023-02-27 09:02:55 +01:00
Felicity Chapman
8af12071e1 First draft with bare bones 2023-02-24 21:39:16 +00:00
Geoffrey White
e71c7e7842 Swift: Autoformat. 2023-02-24 19:09:14 +00:00
Geoffrey White
a5943603ea Swift: 'Any' -> 'An' (make QL-for-QL happy) 2023-02-24 19:08:11 +00:00
Alvaro Muñoz
f393a3c549 Add toExternalForm 2023-02-24 18:50:31 +01:00
Alvaro Muñoz
f1d765aa27 Missing taintstep for java.net.URL.toURI() 2023-02-24 18:45:52 +01:00
Felicity Chapman
874c362961 Add basic framework of new articles 2023-02-24 17:14:49 +00:00
Michael B. Gale
e2af8f1b43 Simplify Xamarin query to be platform-independent 2023-02-24 17:13:10 +00:00
Michael B. Gale
31673431af Add test for missing Xamarin SDKs 2023-02-24 16:24:32 +00:00
Michael B. Gale
3ef3441883 Add test for missing project files 2023-02-24 16:24:07 +00:00
Michael B. Gale
354f716ca8 Add test for dotnet incompatible projects 2023-02-24 16:23:52 +00:00
Michael B. Gale
430af661cd Show .NET core error only if files exist 2023-02-24 16:16:33 +00:00
Mathias Vorreiter Pedersen
f92433171d Merge pull request #12304 from MathiasVP/more-fixes-to-large-join-order-query
QL: More fixes to the join-order query
2023-02-24 14:21:05 +00:00
Michael B. Gale
b203533fc6 Fix C++ test missing env var 2023-02-24 14:16:20 +00:00
Michael B. Gale
7de26550ad Add tests for build script diagnostics 2023-02-24 13:49:06 +00:00
Michael B. Gale
bdbcaab0ba Use relative paths 2023-02-24 13:49:06 +00:00
Michael B. Gale
1e2329d0dd Add diagnostic for missing project files 2023-02-24 13:49:05 +00:00
Michael B. Gale
3bf6b6f96f Add helper for markdown lists of projects 2023-02-24 13:49:05 +00:00
Mathias Vorreiter Pedersen
c9f8ebd620 QL: Remove redundant conjunct in aggregates. 2023-02-24 13:19:52 +00:00
Mathias Vorreiter Pedersen
375de59a14 QL: More fixes to the join-order query. 2023-02-24 12:44:17 +00:00
Calum Grant
10aad99e21 Add avg case 2023-02-24 11:02:07 +00:00
Grzegorz Niedziela
48007d14d5 move tests to experimental as well and fix .qlref reference 2023-02-24 10:38:21 +00:00
Tom Hvitved
af14f36127 Merge pull request #12289 from hvitved/util/file-system
Util: Add shared file system implementation
2023-02-24 11:23:48 +01:00
Chris Smowton
da459c4086 Merge pull request #12281 from smowton/smowton/feature/kotlin-too-new-diagnostic
Add test for a too-new Kotlin version
2023-02-24 08:48:30 +00:00
Mathias Vorreiter Pedersen
95283154ae Merge pull request #12303 from MathiasVP/join-order-query-fixes 2023-02-23 22:56:29 +00:00
Mathias Vorreiter Pedersen
1f40518c78 QL: Fixup the join-order query. 2023-02-23 22:39:20 +00:00
Mathias Vorreiter Pedersen
a86a8ced54 Merge pull request #12302 from MathiasVP/recursive-join-order-metric
QL: Extend the join-order badness query to recursive predicates
2023-02-23 22:35:35 +00:00
Mathias Vorreiter Pedersen
f0fe6fba88 QL: Accept test changes. 2023-02-23 22:25:04 +00:00
Mathias Vorreiter Pedersen
b0e391cff0 QL: Extend the join order metric to cover recursive predicates. 2023-02-23 22:12:23 +00:00
Mathias Vorreiter Pedersen
bb692a7e4a Merge pull request #12299 from github/calumgrant/qlql
Add classes and predicates to StructuredLogs
2023-02-23 21:47:28 +00:00
Calum Grant
41d88a45d9 Fix merge 2023-02-23 21:02:43 +00:00
Calum Grant
efa2647f09 Merge branch 'main' into calumgrant/qlql 2023-02-23 20:55:09 +00:00
Taus
b993b5ef77 Merge pull request #12298 from MathiasVP/join-order-metric-query-with-more-rows
QL: Output more rows in the join order query
2023-02-23 20:31:43 +01:00
Taus
6141c96b8c Merge pull request #12294 from MathiasVP/visit-recursive-evaluation
QL: Add a visitor for traversing recursive evaluations
2023-02-23 20:28:53 +01:00
Henry Mercer
39a30cf34b Merge pull request #12297 from github/codeql-ci/atm/release-0.4.8
JS: Bump version numbers of ML-powered packs after 0.4.8 release
2023-02-23 19:18:28 +00:00
Mathias Vorreiter Pedersen
9ee078d1f2 QL: More column information. 2023-02-23 19:17:22 +00:00
Calum Grant
dde18de2d1 Fixes 2023-02-23 19:03:05 +00:00
Calum Grant
196dbd3a33 Exploratory query to test the API 2023-02-23 19:01:52 +00:00
Calum Grant
77871e287d Use RAExpr 2023-02-23 18:35:24 +00:00
Calum Grant
e368b8f72a Add classes and predicates to StructuredLogs 2023-02-23 17:48:21 +00:00
Mathias Vorreiter Pedersen
229e291e1b QL: Fix naming. 2023-02-23 17:34:07 +00:00
Mathias Vorreiter Pedersen
dcc9b66aae Merge branch 'main' into visit-recursive-evaluation 2023-02-23 17:16:47 +00:00
Mathias Vorreiter Pedersen
9c8b8dff88 QL: Output more rows in the join order query. 2023-02-23 17:07:27 +00:00
Mathias Vorreiter Pedersen
48bf15f79c Merge pull request #12291 from github/calumgrant/slow-predicates
Slow predicates query
2023-02-23 16:41:39 +00:00
Mathias Vorreiter Pedersen
11ea8e0f85 Merge pull request #12295 from MathiasVP/join-order-metric-query
QL: Non-recursive join-order-metric query
2023-02-23 16:40:07 +00:00
Geoffrey White
1a7e7481b2 Swift: Add flow thtaint flow through assignments other than =. 2023-02-23 16:25:32 +00:00
Geoffrey White
a222757e69 Swift: Add support for pointwise assignment operators. 2023-02-23 16:25:32 +00:00
Geoffrey White
15e3892b03 Swift: Add support for overflow assignment operators. 2023-02-23 16:25:32 +00:00
Geoffrey White
1d4925d7af Swift: Expand assignment operations. 2023-02-23 16:25:31 +00:00
Henry Mercer
eb1fe57590 Merge branch 'main' into codeql-ci/atm/release-0.4.8 2023-02-23 16:23:32 +00:00
github-actions[bot]
7e2b286f03 JS: Bump version of ML-powered library and query packs to 0.4.9 2023-02-23 16:12:23 +00:00
github-actions[bot]
e02368f6fa JS: Bump patch version of ML-powered library and query packs 2023-02-23 16:04:39 +00:00
Mathias Vorreiter Pedersen
858b3de547 Merge branch 'main' into join-order-metric-query 2023-02-23 15:54:38 +00:00
Mathias Vorreiter Pedersen
23b9abcbbf QL: Add a query for finding the predicates with the highest tuple sums. 2023-02-23 15:53:32 +00:00
Mathias Vorreiter Pedersen
7595c1c306 QL: Add a visitor for traversing recursive evaluations. 2023-02-23 15:53:32 +00:00
Taus
d48938d168 Merge branch 'main' into calumgrant/slow-predicates 2023-02-23 16:53:04 +01:00
Taus
0419b5b24c Merge pull request #12296 from github/tausbn/ql-remove-unused-predicates
QL: Remove unused predicates
2023-02-23 16:47:34 +01:00
Taus
38ca4a8d3d QL: Remove unused predicates 2023-02-23 15:25:38 +00:00
Michael B. Gale
b034b2f2a3 Refactor autobuild logic into an IBuildRule 2023-02-23 14:54:37 +00:00
Chris Smowton
eb8a0c1129 Add test for a too-new Kotlin version 2023-02-23 14:53:27 +00:00
Mathias Vorreiter Pedersen
d7d9bea5e8 QL: Add a query for computing the join order metric for non-recursive predicates. 2023-02-23 14:27:39 +00:00
Geoffrey White
71813fa0a7 Swift: Implement full tree of Assignment classes 2023-02-23 13:23:36 +00:00
Geoffrey White
aaa89f7f32 Swift: Add a test for assignment exprs. 2023-02-23 13:15:06 +00:00
Mathias Vorreiter Pedersen
d734982e7b Merge pull request #12286 from github/tausbn/ql-add-a-bunch-of-convenience-predicates
QL: Add predicates for timestamps and locations
2023-02-23 12:45:46 +00:00
Calum Grant
fccf2d705e Add the expected file 2023-02-23 12:25:29 +00:00
Calum Grant
6cf575df78 Query and tests for sum without domain 2023-02-23 12:19:25 +00:00
gregxsunday
34b441c3cc move query to experimental folder 2023-02-23 12:12:04 +00:00
gregxsunday
5a85fa12c7 add block test cases and update tests 2023-02-23 12:09:22 +00:00
gregxsunday
f9b5846675 add detection of sources directly used with blocks 2023-02-23 12:09:12 +00:00
Grzegorz Niedziela
4ab6a7bdfd Merge branch 'github:main' into main 2023-02-23 10:50:15 +00:00
Calum Grant
564d7c0d53 Fix bug 2023-02-23 10:22:18 +00:00
Calum Grant
eb553266ae Add this. 2023-02-23 09:51:29 +00:00
Calum Grant
58563744d6 A simple query 2023-02-23 09:50:09 +00:00
Tom Hvitved
ad37523b07 C#: Adopt shared file system implementation 2023-02-23 10:21:04 +01:00
Tom Hvitved
bd5ae88a9a Ruby: Move FileSystem.qll implementation into shared util pack 2023-02-23 10:21:04 +01:00
Chris Smowton
748387a69f Merge pull request #11943 from smowton/smowton/admin/java-autobuilder-diagnostic-tests
Java: Add tests for autobuilder-detected diagnostics
2023-02-23 09:20:03 +00:00
Michael Nebel
cf659f9a5e Merge pull request #12261 from michaelnebel/csharpjava/refactorissupported
C#/Java: Re-factor the `isSupported` predicate.
2023-02-23 10:06:11 +01:00
Michael Nebel
ca94e02107 Merge pull request #12258 from michaelnebel/csharp/enumanddelegatemodfiers
C#: Generalise modifier extraction from symbols.
2023-02-23 10:04:55 +01:00
Paolo Tranquilli
8ed99bc83b Merge pull request #12284 from github/redsun82/swift-printast
Swift: fix comments in PrintAst library
2023-02-23 09:27:14 +01:00
Taus
6a32a3ae58 QL: Add predicates for timestamps and locations 2023-02-22 22:47:51 +00:00
Mathias Vorreiter Pedersen
24935c97bc Merge pull request #12285 from github/calumgrant/ql-ra-parser
RA parser first draft
2023-02-22 19:07:03 +00:00
Chris Smowton
560a341e87 Fix multiple-candidate-builds message 2023-02-22 17:43:08 +00:00
Chris Smowton
c4640a6a9a Fix diagnostic markdown links 2023-02-22 17:43:08 +00:00
Chris Smowton
73e4480cc6 Update test expectations 2023-02-22 17:43:08 +00:00
Chris Smowton
2c216793a4 Diagnostics tests: don't create own diagnostics directory
The CLI does this now. Also omit default arguments to the integration test script.
2023-02-22 17:43:08 +00:00
Chris Smowton
53ac1e0133 Replace test absolute directory 2023-02-22 17:43:08 +00:00
Chris Smowton
57ac951451 Add tests for Java autobuilder errors 2023-02-22 17:43:08 +00:00
Chris Smowton
fd1ce5d12c Switch to using language-specific diagnostic environment variable 2023-02-22 17:43:08 +00:00
Chris Smowton
7a2c6b5645 Java no-build-system test: switch to single-file diagnostics.expected format 2023-02-22 17:43:07 +00:00
Chris Smowton
40e45d3636 Add test for missing Java build system 2023-02-22 17:43:07 +00:00
Chris Smowton
7dc5e7e0fe Merge pull request #12283 from github/smowton/admin/merge-rc38-into-main-2023
Merge rc/3.8 into main
2023-02-22 17:35:11 +00:00
Calum Grant
0fdcf0338a Tidy up warnings 2023-02-22 17:02:49 +00:00
Calum Grant
f3e5a8f90f Minor tidy 2023-02-22 17:01:07 +00:00
Calum Grant
9980756ee8 RA parser first draft 2023-02-22 16:51:16 +00:00
Paolo Tranquilli
62f4e48433 Swift: fix comments in PrintAst library 2023-02-22 16:46:46 +01:00
Mathias Vorreiter Pedersen
676f4125c3 Merge pull request #12282 from MathiasVP/float-and-array-padding
QL: Handle large numbers and -1 padding
2023-02-22 15:16:54 +00:00
Chris Smowton
9155e08b65 Merge remote-tracking branch 'origin/rc/3.8' into smowton/admin/merge-rc38-into-main-2023 2023-02-22 15:12:06 +00:00
Chris Smowton
2c7a2fc6d7 Merge pull request #12272 from smowton/smowton/admin/rc38-ci-fixes
Merge rc/3.7 into rc/3.8
2023-02-22 15:10:35 +00:00
Mathias Vorreiter Pedersen
498d0c359e QL: Convert various int getters to float (to avoid overflow) and correctly handle '-1' padding. 2023-02-22 14:54:40 +00:00
Mathias Vorreiter Pedersen
b738c2684b Merge pull request #12279 from MathiasVP/kind-predicate-logs
QL: Start of the AST for `kind: predicates` evaluator logs
2023-02-22 14:25:11 +00:00
Mathias Vorreiter Pedersen
5e3289a089 Merge pull request #12280 from github/tausbn/ql-make-json-parsing-a-bit-more-robust
QL: Make the JSON parser a bit more robust
2023-02-22 14:16:48 +00:00
Mathias Vorreiter Pedersen
d64d03ec48 QL: Fix Code Scanning warning. 2023-02-22 14:15:47 +00:00
Mathias Vorreiter Pedersen
f155f19725 QL: Respond to comments. 2023-02-22 14:15:18 +00:00
Taus
2cdec47585 QL: Make the JSON parser a bit more robust
Updates the grammar to allow trailing commas in objects and arrays.

Also bumps the file size limit to 10MB.
2023-02-22 13:45:47 +00:00
Mathias Vorreiter Pedersen
161acf0ebe QL: Add more getters. 2023-02-22 13:43:51 +00:00
Mathias Vorreiter Pedersen
2c31d6863c QL: Start on the AST for kind: predicates evaluator logs. 2023-02-22 13:26:47 +00:00
Michael B. Gale
93b7a2bc92 Fix: drop please 2023-02-22 12:32:11 +00:00
Michael B. Gale
c3e25d2549 Add docs link for missing Xamarin SDKs 2023-02-22 12:32:10 +00:00
Michael B. Gale
08b51c3b06 Link to docs for autobuild failures 2023-02-22 12:32:10 +00:00
Michael B. Gale
0f320996cf Make improvements based on PR feedback 2023-02-22 12:32:07 +00:00
Mathias Vorreiter Pedersen
5b1288143f Merge pull request #12277 from github/tausbn/clean-up-structured-logs-module
QL: Clean up structured logs module
2023-02-22 12:27:07 +00:00
Taus
5304fe2bcb QL: Clean up structured logs module
Pushes it into an internal module and removes the abstract class.
2023-02-22 11:07:48 +00:00
Jeroen Ketema
eb6c8480f8 Make "Detecting a potential buffer overflow" example more uniform
All queries that use SSA import `semmle.code.cpp.controlflow.SSA` explicitly,
except for the last one. Also import the library there. Note that this is not
strictly necessary, as the library is transitively imported via `import cpp`.
2023-02-22 10:02:12 +01:00
Mathias Vorreiter Pedersen
dffb12070e Merge pull request #12271 from github/tausbn/ql-fix-json-extraction
QL: Fix JSON extraction
2023-02-22 08:50:49 +00:00
Chris Smowton
b28f1a562a Merge pull request #12273 from intrigus-lgtm/patch-8
Fix grammar
2023-02-22 08:43:07 +00:00
Michael Nebel
47c69d924b C#: Update comment on the isSupported predicate. 2023-02-22 09:05:28 +01:00
Michael Nebel
b4a6d1e1b6 C#: Add change note. 2023-02-22 08:59:14 +01:00
Michael Nebel
3e0aacd36b C#: Generalize modifier extraction from symbols. 2023-02-22 08:53:29 +01:00
intrigus-lgtm
540d3a3a99 Fix grammar 2023-02-22 00:42:50 +01:00
Taus
a3a099cf56 QL: Add a few more methods
Still need to implement something to encapsulate RA, link it up, etc.
2023-02-21 21:27:17 +00:00
Chris Smowton
7106f7d52e Add gradle wrappers to compiler_arguments and kotlin_kfunction tests
`
2023-02-21 21:20:43 +00:00
Chris Smowton
8bb068f3a9 Merge remote-tracking branch 'origin/rc/3.7' into smowton/admin/rc38-ci-fixes 2023-02-21 21:17:30 +00:00
Taus
729563c9a3 QL: Add preliminary support for structured logs 2023-02-21 21:09:34 +00:00
Chris Smowton
d849e27b37 Merge pull request #12259 from smowton/smowton/admin/gradle-wrappers-rc37
[rc/3.7]: Add Gradle wrappers for Kotlin tests
2023-02-21 21:04:39 +00:00
Taus
cf734919b9 QL: Fix bad string grammar
What was there before made it so that you couldn't actually extract the
contents of a string.
2023-02-21 20:20:58 +00:00
Taus
bab53b5736 QL: Fix JSON extraction
I had forgotten about this extra filtering that takes place in the
extractor.
2023-02-21 19:50:27 +00:00
Mathias Vorreiter Pedersen
ad8d9c5b91 Merge pull request #12269 from github/tausbn/ql-add-json-extraction
QL: Add JSON (+C/L) extraction
2023-02-21 16:42:19 +00:00
Arthur Baars
aac65b0df0 Merge pull request #12268 from aibaars/update-erb
Ruby: update tree-sitter-embedded-template
2023-02-21 14:31:30 +01:00
Taus
b5ebd1a0fd QL: Add JSON (+C/L) extraction 2023-02-21 12:59:30 +00:00
Arthur Baars
814bef021d Ruby: update tree-sitter-embedded-template 2023-02-21 13:49:33 +01:00
Anders Schack-Mulligen
46d6f5af7e Java: Update some tests. 2023-02-21 13:14:35 +01:00
Geoffrey White
c462e010d1 Merge pull request #12266 from geoffw0/taintplusequals
Swift: Taint through arithmetic
2023-02-21 09:32:53 +00:00
Anders Schack-Mulligen
acf6a77c6b Dataflow: Amend qldoc 2023-02-21 10:20:42 +01:00
Anders Schack-Mulligen
bb0ec46eb2 Java: Update tests. 2023-02-21 10:04:25 +01:00
Anders Schack-Mulligen
00a273b959 Java: Refactor data flow library. 2023-02-21 10:04:14 +01:00
Tom Hvitved
c3679d0661 Fix bad join 2023-02-21 19:28:55 +13:00
Tom Hvitved
9880952e72 Revert "Ruby: Fix performance of Filter.getAnAction"
This reverts commit f6c863c13bc840cba983ed12232725b8a8552cb4.
2023-02-21 19:28:55 +13:00
Harry Maclean
710ddb1f96 Ruby: Fix performance of Filter.getAnAction
Only look at the current class and the immediate superclass.
This will miss some edge cases but is much faster.
2023-02-21 19:28:54 +13:00
Harry Maclean
2bc7d4e1ee Ruby: Clean up 2023-02-21 19:28:54 +13:00
Harry Maclean
7a01c4a974 Ruby: Add change note for filter dataflow 2023-02-21 19:28:54 +13:00
Harry Maclean
ba4d0a81d5 Ruby: Simplify filter dataflow
This introduces some false flow (the `ThreeController` and
`FourController` examples in `filter_flow.rb`) but is simpler and
in line with how we model flow for normal method calls.
2023-02-21 19:28:53 +13:00
Harry Maclean
0a02b45ad7 Ruby: More filter flow steps
Add a jump step from the last self post-update node in a method to the self parameter of the
next method.
2023-02-21 19:28:26 +13:00
Harry Maclean
fae5320c3a Ruby: Add filter flow tests 2023-02-21 19:27:53 +13:00
Harry Maclean
04e80fa48f Ruby: Use lookupMethod
The hope is that this predicate is already used elsewhere, so its cost
is amortized.
2023-02-21 19:26:36 +13:00
Harry Maclean
889d97163e Ruby: Refactor getFilterCallable
Try to force a join with the filter argument string first, to reduce
tuple counts.
2023-02-21 19:26:36 +13:00
Harry Maclean
2590682262 Ruby: inline RenderCallUtils::getBaseName
This seems to yield a small performance increase.
2023-02-21 19:26:36 +13:00
Harry Maclean
ae3d91b546 Ruby: First draft of rails callback flow 2023-02-21 19:26:36 +13:00
Harry Maclean
6eeb711988 Ruby: Add AdditionalJumpStep class 2023-02-21 19:26:36 +13:00
Geoffrey White
cb8f5979d1 Swift: Update swift/string-length-conflation to taint tracking and remove a special case that's now covered by taint. 2023-02-20 18:18:15 +00:00
Geoffrey White
9b117fefd7 Swift: Generalize the arithmetic we allow taint through. 2023-02-20 18:18:15 +00:00
Geoffrey White
a5bb336647 Merge pull request #12265 from geoffw0/taintunaryplus
Swift: Add unary +
2023-02-20 18:04:37 +00:00
Geoffrey White
87c0b6195f Swift: Add taint tests for various arithmetic operators. 2023-02-20 17:22:51 +00:00
Geoffrey White
3038543242 Swift: Add UnaryPlusExpr. 2023-02-20 17:15:20 +00:00
Calum Grant
779c2365fe Merge pull request #12091 from github/cg/shared-code-metrics
Script to generate shared code metrics
2023-02-20 16:58:30 +00:00
Geoffrey White
e19e28fbb9 Merge pull request #12263 from geoffw0/flowsourceinline
Swift: Convert the flow sources test to inline expectations.
2023-02-20 16:13:01 +00:00
Erik Krogh Kristensen
6894803b14 Merge pull request #12257 from erik-krogh/compile-stuff
CI: Fix CI use of the compilation cache
2023-02-20 16:46:09 +01:00
Geoffrey White
31967cc032 Swift: Add a couple of dataflow test cases for operators that behave as an identity function. 2023-02-20 15:42:07 +00:00
Stephan Brandauer
7714acea82 delete a model that should pbly be a summary step 2023-02-20 15:44:58 +01:00
erik-krogh
389b7ceff5 support the new shared compilation cache directory 2023-02-20 15:34:03 +01:00
erik-krogh
f6fdf45359 remember to actually output the compilation dir 2023-02-20 15:32:50 +01:00
Geoffrey White
690b5debf4 Swift: Remove the old test. 2023-02-20 13:58:53 +00:00
Geoffrey White
dd7f54677b Swift: Add inline expectation tags. 2023-02-20 13:57:24 +00:00
Joe Farebrother
1fb27354b9 Merge pull request #12242 from joefarebrother/testgen-improvements
Java: Test generator fixes
2023-02-20 13:53:18 +00:00
Arthur Baars
f71c3301b3 Ruby: address review comment 2023-02-20 14:32:24 +01:00
Arthur Baars
6fd836d3a9 Ruby: improve wording of error messages 2023-02-20 14:32:02 +01:00
Alex Ford
774030a8db Merge pull request #12083 from pwntester/ruby_twirp_support
[Ruby] Add support for Twirp framework
2023-02-20 13:16:52 +00:00
Michael Nebel
86888b894a Java: Re-factor isSupported for the telemetry queries. 2023-02-20 13:53:18 +01:00
Michael Nebel
f594411c43 C#: Re-factor isSupported for the telemetry queries. 2023-02-20 13:53:18 +01:00
yoff
52dd1f451c Merge pull request #12260 from yoff/python/fix-precision-usafe-unpack
python: Lower precision as discussed
2023-02-20 13:38:50 +01:00
Michael Nebel
cdda4005fd C#: Add missing hasProvenance overrides. 2023-02-20 13:19:56 +01:00
Michael Nebel
813ffa440c Java: Consider ai-generated flow summaries to as generated summaries in dataflow. 2023-02-20 12:11:48 +01:00
Geoffrey White
b66ed57e17 Swift: Fix a mistake in FlowSources.qll. 2023-02-20 11:11:46 +00:00
Rasmus Lerchedahl Petersen
9e97877938 python: lower precision as discussed 2023-02-20 12:06:19 +01:00
Geoffrey White
d9f2d348f4 Swift: Add an inline expectations test for flow sources. 2023-02-20 11:03:10 +00:00
Chris Smowton
dbe0797063 Add Gradle wrappers for Kotlin tests
This avoids tests' behaviour changing due to environmental Gradle version changes
2023-02-20 10:51:51 +00:00
Michael Nebel
54c0404110 Java: Allow ai-generated as a provenance value. 2023-02-20 11:47:09 +01:00
Tom Hvitved
658cc33bb8 Merge pull request #12212 from hvitved/util/inline-expect-test-use-end-line
Util: Use end line instead of start line for actual results
2023-02-20 11:41:02 +01:00
Stephan Brandauer
cf5a651b1f use provenance ai-generated for triage data and use the read-file MaD label 2023-02-20 11:33:18 +01:00
Stephan Brandauer
8d7031c166 Update Java MaD sink decls after triage
Triage request: 2276
2023-02-20 11:33:18 +01:00
Geoffrey White
6cec8ece3f Swift: Split off FlowConfig.qll. 2023-02-20 10:27:40 +00:00
Michael Nebel
35793b4de5 C#: Add change note. 2023-02-20 10:30:11 +01:00
Michael Nebel
7aeb61ca71 C#: Add file scoped test cases. 2023-02-20 10:30:10 +01:00
Michael Nebel
81fde0ea79 C#: Make library support for file scoped types. 2023-02-20 10:30:10 +01:00
Michael Nebel
ffb8a57893 C#: Make extractor support for file scoped types. 2023-02-20 10:30:10 +01:00
Harry Maclean
9aea725f3d Merge pull request #12053 from hmac/actioncontroller-renderer-2
Ruby: Model ApplicationController.renderer
2023-02-20 22:28:30 +13:00
Geoffrey White
343ddede5a Merge branch 'main' into nsstring 2023-02-20 09:15:58 +00:00
Mathias Vorreiter Pedersen
49be5fd19a Merge pull request #12250 from geoffw0/filemanagersource
Swift: Taint sources for FileManager
2023-02-20 09:12:11 +00:00
Tom Hvitved
879eff41ea Merge branch 'main' into util/inline-expect-test-use-end-line 2023-02-20 10:03:38 +01:00
Rasmus Wriedt Larsen
efc75e02cc Merge pull request #12168 from RasmusWL/crypto-stdlib-modeling
Python: Add modeling of `hmac`
2023-02-20 09:26:53 +01:00
ihsinme
213abc6642 Update DivideByZeroUsingReturnValue.expected 2023-02-19 21:42:48 +03:00
ihsinme
54acbf7676 Update test.cpp 2023-02-19 21:42:14 +03:00
ihsinme
49af5ec536 Update DivideByZeroUsingReturnValue.ql 2023-02-19 21:41:28 +03:00
Harry Maclean
4e07fd3eb1 Ruby: Model ApplicationController.renderer 2023-02-19 13:37:27 +13:00
Taus
89aec093c8 Merge pull request #12233 from github/tausbn/add-blame-extractor 2023-02-18 15:06:25 +01:00
erik-krogh
cd823d7495 add git info to the checkout 2023-02-18 13:43:24 +01:00
erik-krogh
52a9d5379b add buramu to the files cached for the extractor 2023-02-18 13:22:41 +01:00
erik-krogh
db9a0d1c52 make the deprecation query calculate based on months, and adjust the cutoff to 14 months 2023-02-18 12:39:16 +01:00
erik-krogh
6f8ae703ca add the deprecation file when running QL-for-QL 2023-02-18 12:31:14 +01:00
erik-krogh
1a308316c6 fix join-order of ql/outdated-deprecation 2023-02-18 12:28:06 +01:00
erik-krogh
fcff18aa3c add query header for OutdatedDeprecations 2023-02-18 12:22:34 +01:00
erik-krogh
4f97c0470b exclude java integration tests from QL-for-QL 2023-02-18 12:21:35 +01:00
Chris Smowton
655aa700bc Merge pull request #12247 from smowton/smowton/fix/integer-conversion-sign
Go integer conversion: check against sink, not source signedness
2023-02-18 08:55:52 +00:00
Jami
f72cb5f650 Merge pull request #12215 from jcogs33/jcogs33/move-awt-swing-from-isJdkInternal
Java: move java.awt and javax.swing from `isJdkInternal` to `isInfrequentlyUsed`
2023-02-17 15:48:39 -05:00
Geoffrey White
7a9bbb1414 Swift: Model FileManager sources. 2023-02-17 20:04:27 +00:00
Chris Smowton
c7da1c9e0d Use example that compiles on 32-bit arch 2023-02-17 19:35:04 +00:00
Chris Smowton
be468fe122 Change note 2023-02-17 19:21:15 +00:00
Chris Smowton
4e86edf4fe Add test case 2023-02-17 19:16:36 +00:00
Chris Smowton
4d1608aafa Go integer conversion: check against sink, not source signedness 2023-02-17 18:53:18 +00:00
Geoffrey White
5d125572ec Swift: Test for FileManager taint sources. 2023-02-17 18:14:16 +00:00
Nick Rolfe
cef6765890 Merge pull request #12221 from github/post-release-prep/codeql-cli-2.12.3
Post-release preparation for codeql-cli-2.12.3
2023-02-17 17:59:45 +00:00
Calum Grant
c72a5d5dc0 Merge pull request #12245 from github/calumgrant/codeowners-dynamic
Update CODEOWNERS for dynamic teams
2023-02-17 17:25:08 +00:00
Chris Smowton
7205f30803 Merge pull request #12223 from github/smowton/admin/announce-jdk-20-2
Java: Announce JDK20 support
2023-02-17 16:10:24 +00:00
Calum Grant
e400a1ad77 Update CODEOWNERS
As agreed in the retro, we'll make all dynamic team members responsible for PRs
2023-02-17 15:48:24 +00:00
Joe Farebrother
a9f1436930 Test generator fixes
- Revert previous change to constructor return values; as constructors are supposed to be modeled using Argument[-1] rather than ReturnValue
- Fix generation of ambiguous calls when one of the conflicting methods is overridden
2023-02-17 15:30:06 +00:00
Nick Rolfe
5929c99eb1 Merge branch 'main' into post-release-prep/codeql-cli-2.12.3 2023-02-17 15:02:17 +00:00
Arthur Baars
71c8bb20f9 Merge pull request #12238 from aibaars/query-format-q
CI: make 'codeql query format' less verbose
2023-02-17 15:58:19 +01:00
Nick Rolfe
3e5534f0ba Merge branch 'main' into post-release-prep/codeql-cli-2.12.3 2023-02-17 14:39:26 +00:00
Taus
9f4f7a76c9 QL: Add query for outdated deprecations 2023-02-17 14:27:15 +00:00
Calum Grant
2cfd6c5597 Update misc/scripts/shared-code-metrics.py
Co-authored-by: Anders Peter Fugmann <anders@fugmann.net>
2023-02-17 14:26:58 +00:00
Calum Grant
35a53fa990 Merge pull request #12183 from RasmusWL/example-update
Python: Update a few examples so queries work on them
2023-02-17 14:21:38 +00:00
Arthur Baars
94467e638e CI: make 'codeql query compile' less verbose 2023-02-17 15:20:31 +01:00
Tom Hvitved
59efcd593a Python: Update test expectations 2023-02-17 15:20:21 +01:00
Tom Hvitved
0bceefc930 Java: Update test expectations 2023-02-17 15:20:21 +01:00
gregxsunday
fe97d2a05d fix file formatting 2023-02-17 14:01:28 +00:00
Arthur Baars
87cb3fd59f Update .github/workflows/compile-queries.yml
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2023-02-17 14:58:19 +01:00
Arthur Baars
c167919ff6 CI: make 'codeql query format' less verbose 2023-02-17 14:53:40 +01:00
Geoffrey White
ad886a3241 Swift: Autoformat. 2023-02-17 13:50:11 +00:00
Taus
db748fae6b QL: Integrate blame parser into extractor 2023-02-17 13:22:18 +00:00
Taus
59c1cfb43a QL: Add grammar for parsing blame files 2023-02-17 13:21:44 +00:00
Taus
0e0ec89e60 QL: Add tool for extracting blame info
I had some trouble getting this to work with version 1.54 of the Rust
toolchain, so I had to bump it up to 1.59.
2023-02-17 13:20:06 +00:00
Grzegorz Niedziela
9d8c117c61 added QLDocs for ZipSlip module 2023-02-17 12:57:35 +00:00
Grzegorz Niedziela
815b5a0312 add changelog file 2023-02-17 12:50:10 +00:00
Grzegorz Niedziela
c03ba2cc13 fix docs references 2023-02-17 12:50:01 +00:00
Grzegorz Niedziela
652c7ff1ed Push Sanitizer definition to ZipSlipCustomization.qll 2023-02-17 12:49:31 +00:00
Grzegorz Niedziela
8bbbb95a87 Make ZipSlip module classes private and push Sanitizer definition to ZipSlipCustomization.qll 2023-02-17 12:49:04 +00:00
Chris Smowton
d3e73891b5 Merge pull request #12229 from smowton/smowton/fix/gradle-wrapper-for-java-tests
Java: Add Gradle wrappers for Kotlin tests
2023-02-17 12:37:25 +00:00
Tom Hvitved
37fc8f5039 Swift: Update test expectations 2023-02-17 13:24:28 +01:00
Tom Hvitved
18c6b68232 Go: Update test expectations 2023-02-17 13:22:29 +01:00
Tom Hvitved
e9bce9f8cd Ruby: Update test expectations 2023-02-17 13:22:28 +01:00
Tom Hvitved
85e4707e0c Util: Use end line instead of start line for actual results 2023-02-17 13:22:28 +01:00
Geoffrey White
417d175ff2 Merge branch 'main' into nsstring 2023-02-17 11:32:40 +00:00
Arthur Baars
51f34eb3e9 Ruby: diagnostics: add support for markdown messages 2023-02-17 12:01:41 +01:00
Michael Nebel
8b967f9706 C#: Re-factor BuildNamedTypeId. 2023-02-17 11:49:12 +01:00
Geoffrey White
4356d359a6 Merge pull request #12226 from geoffw0/stringfix
Swift: Fix minor mistakes in the String models.
2023-02-17 10:23:56 +00:00
Chris Smowton
d1cd4cd099 Add Gradle wrappers for Kotlin tests
This avoids tests' behaviour changing due to environmental Gradle version changes
2023-02-17 10:10:22 +00:00
Geoffrey White
c692a316b0 Swift: Add new results found in UncontrolledFormatString test. 2023-02-17 10:07:32 +00:00
Geoffrey White
9cd9627778 Swift: Fix identical rows. 2023-02-17 10:00:06 +00:00
Geoffrey White
981f232ea9 Swift: Additional test cases. 2023-02-17 09:49:02 +00:00
Rasmus Wriedt Larsen
39e7bba563 Merge pull request #12203 from RasmusWL/import-resolution-phi
Python: Handle if-then-else definitions in import resolution
2023-02-17 10:10:42 +01:00
Paolo Tranquilli
c4c9fd72bb Swift: update to 5.7.3
No changes to the Swift frontend library headers, so no changes to the
extractor seem to be required.
2023-02-17 10:03:52 +01:00
erik-krogh
271cc6b961 remove lefterover debug comment 2023-02-17 09:50:22 +01:00
yoff
2f8dddabb6 Merge pull request #11570 from Sim4n6/UnsafeUnpack
Python: Unsafe unpacking using `shutil.unpack_archive()` query and tests
2023-02-17 09:48:05 +01:00
Geoffrey White
0aa9c76f42 Swift: Grammar and formatting. 2023-02-17 08:45:51 +00:00
Michael Nebel
2f6ffdd88f Merge pull request #12207 from michaelnebel/csharp/requiredmembers
C# 11: Required fields and properties.
2023-02-17 09:29:46 +01:00
Chris Smowton
6fc5bdd871 Announce JDK20 support 2023-02-17 08:15:33 +00:00
Michael Nebel
b87de911ba C#: Add change note. 2023-02-17 08:40:39 +01:00
Michael Nebel
3971dedcf6 C#: Add testcase for required members. 2023-02-17 08:40:39 +01:00
Michael Nebel
c0b8e852c5 C#: Add library support for required members. 2023-02-17 08:40:39 +01:00
Michael Nebel
2d46dd2936 C#: Add extractor support for the required modifier for fields and properties. 2023-02-17 08:40:39 +01:00
Michael Nebel
ff9e738d38 Merge pull request #12167 from michaelnebel/csharp/deprecategetassemblyname
C#: Checked operator support.
2023-02-17 08:39:32 +01:00
Geoffrey White
a894fc6ce8 Swift: Fix mistakes in String.qll models. 2023-02-16 18:24:36 +00:00
Geoffrey White
f64cb2983a Swift: Add tests for a few models we didn't cover. 2023-02-16 18:15:17 +00:00
github-actions[bot]
8eb8daa4d4 Post-release preparation for codeql-cli-2.12.3 2023-02-16 17:23:25 +00:00
Paolo Tranquilli
300db4f236 Merge pull request #12214 from github/redsun82/swift-codegen
Swift: fix weird module naming in codegen
2023-02-16 17:24:03 +01:00
Geoffrey White
cb11524dde Merge pull request #12154 from geoffw0/pathinjectionext
Swift: More path injection sinks
2023-02-16 16:00:31 +00:00
Michael B. Gale
8e83fd00b7 Update C/C++ autobuilder 2023-02-16 15:52:29 +00:00
Michael B. Gale
aa6efce695 Use TryGetValue 2023-02-16 15:52:13 +00:00
Michael B. Gale
5537d79d90 Detect missing Xamarin SDKs 2023-02-16 15:29:16 +00:00
Michael B. Gale
7e4808440e Fixup: better error message for no-projects-or-solutions 2023-02-16 15:29:16 +00:00
Michael B. Gale
c55281a68e Report .NET Core & MSBuild failures 2023-02-16 15:29:15 +00:00
Michael B. Gale
eda33fc5cb Track which projects/solutions fail to build 2023-02-16 15:29:15 +00:00
Michael B. Gale
f68c529f04 Report projects incompatible with .NET Core 2023-02-16 15:29:15 +00:00
Michael B. Gale
61ff4c7896 Set DiagnosticMessage defaults
Refactor `GetDiagnosticSource` into `MakeDiagnostic`
which sets the defaults.
2023-02-16 15:29:13 +00:00
Michael B. Gale
9865c506e6 Change logic for autobuild failures
This is to account for multiple attempted rules that failed
2023-02-16 15:28:42 +00:00
Michael B. Gale
99924919be Support asynchronous stdout/stderr processing 2023-02-16 15:28:42 +00:00
Michael B. Gale
c5a2cfcf95 Fixup: We => CodeQL 2023-02-16 15:28:41 +00:00
Michael B. Gale
219b232c83 Add no projects/solutions diagnostic 2023-02-16 15:28:41 +00:00
Michael B. Gale
7b5e19d462 Add diagnostics for BuildCommandAutoRule 2023-02-16 15:28:37 +00:00
Erik Krogh Kristensen
2b529fbf53 Merge pull request #12213 from github/erik-krogh/patch-test
CI: inline the move-caches script into the action
2023-02-16 16:00:13 +01:00
Michael B. Gale
5963501368 BuildCommandAutoRule: expose more information
We expose the list of candidate script paths and the chosen script path
so that we can inspect them for diagnostics purposes.
2023-02-16 14:16:23 +00:00
Michael B. Gale
f4c4871ab3 Add basic reporting of a general autobuild failure 2023-02-16 14:16:23 +00:00
Michael B. Gale
4e7c39a5d1 Add initial code for diagnostic messages 2023-02-16 14:16:23 +00:00
Michael B. Gale
fce9cb0b28 Read ..._DIAGNOSTIC_DIR variable 2023-02-16 14:16:23 +00:00
Michael B. Gale
fb6c27ba10 Refactor env var code in Autobuilder class 2023-02-16 14:16:22 +00:00
Michael B. Gale
35b60167e1 Merge pull request #12153 from github/mbg/fix/msbuild-on-macos-arm
C#: Improve C# autobuilder compatibility with Arm-based Macs
2023-02-16 14:12:43 +00:00
Jami Cogswell
94fd412809 Java: move awt and swing to isInfrequentlyUsed predicate 2023-02-16 09:02:41 -05:00
erik-krogh
767da59397 remove the paths requirement from running QL-for-QL 2023-02-16 14:57:00 +01:00
Paolo Tranquilli
f50382ba70 Swift: fix weird module naming in codegen 2023-02-16 14:53:31 +01:00
erik-krogh
45d00ae9dd inline the move-caches script into the action 2023-02-16 14:52:46 +01:00
Paolo Tranquilli
7cfe15c304 Merge pull request #12205 from github/redsun82/swift-codegen
Swift: fix subtle `codegen` bug on missing files
2023-02-16 13:45:35 +01:00
Rasmus Wriedt Larsen
9ed021ad66 Python: Accept change to WeakFilePermissions.expected
💪
2023-02-16 13:27:16 +01:00
Arthur Baars
006ee5aad9 Ruby: improve encoding related messages 2023-02-16 13:12:55 +01:00
Grzegorz Niedziela
d8eafea719 Merge branch 'github:main' into main 2023-02-16 11:24:57 +00:00
gregxsunday
d1aaa9ad86 Add ZipSlip/TarSlip query for ruby 2023-02-16 11:24:15 +00:00
Joe Farebrother
430b432add Merge pull request #12195 from joefarebrother/testgen-improvements
Java: Test generator improvements
2023-02-16 11:20:55 +00:00
Michael B. Gale
eab3c6dd5e Fix missing implementations for C++ tests 2023-02-16 11:07:38 +00:00
Michael B. Gale
e28be5d98f Make msbuild work on Arm-based Macs 2023-02-16 11:07:38 +00:00
Michael B. Gale
75c75ea49c Correctly select dotnet platform on arm-based macs 2023-02-16 11:07:37 +00:00
Alex Ford
9cfd0f5f46 JS: fix qldoc 2023-02-16 11:00:37 +00:00
Paolo Tranquilli
3ec2a3c711 Swift: fix subtle codegen bug on missing files
While the internal registry was being cleaned up from files removed by
codegen itself, it was not dropping files removed outside of codegen.

Because of this files removed by the user were not being regenerated
again if no change was staged to them, unless `--force` was provided.

This also fixes some such "ghost" entries in the registry and some
missing generated files.
2023-02-16 11:46:51 +01:00
Paolo Tranquilli
3b1b3b46ae Merge pull request #12202 from github/redsun82/swift-codegen
> Out of curiosity: What is the end goal that we're trying to get to with this?

Up until now we would be writing that predicate by hand, see [this example](29c8260004/swift/ql/lib/codeql/swift/elements/expr/MethodLookupExpr.qll (L29-L30)). Now this will be given to us from the get go.

For me this was prompted to give a nicer live demo later at my presentation 🙂
2023-02-16 11:35:05 +01:00
Michael B. Gale
29c8260004 Merge pull request #12196 from github/mbg/csharp/add-msbuild-integration-tests 2023-02-16 10:29:28 +00:00
Rasmus Wriedt Larsen
766e6c400e Python: Handle if-then-else definitions in import resolution 2023-02-16 11:18:30 +01:00
Rasmus Wriedt Larsen
80f5342a6d Python: Add import regression for if-then-else definitions 2023-02-16 11:12:08 +01:00
Tony Torralba
87b54e674e Merge pull request #12178 from felickz/main
Java - Adding support for com.microsoft.sqlserver.jdbc.SQLServerDataSource  to CWE-798
2023-02-16 11:03:34 +01:00
Michael B. Gale
9db1366e4b Change target framework to 4.0 for mono 2023-02-16 09:55:58 +00:00
Michael B. Gale
f1adb4319a Add C# integration test which uses MSBuild 2023-02-16 09:55:57 +00:00
Paolo Tranquilli
e2d7a6910c Swift: generate raw helpers in synthesized stubs
This will add helpers to get the underlying raw entities or constructor
arguments on stubs for synthesized classes.

For example a schema like:

```
@synth.from_class(A)
class B:
    pass

@synth.on_arguments(base=A, index=int)
class C:
    pass
```

will generate

```
cached
private Raw::A getUnderlyingEntity() { this = Synth::TB(result) }
```
in the `B.qll` stub and
```
cached
private Raw::A getUnderlyingBase() { this = Synth::TC(result, _) }

cached
private int getUnderlyingIndex() { this = Synth::TC(_, result) }
```
in the `C.qll` stub.

As stubs these can be freely changed later on.
2023-02-16 10:49:21 +01:00
Chad Bentz
f3124d3239 Merge branch 'main' into main 2023-02-15 18:46:15 -05:00
Chad Bentz
2f1bd93a49 change-notes for this minorAnalysis lib change 2023-02-15 18:40:40 -05:00
Chad Bentz
2f576a4fe9 test both arguments of getConnection
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-02-15 18:26:56 -05:00
Geoffrey White
00302dc05f Swift: Model NSObject. 2023-02-15 22:12:39 +00:00
Geoffrey White
7e8645a1f6 Swift: Model NSMutableString. 2023-02-15 21:50:05 +00:00
Geoffrey White
d04ed14b8c fix model -2 2023-02-15 21:18:50 +00:00
Rasmus Wriedt Larsen
c4fbfb0d07 Merge branch 'main' into call-graph-code 2023-02-15 20:15:04 +01:00
Geoffrey White
75dd95f458 Swift: Correct one of the tests. 2023-02-15 18:37:51 +00:00
Geoffrey White
99caafb9b9 Swift: Model NSString. 2023-02-15 18:37:51 +00:00
Joe Farebrother
d9e5c6c48a Fix typo 2023-02-15 17:21:03 +00:00
Alex Ford
74782bf6a2 Merge branch 'main' into ruby_twirp_support 2023-02-15 17:15:08 +00:00
Alex Ford
1556b1a728 Merge branch 'main' into js-use-shared-cryptography 2023-02-15 17:13:53 +00:00
Alex Ford
801ed1ce7c Ruby: add Twirp.expected 2023-02-15 17:05:33 +00:00
Alex Ford
1958b9dcd5 JS: add missing qldoc 2023-02-15 16:59:03 +00:00
Alex Ford
43af306d60 dynamic: more detailed qldoc for CryptographicOperation#getBlockMode() 2023-02-15 16:55:18 +00:00
Alex Ford
e8cbf7287d JS: breaking change note for CryptographicOperation sync 2023-02-15 16:50:24 +00:00
Alex Ford
925b4a3fa8 JS: improve documentation on deprecated CryptographicOperation#getInput() predicate 2023-02-15 16:23:46 +00:00
Alex Ford
d4d0b91085 dynamic: switch CryptographicOperation::Range#getBlockMode() back to being an abstract predicate 2023-02-15 16:23:46 +00:00
Alex Ford
c7aaad9ed0 JS: avoid adding a deprecated CryptographicOperation#getInput to py/ruby 2023-02-15 16:23:46 +00:00
Joe Farebrother
95a131d0d3 Update help text 2023-02-15 16:18:47 +00:00
Joe Farebrother
8ee36a5278 Test generator improvements
- Accept yml files as input
- Output the correct type for constructors
2023-02-15 16:11:22 +00:00
erik-krogh
51ddb55d7b use tainted-object to precisely model that plain object are fine, but their properties are not 2023-02-15 15:02:03 +01:00
erik-krogh
09794fa836 delete PrefixStringSanitizer 2023-02-15 14:55:02 +01:00
Geoffrey White
d763c5a3a0 Swift: Update LocalTaint.expected for the changes so far. 2023-02-15 11:42:42 +00:00
Geoffrey White
2882286c3f Swift: Test taint sources for NSString. 2023-02-15 11:42:42 +00:00
Geoffrey White
9f734076b7 Swift: Test taint through NSString member variables. 2023-02-15 11:04:16 +00:00
Geoffrey White
452ca4ef0f Swift: Test taint through NSMutableString. 2023-02-15 11:04:01 +00:00
Geoffrey White
16ec29e3df Swift: Test taint throguh some NSObject methods. 2023-02-15 11:03:45 +00:00
Geoffrey White
85a0fd9b30 Swift: Test taint through NSString. 2023-02-15 11:03:06 +00:00
erik-krogh
bec8dc6775 add explicit this 2023-02-15 10:44:57 +01:00
erik-krogh
25a8469586 update expected output, now that .html.erb files are actually extracted 2023-02-15 10:28:05 +01:00
erik-krogh
710e79b2d5 bump extractor version 2023-02-15 10:26:00 +01:00
erik-krogh
f9b3a5b5e6 actually extract .html.erb files 2023-02-15 10:26:00 +01:00
Rasmus Wriedt Larsen
9e2eb56032 Python: Remove support for late *args arguments
I found this to cause bad performance, so the implementation of this has
to be thought out more carefully.
2023-02-15 09:42:11 +01:00
erik-krogh
b7305fd229 also consider relative exports when finding library inputs 2023-02-14 21:08:13 +01:00
erik-krogh
de4f5017e1 add change-note 2023-02-14 18:36:07 +01:00
Alex Ford
8d90c02a67 JS: remove unused field 2023-02-14 15:24:22 +00:00
erik-krogh
393649b7ce don't call environment variables for command-line arguments 2023-02-14 14:27:41 +01:00
Alvaro Muñoz
4644a88b89 address code review comments 2023-02-14 14:27:17 +01:00
erik-krogh
36478124ae add process.env and process.argv etc. as source for js/regex-injection 2023-02-14 14:21:53 +01:00
erik-krogh
943bdeca6d make appliesTo recursive 2023-02-14 14:16:45 +01:00
erik-krogh
9549cac3e5 add an additional barrier guard that finds "=== true" versions of previous barrier guards 2023-02-14 14:15:23 +01:00
erik-krogh
c355a26657 add failing test 2023-02-14 14:12:35 +01:00
erik-krogh
3f0fe96f85 add getBoolValue() as a utility predicate on BooleanLiteral 2023-02-14 14:12:35 +01:00
Michael Nebel
469b289db9 C#: Add change note. 2023-02-14 13:14:45 +01:00
Michael Nebel
b3c234d020 C#: Add testcases for checked operators. 2023-02-14 12:59:36 +01:00
Michael Nebel
238a70fc55 C#: Add library support for checked operators. 2023-02-14 12:58:15 +01:00
Michael Nebel
b7123aaa89 C#: Add viable callable testcases for regular and checked operators. 2023-02-14 12:57:59 +01:00
Rasmus Wriedt Larsen
dc5bb4fb77 Python: Update a few examples so queries work on them
Fixes problem highlighted in https://github.com/github/codeql/issues/12156
2023-02-14 11:54:18 +01:00
Chad Bentz
b0c8992eef Adding CWE-798 MSSQL Tests 2023-02-13 19:44:02 -05:00
Chad Bentz
cfe169a4f9 Adding MSSQL to SensitiveAPI 2023-02-13 19:42:28 -05:00
Rasmus Wriedt Larsen
1c7fe97427 Python: Add modeling of hmac 2023-02-13 15:39:43 +01:00
Rasmus Wriedt Larsen
df22181963 Python: Add tests of hmac 2023-02-13 15:38:14 +01:00
Michael Nebel
b3602a5b7f C#: Use functionname as stored in the database. 2023-02-13 13:53:46 +01:00
Sim4n6
d7af80136e Fail tests when missing annotation on sink orfail 2023-02-12 21:27:20 +01:00
Sim4n6
518684b736 Put back the annotation result=BAD 2023-02-12 21:26:12 +01:00
Sim4n6
80d4fb5e33 Organisation TarSlip/UnsafeUnpack into two folders 2023-02-12 10:51:53 +01:00
Sim4n6
eed19a3e15 Fix autoformatting issues 2023-02-10 21:58:29 +01:00
Geoffrey White
ad85b37585 Swift: Tidy up indenting. 2023-02-10 18:06:56 +00:00
Geoffrey White
d0efbbf5b8 Swift: More path injection models. 2023-02-10 18:02:50 +00:00
Geoffrey White
82f09b8511 Swift: More path injection test cases. 2023-02-10 17:55:06 +00:00
Arthur Baars
ecbd768df4 Ruby: reduce number of diagnostic messages with the status_page flag
For now we only report real parse errors and character encoding errors. Warnings about
unexpected or missing nodes in the AST are not reported. These are typically side effects
of earlier parse errors.
2023-02-10 18:53:46 +01:00
Sim4n6
09df055d86 Fix the exists cast warning 2023-02-09 15:25:54 +01:00
Sim4n6
b04d5684fb add a blank line at the end of the file 2023-02-09 15:23:58 +01:00
Sim4n6
16ef50401b Update python/ql/src/experimental/Security/UnsafeUnpackQuery.qll
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-02-09 14:59:28 +01:00
Sim4n6
4196230a8a use if-then-else rather than nested exists 2023-02-08 21:46:50 +01:00
Sim4n6
9e285020a1 Comment modif + remove redundant cast 2023-02-08 21:14:53 +01:00
Rasmus Wriedt Larsen
5c23b47ef4 Python: Fix typo in QLDoc
Co-authored-by: Taus <tausbn@github.com>
2023-02-08 16:27:06 +01:00
Rasmus Wriedt Larsen
8bb1d8631a Python: Add call-graph hotfix for sympy 2023-02-08 16:19:29 +01:00
Rasmus Wriedt Larsen
23144f584a Merge branch 'main' into call-graph-code 2023-02-08 16:17:34 +01:00
Alvaro Muñoz
642a138eaa Update Twirp.qll 2023-02-07 10:44:48 +01:00
ihsinme
065ca3c227 Update DivideByZeroUsingReturnValue.ql 2023-02-06 19:42:46 +03:00
Sim4n6
ec82d61991 Add another frequently used step 2023-02-05 14:36:17 +01:00
erik-krogh
ecafce8191 improve the CryptoJS model by using API::Node 2023-02-03 21:44:23 +01:00
Calum Grant
7d8b624a71 Basic script to generate shared code metrics 2023-02-03 16:24:39 +00:00
Alex Ford
7768026e70 Merge branch 'main' into js-use-shared-cryptography 2023-02-03 15:18:30 +00:00
Alex Ford
6c35feaa98 ConceptsShared: add a default implementation of BlockMode CryptographicOperation#getBlockMode() for compatibility with external code 2023-02-03 14:39:32 +00:00
Alex Ford
b968b59afc CryptoAlgorithms: make CryptographicAlgorithm#matchesName hold only if that algorithm is the most specific match 2023-02-03 14:15:32 +00:00
Alex Ford
e17b3d975d JS: pick up CryptographicKeys used in asmCrypto encrypt/decrypt calls 2023-02-03 12:16:25 +00:00
Alex Ford
6b2a92a7ca JS: update CryptographicKey.expected 2023-02-03 12:12:47 +00:00
Alvaro Muñoz
3a9d650cb9 add qldocs for member predicates 2023-02-03 10:09:16 +01:00
Alvaro Muñoz
dd31be43e0 Support for Twirp framework 2023-02-03 09:35:22 +01:00
Sim4n6
a0150849cb Updated the expected test file 2023-02-02 21:42:47 +01:00
Alex Ford
b0b8f8725e JS: add some CryptographicOperation#getBlockMode() tests 2023-02-02 20:30:30 +00:00
Alex Ford
aa2c532a78 JS: adjust test whitespace 2023-02-02 20:30:30 +00:00
Alex Ford
c25dc978df JS: add blockMode to CryptographicOperation tests 2023-02-02 20:30:30 +00:00
Alex Ford
1435ef1862 CryptoAlgorithms: make CryptographicAlgorithm#matchesName split on underscores 2023-02-02 20:30:30 +00:00
Alex Ford
983055b8f9 JS: Use shared CryptographicOperation concept and implement BlockMode getBlockMode() 2023-02-02 20:30:30 +00:00
Alex Ford
e5dfbe2c8d ConceptsShared: Add BlockMode#matchesString(string) predicate 2023-02-02 20:27:52 +00:00
Alex Ford
61095b3c58 ConceptsShared: Add deprecated DataFlow::Node CryptographicOperation#getInput() predicate 2023-02-02 20:27:05 +00:00
Sim4n6
1a8c9abee2 Incorporate Sink & Source as steps from TarSlipQry 2023-02-02 21:09:40 +01:00
Rasmus Wriedt Larsen
db114bb104 Merge branch 'main' into call-graph-code 2023-02-02 11:56:55 +01:00
Rasmus Wriedt Larsen
fdb33ff48e Python: Fix grammar in change-note
Co-authored-by: Taus <tausbn@github.com>
2023-02-01 14:01:20 +01:00
Rasmus Wriedt Larsen
c7e552b343 Python: Fix grammar in qldoc
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-01-30 09:45:45 +01:00
Rasmus Wriedt Larsen
a1c2f4c138 Python: Small rewrite of **kwargs getParameter logic 2023-01-30 09:42:43 +01:00
Sim4n6
7079def7ce Add an S3 source with Session or download_fileobj 2023-01-30 00:49:23 +01:00
Sim4n6
0707064ab5 Constrain the save/path step 2023-01-28 10:14:24 +01:00
Sim4n6
a4aaf0ec6f Remove a write step & update the builtin open step 2023-01-28 09:53:54 +01:00
Sim4n6
0e2f37825d Organize steps to correspond to the sample code 2023-01-27 23:58:03 +01:00
Sim4n6
ee213123ac Add builtin open as an additional step 2023-01-27 18:16:11 +01:00
Sim4n6
0b27b1314a Update python/ql/src/experimental/Security/UnsafeUnpackQuery.qll
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-01-27 16:12:08 +01:00
Sim4n6
7a126a2317 Merge branch 'github:main' into UnsafeUnpack 2023-01-27 16:09:41 +01:00
Sim4n6
8ef2aa00e7 Update python/ql/src/experimental/Security/UnsafeUnpackQuery.qll
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-01-27 16:07:39 +01:00
Rasmus Wriedt Larsen
cef933f813 Python: Add comment explaining SINK3_F(kwargs["c"]) test
Co-authored-by: yoff <yoff@github.com>
2023-01-27 15:48:59 +01:00
Rasmus Wriedt Larsen
c099dbd04c Python: Expand notes around bound methods self argument passing 2023-01-27 15:27:45 +01:00
Sim4n6
207ed3da9c Constrain the object & the call 2023-01-27 15:07:20 +01:00
Sim4n6
18d8bbc9a4 Updated the expected results accordingly 2023-01-27 14:05:25 +01:00
Sim4n6
e41042418a Update the import relative to the dataflow config 2023-01-27 13:46:57 +01:00
Sim4n6
5f0bf1053a Update the dataflow test query and the expected results 2023-01-27 13:42:57 +01:00
Sim4n6
bca053f855 Move the config query to the parent directory 2023-01-27 13:42:14 +01:00
Rasmus Wriedt Larsen
02b3a1b515 Python: At most one **kwargs ParameterNode per callable
Similar to the Ruby changes from
https://github.com/github/codeql/pull/11461

I feel the change to `DataFlowFunciton.getParameter` where we use
`not exists(func.getArgByName(_))` is not very great, but I was not allowed
to use `not exists(this.getParameter(any(ParameterPosition _).isKeyword(_)))`
because of negative recursion.
2023-01-27 11:14:42 +01:00
Sim4n6
998f1bf215 Some reformatting 2023-01-26 18:54:36 +01:00
Sim4n6
1a211485a4 Restrain the source and add two steps. 2023-01-26 17:07:59 +01:00
Sim4n6
51b11de44a Add a Django Upload examples 2023-01-26 15:16:24 +01:00
Sim4n6
54cc4d6498 Opt for any source from RemoteFlowSource. 2023-01-26 12:51:55 +01:00
Sim4n6
aaa0040612 Seperate the dataflow config from the query 2023-01-26 08:53:47 +01:00
Sim4n6
9464940214 Add expected results for argparse source 2023-01-26 01:00:19 +01:00
Sim4n6
2e4cb63049 Optimize the Argparse filename as a source. 2023-01-26 01:00:01 +01:00
Sim4n6
f867c9008f Commit the expected results 2023-01-26 00:08:54 +01:00
Sim4n6
9b5b0c60b8 Handle the download of a tarball using wget pkg. 2023-01-26 00:02:20 +01:00
Sim4n6
22af6f5182 Restrict download_file() to boto3 lib 2023-01-25 23:00:00 +01:00
Sim4n6
2d38993075 Add a missing "and" 2023-01-25 19:46:13 +01:00
Sim4n6
0ed480855a Update python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql
Yes, definitely

Co-authored-by: yoff <lerchedahl@gmail.com>
2023-01-25 19:44:28 +01:00
Sim4n6
10d6ebf95b Use of inline tests for dataflow queries 2023-01-25 19:28:05 +01:00
Sim4n6
b5a6f6e165 Merge pull request #1 from github/main
Sync with the upstream
2023-01-25 19:13:35 +01:00
Rasmus Wriedt Larsen
f262dc68f8 Python: Reword note about debugging getNextClassInMro 2023-01-25 10:08:43 +01:00
Rasmus Wriedt Larsen
63b2bd0871 Python: Fixup test_only_starargs addition
validTest.py did not pass, since we use `SINK3_F`.

I initially tried swapping the order

```
args = (arg1, arg2) # $ arg1 arg2 func=starargs_only
more_args = (arg4, arg3)
starargs_only(*args, *more_args)
```

But then asked myself, what is it _actually_ we're testing here? and it
seems to be the way we handle multiple *args arguments in the same call,
so I converted the test to be that instead! (and it matches what we do
in test_stararg_mixed)
2023-01-25 09:37:07 +01:00
Rasmus Wriedt Larsen
0879c8f8e1 Python: Expand comments on C3 MRO 2023-01-23 17:40:24 +01:00
Rasmus Wriedt Larsen
80324735bb Python: Fixup annotation for CWE-022-PathInjection/pathlib_use.py 2023-01-23 17:40:24 +01:00
Rasmus Wriedt Larsen
753192bb4d Merge branch 'main' into call-graph-code 2023-01-23 11:25:02 +01:00
Rasmus Wriedt Larsen
25a68c4d71 Python: Include @yoff's suggestion on synthetic *args handling 2023-01-20 16:49:33 +01:00
Rasmus Wriedt Larsen
41ebb4fb55 Python: Add p2 in QLDoc example code for synthetic **kwargs 2023-01-20 16:40:39 +01:00
Rasmus Wriedt Larsen
d9fbe58ad5 Python: Expand starargs_only test 2023-01-20 16:34:59 +01:00
Rasmus Wriedt Larsen
0df3dd68d6 Python: Remove (now) redundant cast 2023-01-20 15:13:02 +01:00
Rasmus Wriedt Larsen
1bd969c219 Merge branch 'main' into call-graph-code 2023-01-20 15:11:49 +01:00
Rasmus Wriedt Larsen
4df946b161 Python: call-graph: Don't design for special method calls yet
The `call` arguments were not `CallNode`s before, to allow for easier
support of special method calls, such as `a + b` going to `__add__`.

However, this is not implemented yet, so for now we can keep things
simple.

Co-authored-by: Taus <tausbn@github.com>
2023-01-18 12:30:53 +01:00
Rasmus Wriedt Larsen
b83fc3b6eb Python: Update QLDoc for clsArgumentTracker 2023-01-17 14:38:56 +01:00
Rasmus Wriedt Larsen
24892801ec Python: clsTracker => clsArgumentTracker
Co-authored-by: Taus <tausbn@github.com>
2023-01-17 14:16:56 +01:00
Rasmus Wriedt Larsen
1c8cc6a32a Python: Add QLDoc for TFunction 2023-01-17 14:14:05 +01:00
Rasmus Wriedt Larsen
dad6221b61 Python: Accept dataflow-consistency.expected changes for now
As highlighted in the configuration file, there are some things to catch
up on, and we also need to apply the same fix as Ruby for **kwargs
handling.
2023-01-17 13:58:40 +01:00
Rasmus Wriedt Larsen
749e81367d Python: Allow multiple **kwargs parameters outside our test code 2023-01-17 13:58:40 +01:00
Rasmus Wriedt Larsen
b6272b383d Python: Allow non-unique parameter positions for normal parameters 2023-01-17 13:58:40 +01:00
Rasmus Wriedt Larsen
a6fd5b6e59 DataFlow: Add uniqueParameterNodePositionExclude 2023-01-17 13:58:37 +01:00
Rasmus Wriedt Larsen
7a423622f8 DataFlow: Add uniqueParameterNodeAtPositionExclude 2023-01-17 13:57:31 +01:00
Rasmus Wriedt Larsen
e3fcfd0a66 Python: Use configuration for dataflow consistency checks in dataflow/exceptions 2023-01-17 13:55:22 +01:00
Rasmus Wriedt Larsen
f8d7a367ad Python: Rewrite test for __add__ special method
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-01-17 11:45:57 +01:00
Rasmus Wriedt Larsen
ae1d4decc3 Python: ExternalAPIs.qll: Swap order of classes
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-01-17 11:01:47 +01:00
Rasmus Wriedt Larsen
b6f76d784c Python: Remove accidentally committed files 2023-01-17 10:59:11 +01:00
Rasmus Wriedt Larsen
479f019eb0 Python: Minor rewrite removing unnecessary exists
Co-authored-by: Taus <tausbn@github.com>
2023-01-17 10:59:11 +01:00
Rasmus Wriedt Larsen
608b16c98a Python: Minor adjustment in QLDoc
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-01-17 10:56:53 +01:00
Rasmus Wriedt Larsen
700e40b11b Python: Fix ql4ql 2023-01-17 10:35:20 +01:00
Rasmus Wriedt Larsen
4f3876f184 Python: Accept rewrite for _join( predicates
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-01-17 10:32:31 +01:00
Rasmus Wriedt Larsen
7c242b1409 Python: Minor QLDoc fix
Co-authored-by: Taus <tausbn@github.com>
2023-01-17 10:32:15 +01:00
Rasmus Wriedt Larsen
690a09d9b6 Python: new-call-graph: pragma[noinline] => pragma[nomagic]
As suggested by @tausbn. Obviously, this needs to be performance tested.
2023-01-16 20:45:44 +01:00
Rasmus Wriedt Larsen
a3b7273844 Python: Fix duplicated meta query id 2023-01-16 20:33:28 +01:00
Rasmus Wriedt Larsen
3fcb8f3f4b Python: Accept suggestions from code-review 2023-01-16 20:33:28 +01:00
Rasmus Wriedt Larsen
a1513cc1d3 Python: Minor QLDoc fix 2023-01-16 14:07:11 +01:00
Rasmus Wriedt Larsen
dfbb744a7a Python: Add comment on *args argument handling 2023-01-16 14:04:25 +01:00
Rasmus Wriedt Larsen
e5e5d84361 Python: Add change-note 2023-01-16 13:44:24 +01:00
Rasmus Wriedt Larsen
61151d4aa7 Merge branch 'main' into call-graph-code 2023-01-16 13:39:15 +01:00
ihsinme
a2836dc72a Update test.cpp 2022-12-18 00:38:32 +03:00
ihsinme
945cdef18d Update DivideByZeroUsingReturnValue.expected 2022-12-18 00:35:28 +03:00
ihsinme
c790b0fed6 Update DivideByZeroUsingReturnValue.ql 2022-12-18 00:34:14 +03:00
Sim4n6
4376870a51 An uploded file is considered a source 2022-12-15 23:39:02 +01:00
ALJI Mohamed
54109b8ea7 Add source wget.download 2022-12-13 15:34:01 +01:00
ALJI Mohamed
2f68b54b27 A simple download_file() call from maybe boto3 2022-12-12 19:46:34 +01:00
ALJI Mohamed
b19452467d read by chunks as additional step 2022-12-10 21:59:14 +01:00
ALJI Mohamed
eff132512c Copying the response data to the archive 2022-12-10 08:15:42 +01:00
ALJI Mohamed
545aab0e07 tarball path provided using CLI argument (source) 2022-12-09 15:54:43 +01:00
ALJI Mohamed
9336f4f1a2 Considering the use of contextlib.closing() method 2022-12-08 12:26:59 +01:00
Rasmus Wriedt Larsen
a826c4f48b Merge branch 'main' into call-graph-code 2022-12-08 11:39:30 +01:00
ALJI Mohamed
2801b8495a A fix of the tag name 2022-12-06 14:50:47 +01:00
ALJI Mohamed
4896e62117 Use of more generic terms 2022-12-06 14:44:52 +01:00
Sim4n6
58570b4d2c Update python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2022-12-06 14:40:48 +01:00
Sim4n6
9a60202de6 Update python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2022-12-06 14:40:35 +01:00
Sim4n6
c22c0b5029 Update python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2022-12-06 14:39:16 +01:00
ALJI Mohamed
a5849eb9b0 Improved the additional taint step using InstanceSource 2022-12-06 14:00:08 +01:00
ALJI Mohamed
054c06be65 Update UnsafeUnpack.ql 2022-12-06 02:51:07 +01:00
ALJI Mohamed
68fd75ca34 UnpackUnsafe query and tests 2022-12-05 17:20:22 +01:00
Rasmus Wriedt Larsen
d151e21f15 Python: Move ControlFlowNode.toString() to AST cached stage
This means points-to is no longer evaluated for sql injection 🎉

Thanks @asgerf 💪
2022-11-24 10:14:39 +01:00
Rasmus Wriedt Larsen
69b43f147a Python: Fix ql4ql alerts
The rest will be ignored.
2022-11-22 16:24:47 +01:00
Rasmus Wriedt Larsen
00ec3a23ba Python: Accept fix from module-resolution PR 2022-11-22 14:46:33 +01:00
Rasmus Wriedt Larsen
ee2f7401e8 Python: Add generator-flow/dataflow-consistency.ql 2022-11-22 14:46:33 +01:00
Rasmus Wriedt Larsen
8de5cfef43 Python: Update dataflow-consistency.expected
After merging in main
2022-11-22 14:46:33 +01:00
Rasmus Wriedt Larsen
c0ad870949 Python: Exclude synthetic generator functions from DataFlowCallable 2022-11-22 14:46:33 +01:00
Rasmus Wriedt Larsen
d86f98d60b Python: Accept changes for enclosing-callable test 2022-11-22 14:46:33 +01:00
Rasmus Wriedt Larsen
aa382ac042 Python: Add test for strange generator taint flow
I did check, and this was not a problem with the old call-graph on main!

I'm absolutely baffled!
2022-11-22 14:46:33 +01:00
Rasmus Wriedt Larsen
36e8b8bfb9 Python: Add call-graph to cached dataflow stage
I didn't do any performance investigation on this, since it just seems
so much like the right approach.
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
fc0545561e Python: Introduce points-to cached stage
With points-to not being used for the call-graph any longer, it's time
to split them.
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
bd46b7deaa Python: Cache a few call-graph predicates
We DON'T want to recompute these ones for sure!
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
6646e98d20 Python: Fix results outside DB for StackTraceExposure 2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
972cfa5cf6 Python: Accept bad StackTraceExposure.expected
This is only Python 2 though
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
a301c93ebf Python: Fix results outside DB for CleartextLogging 2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
0a41d8d2c1 Python: Accept bad CleartextLogging.expected 2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
39ce50fadc Python: Fix problems with sinks in pathlib
This must mean that we did not have this flow with the old call-graph,
which means the new call-graph is doing a better job (yay).
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
edcaff26af Python: Add path-injection test using pathlib
Since it has the same problem of showing sinks inside the extracted
stdlib
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
9d29a0a044 Python: Accept changes to .expected from more pathlib flow
But we don't want to keep this, this commit is just to show why we need a fix :)
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
df4d09b3f9 Python: Don't rely on all DataFlowCall being resolved
I've been living dangerously with that assumption :|
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
478f5ffe96 Python: Limit self argument for PotentialLibraryCall
Using the object from `MethodCallNode` meant that in the code below,
`lib` from the import expression would be considered a self argument

(this showed up in dataflow-consistency query results, that were not
comitted... sorry)

```
from lib import func
func()
```
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
c4122275dc Python: Bring back support for flow-summaries
Also needed to fix up `TestUtil/UnresolvedCalls.qll` after a bad merge
conflict resolution. Since all calls are now DataFlowCall, and not JUST
the ones that can be resolved, we need to put in the restriction that
the callable can also be resolved.
2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
e5fdeae6fc Python: Add return (func_ref, ...) test 2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
fb0cc184d9 Python: Add test of multi func def based on runtime decision 2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
276a825cd0 Python: Allow same function name in call-graph tests 2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
8a56b48357 Python: Support super().__new__(cls) 2022-11-22 14:46:32 +01:00
Rasmus Wriedt Larsen
2b76964f7f Python: Expand tests of __new__ a bit more 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
a4e6433942 Python: add support for type(self)() 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
d43a48c265 Python: Add type(self)() tests 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
16483f7d40 Python: Add funky call-graph regression
I don't even know how to phrase this :D
2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
1e96ced3ab Python: Ignore functions with @property decorator for now 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
cba93ded77 Python: Add test for @property problem 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
b33f02f9dc Python: Fix self-passing problems
This also fixes performance problems for pandas-dev/pandas
2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
722c69edcc Python: Add test showing self type-tracking problems 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
5e5bab5a7c Python: Don't pass synthetic class instance to __new__ on class calls 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
9949824810 Python: Expand implicit classmethods 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
6fefd54533 Python: Consider __new__ a classmethod 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
f040ad8dac Python: Add test of __new__ handling 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
57c7dc8ea9 Python: Allow cls passing to classmethod 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
0cf13e9976 Python: Expand argument highlighting test 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
8e0bb62516 Python: Remove pragma[inline] from parameterMatch
It's gotten complex enough that it doesn't by definition seem necessary
to inline it. (in the range of ~2200 results for django and pandas)
2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
4416037dc6 Python: Ignore SPURIOUS call-graph edges in points-to vs. type-tracker results 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
6351defe0d Python: Add call-graph tests with isinstance 2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
5fc127cb2c Python: Make UnresolvedCalls.qll handle class calls without __init__
This commit used to make sense to have here in the ordering of commits,
but due to various rebases it no longer changes any test output..

it's still a good change though, so I'll keep it.
2022-11-22 14:46:31 +01:00
Rasmus Wriedt Larsen
98a849405f Python: Add support for late *args arguments 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
035d083515 Python: Support flow to *args param from positional arg 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
db921ac036 Python: Add basic support for *args 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
b6314dd19d Python: Add *args tests 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
c687df4ddc Python: Support flow to keyword param from **kwargs arg
When resolving merge conflict after flow-summaries was merged, this is
the original commit where I introduced ParameterNodeImpl, so this is the
commit where differences in that implementation was committed...

I removed TParameterNode, since I could not see we we gain anything from
having it.
2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
215a03d948 Python: Support flow to **kwargs param from keyword arg 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
503ad544e9 Python: Remove impossible flow for **kwargs params 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
eb600f07b7 Python: Use config for dataflow-consistency.ql
And ignore post-update nodes for `**kwargs` arguments
2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
5722d231bd Python: Add basic support for **kwargs
For now this is JUST from `**kwargs` in arguments, to `**kwargs`
parameters, and this part is based on field-flow

Note that dataflow-library complains about missing post update nodes for
these. This needs to be ignored, since post update nodes for `**kwargs`
arguments doesn't make sense, it's not possible to alter the dictionary
inside the method.
2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
9b2663034d Python: Change test .ql to also show bad argument flow 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
5a976cfb14 Python: Add more **kwargs arg passing tests 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
e7a337991a Python: Accept fix from extractor change
namely the variable access mentioned in
https://github.com/github/codeql/pull/10171
2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
7014be2047 Python: Reduce size of attrReadTracker
On pallets/flask, this reduced the number of tuples from
100866 results => 33060 results
2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
61410191e7 Python: Fix bug in argumentRoutingTest.ql
Since `DataFlowPrivate::DataFlowCall` only exists for calls resolved to
a function, we didn't have any results before... but allowing any call
helps things!
2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
a5c3e850f1 Python: Handle __call__ 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
b5e8bf7882 Python: Add note about trying DataFlowDispatchPointsTo for InlineCallGraphTest
Since I was very confused about no results for __call__, I tried to see
whether I had cheated by making the comparison too unfair. But it didn't
seem to be the case.
2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
f3ac81a013 Python: Expand tests for special method calls 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
f2e92bf963 Python: Port py/meta/call-graph 2022-11-22 14:46:30 +01:00
Rasmus Wriedt Larsen
7c1320ed4b Python: Adjust ExternalAPI qhelp files 2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
af9be6ad7e Python: Suppress more spurious alerts from ExternalAPI queries 2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
70cc986d5f Python: Suppress None.json.dumps from ExternalAPI queries 2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
0bdc808a7a Python: Add ExternalAPI test None.json.dumps 2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
7648462f98 Python: Fix ExternalAPIs queries
The output might end up being slightly more noisy since we don't
collapse positional and keyword arguments when the external target
function is included in the database, but this aligns with our long-term
goal of not doing that anymore, so I think it's fine.
2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
2e2cee06c3 Python: Adjust InsecureRandomnessCustomizations.qll 2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
ed70e118a9 Python: Make test/Filter query more robust
Since if you had tornado installed, we would follow imports and have
results from those files as well :|
2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
9c275c177a Python: Implement call-graph with type-trackers
This commit is a squash of 80 other commits. While developing, things
changed majorly 2-3 times, and it just wasn't feasible to go back and
write a really nice commit history.

My apologies for this HUGE commit.

Also, later on this is where I solved merge conflicts after flow-summaries
PR was merged.

For your amusement, I've included the original commit messages below.

Python: Add proper argument/parameter positions

Python: Handle normal function calls

Python: Reduce dataflow-consistency warnings

Previously there was a lot of failures for `uniqueEnclosingCallable` and
`argHasPostUpdate`

Removing the override of `getEnclosingCallable` in ParameterNode is
probably the most controversial... although from my point of view it's a
change for the better, since we're able to provide data-flow
ParameterNodes for more of the AST parameter nodes.

Python: Adjust `dataflow/calls` test

Python: Implement `isParameterOf`/`argumentOf`/`OutNode`

This makes the tests under `dataflow/basic` work as well 👍

(initially I had these as separate commits, but it felt like it was too much noise)

Python: Accept fix for `dataflow/consistency`

Python: Changes to `coverage/argumentRoutingTest.ql`

Notice we gain a few new resolved arguments.

We loose out on stuff due to:

1. not handling `*` or `**` in either arguments/parameters (yet)
2. not handling special calls (yet)

Python: Small fix for `TestUtil/RoutingTest.qll`

Since the helper predicates do not depend on this, moved outside class.

Python: Accept changes to `dataflow/coverage/NormalDataflowTest.ql`

Most of this is due to:

- not handling any kinds of methods yet
- not handling `*` or `**`

Python: Small investigation of `test_deep_callgraph`

Python: Accept changes to `coverage/localFlow.ql`

I don't fully understand why the .expected file changed.

Since we still have the desired flow, I'm not going to worry too much
about it.

with this commit, the `dataflow/coverage` tests passes 👍

Python: Minor doc update

Python: Add staticmethod/classmethod to `dataflow/calls`

Python: Handle method calls on class instances

without trying to deal with any class inheritance, or
staticmethod/classmethod at all.

Notice that with this change, we only have a DataFlowCall for the calls
that we can actually resolve. I'm not 100% sure if we need to add a
`UnresolvedCall` subclass of `DataFlowCall` for MaD in the future, but
it should be easy to do.

I'm still unsure about the value of `classesCallGraph`, but have just
accepted the changes.

Python: Handle direct method calls `C.foo(C, arg0)`

Python: Handle `@staticmethod`

Python: Handle class method calls... but the code is shit

WIP todo

Rewrite method calls to be better

also fixed a problem with `self` being an argument to the `x.staticmethod()` call :|

Python: Add subclass tests

Python: Split `class_advanced` test

Python: Rewrite call-graph tests to be inline expectation (1/2)

This adds inline expectations, next commit will remove old annotations
code... but I thought it would be easier to review like this.

Minor fixup

Python: Add simple subclass support

Python: more precise subclass lookup

Still not 100% precise.. but it's better

New ambiguous

Python: Add test for `self.m()` and `cls.m()` calls

Python: Handle `self.m()` and `cls.m()` calls

Python: Add tests for `__init__` and `__new__`

Python: Handle class calls

Python: Fix `self` argument passing for class calls

Now field-flow tests also pass 💪 (although the crosstalk
fieldflow test changes were due to this specific commit)

I also copied much of the setup for pre/post update nodes from Ruby,
specifically having the abstract `PostUpdateNodeImpl` in DataFlowPrivate
seemed like a nice change.

Same for the setup with `TNode` definition having the specification
directly in the body, instead of a `NeedsSyntheticPostUpdateNode` class.

Python: Add new crosstalk test WIP

Maybe needs a bit of refactoring, and to see how it all behaves with points-to

Python: Add `super()` call-graph tests

Python: Refactor MethodCall char-pred

In anticipation of supporting `super(MyClass, self).foo()`, where the
`self` argument doesn't come from an AttrNode, but from the second
argument to super.

Without `pragma[inline]` the optimizer found a terrible join-order --
this won't guarantee a good join-order for the future, but for now it
was just so simple and could let me move on with life.

Python: Add basic `super()` support

I debated a little (with myself) whether I should really do
`superTracker`, but I thought "why not" and just rolled with it. I did
not confirm whether it was actually needed anywhere, that is if anyone
does `ref = super; ref().foo()` -- although I certainly doubt it's very
wide-spread.

Python: InlineCallGraphTest: Allow non-unique callable name in different files

Python: more MRO tests

Python: Add MRO approximation for `super()`

Although it's not 100% accurate, it seems to be on level with the one in
points-to.

Python: Remove some spurious targets for direct calls

removal of TODO from refactoring

remove TODOs class call support

Python: Add contrived subclass call example

Python: Remove more spurious call targets

NOTE: I initially forgot to use
`findFunctionAccordingToMroKnownStartingClass` instead of
`findFunctionAccordingToMro` for __init__ and __new__, and since I did
make that mistake myself, I wanted to add something to the test to
highlight this fact, and make it viewable by PR reviewer... this will be
fixed in the next commit.

Python: Proper fix for spurious __init__ targets

Python: Add call-graph example of class decorator

Python: Support decorated classes in new call-graph

Python: Add call-graph tests for `type(obj).meth()`

Python: support `type(obj).meth()`

Python: Add test for callable defined in function

Python: Add test for callable as argument

Current'y we don't find these with type-tracking, which is super
mysterious. I did check that we have proper flow from the arguments to
the parameters.

Python: Found problem for callable as argument :| MAJOR WIP

WIP commit

IT WORKS AGAIN (but terrible performance)

remove pragma[inline]

remove oops

Fix performance problem

I tried to optimize it even further, but I didn't end up achieving anything :|

Fix call-graph comparison

add comparison version with easy lookup

incomplete missing call-graph tests

unhandled tests

trying to replicate missing call-edge due to missing imports ... but it's hard

also seems to be problems with the inline-expectation-value that I used, seems like it has both missing/unexpected results with same value

Python: Add import-problem test

Python: Add shadowing problem

some cleanup of rewrite fix

a little more cleanup

Add consistency queries to call-graph tests

Python: Add post-update nodes for `self` in implicit `super()` uses

But we do need to discuss whether this is the right approach :O

Fix for field-flow tests

This came from more precise argument passing

Fixed results in type-tracking

Comes from better argument passing with super() and handling of
functions with decorators

fix of inline call graph tests

Fixup call annotation test

Many minor cleanups/fixes

NewNormalCall -> NormalCall

Python: Major restructuring + qldoc writing

Python: Accept changes from pre/post update node .toString changes

Python: Reduce `super` complexity !! WIP !!

Python: Only pass self-reference if in same enclosing-callable

Python: Add call-graph test with nested class

This was inspired by the ImpliesDataflow test that showed missing flow
for q_super, but at least for the call-graph, I'm not able to reproduce
this missing result :|

Python: Restrict `super()` to function defined directly on class

Python: Accept fixes to ImpliesDataflow

Python: Expand field-flow crosstalk tests
2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
aa78a43407 Python: Enable type-tracking in call-graph test 2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
c85ccb2003 Python: Add call-graph compare meta-queries
Also changed the definition of a relevant call-target, so it's only what
is in the actual source code, which is what we want in the future! (so
what we're designing type-tracking to handle)

I also changed terminology from `callee` to `target`. It felt more
natural this way in my opinion.
2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
a98554b6ed Python: Accept tmp changes to flow summaries
After solving merge conflict
2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
716576b1d6 Python: Minimal type-tracking call-graph
That does absolutely nothing so far, but compiles
2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
6f5007b810 Python: Rename -> DataFlowDispatch
So diff can make more sense when introducing blank state for type-tracking based call-graph
2022-11-22 14:46:29 +01:00
Rasmus Wriedt Larsen
f327a3f62a Python: Remove strange-pointsto-interaction-investigation
These tests are not relevant anymore 💪
2022-11-22 14:46:29 +01:00
ihsinme
5ceab40841 Update DivideByZeroUsingReturnValue.ql 2022-11-22 10:11:18 +03:00
ihsinme
0fb1dedbb2 Update DivideByZeroUsingReturnValue.ql 2022-11-11 11:38:48 +03:00
ihsinme
3954da5938 Update DivideByZeroUsingReturnValue.ql 2022-10-11 13:11:45 +03:00
ihsinme
01b357e749 Update DivideByZeroUsingReturnValue.ql 2022-10-10 12:33:11 +03:00
ihsinme
392c948487 Update DivideByZeroUsingReturnValue.ql 2022-10-05 09:27:20 +03:00
ihsinme
50105c1f6d create new branchihsinme-patch-111 in fork 2022-09-15 06:35:42 +00:00
1770 changed files with 123481 additions and 195707 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -26,9 +26,8 @@ jobs:
shell: bash
run: |
EXIT_CODE=0
# TODO: remove the swift exception from the regex when we fix generated QLdoc
# TODO: remove the shared exception from the regex when coverage of qlpacks without dbschemes is supported
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!(swift|shared))[a-z]*/ql/lib' || true; } | sort -u)"
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!(shared))[a-z]*/ql/lib' || true; } | sort -u)"
for pack_dir in ${changed_lib_packs}; do
lang="${pack_dir%/ql/lib}"
codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"

View File

@@ -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 }}"

View File

@@ -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:

View File

@@ -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/**

View File

@@ -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

View File

@@ -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

View File

@@ -1,6 +1,28 @@
{
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlow.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlow.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlow.qll",
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlow.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlow.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlow.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlow.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlow.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlow.qll"
],
"DataFlowImpl Java/C++/C#/Go/Python/Ruby/Swift": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
],
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Legacy Configuration": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll",
@@ -8,38 +30,38 @@
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll",
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll",
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll",
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll",
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImplForStringsNewReplacer.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplForRegExp.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll"
],
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Common": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
@@ -52,7 +74,18 @@
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplCommon.qll"
],
"TaintTracking::Configuration Java/C++/C#/Go/Python/Ruby/Swift": [
"TaintTracking Java/C++/C#/Go/Python/Ruby/Swift": [
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTracking.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTracking.qll",
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTracking.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTracking.qll",
"go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTracking.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTracking.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTracking.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTracking.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTracking.qll"
],
"TaintTracking Legacy Configuration Java/C++/C#/Go/Python/Ruby/Swift": [
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",

View File

@@ -1,5 +1,6 @@
using Xunit;
using Semmle.Autobuild.Shared;
using Semmle.Util;
using System.Collections.Generic;
using System;
using System.Linq;
@@ -75,6 +76,15 @@ namespace Semmle.Autobuild.Cpp.Tests
throw new ArgumentException("Missing RunProcess " + pattern);
}
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
var ret = (this as IBuildActions).RunProcess(cmd, args, workingDirectory, env, out var stdout);
stdout.ForEach(line => onOutput(line));
return ret;
}
public IList<string> DirectoryDeleteIn = new List<string>();
void IBuildActions.DirectoryDelete(string dir, bool recursive)
@@ -131,6 +141,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)));
@@ -176,6 +194,15 @@ namespace Semmle.Autobuild.Cpp.Tests
if (!DownloadFiles.Contains((address, fileName)))
throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}");
}
public IDiagnosticsWriter CreateDiagnosticsWriter(string filename) => new TestDiagnosticWriter();
}
internal class TestDiagnosticWriter : IDiagnosticsWriter
{
public IList<DiagnosticMessage> Diagnostics { get; } = new List<DiagnosticMessage>();
public void AddEntry(DiagnosticMessage message) => this.Diagnostics.Add(message);
}
/// <summary>
@@ -235,6 +262,7 @@ namespace Semmle.Autobuild.Cpp.Tests
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = "";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_DIAGNOSTIC_DIR"] = "";
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
Actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = "win64";
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";

View File

@@ -1,4 +1,5 @@
using Semmle.Autobuild.Shared;
using Semmle.Util;
namespace Semmle.Autobuild.Cpp
{
@@ -21,7 +22,7 @@ namespace Semmle.Autobuild.Cpp
public class CppAutobuilder : Autobuilder<CppAutobuildOptions>
{
public CppAutobuilder(IBuildActions actions, CppAutobuildOptions options) : base(actions, options) { }
public CppAutobuilder(IBuildActions actions, CppAutobuildOptions options) : base(actions, options, new DiagnosticClassifier()) { }
public override BuildScript GetBuildScript()
{

View File

@@ -0,0 +1,9 @@
---
category: majorAnalysis
---
* The main data flow and taint tracking APIs have been changed. The old APIs
remain in place for now and translate to the new through a
backwards-compatible wrapper. If multiple configurations are in scope
simultaneously, then this may affect results slightly. The new API is quite
similar to the old, but makes use of a configuration module instead of a
configuration class.

View File

@@ -22,5 +22,6 @@
import cpp
module DataFlow {
import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl
import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlow
import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
}

View File

@@ -19,5 +19,6 @@ import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.dataflow.DataFlow2
module TaintTracking {
import experimental.semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTracking
import experimental.semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
}

View File

@@ -0,0 +1,245 @@
/**
* Provides an implementation of global (interprocedural) data flow. This file
* re-exports the local (intraprocedural) data flow analysis from
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
* through the `Make` and `MakeWithState` modules.
*/
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
private import DataFlowImpl
/** An input configuration for data flow. */
signature module ConfigSig {
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source);
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/** An input configuration for data flow using flow state. */
signature module StateConfigSig {
bindingset[this]
class FlowState;
/**
* Holds if `source` is a relevant data flow source with the given initial
* `state`.
*/
predicate isSource(Node source, FlowState state);
/**
* Holds if `sink` is a relevant data flow sink accepting `state`.
*/
predicate isSink(Node sink, FlowState state);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/**
* Holds if data flow through `node` is prohibited when the flow state is
* `state`.
*/
predicate isBarrier(Node node, FlowState state);
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
signature int explorationLimitSig();
/**
* The output of a data flow computation.
*/
signature module DataFlowSig {
/**
* A `Node` augmented with a call context (except for sinks) and an access path.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode;
/**
* Holds if data can flow from `source` to `sink`.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink);
/**
* Holds if data can flow from `source` to `sink`.
*/
predicate hasFlow(Node source, Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate hasFlowTo(Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate hasFlowToExpr(DataFlowExpr sink);
}
/**
* Constructs a standard data flow computation.
*/
module Make<ConfigSig Config> implements DataFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
}
import Impl<C>
}
/**
* Constructs a data flow computation using flow state.
*/
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
private module C implements FullStateConfigSig {
import Config
}
import Impl<C>
}

View File

@@ -0,0 +1,396 @@
/**
* DEPRECATED: Use `Make` and `MakeWithState` instead.
*
* Provides a `Configuration` class backwards-compatible interface to the data
* flow library.
*/
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
/**
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
* of this abstract class. To create a configuration, extend this class with
* a subclass whose characteristic predicate is a unique singleton string.
* For example, write
*
* ```ql
* class MyAnalysisConfiguration extends DataFlow::Configuration {
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
* // Override `isSource` and `isSink`.
* // Optionally override `isBarrier`.
* // Optionally override `isAdditionalFlowStep`.
* }
* ```
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
* the edges are those data-flow steps that preserve the value of the node
* along with any additional edges defined by `isAdditionalFlowStep`.
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
* and/or out-going edges from those nodes, respectively.
*
* Then, to query whether there is flow between some `source` and `sink`,
* write
*
* ```ql
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
* ```
*
* Multiple configurations can coexist, but two classes extending
* `DataFlow::Configuration` should never depend on each other. One of them
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source) { none() }
/**
* Holds if `source` is a relevant data flow source with the given initial
* `state`.
*/
predicate isSource(Node source, FlowState state) { none() }
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink) { none() }
/**
* Holds if `sink` is a relevant data flow sink accepting `state`.
*/
predicate isSink(Node sink, FlowState state) { none() }
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
predicate isBarrier(Node node) { none() }
/**
* Holds if data flow through `node` is prohibited when the flow state is
* `state`.
*/
predicate isBarrier(Node node, FlowState state) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
none()
}
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (for example in a `path-problem` query).
*/
predicate includeHiddenNodes() { none() }
}
/**
* This class exists to prevent mutual recursion between the user-overridden
* member predicates of `Configuration` and the rest of the data-flow library.
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
override predicate hasFlow(Node source, Node sink) {
strictcount(Node n | this.isSource(n)) < 0
or
strictcount(Node n | this.isSource(n, _)) < 0
or
strictcount(Node n | this.isSink(n)) < 0
or
strictcount(Node n | this.isSink(n, _)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
or
super.hasFlow(source, sink)
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
config.isAdditionalFlowStep(_, result, _, _) or
config.isAdditionalFlowStep(_, _, _, result)
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
getConfig(state).isSource(source, getState(state))
or
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
}
predicate isBarrier(Node node) { none() }
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
getConfig(state2) = getConfig(state1)
or
not singleConfiguration() and
getConfig(state1).isAdditionalFlowStep(node1, node2) and
state2 = state1
}
predicate allowImplicitRead(Node node, ContentSet c) {
any(Configuration config).allowImplicitRead(node, c)
}
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
import I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
sink0.getNode() = sink
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
hasFlowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;

View File

@@ -3,15 +3,18 @@ private import DataFlowImplSpecific::Public
import Cached
module DataFlowImplCommonPublic {
/** A state value to track during data flow. */
class FlowState = string;
/** Provides `FlowState = string`. */
module FlowStateString {
/** A state value to track during data flow. */
class FlowState = string;
/**
* The default state, which is used when the state is unspecified for a source
* or a sink.
*/
class FlowStateEmpty extends FlowState {
FlowStateEmpty() { this = "" }
/**
* The default state, which is used when the state is unspecified for a source
* or a sink.
*/
class FlowStateEmpty extends FlowState {
FlowStateEmpty() { this = "" }
}
}
private newtype TFlowFeature =

View File

@@ -565,3 +565,12 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
any()
}
}
/**
* Gets an additional term that is added to the `join` and `branch` computations to reflect
* an additional forward or backwards branching factor that is not taken into account
* when calculating the (virtual) dispatch cost.
*
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
*/
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }

View File

@@ -97,23 +97,23 @@ private string getNodeProperty(DataFlow::Node node, string key) {
|
kind, ", "
)
or
// Is there partial flow from a source to this node?
// This property will only be emitted if partial flow is enabled by overriding
// `DataFlow::Configuration::explorationLimit()`.
key = "pflow" and
result =
strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
int order1, int order2 |
any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
destNode.getNode() = node and
// Only print flow from a source in the same function.
sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
|
nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
order by
order1, order2, dist desc
)
// or
// // Is there partial flow from a source to this node?
// // This property will only be emitted if partial flow is enabled by overriding
// // `DataFlow::Configuration::explorationLimit()`.
// key = "pflow" and
// result =
// strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
// int order1, int order2 |
// any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
// destNode.getNode() = node and
// // Only print flow from a source in the same function.
// sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
// |
// nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
// order by
// order1, order2, dist desc
// )
}
/**

View File

@@ -0,0 +1,63 @@
/**
* Provides classes for performing local (intra-procedural) and
* global (inter-procedural) taint-tracking analyses.
*/
import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
DataFlowInternal::FullStateConfigSig {
import Config
predicate isBarrier(DataFlow::Node node) {
Config::isBarrier(node) or defaultTaintSanitizer(node)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
Config::isAdditionalFlowStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
}
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
Config::allowImplicitRead(node, c)
or
(
Config::isSink(node, _) or
Config::isAdditionalFlowStep(node, _) or
Config::isAdditionalFlowStep(node, _, _, _)
) and
defaultImplicitTaintRead(node, c)
}
}
/**
* Constructs a standard taint tracking computation.
*/
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
import DataFlowInternal::Impl<C>
}
/**
* Constructs a taint tracking computation using flow state.
*/
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
import DataFlowInternal::Impl<C>
}

View File

@@ -2,4 +2,5 @@ import experimental.semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Pu
module Private {
import experimental.semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow
import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl as DataFlowInternal
}

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.5.3
version: 0.5.4-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -68,7 +68,9 @@ class Declaration extends Locatable, @declaration {
* Holds if this declaration has the fully-qualified name `qualifiedName`.
* See `getQualifiedName`.
*/
predicate hasQualifiedName(string qualifiedName) { this.getQualifiedName() = qualifiedName }
deprecated predicate hasQualifiedName(string qualifiedName) {
this.getQualifiedName() = qualifiedName
}
/**
* Holds if this declaration has a fully-qualified name with a name-space
@@ -184,7 +186,7 @@ class Declaration extends Locatable, @declaration {
predicate hasDefinition() { exists(this.getDefinition()) }
/** DEPRECATED: Use `hasDefinition` instead. */
predicate isDefined() { this.hasDefinition() }
deprecated predicate isDefined() { this.hasDefinition() }
/** Gets the preferred location of this declaration, if any. */
override Location getLocation() { none() }

View File

@@ -41,7 +41,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* `min<int>(int, int) -> int`, and the full signature of the uninstantiated
* template on the first line would be `min<T>(T, T) -> T`.
*/
string getFullSignature() {
deprecated string getFullSignature() {
exists(string name, string templateArgs, string args |
result = name + templateArgs + args + " -> " + this.getType().toString() and
name = this.getQualifiedName() and

View File

@@ -12,7 +12,9 @@ predicate freeFunction(Function f, int argNum) { argNum = f.(DeallocationFunctio
*
* DEPRECATED: Use `DeallocationExpr` instead (this also includes `delete` expressions).
*/
predicate freeCall(FunctionCall fc, Expr arg) { arg = fc.(DeallocationExpr).getFreedExpr() }
deprecated predicate freeCall(FunctionCall fc, Expr arg) {
arg = fc.(DeallocationExpr).getFreedExpr()
}
/**
* Is e some kind of allocation or deallocation (`new`, `alloc`, `realloc`, `delete`, `free` etc)?

View File

@@ -20,5 +20,6 @@
import cpp
module DataFlow {
import semmle.code.cpp.dataflow.internal.DataFlowImpl
import semmle.code.cpp.dataflow.internal.DataFlow
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
}

View File

@@ -19,5 +19,6 @@ import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.dataflow.DataFlow2
module TaintTracking {
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTracking
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
}

View File

@@ -0,0 +1,245 @@
/**
* Provides an implementation of global (interprocedural) data flow. This file
* re-exports the local (intraprocedural) data flow analysis from
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
* through the `Make` and `MakeWithState` modules.
*/
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
private import DataFlowImpl
/** An input configuration for data flow. */
signature module ConfigSig {
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source);
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/** An input configuration for data flow using flow state. */
signature module StateConfigSig {
bindingset[this]
class FlowState;
/**
* Holds if `source` is a relevant data flow source with the given initial
* `state`.
*/
predicate isSource(Node source, FlowState state);
/**
* Holds if `sink` is a relevant data flow sink accepting `state`.
*/
predicate isSink(Node sink, FlowState state);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/**
* Holds if data flow through `node` is prohibited when the flow state is
* `state`.
*/
predicate isBarrier(Node node, FlowState state);
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
signature int explorationLimitSig();
/**
* The output of a data flow computation.
*/
signature module DataFlowSig {
/**
* A `Node` augmented with a call context (except for sinks) and an access path.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode;
/**
* Holds if data can flow from `source` to `sink`.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink);
/**
* Holds if data can flow from `source` to `sink`.
*/
predicate hasFlow(Node source, Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate hasFlowTo(Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate hasFlowToExpr(DataFlowExpr sink);
}
/**
* Constructs a standard data flow computation.
*/
module Make<ConfigSig Config> implements DataFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
}
import Impl<C>
}
/**
* Constructs a data flow computation using flow state.
*/
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
private module C implements FullStateConfigSig {
import Config
}
import Impl<C>
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,396 @@
/**
* DEPRECATED: Use `Make` and `MakeWithState` instead.
*
* Provides a `Configuration` class backwards-compatible interface to the data
* flow library.
*/
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
/**
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
* of this abstract class. To create a configuration, extend this class with
* a subclass whose characteristic predicate is a unique singleton string.
* For example, write
*
* ```ql
* class MyAnalysisConfiguration extends DataFlow::Configuration {
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
* // Override `isSource` and `isSink`.
* // Optionally override `isBarrier`.
* // Optionally override `isAdditionalFlowStep`.
* }
* ```
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
* the edges are those data-flow steps that preserve the value of the node
* along with any additional edges defined by `isAdditionalFlowStep`.
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
* and/or out-going edges from those nodes, respectively.
*
* Then, to query whether there is flow between some `source` and `sink`,
* write
*
* ```ql
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
* ```
*
* Multiple configurations can coexist, but two classes extending
* `DataFlow::Configuration` should never depend on each other. One of them
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source) { none() }
/**
* Holds if `source` is a relevant data flow source with the given initial
* `state`.
*/
predicate isSource(Node source, FlowState state) { none() }
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink) { none() }
/**
* Holds if `sink` is a relevant data flow sink accepting `state`.
*/
predicate isSink(Node sink, FlowState state) { none() }
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
predicate isBarrier(Node node) { none() }
/**
* Holds if data flow through `node` is prohibited when the flow state is
* `state`.
*/
predicate isBarrier(Node node, FlowState state) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
none()
}
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (for example in a `path-problem` query).
*/
predicate includeHiddenNodes() { none() }
}
/**
* This class exists to prevent mutual recursion between the user-overridden
* member predicates of `Configuration` and the rest of the data-flow library.
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
override predicate hasFlow(Node source, Node sink) {
strictcount(Node n | this.isSource(n)) < 0
or
strictcount(Node n | this.isSource(n, _)) < 0
or
strictcount(Node n | this.isSink(n)) < 0
or
strictcount(Node n | this.isSink(n, _)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
or
super.hasFlow(source, sink)
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
config.isAdditionalFlowStep(_, result, _, _) or
config.isAdditionalFlowStep(_, _, _, result)
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
getConfig(state).isSource(source, getState(state))
or
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
}
predicate isBarrier(Node node) { none() }
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
getConfig(state2) = getConfig(state1)
or
not singleConfiguration() and
getConfig(state1).isAdditionalFlowStep(node1, node2) and
state2 = state1
}
predicate allowImplicitRead(Node node, ContentSet c) {
any(Configuration config).allowImplicitRead(node, c)
}
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
import I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
sink0.getNode() = sink
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
hasFlowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,15 +3,18 @@ private import DataFlowImplSpecific::Public
import Cached
module DataFlowImplCommonPublic {
/** A state value to track during data flow. */
class FlowState = string;
/** Provides `FlowState = string`. */
module FlowStateString {
/** A state value to track during data flow. */
class FlowState = string;
/**
* The default state, which is used when the state is unspecified for a source
* or a sink.
*/
class FlowStateEmpty extends FlowState {
FlowStateEmpty() { this = "" }
/**
* The default state, which is used when the state is unspecified for a source
* or a sink.
*/
class FlowStateEmpty extends FlowState {
FlowStateEmpty() { this = "" }
}
}
private newtype TFlowFeature =

View File

@@ -318,3 +318,12 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
// consistency alerts enough that most of them are interesting.
}
}
/**
* Gets an additional term that is added to the `join` and `branch` computations to reflect
* an additional forward or backwards branching factor that is not taken into account
* when calculating the (virtual) dispatch cost.
*
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
*/
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }

View File

@@ -0,0 +1,63 @@
/**
* Provides classes for performing local (intra-procedural) and
* global (inter-procedural) taint-tracking analyses.
*/
import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
DataFlowInternal::FullStateConfigSig {
import Config
predicate isBarrier(DataFlow::Node node) {
Config::isBarrier(node) or defaultTaintSanitizer(node)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
Config::isAdditionalFlowStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
}
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
Config::allowImplicitRead(node, c)
or
(
Config::isSink(node, _) or
Config::isAdditionalFlowStep(node, _) or
Config::isAdditionalFlowStep(node, _, _, _)
) and
defaultImplicitTaintRead(node, c)
}
}
/**
* Constructs a standard taint tracking computation.
*/
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
import DataFlowInternal::Impl<C>
}
/**
* Constructs a taint tracking computation using flow state.
*/
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
import DataFlowInternal::Impl<C>
}

View File

@@ -2,4 +2,5 @@ import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public
module Private {
import semmle.code.cpp.dataflow.DataFlow::DataFlow as DataFlow
import semmle.code.cpp.dataflow.internal.DataFlowImpl as DataFlowInternal
}

View File

@@ -22,5 +22,6 @@
import cpp
module DataFlow {
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl
import semmle.code.cpp.ir.dataflow.internal.DataFlow
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
}

View File

@@ -19,5 +19,6 @@ import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.dataflow.DataFlow2
module TaintTracking {
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTracking
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
}

View File

@@ -0,0 +1,245 @@
/**
* Provides an implementation of global (interprocedural) data flow. This file
* re-exports the local (intraprocedural) data flow analysis from
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
* through the `Make` and `MakeWithState` modules.
*/
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
private import DataFlowImpl
/** An input configuration for data flow. */
signature module ConfigSig {
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source);
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/** An input configuration for data flow using flow state. */
signature module StateConfigSig {
bindingset[this]
class FlowState;
/**
* Holds if `source` is a relevant data flow source with the given initial
* `state`.
*/
predicate isSource(Node source, FlowState state);
/**
* Holds if `sink` is a relevant data flow sink accepting `state`.
*/
predicate isSink(Node sink, FlowState state);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/**
* Holds if data flow through `node` is prohibited when the flow state is
* `state`.
*/
predicate isBarrier(Node node, FlowState state);
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
signature int explorationLimitSig();
/**
* The output of a data flow computation.
*/
signature module DataFlowSig {
/**
* A `Node` augmented with a call context (except for sinks) and an access path.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode;
/**
* Holds if data can flow from `source` to `sink`.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink);
/**
* Holds if data can flow from `source` to `sink`.
*/
predicate hasFlow(Node source, Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate hasFlowTo(Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate hasFlowToExpr(DataFlowExpr sink);
}
/**
* Constructs a standard data flow computation.
*/
module Make<ConfigSig Config> implements DataFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
}
import Impl<C>
}
/**
* Constructs a data flow computation using flow state.
*/
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
private module C implements FullStateConfigSig {
import Config
}
import Impl<C>
}

View File

@@ -0,0 +1,396 @@
/**
* DEPRECATED: Use `Make` and `MakeWithState` instead.
*
* Provides a `Configuration` class backwards-compatible interface to the data
* flow library.
*/
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
/**
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
* of this abstract class. To create a configuration, extend this class with
* a subclass whose characteristic predicate is a unique singleton string.
* For example, write
*
* ```ql
* class MyAnalysisConfiguration extends DataFlow::Configuration {
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
* // Override `isSource` and `isSink`.
* // Optionally override `isBarrier`.
* // Optionally override `isAdditionalFlowStep`.
* }
* ```
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
* the edges are those data-flow steps that preserve the value of the node
* along with any additional edges defined by `isAdditionalFlowStep`.
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
* and/or out-going edges from those nodes, respectively.
*
* Then, to query whether there is flow between some `source` and `sink`,
* write
*
* ```ql
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
* ```
*
* Multiple configurations can coexist, but two classes extending
* `DataFlow::Configuration` should never depend on each other. One of them
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source) { none() }
/**
* Holds if `source` is a relevant data flow source with the given initial
* `state`.
*/
predicate isSource(Node source, FlowState state) { none() }
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink) { none() }
/**
* Holds if `sink` is a relevant data flow sink accepting `state`.
*/
predicate isSink(Node sink, FlowState state) { none() }
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
predicate isBarrier(Node node) { none() }
/**
* Holds if data flow through `node` is prohibited when the flow state is
* `state`.
*/
predicate isBarrier(Node node, FlowState state) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
none()
}
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (for example in a `path-problem` query).
*/
predicate includeHiddenNodes() { none() }
}
/**
* This class exists to prevent mutual recursion between the user-overridden
* member predicates of `Configuration` and the rest of the data-flow library.
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
override predicate hasFlow(Node source, Node sink) {
strictcount(Node n | this.isSource(n)) < 0
or
strictcount(Node n | this.isSource(n, _)) < 0
or
strictcount(Node n | this.isSink(n)) < 0
or
strictcount(Node n | this.isSink(n, _)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
or
super.hasFlow(source, sink)
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
config.isAdditionalFlowStep(_, result, _, _) or
config.isAdditionalFlowStep(_, _, _, result)
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
getConfig(state).isSource(source, getState(state))
or
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
}
predicate isBarrier(Node node) { none() }
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
getConfig(state2) = getConfig(state1)
or
not singleConfiguration() and
getConfig(state1).isAdditionalFlowStep(node1, node2) and
state2 = state1
}
predicate allowImplicitRead(Node node, ContentSet c) {
any(Configuration config).allowImplicitRead(node, c)
}
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
import I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
sink0.getNode() = sink
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
hasFlowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;

View File

@@ -3,15 +3,18 @@ private import DataFlowImplSpecific::Public
import Cached
module DataFlowImplCommonPublic {
/** A state value to track during data flow. */
class FlowState = string;
/** Provides `FlowState = string`. */
module FlowStateString {
/** A state value to track during data flow. */
class FlowState = string;
/**
* The default state, which is used when the state is unspecified for a source
* or a sink.
*/
class FlowStateEmpty extends FlowState {
FlowStateEmpty() { this = "" }
/**
* The default state, which is used when the state is unspecified for a source
* or a sink.
*/
class FlowStateEmpty extends FlowState {
FlowStateEmpty() { this = "" }
}
}
private newtype TFlowFeature =

View File

@@ -414,3 +414,12 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
any()
}
}
/**
* Gets an additional term that is added to the `join` and `branch` computations to reflect
* an additional forward or backwards branching factor that is not taken into account
* when calculating the (virtual) dispatch cost.
*
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
*/
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }

View File

@@ -97,23 +97,23 @@ private string getNodeProperty(DataFlow::Node node, string key) {
|
kind, ", "
)
or
// Is there partial flow from a source to this node?
// This property will only be emitted if partial flow is enabled by overriding
// `DataFlow::Configuration::explorationLimit()`.
key = "pflow" and
result =
strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
int order1, int order2 |
any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
destNode.getNode() = node and
// Only print flow from a source in the same function.
sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
|
nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
order by
order1, order2, dist desc
)
// or
// // Is there partial flow from a source to this node?
// // This property will only be emitted if partial flow is enabled by overriding
// // `DataFlow::Configuration::explorationLimit()`.
// key = "pflow" and
// result =
// strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
// int order1, int order2 |
// any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
// destNode.getNode() = node and
// // Only print flow from a source in the same function.
// sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
// |
// nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
// order by
// order1, order2, dist desc
// )
}
/**

View File

@@ -0,0 +1,63 @@
/**
* Provides classes for performing local (intra-procedural) and
* global (inter-procedural) taint-tracking analyses.
*/
import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
DataFlowInternal::FullStateConfigSig {
import Config
predicate isBarrier(DataFlow::Node node) {
Config::isBarrier(node) or defaultTaintSanitizer(node)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
Config::isAdditionalFlowStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
}
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
Config::allowImplicitRead(node, c)
or
(
Config::isSink(node, _) or
Config::isAdditionalFlowStep(node, _) or
Config::isAdditionalFlowStep(node, _, _, _)
) and
defaultImplicitTaintRead(node, c)
}
}
/**
* Constructs a standard taint tracking computation.
*/
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
import DataFlowInternal::Impl<C>
}
/**
* Constructs a taint tracking computation using flow state.
*/
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
import DataFlowInternal::Impl<C>
}

View File

@@ -2,4 +2,5 @@ import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
module Private {
import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl as DataFlowInternal
}

View File

@@ -22,7 +22,7 @@ import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.dataflow.TaintTracking2
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.models.implementations.Strcat
import DataFlow::PathGraph
import ExecTaint::PathGraph
Expr sinkAsArgumentIndirection(DataFlow::Node sink) {
result =
@@ -67,28 +67,28 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
)
}
class ConcatState extends DataFlow::FlowState {
ConcatState() { this = "ConcatState" }
newtype TState =
TConcatState() or
TExecState(DataFlow::Node fst, DataFlow::Node snd) { interestingConcatenation(fst, snd) }
class ConcatState extends TConcatState {
string toString() { result = "ConcatState" }
}
class ExecState extends DataFlow::FlowState {
class ExecState extends TExecState {
DataFlow::Node fst;
DataFlow::Node snd;
ExecState() {
this =
"ExecState (" + fst.getLocation() + " | " + fst + ", " + snd.getLocation() + " | " + snd + ")" and
interestingConcatenation(pragma[only_bind_into](fst), pragma[only_bind_into](snd))
}
ExecState() { this = TExecState(fst, snd) }
DataFlow::Node getFstNode() { result = fst }
DataFlow::Node getSndNode() { result = snd }
/** Holds if this is a possible `ExecState` for `sink`. */
predicate isFeasibleForSink(DataFlow::Node sink) {
any(ExecStateConfiguration conf).hasFlow(snd, sink)
}
predicate isFeasibleForSink(DataFlow::Node sink) { ExecState::hasFlow(snd, sink) }
string toString() { result = "ExecState" }
}
/**
@@ -96,45 +96,42 @@ class ExecState extends DataFlow::FlowState {
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
* `ExecTaintConfiguration::isSink`.
*/
class ExecStateConfiguration extends TaintTracking2::Configuration {
ExecStateConfiguration() { this = "ExecStateConfiguration" }
override predicate isSource(DataFlow::Node source) {
module ExecStateConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(ExecState state | state.getSndNode() = source)
}
override predicate isSink(DataFlow::Node sink) {
shellCommand(sinkAsArgumentIndirection(sink), _)
}
predicate isSink(DataFlow::Node sink) { shellCommand(sinkAsArgumentIndirection(sink), _) }
override predicate isSanitizerOut(DataFlow::Node node) {
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
predicate isBarrierOut(DataFlow::Node node) {
isSink(node) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
}
class ExecTaintConfiguration extends TaintTracking::Configuration {
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
module ExecState = TaintTracking::Make<ExecStateConfiguration>;
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
module ExecTaintConfiguration implements DataFlow::StateConfigSig {
class FlowState = TState;
predicate isSource(DataFlow::Node source, FlowState state) {
source instanceof FlowSource and
state instanceof ConcatState
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
any(ExecStateConfiguration conf).isSink(sink) and
predicate isSink(DataFlow::Node sink, FlowState state) {
ExecStateConfiguration::isSink(sink) and
state.(ExecState).isFeasibleForSink(sink)
}
override predicate isAdditionalTaintStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
state1 instanceof ConcatState and
state2.(ExecState).getFstNode() = node1 and
state2.(ExecState).getSndNode() = node2
}
override predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) {
predicate isBarrier(DataFlow::Node node, FlowState state) {
(
node.asInstruction().getResultType() instanceof IntegralType
or
@@ -143,16 +140,18 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
state instanceof ConcatState
}
override predicate isSanitizerOut(DataFlow::Node node) {
predicate isBarrierOut(DataFlow::Node node) {
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
}
module ExecTaint = TaintTracking::MakeWithState<ExecTaintConfiguration>;
from
ExecTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode,
string taintCause, string callChain, DataFlow::Node concatResult
ExecTaint::PathNode sourceNode, ExecTaint::PathNode sinkNode, string taintCause, string callChain,
DataFlow::Node concatResult
where
conf.hasFlowPath(sourceNode, sinkNode) and
ExecTaint::hasFlowPath(sourceNode, sinkNode) and
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain) and
concatResult = sinkNode.getState().(ExecState).getSndNode()

View File

@@ -1,11 +1,11 @@
int write_default_config_bad() {
void write_default_config_bad() {
// BAD - this is world-writable so any user can overwrite the config
FILE* out = creat(OUTFILE, 0666);
fprintf(out, DEFAULT_CONFIG);
int out = creat(OUTFILE, 0666);
dprintf(out, DEFAULT_CONFIG);
}
int write_default_config_good() {
void write_default_config_good() {
// GOOD - this allows only the current user to modify the file
FILE* out = creat(OUTFILE, S_IWUSR | S_IRUSR);
fprintf(out, DEFAULT_CONFIG);
int out = creat(OUTFILE, S_IWUSR | S_IRUSR);
dprintf(out, DEFAULT_CONFIG);
}

View File

@@ -0,0 +1,7 @@
...
a = getc(f);
if (a < 123) ret = 123/a; // BAD
...
if (a != 0) ret = 123/a; // GOOD
...

View File

@@ -0,0 +1,23 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p> Possible cases of division by zero when using the return value from functions.</p>
</overview>
<example>
<p>The following example shows the use of a function with an error when using the return value and without an error.</p>
<sample src="DivideByZeroUsingReturnValue.cpp" />
</example>
<references>
<li>
CERT Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/INT33-C.+Ensure+that+division+and+remainder+operations+do+not+result+in+divide-by-zero+errors">INT33-C. Ensure that division and remainder operations do not result in divide-by-zero errors - SEI CERT C Coding Standard - Confluence</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,274 @@
/**
* @name Divide by zero using return value
* @description Possible cases of division by zero when using the return value from functions.
* @kind problem
* @id cpp/divide-by-zero-using-return-value
* @problem.severity warning
* @precision medium
* @tags correctness
* security
* external/cwe/cwe-369
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.controlflow.Guards
/** Holds if function `fn` can return a value equal to value `val` */
predicate mayBeReturnValue(Function fn, float val) {
exists(Expr tmpExp, ReturnStmt rs |
tmpExp.getValue().toFloat() = val and
rs.getEnclosingFunction() = fn and
(
globalValueNumber(rs.getExpr()) = globalValueNumber(tmpExp)
or
exists(AssignExpr ae |
ae.getLValue().(VariableAccess).getTarget() =
globalValueNumber(rs.getExpr()).getAnExpr().(VariableAccess).getTarget() and
globalValueNumber(ae.getRValue()) = globalValueNumber(tmpExp)
)
or
exists(Initializer it |
globalValueNumber(it.getExpr()) = globalValueNumber(tmpExp) and
it.getDeclaration().(Variable).getAnAccess().getTarget() =
globalValueNumber(rs.getExpr()).getAnExpr().(VariableAccess).getTarget()
)
)
)
}
/** Holds if function `fn` can return a value equal zero */
predicate mayBeReturnZero(Function fn) {
mayBeReturnValue(fn, 0)
or
fn.hasName([
"iswalpha", "iswlower", "iswprint", "iswspace", "iswblank", "iswupper", "iswcntrl",
"iswctype", "iswalnum", "iswgraph", "iswxdigit", "iswdigit", "iswpunct", "isblank", "isupper",
"isgraph", "isalnum", "ispunct", "islower", "isspace", "isprint", "isxdigit", "iscntrl",
"isdigit", "isalpha", "timespec_get", "feof", "atomic_is_lock_free",
"atomic_compare_exchange", "thrd_equal", "isfinite", "islessequal", "isnan", "isgreater",
"signbit", "isinf", "islessgreater", "isnormal", "isless", "isgreaterequal", "isunordered",
"ferror"
])
or
fn.hasName([
"thrd_sleep", "feenv", "feholdexcept", "feclearexcept", "feexceptflag", "feupdateenv",
"remove", "fflush", "setvbuf", "fgetpos", "fsetpos", "fclose", "rename", "fseek", "raise"
])
or
fn.hasName(["tss_get", "gets"])
or
fn.hasName(["getc", "atoi"])
}
/** Gets the Guard which compares the expression `bound` */
pragma[inline]
GuardCondition checkByValue(Expr bound, Expr val) {
exists(GuardCondition gc |
(
gc.ensuresEq(bound, val, _, _, _) or
gc.ensuresEq(val, bound, _, _, _) or
gc.ensuresLt(bound, val, _, _, _) or
gc.ensuresLt(val, bound, _, _, _) or
gc = globalValueNumber(bound).getAnExpr()
) and
result = gc
)
}
/** Holds if there are no comparisons between the value returned by possible function calls `compArg` and the value `valArg`, or when these comparisons do not exclude equality to the value `valArg`. */
pragma[inline]
predicate compareFunctionWithValue(Expr guardExp, Function compArg, Expr valArg) {
not exists(Expr exp |
exp.getAChild*() = globalValueNumber(compArg.getACallToThisFunction()).getAnExpr() and
checkByValue(exp, valArg).controls(guardExp.getBasicBlock(), _)
)
or
exists(GuardCondition gc |
(
gc.ensuresEq(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), valArg, 0,
guardExp.getBasicBlock(), true)
or
gc.ensuresEq(valArg, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
guardExp.getBasicBlock(), true)
or
gc.ensuresLt(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), valArg, 0,
guardExp.getBasicBlock(), false)
or
gc.ensuresLt(valArg, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
guardExp.getBasicBlock(), false)
)
or
exists(Expr exp |
exp.getValue().toFloat() > valArg.getValue().toFloat() and
gc.ensuresLt(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), exp, 0,
guardExp.getBasicBlock(), true)
or
exp.getValue().toFloat() < valArg.getValue().toFloat() and
gc.ensuresLt(exp, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
guardExp.getBasicBlock(), true)
)
)
or
valArg.getValue().toFloat() = 0 and
exists(NotExpr ne, IfStmt ifne |
ne.getOperand() = globalValueNumber(compArg.getACallToThisFunction()).getAnExpr() and
ifne.getCondition() = ne and
ifne.getThen().getAChild*() = guardExp
)
}
/** Wraping predicate for call `compareFunctionWithValue`. */
pragma[inline]
predicate checkConditions1(Expr div, Function fn, float changeInt) {
exists(Expr val |
val.getEnclosingFunction() = fn and
val.getValue().toFloat() = changeInt and
compareFunctionWithValue(div, fn, val)
)
}
/** Holds if there are no comparisons between the value `compArg` and the value `valArg`, or when these comparisons do not exclude equality to the value `valArg`. */
pragma[inline]
predicate compareExprWithValue(Expr guardExp, Expr compArg, Expr valArg) {
not exists(Expr exp |
exp.getAChild*() = globalValueNumber(compArg).getAnExpr() and
checkByValue(exp, valArg).controls(guardExp.getBasicBlock(), _)
)
or
exists(GuardCondition gc |
(
gc.ensuresEq(globalValueNumber(compArg).getAnExpr(), valArg, 0, guardExp.getBasicBlock(), true)
or
gc.ensuresEq(valArg, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(), true)
or
gc.ensuresLt(globalValueNumber(compArg).getAnExpr(), valArg, 0, guardExp.getBasicBlock(),
false)
or
gc.ensuresLt(valArg, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(),
false)
)
or
exists(Expr exp |
exp.getValue().toFloat() > valArg.getValue().toFloat() and
gc.ensuresLt(globalValueNumber(compArg).getAnExpr(), exp, 0, guardExp.getBasicBlock(), true)
or
exp.getValue().toFloat() < valArg.getValue().toFloat() and
gc.ensuresLt(exp, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(), true)
)
)
or
valArg.getValue().toFloat() = 0 and
exists(NotExpr ne, IfStmt ifne |
ne.getOperand() = globalValueNumber(compArg).getAnExpr() and
ifne.getCondition() = ne and
ifne.getThen().getAChild*() = guardExp
)
}
/** Wraping predicate for call `compareExprWithValue`. */
pragma[inline]
predicate checkConditions2(Expr div, Expr divVal, float changeInt2) {
exists(Expr val |
(
val.getEnclosingFunction() =
div.getEnclosingFunction().getACallToThisFunction().getEnclosingFunction() or
val.getEnclosingFunction() = div.getEnclosingFunction()
) and
val.getValue().toFloat() = changeInt2 and
compareExprWithValue(div, divVal, val)
)
}
/** Gets the value of the difference or summand from the expression `src`. */
float getValueOperand(Expr src, Expr e1, Expr e2) {
src.(SubExpr).hasOperands(e1, e2) and
result = e2.getValue().toFloat()
or
src.(AddExpr).hasOperands(e1, e2) and
result = -e2.getValue().toFloat()
}
/** Function the return of the expression `e1` and the multiplication operands, or the left operand of division if `e1` contains a multiplication or division, respectively. */
Expr getMulDivOperand(Expr e1) {
result = e1 or
result = e1.(MulExpr).getAnOperand() or
result = e1.(DivExpr).getLeftOperand()
}
/** The class that defines possible variants of the division expression or the search for the remainder. */
class MyDiv extends Expr {
MyDiv() {
this instanceof DivExpr or
this instanceof RemExpr or
this instanceof AssignDivExpr or
this instanceof AssignRemExpr
}
Expr getRV() {
result = this.(AssignArithmeticOperation).getRValue() or
result = this.(BinaryArithmeticOperation).getRightOperand()
}
}
from Expr exp, string msg, Function fn, GVN findVal, float changeInt, MyDiv div
where
findVal = globalValueNumber(fn.getACallToThisFunction()) and
(
// Look for divide-by-zero operations possible due to the return value of the function `fn`.
checkConditions1(div, fn, changeInt) and
(
// Function return value can be zero.
mayBeReturnZero(fn) and
getMulDivOperand(globalValueNumber(div.getRV()).getAnExpr()) = findVal.getAnExpr() and
changeInt = 0
or
// Denominator can be sum or difference.
changeInt = getValueOperand(div.getRV(), findVal.getAnExpr(), _) and
mayBeReturnValue(fn, changeInt)
) and
exp = div and
msg =
"Can lead to division by 0, since the function " + fn.getName() + " can return a value " +
changeInt.toString() + "."
or
// Search for situations where division by zero is possible inside the `divFn` function if the passed argument can be equal to a certain value.
exists(int posArg, Expr divVal, FunctionCall divFc, float changeInt2 |
// Division is associated with the function argument.
exists(Function divFn |
divFn.getParameter(posArg).getAnAccess() = divVal and
divVal.getEnclosingStmt() = div.getEnclosingStmt() and
divFc = divFn.getACallToThisFunction()
) and
(
divVal = div.getRV() and
divFc.getArgument(posArg) != findVal.getAnExpr() and
(
// Function return value can be zero.
mayBeReturnZero(fn) and
getMulDivOperand(globalValueNumber(divFc.getArgument(posArg)).getAnExpr()) =
findVal.getAnExpr() and
changeInt = 0 and
changeInt2 = 0
or
// Denominator can be sum or difference.
changeInt = getValueOperand(divFc.getArgument(posArg), findVal.getAnExpr(), _) and
mayBeReturnValue(fn, changeInt) and
changeInt2 = 0
)
or
// Look for a situation where the difference or subtraction is considered as an argument, and it can be used in the same way.
changeInt = getValueOperand(div.getRV(), divVal, _) and
changeInt2 = changeInt and
mayBeReturnValue(fn, changeInt) and
divFc.getArgument(posArg) = findVal.getAnExpr()
) and
checkConditions2(div, divVal, changeInt2) and
checkConditions1(divFc, fn, changeInt) and
exp = divFc and
msg =
"Can lead to division by 0, since the function " + fn.getName() + " can return a value " +
changeInt.toString() + "."
)
)
select exp, msg

View File

@@ -14,8 +14,8 @@ import cpp
from FunctionCall fc, FunctionCall fc2, LocalScopeVariable v
where
freeCall(fc, v.getAnAccess()) and
freeCall(fc2, v.getAnAccess()) and
fc.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
fc2.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
fc != fc2 and
fc.getASuccessor*() = fc2 and
not exists(Expr exptmp |

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.5.3
version: 0.5.4-dev
groups:
- cpp
- queries

View File

@@ -0,0 +1,27 @@
| test.cpp:47:24:47:31 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:48:15:48:34 | ... / ... | Can lead to division by 0, since the function getSize2 can return a value 0. |
| test.cpp:53:10:53:17 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:65:15:65:22 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:68:15:68:22 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:71:9:71:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:74:9:74:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:77:21:77:28 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:79:25:79:32 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:81:24:81:31 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:128:10:128:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:135:10:135:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:141:10:141:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:153:12:153:19 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:172:3:172:12 | ... /= ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:173:3:173:12 | ... %= ... | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:187:10:187:17 | ... / ... | Can lead to division by 0, since the function getSizeFloat can return a value 0. |
| test.cpp:199:12:199:25 | ... / ... | Can lead to division by 0, since the function getSize can return a value -1. |
| test.cpp:202:12:202:25 | ... / ... | Can lead to division by 0, since the function getSize can return a value 1. |
| test.cpp:205:10:205:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 1. |
| test.cpp:210:10:210:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 3. |
| test.cpp:258:3:258:10 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 0. |
| test.cpp:259:3:259:10 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 2. |
| test.cpp:260:3:260:13 | call to badMySubDiv | Can lead to division by 0, since the function getSize can return a value 3. |
| test.cpp:263:5:263:15 | call to badMySubDiv | Can lead to division by 0, since the function getSize can return a value 3. |
| test.cpp:273:5:273:12 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 3. |
| test.cpp:275:5:275:12 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value -1. |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-369/DivideByZeroUsingReturnValue.ql

View File

@@ -0,0 +1,278 @@
typedef struct {}
FILE;
int getc(FILE * stream);
int getSize(int type) {
int st;
switch (type) {
case 1:
st = 1;
break;
case 2:
st = 2;
break;
case 3:
st = 3;
break;
case 4:
st = -1;
break;
default:
st = 0;
break;
}
return st;
}
int getSize2(int type) {
int st = 0;
switch (type) {
case 1:
st = 1;
break;
case 2:
st = 2;
break;
case 3:
st = 3;
break;
case 4:
st = -1;
break;
}
return st;
}
int badTestf1(int type, int met) {
int is = getSize(type);
if (met == 1) return 123 / is; // BAD
else return 123 / getSize2(type); // BAD
}
int badTestf2(int type) {
int is;
is = getSize(type);
return 123 / is; // BAD
}
int badTestf3(int type, int met) {
int is;
is = getSize(type);
switch (met) {
case 1:
if (is >= 0) return 123 / is; // BAD [NOT DETECTED]
case 2:
if (0 == is) return 123 / is; // BAD [NOT DETECTED]
case 3:
if (!is & 123 / is) // BAD
return 123;
case 4:
if (!is | 123 / is) // BAD
return 123;
case 5:
if (123 / is || !is) // BAD
return 123;
case 6:
if (123 / is && !is) // BAD
return 123;
case 7:
if (!is) return 123 / is; // BAD
case 8:
if (is > -1) return 123 / is; // BAD
case 9:
if (is < 2) return 123 / is; // BAD
}
if (is != 0) return -1;
if (is == 0) type += 1;
return 123 / is; // BAD [NOT DETECTED]
}
int goodTestf3(int type, int met) {
int is = getSize(type);
if (is == 0) return -1;
switch (met) {
case 1:
if (is < 0) return 123 / is; // GOOD
case 2:
if (!is && 123 / is) // GOOD
return 123;
case 3:
if (!is || 123 / is) // GOOD
return 123;
case 8:
if (is < -1) return 123 / is; // GOOD
case 9:
if (is > 2) return 123 / is; // GOOD
}
return 123 / is;
}
int goodTestf3a(int type, int met) {
int is = getSize(type);
switch (met) {
case 1:
if (is < 0)
return 123 / is; // GOOD
case 2:
if (!is && 123 / is) // GOOD
return 123;
case 3:
if (!is || 123 / is) // GOOD
return 123;
}
return 1;
}
int badTestf4(int type) {
int is = getSize(type);
int d;
d = type * is;
return 123 / d; // BAD
}
int badTestf5(int type) {
int is = getSize(type);
int d;
d = is / type;
return 123 / d; // BAD
}
int badTestf6(int type) {
int is = getSize(type);
int d;
d = is / type;
return type * 123 / d; // BAD
}
int badTestf7(int type, int met) {
int is = getSize(type);
if (is == 0) goto quit;
switch (met) {
case 1:
if (is < 0)
return 123 / is; // GOOD
}
quit:
return 123 / is; // BAD
}
int goodTestf7(int type, int met) {
int is = getSize(type);
if (is == 0) goto quit2;
if (is == 0.) return -1;
switch (met) {
case 1:
if (is < 0.)
return 123 / is; // GOOD
}
return 123 / is; // GOOD
quit2:
return -1;
}
int badTestf8(int type) {
int is = getSize(type);
type /= is; // BAD
type %= is; // BAD
return type;
}
float getSizeFloat(float type) {
float st;
if (type)
st = 1.0;
else
st = 0.0;
return st;
}
float badTestf9(float type) {
float is = getSizeFloat(type);
return 123 / is; // BAD
}
float goodTestf9(float type) {
float is = getSizeFloat(type);
if (is == 0.0) return -1;
return 123 / is; // GOOD
}
int badTestf10(int type) {
int out = type;
int is = getSize(type);
if (is > -2) {
out /= 123 / (is + 1); // BAD
}
if (is > 0) {
return 123 / (is - 1); // BAD
}
if (is <= 0) return 0;
return 123 / (is - 1); // BAD
return 0;
}
int badTestf11(int type) {
int is = getSize(type);
return 123 / (is - 3); // BAD
}
int goodTestf11(int type) {
int is = getSize(type);
if (is > 1) {
return 123 / (is - 1); // GOOD
} else {
return 0;
}
}
int badTestf12(FILE * f) {
int a;
int ret = -1;
a = getc(f);
if (a == 0) ret = 123 / a; // BAD [NOT DETECTED]
return ret;
}
int goodTestf12(FILE * f) {
int a;
int ret = -1;
a = getc(f);
if (a != 0) ret = 123 / a; // GOOD
return ret;
}
int badMyDiv(int type, int is) {
type /= is;
type %= is;
return type;
}
int goodMyDiv(int type, int is) {
if (is == 0) return -1;
type /= is;
type %= is;
return type;
}
int badMySubDiv(int type, int is) {
type /= (is - 3);
type %= (is + 1);
return type;
}
void badTestf13(int type) {
int is = getSize(type);
badMyDiv(type, is); // BAD
badMyDiv(type, is - 2); // BAD
badMySubDiv(type, is); // BAD
goodMyDiv(type, is); // GOOD
if (is < 5)
badMySubDiv(type, is); // BAD
if (is < 0)
badMySubDiv(type, is); // BAD [NOT DETECTED]
if (is > 5)
badMySubDiv(type, is); // GOOD
if (is == 0)
badMyDiv(type, is); // BAD
if (is > 0)
badMyDiv(type, is); // GOOD
if (is < 5)
badMyDiv(type, is - 3); // BAD
if (is < 0)
badMyDiv(type, is + 1); // BAD
if (is > 5)
badMyDiv(type, is - 3); // GOOD
}

View File

@@ -1,14 +1,14 @@
| CPP-205.cpp:0:0:0:0 | CPP-205.cpp | |
| CPP-205.cpp:1:20:1:20 | T | |
| CPP-205.cpp:1:20:1:20 | definition of T | |
| CPP-205.cpp:2:5:2:5 | definition of fn | function declaration entry for fn<int>(int) -> int |
| CPP-205.cpp:2:5:2:5 | fn | function fn<int>(int) -> int |
| CPP-205.cpp:2:5:2:6 | definition of fn | function declaration entry for fn<T>(T) -> int |
| CPP-205.cpp:2:5:2:6 | fn | function fn<T>(T) -> int |
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for fn<T>(T) -> int |
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for fn<int>(int) -> int |
| CPP-205.cpp:2:10:2:12 | out | parameter for fn<T>(T) -> int |
| CPP-205.cpp:2:10:2:12 | out | parameter for fn<int>(int) -> int |
| CPP-205.cpp:2:5:2:5 | definition of fn | function declaration entry for int fn<int>(int) |
| CPP-205.cpp:2:5:2:5 | fn | function int fn<int>(int) |
| CPP-205.cpp:2:5:2:6 | definition of fn | function declaration entry for int fn<T>(T) |
| CPP-205.cpp:2:5:2:6 | fn | function int fn<T>(T) |
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for int fn<T>(T) |
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for int fn<int>(int) |
| CPP-205.cpp:2:10:2:12 | out | parameter for int fn<T>(T) |
| CPP-205.cpp:2:10:2:12 | out | parameter for int fn<int>(int) |
| CPP-205.cpp:2:15:5:1 | { ... } | |
| CPP-205.cpp:2:15:5:1 | { ... } | |
| CPP-205.cpp:3:3:3:33 | declaration | |
@@ -20,16 +20,16 @@
| CPP-205.cpp:4:3:4:11 | return ... | |
| CPP-205.cpp:4:10:4:10 | 0 | |
| CPP-205.cpp:4:10:4:10 | 0 | |
| CPP-205.cpp:7:5:7:8 | definition of main | function declaration entry for main() -> int |
| CPP-205.cpp:7:5:7:8 | main | function main() -> int |
| CPP-205.cpp:7:5:7:8 | definition of main | function declaration entry for int main() |
| CPP-205.cpp:7:5:7:8 | main | function int main() |
| CPP-205.cpp:7:12:9:1 | { ... } | |
| CPP-205.cpp:8:3:8:15 | return ... | |
| CPP-205.cpp:8:10:8:11 | call to fn | |
| CPP-205.cpp:8:13:8:13 | 0 | |
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & |
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & |
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) |
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) |
| file://:0:0:0:0 | __super | |
| file://:0:0:0:0 | __va_list_tag | |
| file://:0:0:0:0 | operator= | function __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & |
| file://:0:0:0:0 | operator= | function __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & |
| file://:0:0:0:0 | operator= | function __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) |
| file://:0:0:0:0 | operator= | function __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) |
| file://:0:0:0:0 | y | |

View File

@@ -1,17 +1,19 @@
import cpp
import semmle.code.cpp.Print
string describe(Element e) {
result = "function " + e.(Function).getFullSignature()
e instanceof Function and
result = "function " + getIdentityString(e)
or
result =
"function declaration entry for " +
e.(FunctionDeclarationEntry).getFunction().getFullSignature()
getIdentityString(e.(FunctionDeclarationEntry).getFunction())
or
result = "parameter for " + e.(Parameter).getFunction().getFullSignature()
result = "parameter for " + getIdentityString(e.(Parameter).getFunction())
or
result =
"parameter declaration entry for " +
e.(ParameterDeclarationEntry).getFunctionDeclarationEntry().getFunction().getFullSignature()
getIdentityString(e.(ParameterDeclarationEntry).getFunctionDeclarationEntry().getFunction())
}
from Element e

View File

@@ -1,51 +1,51 @@
newExprs
| allocators.cpp:49:3:49:9 | new | int | operator new(unsigned long) -> void * | 4 | 4 | | |
| allocators.cpp:50:3:50:15 | new | int | operator new(size_t, float) -> void * | 4 | 4 | | |
| allocators.cpp:51:3:51:11 | new | int | operator new(unsigned long) -> void * | 4 | 4 | | |
| allocators.cpp:52:3:52:14 | new | String | operator new(unsigned long) -> void * | 8 | 8 | | |
| allocators.cpp:53:3:53:27 | new | String | operator new(size_t, float) -> void * | 8 | 8 | | |
| allocators.cpp:54:3:54:17 | new | Overaligned | operator new(unsigned long, align_val_t) -> void * | 256 | 128 | aligned | |
| allocators.cpp:55:3:55:25 | new | Overaligned | operator new(size_t, align_val_t, float) -> void * | 256 | 128 | aligned | |
| allocators.cpp:107:3:107:18 | new | FailedInit | FailedInit::operator new(size_t) -> void * | 1 | 1 | | |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | FailedInitOveraligned::operator new(size_t, align_val_t, float) -> void * | 128 | 128 | aligned | |
| allocators.cpp:129:3:129:21 | new | int | operator new(size_t, void *) -> void * | 4 | 4 | | & ... |
| allocators.cpp:135:3:135:26 | new | int | operator new(size_t, const nothrow_t &) -> void * | 4 | 4 | | |
| allocators.cpp:49:3:49:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
| allocators.cpp:50:3:50:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
| allocators.cpp:51:3:51:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
| allocators.cpp:52:3:52:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
| allocators.cpp:53:3:53:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
| allocators.cpp:54:3:54:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
| allocators.cpp:55:3:55:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
| allocators.cpp:107:3:107:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
| allocators.cpp:129:3:129:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
| allocators.cpp:135:3:135:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
newArrayExprs
| allocators.cpp:68:3:68:12 | new[] | int[] | int | operator new[](unsigned long) -> void * | 4 | 4 | | n | |
| allocators.cpp:69:3:69:18 | new[] | int[] | int | operator new[](size_t, float) -> void * | 4 | 4 | | n | |
| allocators.cpp:70:3:70:15 | new[] | String[] | String | operator new[](unsigned long) -> void * | 8 | 8 | | n | |
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | operator new[](unsigned long, align_val_t) -> void * | 256 | 128 | aligned | n | |
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | operator new[](unsigned long) -> void * | 8 | 8 | | | |
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | FailedInit::operator new[](size_t) -> void * | 1 | 1 | | n | |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | FailedInitOveraligned::operator new[](size_t, align_val_t, float) -> void * | 128 | 128 | aligned | | |
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | operator new[](size_t, void *) -> void * | 4 | 4 | | | buf |
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | operator new[](size_t, const nothrow_t &) -> void * | 4 | 4 | | | |
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | operator new[](unsigned long) -> void * | 10 | 1 | | x | |
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | operator new[](unsigned long) -> void * | 20 | 1 | | | |
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | operator new[](unsigned long) -> void * | 900 | 1 | | x | |
| allocators.cpp:68:3:68:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
| allocators.cpp:69:3:69:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
| allocators.cpp:70:3:70:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
newExprDeallocators
| allocators.cpp:52:3:52:14 | new | String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:53:3:53:27 | new | String | operator delete(void *, float) -> void | 8 | 8 | |
| allocators.cpp:107:3:107:18 | new | FailedInit | FailedInit::operator delete(void *, size_t) -> void | 1 | 1 | sized |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | FailedInitOveraligned::operator delete(void *, align_val_t, float) -> void | 128 | 128 | aligned |
| allocators.cpp:52:3:52:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:53:3:53:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
| allocators.cpp:107:3:107:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
newArrayExprDeallocators
| allocators.cpp:70:3:70:15 | new[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:72:3:72:16 | new[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:108:3:108:19 | new[] | FailedInit | FailedInit::operator delete[](void *, size_t) -> void | 1 | 1 | sized |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | FailedInitOveraligned::operator delete[](void *, align_val_t, float) -> void | 128 | 128 | aligned |
| allocators.cpp:70:3:70:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:72:3:72:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:108:3:108:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
deleteExprs
| allocators.cpp:59:3:59:35 | delete | int | operator delete(void *, unsigned long) -> void | 4 | 4 | sized |
| allocators.cpp:60:3:60:38 | delete | String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | SizedDealloc::operator delete(void *, size_t) -> void | 32 | 1 | sized |
| allocators.cpp:62:3:62:43 | delete | Overaligned | operator delete(void *, unsigned long, align_val_t) -> void | 256 | 128 | sized aligned |
| allocators.cpp:64:3:64:44 | delete | const String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:59:3:59:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized |
| allocators.cpp:60:3:60:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized |
| allocators.cpp:62:3:62:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
| allocators.cpp:64:3:64:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
deleteArrayExprs
| allocators.cpp:78:3:78:37 | delete[] | int | operator delete[](void *, unsigned long) -> void | 4 | 4 | sized |
| allocators.cpp:79:3:79:40 | delete[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | SizedDealloc::operator delete[](void *, size_t) -> void | 32 | 1 | sized |
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | operator delete[](void *, unsigned long, align_val_t) -> void | 256 | 128 | sized aligned |
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
| allocators.cpp:83:3:83:23 | delete[] | int | operator delete[](void *, unsigned long) -> void | 4 | 4 | sized |
| allocators.cpp:78:3:78:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
| allocators.cpp:79:3:79:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
| allocators.cpp:83:3:83:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
allocationFunctions
| allocators.cpp:7:7:7:18 | operator new | getSizeArg = 0, requiresDealloc |
| allocators.cpp:8:7:8:20 | operator new[] | getSizeArg = 0, requiresDealloc |

View File

@@ -1,12 +1,13 @@
import cpp
import semmle.code.cpp.models.implementations.Allocation
import semmle.code.cpp.Print
query predicate newExprs(
NewExpr expr, string type, string sig, int size, int alignment, string form, string placement
) {
exists(Function allocator, Type allocatedType |
expr.getAllocator() = allocator and
sig = allocator.getFullSignature() and
sig = getIdentityString(allocator) and
allocatedType = expr.getAllocatedType() and
type = allocatedType.toString() and
size = allocatedType.getSize() and
@@ -24,7 +25,7 @@ query predicate newArrayExprs(
) {
exists(Function allocator, Type arrayType, Type elementType |
expr.getAllocator() = allocator and
sig = allocator.getFullSignature() and
sig = getIdentityString(allocator) and
arrayType = expr.getAllocatedType() and
t1 = arrayType.toString() and
elementType = expr.getAllocatedElementType() and
@@ -44,7 +45,7 @@ query predicate newExprDeallocators(
) {
exists(Function deallocator, Type allocatedType |
expr.getDeallocator() = deallocator and
sig = deallocator.getFullSignature() and
sig = getIdentityString(deallocator) and
allocatedType = expr.getAllocatedType() and
type = allocatedType.toString() and
size = allocatedType.getSize() and
@@ -62,7 +63,7 @@ query predicate newArrayExprDeallocators(
) {
exists(Function deallocator, Type elementType |
expr.getDeallocator() = deallocator and
sig = deallocator.getFullSignature() and
sig = getIdentityString(deallocator) and
elementType = expr.getAllocatedElementType() and
type = elementType.toString() and
size = elementType.getSize() and
@@ -80,7 +81,7 @@ query predicate deleteExprs(
) {
exists(Function deallocator, Type deletedType |
expr.getDeallocator() = deallocator and
sig = deallocator.getFullSignature() and
sig = getIdentityString(deallocator) and
deletedType = expr.getDeletedObjectType() and
type = deletedType.toString() and
size = deletedType.getSize() and
@@ -98,7 +99,7 @@ query predicate deleteArrayExprs(
) {
exists(Function deallocator, Type elementType |
expr.getDeallocator() = deallocator and
sig = deallocator.getFullSignature() and
sig = getIdentityString(deallocator) and
elementType = expr.getDeletedElementType() and
type = elementType.toString() and
size = elementType.getSize() and

View File

@@ -1,30 +1,30 @@
| copy_from_prototype.cpp:3:7:3:7 | a | a<int>::a(a<int> &&) -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | a | a<int>::a(const a<int> &) -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>::operator=(a<int> &&) -> a<int> & | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>::operator=(const a<int> &) -> a<int> & | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:4:26:4:26 | a | a<<unnamed>>::a<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a<<unnamed>> | 123 |
| copy_from_prototype.cpp:4:26:4:26 | a | a<int>::a<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | b::b() -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | b::b(b &&) -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | b::b(const b &) -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | operator= | b::operator=(b &&) -> b & | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | operator= | b::operator=(const b &) -> b & | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(c<int> &&) -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(const c<int> &) -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(c<int> &&) -> c<int> & | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(const c<int> &) -> c<int> & | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:14:26:14:26 | c | c<T>::c<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<T> | X |
| copy_from_prototype.cpp:14:26:14:26 | c | c<int>::c<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | d::d() -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(const d &) -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(d &&) -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | operator= | d::operator=(const d &) -> d & | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | operator= | d::operator=(d &&) -> d & | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | e | e<int>::e(const e<int> &) -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | e | e<int>::e(e<int> &&) -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>::operator=(const e<int> &) -> e<int> & | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>::operator=(e<int> &&) -> e<int> & | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:23:26:23:26 | e | e<T>::e<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e<T> | 456 |
| copy_from_prototype.cpp:26:35:26:43 | e | e<int>::e<(unnamed template parameter)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | 456 |
| file://:0:0:0:0 | operator= | __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & | file://:0:0:0:0 | __va_list_tag | <none> |
| file://:0:0:0:0 | operator= | __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & | file://:0:0:0:0 | __va_list_tag | <none> |
| copy_from_prototype.cpp:3:7:3:7 | a | void a<int>::a(a<int> const&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | a | void a<int>::a(a<int>&&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>& a<int>::operator=(a<int> const&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>& a<int>::operator=(a<int>&&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:4:26:4:26 | a | void a<(unnamed template parameter)>::a<(unnamed template parameter)>() | copy_from_prototype.cpp:3:7:3:7 | a<<unnamed>> | 123 |
| copy_from_prototype.cpp:4:26:4:26 | a | void a<int>::a<(unnamed template parameter)>() | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | void b::b() | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | void b::b(b const&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | b | void b::b(b&&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | operator= | b& b::operator=(b const&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:7:7:7:7 | operator= | b& b::operator=(b&&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | c | void c<int>::c(c<int> const&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | c | void c<int>::c(c<int>&&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>& c<int>::operator=(c<int> const&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>& c<int>::operator=(c<int>&&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:14:26:14:26 | c | void c<T>::c<(unnamed template parameter)>() | copy_from_prototype.cpp:13:7:13:7 | c<T> | X |
| copy_from_prototype.cpp:14:26:14:26 | c | void c<int>::c<(unnamed template parameter)>() | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | void d::d() | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | void d::d(d const&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | d | void d::d(d&&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | operator= | d& d::operator=(d const&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:17:7:17:7 | operator= | d& d::operator=(d&&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | e | void e<int>::e(e<int> const&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | e | void e<int>::e(e<int>&&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>& e<int>::operator=(e<int> const&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>& e<int>::operator=(e<int>&&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
| copy_from_prototype.cpp:23:26:23:26 | e | void e<T>::e<(unnamed template parameter)>() | copy_from_prototype.cpp:22:8:22:8 | e<T> | 456 |
| copy_from_prototype.cpp:26:35:26:43 | e | void e<int>::e<(unnamed template parameter)>() | copy_from_prototype.cpp:22:8:22:8 | e<int> | 456 |
| file://:0:0:0:0 | operator= | __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) | file://:0:0:0:0 | __va_list_tag | <none> |
| file://:0:0:0:0 | operator= | __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) | file://:0:0:0:0 | __va_list_tag | <none> |

View File

@@ -1,4 +1,5 @@
import cpp
import semmle.code.cpp.Print
from Function f, string e
where
@@ -8,4 +9,4 @@ where
then e = f.getADeclarationEntry().getNoExceptExpr().toString()
else e = "<no expr>"
else e = "<none>"
select f, f.getFullSignature(), f.getDeclaringType(), e
select f, getIdentityString(f), f.getDeclaringType(), e

View File

@@ -19,3 +19,6 @@
| test.cpp:302:8:302:12 | ptr_i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:301:3:301:7 | call to scanf | call to scanf |
| test.cpp:310:7:310:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:309:3:309:7 | call to scanf | call to scanf |
| test.cpp:404:25:404:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:403:6:403:11 | call to sscanf | call to sscanf |
| test.cpp:416:7:416:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:413:7:413:11 | call to scanf | call to scanf |
| test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
| test.cpp:430:6:430:6 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:429:2:429:6 | call to scanf | call to scanf |

View File

@@ -406,3 +406,26 @@ char *my_string_copy() {
*ptr++ = 0;
return DST_STRING;
}
void scan_and_write() {
{
int i;
if (scanf("%d", &i) < 1) {
i = 0;
}
use(i); // GOOD [FALSE POSITIVE]: variable is overwritten with a default value when scanf fails
}
{
int i;
if (scanf("%d", &i) != 1) {
i = 0;
}
use(i); // GOOD [FALSE POSITIVE]: variable is overwritten with a default value when scanf fails
}
}
void scan_and_static_variable() {
static int i;
scanf("%d", &i);
use(i); // GOOD [FALSE POSITIVE]: static variables are always 0-initialized
}

View File

@@ -71,8 +71,6 @@ edges
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
nodes
| test.cpp:15:27:15:30 | argv | semmle.label | argv |
| test.cpp:22:13:22:20 | sprintf output argument | semmle.label | sprintf output argument |
@@ -151,6 +149,7 @@ nodes
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
| test.cpp:222:32:222:38 | command indirection | semmle.label | command indirection |
| test.cpp:222:32:222:38 | command indirection | semmle.label | command indirection |
subpaths
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |

View File

@@ -1,5 +1,6 @@
using Xunit;
using Semmle.Autobuild.Shared;
using Semmle.Util;
using System.Collections.Generic;
using System;
using System.Linq;
@@ -85,6 +86,15 @@ namespace Semmle.Autobuild.CSharp.Tests
return ret;
}
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
var ret = (this as IBuildActions).RunProcess(cmd, args, workingDirectory, env, out var stdout);
stdout.ForEach(line => onOutput(line));
return ret;
}
public IList<string> DirectoryDeleteIn { get; } = new List<string>();
void IBuildActions.DirectoryDelete(string dir, bool recursive)
@@ -145,6 +155,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)));
@@ -192,6 +210,16 @@ namespace Semmle.Autobuild.CSharp.Tests
if (!DownloadFiles.Contains((address, fileName)))
throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}");
}
public IDiagnosticsWriter CreateDiagnosticsWriter(string filename) => new TestDiagnosticWriter();
}
internal class TestDiagnosticWriter : IDiagnosticsWriter
{
public IList<DiagnosticMessage> Diagnostics { get; } = new List<DiagnosticMessage>();
public void AddEntry(DiagnosticMessage message) => this.Diagnostics.Add(message);
}
/// <summary>
@@ -383,6 +411,7 @@ namespace Semmle.Autobuild.CSharp.Tests
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = "";
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_DIAGNOSTIC_DIR"] = "";
actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = isWindows ? "win64" : "linux64";
actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion;

View File

@@ -0,0 +1,69 @@
using Semmle.Autobuild.Shared;
using Semmle.Extraction.CSharp;
namespace Semmle.Autobuild.CSharp
{
internal class AutoBuildRule : IBuildRule<CSharpAutobuildOptions>
{
private readonly CSharpAutobuilder autobuilder;
public DotNetRule DotNetRule { get; }
public MsBuildRule MsBuildRule { get; }
public BuildCommandAutoRule BuildCommandAutoRule { get; }
public AutoBuildRule(CSharpAutobuilder autobuilder)
{
this.autobuilder = autobuilder;
this.DotNetRule = new DotNetRule();
this.MsBuildRule = new MsBuildRule();
this.BuildCommandAutoRule = new BuildCommandAutoRule(DotNetRule.WithDotNet);
}
public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool auto)
{
var cleanTrapFolder =
BuildScript.DeleteDirectory(this.autobuilder.TrapDir);
var cleanSourceArchive =
BuildScript.DeleteDirectory(this.autobuilder.SourceArchiveDir);
var tryCleanExtractorArgsLogs =
BuildScript.Create(actions =>
{
foreach (var file in Extractor.GetCSharpArgsLogs())
{
try
{
actions.FileDelete(file);
}
catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block]
{ }
}
return 0;
});
var attemptExtractorCleanup =
BuildScript.Try(cleanTrapFolder) &
BuildScript.Try(cleanSourceArchive) &
tryCleanExtractorArgsLogs &
BuildScript.DeleteFile(Extractor.GetCSharpLogPath());
/// <summary>
/// Execute script `s` and check that the C# extractor has been executed.
/// If either fails, attempt to cleanup any artifacts produced by the extractor,
/// and exit with code 1, in order to proceed to the next attempt.
/// </summary>
BuildScript IntermediateAttempt(BuildScript s) =>
(s & this.autobuilder.CheckExtractorRun(false)) |
(attemptExtractorCleanup & BuildScript.Failure);
return
// First try .NET Core
IntermediateAttempt(this.DotNetRule.Analyse(this.autobuilder, true)) |
// Then MSBuild
(() => IntermediateAttempt(this.MsBuildRule.Analyse(this.autobuilder, true))) |
// And finally look for a script that might be a build script
(() => this.BuildCommandAutoRule.Analyse(this.autobuilder, true) & this.autobuilder.CheckExtractorRun(true));
}
}
}

View File

@@ -1,6 +1,8 @@
using Semmle.Extraction.CSharp;
using Semmle.Util.Logging;
using Semmle.Autobuild.Shared;
using Semmle.Util;
using System.Linq;
namespace Semmle.Autobuild.CSharp
{
@@ -29,25 +31,16 @@ namespace Semmle.Autobuild.CSharp
public class CSharpAutobuilder : Autobuilder<CSharpAutobuildOptions>
{
public CSharpAutobuilder(IBuildActions actions, CSharpAutobuildOptions options) : base(actions, options) { }
private const string buildCommandDocsUrl =
"https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages";
private readonly AutoBuildRule autoBuildRule;
public CSharpAutobuilder(IBuildActions actions, CSharpAutobuildOptions options) : base(actions, options, new CSharpDiagnosticClassifier()) =>
this.autoBuildRule = new AutoBuildRule(this);
public override BuildScript GetBuildScript()
{
/// <summary>
/// A script that checks that the C# extractor has been executed.
/// </summary>
BuildScript CheckExtractorRun(bool warnOnFailure) =>
BuildScript.Create(actions =>
{
if (actions.FileExists(Extractor.GetCSharpLogPath()))
return 0;
if (warnOnFailure)
Log(Severity.Error, "No C# code detected during build.");
return 1;
});
var attempt = BuildScript.Failure;
switch (GetCSharpBuildStrategy())
{
@@ -65,47 +58,9 @@ namespace Semmle.Autobuild.CSharp
attempt = new DotNetRule().Analyse(this, false) & CheckExtractorRun(true);
break;
case CSharpBuildStrategy.Auto:
var cleanTrapFolder =
BuildScript.DeleteDirectory(TrapDir);
var cleanSourceArchive =
BuildScript.DeleteDirectory(SourceArchiveDir);
var tryCleanExtractorArgsLogs =
BuildScript.Create(actions =>
{
foreach (var file in Extractor.GetCSharpArgsLogs())
{
try
{
actions.FileDelete(file);
}
catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block]
{ }
}
return 0;
});
var attemptExtractorCleanup =
BuildScript.Try(cleanTrapFolder) &
BuildScript.Try(cleanSourceArchive) &
tryCleanExtractorArgsLogs &
BuildScript.DeleteFile(Extractor.GetCSharpLogPath());
/// <summary>
/// Execute script `s` and check that the C# extractor has been executed.
/// If either fails, attempt to cleanup any artifacts produced by the extractor,
/// and exit with code 1, in order to proceed to the next attempt.
/// </summary>
BuildScript IntermediateAttempt(BuildScript s) =>
(s & CheckExtractorRun(false)) |
(attemptExtractorCleanup & BuildScript.Failure);
attempt =
// First try .NET Core
IntermediateAttempt(new DotNetRule().Analyse(this, true)) |
// Then MSBuild
(() => IntermediateAttempt(new MsBuildRule().Analyse(this, true))) |
// And finally look for a script that might be a build script
(() => new BuildCommandAutoRule(DotNetRule.WithDotNet).Analyse(this, true) & CheckExtractorRun(true)) |
// Attempt a few different build strategies to see if one works
this.autoBuildRule.Analyse(this, true) |
// All attempts failed: print message
AutobuildFailure();
break;
@@ -114,6 +69,127 @@ namespace Semmle.Autobuild.CSharp
return attempt;
}
/// <summary>
/// A script that checks that the C# extractor has been executed.
/// </summary>
public BuildScript CheckExtractorRun(bool warnOnFailure) =>
BuildScript.Create(actions =>
{
if (actions.FileExists(Extractor.GetCSharpLogPath()))
return 0;
if (warnOnFailure)
Log(Severity.Error, "No C# code detected during build.");
return 1;
});
protected override void AutobuildFailureDiagnostic()
{
// if `ScriptPath` is not null here, the `BuildCommandAuto` rule was
// run and found at least one script to execute
if (this.autoBuildRule.BuildCommandAutoRule.ScriptPath is not null)
{
var relScriptPath = this.MakeRelative(autoBuildRule.BuildCommandAutoRule.ScriptPath);
// if we found multiple build scripts in the project directory, then we can say
// as much to indicate that we may have picked the wrong one;
// otherwise, we just report that the one script we found didn't work
DiagnosticMessage message =
this.autoBuildRule.BuildCommandAutoRule.CandidatePaths.Count() > 1 ?
new(
this.Options.Language,
"multiple-build-scripts",
"There are multiple potential build scripts",
markdownMessage:
"CodeQL found multiple potential build scripts for your project and " +
$"attempted to run `{relScriptPath}`, which failed. " +
"This may not be the right build script for your project. " +
$"Set up a [manual build command]({buildCommandDocsUrl})."
) :
new(
this.Options.Language,
"script-failure",
"Unable to build project using build script",
markdownMessage:
"CodeQL attempted to build your project using a script located at " +
$"`{relScriptPath}`, which failed. " +
$"Set up a [manual build command]({buildCommandDocsUrl})."
);
AddDiagnostic(message);
}
// project files which don't exist get marked as not .NET core projects, but we don't want
// to show an error for this if the files don't exist
var foundNotDotNetProjects = autoBuildRule.DotNetRule.NotDotNetProjects.Where(
proj => this.Actions.FileExists(proj.FullPath)
);
// both dotnet and msbuild builds require project or solution files; if we haven't found any
// then neither of those rules would've worked
if (this.ProjectsOrSolutionsToBuild.Count == 0)
{
this.AddDiagnostic(new(
this.Options.Language,
"no-projects-or-solutions",
"No project or solutions files found",
markdownMessage:
"CodeQL could not find any project or solution files in your repository. " +
$"Set up a [manual build command]({buildCommandDocsUrl})."
));
}
// show a warning if there are projects which are not compatible with .NET Core, in case that is unintentional
else if (foundNotDotNetProjects.Any())
{
this.AddDiagnostic(new(
this.Options.Language,
"dotnet-incompatible-projects",
"Some projects are incompatible with .NET Core",
severity: DiagnosticMessage.TspSeverity.Warning,
markdownMessage: $"""
CodeQL found some projects which cannot be built with .NET Core:
{autoBuildRule.DotNetRule.NotDotNetProjects.Select(p => this.MakeRelative(p.FullPath)).ToMarkdownList(MarkdownUtil.CodeFormatter, 5)}
"""
));
}
// report any projects that failed to build with .NET Core
if (autoBuildRule.DotNetRule.FailedProjectsOrSolutions.Any())
{
this.AddDiagnostic(new(
this.Options.Language,
"dotnet-build-failure",
"Some projects or solutions failed to build using .NET Core",
markdownMessage: $"""
CodeQL was unable to build the following projects using .NET Core:
{autoBuildRule.DotNetRule.FailedProjectsOrSolutions.Select(p => this.MakeRelative(p.FullPath)).ToMarkdownList(MarkdownUtil.CodeFormatter, 10)}
Set up a [manual build command]({buildCommandDocsUrl}).
"""
));
}
// report any projects that failed to build with MSBuild
if (autoBuildRule.MsBuildRule.FailedProjectsOrSolutions.Any())
{
this.AddDiagnostic(new(
this.Options.Language,
"msbuild-build-failure",
"Some projects or solutions failed to build using MSBuild",
markdownMessage: $"""
CodeQL was unable to build the following projects using MSBuild:
{autoBuildRule.MsBuildRule.FailedProjectsOrSolutions.Select(p => this.MakeRelative(p.FullPath)).ToMarkdownList(MarkdownUtil.CodeFormatter, 10)}
Set up a [manual build command]({buildCommandDocsUrl}).
"""
));
}
}
/// <summary>
/// Gets the build strategy that the autobuilder should apply, based on the
/// options in the `lgtm.yml` file.

View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Semmle.Autobuild.Shared;
using Semmle.Util;
namespace Semmle.Autobuild.CSharp
{
/// <summary>
/// A diagnostic rule which tries to identify missing Xamarin SDKs.
/// </summary>
public class MissingXamarinSdkRule : DiagnosticRule
{
private const string docsUrl = "https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-xamarin-applications";
public class Result : IDiagnosticsResult
{
/// <summary>
/// The name of the SDK that is missing.
/// </summary>
public string SDKName { get; }
public Result(string sdkName)
{
this.SDKName = sdkName;
}
public DiagnosticMessage ToDiagnosticMessage<T>(Autobuilder<T> builder, DiagnosticMessage.TspSeverity? severity = null) where T : AutobuildOptionsShared => new(
builder.Options.Language,
$"missing-xamarin-{this.SDKName.ToLower()}-sdk",
$"Missing Xamarin SDK for {this.SDKName}",
severity: severity ?? DiagnosticMessage.TspSeverity.Error,
markdownMessage: $"[Configure your workflow]({docsUrl}) for this SDK before running CodeQL."
);
}
public MissingXamarinSdkRule() :
base("MSB4019:[^\"]*\"[^\"]*Xamarin\\.(?<sdkName>[^\\.]*)\\.CSharp\\.targets\"")
{
}
public override void Fire(DiagnosticClassifier classifier, Match match)
{
if (!match.Groups.TryGetValue("sdkName", out var sdkName))
throw new ArgumentException("Expected regular expression match to contain sdkName");
var xamarinResults = classifier.Results.OfType<Result>().Where(result =>
result.SDKName.Equals(sdkName.Value)
);
if (!xamarinResults.Any())
classifier.Results.Add(new Result(sdkName.Value));
}
}
public class MissingProjectFileRule : DiagnosticRule
{
private const string runsOnDocsUrl = "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on";
private const string checkoutDocsUrl = "https://github.com/actions/checkout#usage";
public class Result : IDiagnosticsResult
{
/// <summary>
/// A set of missing project files.
/// </summary>
public HashSet<string> MissingProjectFiles { get; }
public Result()
{
this.MissingProjectFiles = new HashSet<string>();
}
public DiagnosticMessage ToDiagnosticMessage<T>(Autobuilder<T> builder, DiagnosticMessage.TspSeverity? severity = null) where T : AutobuildOptionsShared => new(
builder.Options.Language,
"missing-project-files",
"Missing project files",
severity: severity ?? DiagnosticMessage.TspSeverity.Warning,
markdownMessage: $"""
Some project files were not found when CodeQL built your project:
{this.MissingProjectFiles.AsEnumerable().Select(p => builder.MakeRelative(p)).ToMarkdownList(MarkdownUtil.CodeFormatter, 5)}
This may lead to subsequent failures. You can check for common causes for missing project files:
- Ensure that the project is built using the {runsOnDocsUrl.ToMarkdownLink("intended operating system")} and that filenames on case-sensitive platforms are correctly specified.
- If your repository uses Git submodules, ensure that those are {checkoutDocsUrl.ToMarkdownLink("checked out")} before the CodeQL action is run.
- If you auto-generate some project files as part of your build process, ensure that these are generated before the CodeQL action is run.
"""
);
}
public MissingProjectFileRule() :
base("MSB3202: The project file \"(?<projectFile>[^\"]+)\" was not found. \\[(?<location>[^\\]]+)\\]")
{
}
public override void Fire(DiagnosticClassifier classifier, Match match)
{
if (!match.Groups.TryGetValue("projectFile", out var projectFile))
throw new ArgumentException("Expected regular expression match to contain projectFile");
if (!match.Groups.TryGetValue("location", out var location))
throw new ArgumentException("Expected regular expression match to contain location");
var result = classifier.Results.OfType<Result>().FirstOrDefault();
// if we do not yet have a result for this rule, create one and add it to the list
// of results the classifier knows about
if (result is null)
{
result = new Result();
classifier.Results.Add(result);
}
// then add the missing project file
result.MissingProjectFiles.Add(projectFile.Value);
}
}
/// <summary>
/// Implements a <see cref="DiagnosticClassifier" /> which applies C#-specific rules to
/// the build output.
/// </summary>
public class CSharpDiagnosticClassifier : DiagnosticClassifier
{
public CSharpDiagnosticClassifier()
{
// add C#-specific rules to this classifier
this.AddRule(new MissingXamarinSdkRule());
this.AddRule(new MissingProjectFileRule());
}
}
}

View File

@@ -15,6 +15,15 @@ namespace Semmle.Autobuild.CSharp
/// </summary>
internal class DotNetRule : IBuildRule<CSharpAutobuildOptions>
{
public readonly List<IProjectOrSolution> FailedProjectsOrSolutions = new();
/// <summary>
/// A list of projects which are incompatible with DotNet.
/// </summary>
public IEnumerable<Project<CSharpAutobuildOptions>> NotDotNetProjects { get; private set; }
public DotNetRule() => NotDotNetProjects = new List<Project<CSharpAutobuildOptions>>();
public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool auto)
{
if (!builder.ProjectsOrSolutionsToBuild.Any())
@@ -22,10 +31,12 @@ namespace Semmle.Autobuild.CSharp
if (auto)
{
var notDotNetProject = builder.ProjectsOrSolutionsToBuild
NotDotNetProjects = builder.ProjectsOrSolutionsToBuild
.SelectMany(p => Enumerators.Singleton(p).Concat(p.IncludedProjects))
.OfType<Project<CSharpAutobuildOptions>>()
.FirstOrDefault(p => !p.DotNetProject);
.Where(p => !p.DotNetProject);
var notDotNetProject = NotDotNetProjects.FirstOrDefault();
if (notDotNetProject is not null)
{
builder.Log(Severity.Info, "Not using .NET Core because of incompatible project {0}", notDotNetProject);
@@ -50,7 +61,10 @@ namespace Semmle.Autobuild.CSharp
var build = GetBuildScript(builder, dotNetPath, environment, projectOrSolution.FullPath);
ret &= BuildScript.Try(clean) & BuildScript.Try(restore) & build;
ret &= BuildScript.Try(clean) & BuildScript.Try(restore) & BuildScript.OnFailure(build, ret =>
{
FailedProjectsOrSolutions.Add(projectOrSolution);
});
}
return ret;
});

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{

View File

@@ -1,3 +1,4 @@
using Semmle.Util;
using Semmle.Util.Logging;
using System;
using System.Collections.Generic;
@@ -189,10 +190,11 @@ namespace Semmle.Autobuild.Shared
/// solution file and tools.
/// </summary>
/// <param name="options">The command line options.</param>
protected Autobuilder(IBuildActions actions, TAutobuildOptions options)
protected Autobuilder(IBuildActions actions, TAutobuildOptions options, DiagnosticClassifier diagnosticClassifier)
{
Actions = actions;
Options = options;
DiagnosticClassifier = diagnosticClassifier;
pathsLazy = new Lazy<IEnumerable<(string, int)>>(() =>
{
@@ -232,24 +234,53 @@ namespace Semmle.Autobuild.Shared
return ret ?? new List<IProjectOrSolution>();
});
CodeQLExtractorLangRoot = Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_ROOT");
CodeQlPlatform = Actions.GetEnvironmentVariable("CODEQL_PLATFORM");
CodeQLExtractorLangRoot = Actions.GetEnvironmentVariable(EnvVars.Root(this.Options.Language));
CodeQlPlatform = Actions.GetEnvironmentVariable(EnvVars.Platform);
TrapDir =
Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR") ??
throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR has not been set.");
TrapDir = RequireEnvironmentVariable(EnvVars.TrapDir(this.Options.Language));
SourceArchiveDir = RequireEnvironmentVariable(EnvVars.SourceArchiveDir(this.Options.Language));
DiagnosticsDir = RequireEnvironmentVariable(EnvVars.DiagnosticDir(this.Options.Language));
SourceArchiveDir =
Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR") ??
throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR has not been set.");
this.diagnostics = actions.CreateDiagnosticsWriter(Path.Combine(DiagnosticsDir, $"autobuilder-{DateTime.UtcNow:yyyyMMddHHmm}.jsonc"));
}
protected string TrapDir { get; }
/// <summary>
/// Retrieves the value of an environment variable named <paramref name="name"> or throws
/// an exception if no such environment variable has been set.
/// </summary>
/// <param name="name">The name of the environment variable.</param>
/// <returns>The value of the environment variable.</returns>
/// <exception cref="InvalidEnvironmentException">
/// Thrown if the environment variable is not set.
/// </exception>
protected string RequireEnvironmentVariable(string name)
{
return Actions.GetEnvironmentVariable(name) ??
throw new InvalidEnvironmentException($"The environment variable {name} has not been set.");
}
protected string SourceArchiveDir { get; }
public string TrapDir { get; }
public string SourceArchiveDir { get; }
public string DiagnosticsDir { get; }
protected DiagnosticClassifier DiagnosticClassifier { get; }
private readonly ILogger logger = new ConsoleLogger(Verbosity.Info);
private readonly IDiagnosticsWriter diagnostics;
/// <summary>
/// Makes <see cref="path" /> relative to the root source directory.
/// </summary>
/// <param name="path">The path which to make relative.</param>
/// <returns>The relative path.</returns>
public string MakeRelative(string path)
{
return Path.GetRelativePath(this.RootDirectory, path);
}
/// <summary>
/// Log a given build event to the console.
/// </summary>
@@ -260,6 +291,15 @@ namespace Semmle.Autobuild.Shared
logger.Log(severity, format, args);
}
/// <summary>
/// Write <paramref name="diagnostic"/> to the diagnostics file.
/// </summary>
/// <param name="diagnostic">The diagnostics entry to write.</param>
public void AddDiagnostic(DiagnosticMessage diagnostic)
{
diagnostics.AddEntry(diagnostic);
}
/// <summary>
/// Attempt to build this project.
/// </summary>
@@ -283,7 +323,19 @@ namespace Semmle.Autobuild.Shared
Log(silent ? Severity.Debug : Severity.Info, $"Exit code {ret}{(string.IsNullOrEmpty(msg) ? "" : $": {msg}")}");
}
return script.Run(Actions, startCallback, exitCallback);
var onOutput = BuildOutputHandler(Console.Out);
var onError = BuildOutputHandler(Console.Error);
var buildResult = script.Run(Actions, startCallback, exitCallback, onOutput, onError);
// if the build succeeded, all diagnostics we captured from the build output should be warnings;
// otherwise they should all be errors
var diagSeverity = buildResult == 0 ? DiagnosticMessage.TspSeverity.Warning : DiagnosticMessage.TspSeverity.Error;
this.DiagnosticClassifier.Results
.Select(result => result.ToDiagnosticMessage(this, diagSeverity))
.ForEach(AddDiagnostic);
return buildResult;
}
/// <summary>
@@ -291,13 +343,58 @@ namespace Semmle.Autobuild.Shared
/// </summary>
public abstract BuildScript GetBuildScript();
/// <summary>
/// Produces a diagnostic for the tool status page that we were unable to automatically
/// build the user's project and that they can manually specify a build command. This
/// can be overriden to implement more specific messages depending on the origin of
/// the failure.
/// </summary>
protected virtual void AutobuildFailureDiagnostic() => AddDiagnostic(new DiagnosticMessage(
this.Options.Language,
"autobuild-failure",
"Unable to build project",
visibility: new DiagnosticMessage.TspVisibility(statusPage: true),
plaintextMessage: """
We were unable to automatically build your project.
Set up a manual build command.
"""
));
/// <summary>
/// Returns a build script that can be run upon autobuild failure.
/// </summary>
/// <returns>
/// A build script that reports that we could not automatically detect a suitable build method.
/// </returns>
protected BuildScript AutobuildFailure() =>
BuildScript.Create(actions =>
{
Log(Severity.Error, "Could not auto-detect a suitable build method");
AutobuildFailureDiagnostic();
return 1;
});
/// <summary>
/// Constructs a <see cref="BuildOutputHandler" /> which uses the <see cref="DiagnosticClassifier" />
/// to classify build output. All data also gets written to <paramref name="writer" />.
/// </summary>
/// <param name="writer">
/// The <see cref="TextWriter" /> to which the build output would have normally been written to.
/// This is normally <see cref="Console.Out" /> or <see cref="Console.Error" />.
/// </param>
/// <returns>The constructed <see cref="BuildOutputHandler" />.</returns>
protected BuildOutputHandler BuildOutputHandler(TextWriter writer) => new(data =>
{
if (data is not null)
{
writer.WriteLine(data);
DiagnosticClassifier.ClassifyLine(data);
}
});
/// <summary>
/// Value of CODEQL_EXTRACTOR_<LANG>_ROOT environment variable.
/// </summary>

View File

@@ -7,14 +7,30 @@ using System.Xml;
using System.Net.Http;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace Semmle.Autobuild.Shared
{
public delegate void BuildOutputHandler(string? data);
/// <summary>
/// Wrapper around system calls so that the build scripts can be unit-tested.
/// </summary>
public interface IBuildActions
{
/// <summary>
/// Runs a process, captures its output, and provides it asynchronously.
/// </summary>
/// <param name="exe">The exe to run.</param>
/// <param name="args">The other command line arguments.</param>
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
/// <param name="env">Additional environment variables.</param>
/// <param name="onOutput">A handler for stdout output.</param>
/// <param name="onError">A handler for stderr output.</param>
/// <returns>The process exit code.</returns>
int RunProcess(string exe, string args, string? workingDirectory, IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError);
/// <summary>
/// Runs a process and captures its output.
/// </summary>
@@ -98,6 +114,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>
@@ -139,6 +167,17 @@ namespace Semmle.Autobuild.Shared
/// Downloads the resource with the specified URI to a local file.
/// </summary>
void DownloadFile(string address, string fileName);
/// <summary>
/// Creates an <see cref="IDiagnosticsWriter" /> for the given <paramref name="filename" />.
/// </summary>
/// <param name="filename">
/// The path suggesting where the diagnostics should be written to.
/// </param>
/// <returns>
/// A <see cref="IDiagnosticsWriter" /> to which diagnostic entries can be added.
/// </returns>
IDiagnosticsWriter CreateDiagnosticsWriter(string filename);
}
/// <summary>
@@ -169,6 +208,26 @@ namespace Semmle.Autobuild.Shared
return pi;
}
int IBuildActions.RunProcess(string exe, string args, string? workingDirectory, System.Collections.Generic.IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
var pi = GetProcessStartInfo(exe, args, workingDirectory, env, true);
using var p = new Process
{
StartInfo = pi
};
p.StartInfo.RedirectStandardError = true;
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) => onOutput(e.Data));
p.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => onError(e.Data));
p.Start();
p.BeginErrorReadLine();
p.BeginOutputReadLine();
p.WaitForExit();
return p.ExitCode;
}
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? environment)
{
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, false);
@@ -203,6 +262,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);
@@ -234,6 +299,8 @@ namespace Semmle.Autobuild.Shared
public void DownloadFile(string address, string fileName) =>
DownloadFileAsync(address, fileName).Wait();
public IDiagnosticsWriter CreateDiagnosticsWriter(string filename) => new DiagnosticsStream(filename);
public static IBuildActions Instance { get; } = new SystemBuildActions();
}
}

View File

@@ -11,22 +11,42 @@ namespace Semmle.Autobuild.Shared
{
private readonly WithDotNet<AutobuildOptionsShared> withDotNet;
/// <summary>
/// A list of paths to files in the project directory which we classified as scripts.
/// </summary>
public IEnumerable<string> CandidatePaths { get; private set; }
/// <summary>
/// The path of the script we decided to run, if any.
/// </summary>
public string? ScriptPath { get; private set; }
public BuildCommandAutoRule(WithDotNet<AutobuildOptionsShared> withDotNet)
{
this.withDotNet = withDotNet;
this.CandidatePaths = new List<string>();
}
/// <summary>
/// A list of extensions that we consider to be for scripts on Windows.
/// </summary>
private readonly IEnumerable<string> winExtensions = new List<string> {
".bat",
".cmd",
".exe"
};
/// <summary>
/// A list of extensions that we consider to be for scripts on Linux.
/// </summary>
private readonly IEnumerable<string> linuxExtensions = new List<string> {
"",
".sh"
};
/// <summary>
/// A list of filenames without extensions that we think might be build scripts.
/// </summary>
private readonly IEnumerable<string> buildScripts = new List<string> {
"build"
};
@@ -35,18 +55,25 @@ namespace Semmle.Autobuild.Shared
{
builder.Log(Severity.Info, "Attempting to locate build script");
// a list of extensions for files that we consider to be scripts on the current platform
var extensions = builder.Actions.IsWindows() ? winExtensions : linuxExtensions;
// a list of combined base script names with the current platform's script extensions
// e.g. for Linux: build, build.sh
var scripts = buildScripts.SelectMany(s => extensions.Select(e => s + e));
var scriptPath = builder.Paths.Where(p => scripts.Any(p.Item1.ToLower().EndsWith)).OrderBy(p => p.Item2).Select(p => p.Item1).FirstOrDefault();
// search through the files in the project directory for paths which end in one of
// the names given by `scripts`, then order them by their distance from the root
this.CandidatePaths = builder.Paths.Where(p => scripts.Any(p.Item1.ToLower().EndsWith)).OrderBy(p => p.Item2).Select(p => p.Item1);
// pick the first matching path, if there is one
this.ScriptPath = this.CandidatePaths.FirstOrDefault();
if (scriptPath is null)
if (this.ScriptPath is null)
return BuildScript.Failure;
var chmod = new CommandBuilder(builder.Actions);
chmod.RunCommand("/bin/chmod", $"u+x {scriptPath}");
chmod.RunCommand("/bin/chmod", $"u+x {this.ScriptPath}");
var chmodScript = builder.Actions.IsWindows() ? BuildScript.Success : BuildScript.Try(chmod.Script);
var dir = builder.Actions.GetDirectoryName(scriptPath);
var dir = builder.Actions.GetDirectoryName(this.ScriptPath);
// A specific .NET Core version may be required
return chmodScript & withDotNet(builder, environment =>
@@ -58,7 +85,7 @@ namespace Semmle.Autobuild.Shared
if (vsTools is not null)
command.CallBatFile(vsTools.Path);
command.RunCommand(scriptPath);
command.RunCommand(this.ScriptPath);
return command.Script;
});
}

View File

@@ -46,6 +46,33 @@ namespace Semmle.Autobuild.Shared
/// <returns>The exit code from this build script.</returns>
public abstract int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, out IList<string> stdout);
/// <summary>
/// Runs this build command.
/// </summary>
/// <param name="actions">
/// The interface used to implement the build actions.
/// </param>
/// <param name="startCallback">
/// A call back that is called every time a new process is started. The
/// argument to the call back is a textual representation of the process.
/// </param>
/// <param name="exitCallBack">
/// A call back that is called every time a new process exits. The first
/// argument to the call back is the exit code, and the second argument is
/// an exit message.
/// </param>
/// <param name="onOutput">
/// A handler for data read from stdout.
/// </param>
/// <param name="onError">
/// A handler for data read from stderr.
/// </param>
/// <returns>The exit code from this build script.</returns>
public abstract int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, BuildOutputHandler onOutput, BuildOutputHandler onError);
/// <summary>
/// A build script which executes an external program or script.
/// </summary>
private class BuildCommand : BuildScript
{
private readonly string exe, arguments;
@@ -110,8 +137,29 @@ namespace Semmle.Autobuild.Shared
return ret;
}
public override int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
startCallback(this.ToString(), silent);
var ret = 1;
var retMessage = "";
try
{
ret = actions.RunProcess(exe, arguments, workingDirectory, environment, onOutput, onError);
}
catch (Exception ex)
when (ex is System.ComponentModel.Win32Exception || ex is FileNotFoundException)
{
retMessage = ex.Message;
}
exitCallBack(ret, retMessage, silent);
return ret;
}
}
/// <summary>
/// A build script which runs a C# function.
/// </summary>
private class ReturnBuildCommand : BuildScript
{
private readonly Func<IBuildActions, int> func;
@@ -127,8 +175,13 @@ namespace Semmle.Autobuild.Shared
stdout = Array.Empty<string>();
return func(actions);
}
public override int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, BuildOutputHandler onOutput, BuildOutputHandler onError) => func(actions);
}
/// <summary>
/// Allows two build scripts to be composed sequentially.
/// </summary>
private class BindBuildScript : BuildScript
{
private readonly BuildScript s1;
@@ -175,6 +228,32 @@ namespace Semmle.Autobuild.Shared
stdout = @out;
return ret2;
}
public override int Run(IBuildActions actions, Action<string, bool> startCallback, Action<int, string, bool> exitCallBack, BuildOutputHandler onOutput, BuildOutputHandler onError)
{
int ret1;
if (s2a is not null)
{
var stdout1 = new List<string>();
var onOutputWrapper = new BuildOutputHandler(data =>
{
if (data is not null)
stdout1.Add(data);
onOutput(data);
});
ret1 = s1.Run(actions, startCallback, exitCallBack, onOutputWrapper, onError);
return s2a(stdout1, ret1).Run(actions, startCallback, exitCallBack, onOutput, onError);
}
if (s2b is not null)
{
ret1 = s1.Run(actions, startCallback, exitCallBack, onOutput, onError);
return s2b(ret1).Run(actions, startCallback, exitCallBack, onOutput, onError);
}
throw new InvalidOperationException("Unexpected error");
}
}
/// <summary>
@@ -260,6 +339,23 @@ namespace Semmle.Autobuild.Shared
/// </summary>
public static BuildScript Try(BuildScript s) => s | Success;
/// <summary>
/// Creates a build script that runs the build script <paramref name="s" />. If
/// running <paramref name="s" /> fails, <paramref name="k" /> is invoked with
/// the exit code.
/// </summary>
/// <param name="s">The build script to run.</param>
/// <param name="k">
/// The callback that is invoked if <paramref name="s" /> failed.
/// </param>
/// <returns>The build script which implements this.</returns>
public static BuildScript OnFailure(BuildScript s, Action<int> k) =>
new BindBuildScript(s, ret => Create(actions =>
{
if (!Succeeded(ret)) k(ret);
return ret;
}));
/// <summary>
/// Creates a build script that deletes the given directory.
/// </summary>

View File

@@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{
/// <summary>
/// Direct results result from the successful application of a <see cref="DiagnosticRule" />,
/// which can later be converted to a corresponding <see cref="DiagnosticMessage" />.
/// </summary>
public interface IDiagnosticsResult
{
/// <summary>
/// Produces a <see cref="DiagnosticMessage" /> corresponding to this result.
/// </summary>
/// <param name="builder">
/// The autobuilder to use for constructing the base <see cref="DiagnosticMessage" />.
/// </param>
/// <param name="severity">
/// An optional severity value which overrides the default severity of the diagnostic.
/// </param>
/// <returns>The <see cref="DiagnosticMessage" /> corresponding to this result.</returns>
DiagnosticMessage ToDiagnosticMessage<T>(Autobuilder<T> builder, DiagnosticMessage.TspSeverity? severity = null) where T : AutobuildOptionsShared;
}
public class DiagnosticRule
{
/// <summary>
/// The pattern against which this rule matches build output.
/// </summary>
public Regex Pattern { get; }
/// <summary>
/// Constructs a diagnostic rule for the given <paramref name="pattern" />.
/// </summary>
/// <param name="pattern"></param>
public DiagnosticRule(Regex pattern)
{
this.Pattern = pattern;
}
/// <summary>
/// Constructs a diagnostic rule for the given regular expression <paramref name="pattern" />.
/// </summary>
/// <param name="pattern"></param>
public DiagnosticRule(string pattern)
{
this.Pattern = new Regex(pattern, RegexOptions.Compiled);
}
/// <summary>
/// Used by a <see cref="DiagnosticClassifier" /> <paramref name="classifier" /> to
/// signal that the rule has matched some build output with <paramref name="match" />.
/// </summary>
/// <param name="classifier">The classifier which is firing the rule.</param>
/// <param name="match">The <see cref="Match" /> that resulted from applying the rule.</param>
public virtual void Fire(DiagnosticClassifier classifier, Match match) { }
}
/// <summary>
/// A <see cref="DiagnosticRule" /> which detects arbitrary build messages from MSBuild, CSC, NETSDK, etc. and
/// reports them, up to a limit, as telemetry-only diagnostics.
/// </summary>
public class BuildMessageRule : DiagnosticRule
{
public class Result : IDiagnosticsResult, IEquatable<Result>
{
/// <summary>
/// A value indicating whether this a warning or an error.
/// </summary>
public string Type { get; }
/// <summary>
/// The source of the message, such as "MSB" or "NETSDK".
/// </summary>
public string Source { get; }
/// <summary>
/// The numeric id of the message.
/// </summary>
public int Code { get; }
/// <summary>
/// The message contents.
/// </summary>
public string Message { get; }
public Result(string type, string source, int code, string message)
{
this.Type = type;
this.Source = source;
this.Code = code;
this.Message = message;
}
public DiagnosticMessage ToDiagnosticMessage<T>(Autobuilder<T> builder, DiagnosticMessage.TspSeverity? severity = null) where T : AutobuildOptionsShared => new(
builder.Options.Language,
$"{this.Source.ToLower()}-{this.Code}",
$"{this.Source.ToUpper()}{this.Code}",
plaintextMessage: this.Message,
severity:
this.Type.Equals("error") ?
DiagnosticMessage.TspSeverity.Error :
DiagnosticMessage.TspSeverity.Warning,
// the messages we capture here are visible in the build log, so there is no need
// to show them other than in telemetry
visibility: new(telemetry: true)
);
public bool Equals(Result? x)
{
return x is not null &&
x.Code == this.Code &&
x.Type == this.Type &&
x.Source == this.Source &&
x.Message == this.Message;
}
public override bool Equals(object? obj)
{
return obj is Result && this.Equals(obj);
}
public override int GetHashCode()
{
return HashCode.Combine(this.Type, this.Source, this.Code, this.Message);
}
}
/// <summary>
/// The maximum number of diagnostics we should emit for this rule.
/// </summary>
private const int maxDiagnostics = 10;
/// <summary>
/// The number of diagnostics this rule has emitted so far.
/// </summary>
private int diagnostics = 0;
public BuildMessageRule() : base("(?<type>error|warning) (?<source>[A-Z]+)(?<code>\\d+): (?<message>.*)") { }
public override void Fire(DiagnosticClassifier classifier, Match match)
{
if (!match.Groups.TryGetValue("type", out var type))
throw new ArgumentException("Expected regular expression match to contain type");
if (!match.Groups.TryGetValue("source", out var source))
throw new ArgumentException("Expected regular expression match to contain source");
if (!match.Groups.TryGetValue("code", out var codeStr))
throw new ArgumentException("Expected regular expression match to contain code");
if (!match.Groups.TryGetValue("message", out var message))
throw new ArgumentException("Expected regular expression match to contain message");
if (!int.TryParse(codeStr.Value, out var code))
throw new ArgumentException("Expected code to be numeric");
// check that we have not yet exceeded our limit for emitting diagnostics
if (this.diagnostics < BuildMessageRule.maxDiagnostics)
{
var result = new Result(type.Value, source.Value, code, message.Value);
// add this result if we don't already have an identical one
if (!classifier.Results.OfType<Result>().Any(d => d.Equals(result)))
{
classifier.Results.Add(result);
this.diagnostics++;
}
}
}
}
public class DiagnosticClassifier
{
private readonly List<DiagnosticRule> rules;
public readonly List<IDiagnosticsResult> Results;
public DiagnosticClassifier()
{
this.rules = new List<DiagnosticRule>();
this.Results = new List<IDiagnosticsResult>();
this.AddRule(new BuildMessageRule());
}
/// <summary>
/// Adds <paramref name="rule" /> to this classifier.
/// </summary>
/// <param name="rule">The rule to add.</param>
protected void AddRule(DiagnosticRule rule)
{
this.rules.Add(rule);
}
/// <summary>
/// Applies all of this classifier's rules to <paramref name="line" /> to see which match.
/// </summary>
/// <param name="line">The line to which the rules should be applied to.</param>
public void ClassifyLine(string line)
{
this.rules.ForEach(rule =>
{
var match = rule.Pattern.Match(line);
if (match.Success)
{
rule.Fire(this, match);
}
});
}
}
}

View File

@@ -0,0 +1,13 @@
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{
public static class EnvVars
{
public const string Platform = "CODEQL_PLATFORM";
public static string Root(Language language) => $"CODEQL_EXTRACTOR_{language.UpperCaseName}_ROOT";
public static string TrapDir(Language language) => $"CODEQL_EXTRACTOR_{language.UpperCaseName}_TRAP_DIR";
public static string SourceArchiveDir(Language language) => $"CODEQL_EXTRACTOR_{language.UpperCaseName}_SOURCE_ARCHIVE_DIR";
public static string DiagnosticDir(Language language) => $"CODEQL_EXTRACTOR_{language.UpperCaseName}_DIAGNOSTIC_DIR";
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Semmle.Autobuild.Shared
{
public static class MarkdownUtil
{
/// <summary>
/// Formats items as markdown inline code.
/// </summary>
/// <returns>A function which formats items as markdown inline code.</returns>
public static readonly Func<string, string> CodeFormatter = item => $"`{item}`";
/// <summary>
/// Formats the string as a markdown link.
/// </summary>
/// <param name="link">The URL for the link.</param>
/// <param name="title">The text that is displayed.</param>
/// <returns>A string containing a markdown-formatted link.</returns>
public static string ToMarkdownLink(this string link, string title) => $"[{title}]({link})";
/// <summary>
/// Renders <see cref="projects" /> as a markdown list of the project paths.
/// </summary>
/// <param name="projects">
/// The list of projects whose paths should be rendered as a markdown list.
/// </param>
/// <param name="limit">The maximum number of items to include in the list.</param>
/// <returns>Returns the markdown list as a string.</returns>
public static string ToMarkdownList(this IEnumerable<IProjectOrSolution> projects, int? limit = null)
{
return projects.ToMarkdownList(p => $"`{p.FullPath}`", limit);
}
/// <summary>
/// Renders <see cref="items" /> as a markdown list.
/// </summary>
/// <typeparam name="T">The item type.</typeparam>
/// <param name="items">The list that should be formatted as a markdown list.</param>
/// <param name="formatter">A function which converts individual items into a string representation.</param>
/// <param name="limit">The maximum number of items to include in the list.</param>
/// <returns>Returns the markdown list as a string.</returns>
public static string ToMarkdownList<T>(this IEnumerable<T> items, Func<T, string> formatter, int? limit = null)
{
var sb = new StringBuilder();
// if there is a limit, take at most that many items from the start of the list
var list = limit is not null ? items.Take(limit.Value) : items;
sb.Append(string.Join('\n', list.Select(item => $"- {formatter(item)}")));
// if there were more items than allowed in the list, add an extra item indicating
// how many more items there were
var length = items.Count();
if (limit is not null && length > limit)
{
sb.Append($"\n- and {length - limit} more. View the CodeQL logs for a full list.");
}
return sb.ToString();
}
}
}

View File

@@ -1,17 +1,39 @@
using Semmle.Util.Logging;
using System.Collections.Generic;
using System.Linq;
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.
/// A list of solutions or projects which failed to build.
/// </summary>
private const string msBuild = "msbuild";
public readonly List<IProjectOrSolution> FailedProjectsOrSolutions = new();
public BuildScript Analyse(IAutobuilder<AutobuildOptionsShared> builder, bool auto)
{
@@ -57,7 +79,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 +117,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";
@@ -110,7 +132,13 @@ namespace Semmle.Autobuild.Shared
command.Argument(builder.Options.MsBuildArguments);
ret &= command.Script;
// append the build script which invokes msbuild to the overall build script `ret`;
// we insert a check that building the current project or solution was successful:
// if it was not successful, we add it to `FailedProjectsOrSolutions`
ret &= BuildScript.OnFailure(command.Script, ret =>
{
FailedProjectsOrSolutions.Add(projectOrSolution);
});
}
return ret;

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{

View File

@@ -10,6 +10,8 @@ namespace Semmle.Extraction.CSharp.Entities
private Conversion(Context cx, IMethodSymbol init)
: base(cx, init) { }
protected override MethodKind ExplicitlyImplementsKind => MethodKind.Conversion;
public static new Conversion Create(Context cx, IMethodSymbol symbol) =>
ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol);

View File

@@ -83,10 +83,12 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
protected virtual MethodKind ExplicitlyImplementsKind => MethodKind.Ordinary;
public void Overrides(TextWriter trapFile)
{
foreach (var explicitInterface in Symbol.ExplicitInterfaceImplementations
.Where(sym => sym.MethodKind == MethodKind.Ordinary)
.Where(sym => sym.MethodKind == ExplicitlyImplementsKind)
.Select(impl => Type.Create(Context, impl.ContainingType)))
{
trapFile.explicitly_implements(this, explicitInterface.TypeRef);

View File

@@ -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)
@@ -76,6 +85,9 @@ namespace Semmle.Extraction.CSharp.Entities
if (nt.IsRecord)
HasModifier(cx, trapFile, key, Modifiers.Record);
if (nt.IsFileLocal)
HasModifier(cx, trapFile, key, Modifiers.File);
if (nt.TypeKind == TypeKind.Struct)
{
if (nt.IsReadOnly)
@@ -88,7 +100,11 @@ namespace Semmle.Extraction.CSharp.Entities
public static void ExtractModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol)
{
HasAccessibility(cx, trapFile, key, symbol.DeclaredAccessibility);
// A file scoped type has declared accessibility `internal` which we shouldn't extract.
// The file modifier is extracted as a source level modifier.
if (symbol.Kind != SymbolKind.NamedType || !((INamedTypeSymbol)symbol).IsFileLocal)
HasAccessibility(cx, trapFile, key, symbol.DeclaredAccessibility);
if (symbol.Kind == SymbolKind.ErrorType)
trapFile.has_modifiers(key, Modifier.Create(cx, Accessibility.Public));
@@ -106,8 +122,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);

View File

@@ -4,6 +4,7 @@ internal static class Modifiers
public const string Async = "async";
public const string Const = "const";
public const string Extern = "extern";
public const string File = "file";
public const string Internal = "internal";
public const string New = "new";
public const string Override = "override";
@@ -13,6 +14,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";

View File

@@ -11,6 +11,8 @@ namespace Semmle.Extraction.CSharp.Entities
protected UserOperator(Context cx, IMethodSymbol init)
: base(cx, init) { }
protected override MethodKind ExplicitlyImplementsKind => MethodKind.UserDefinedOperator;
public override void Populate(TextWriter trapFile)
{
PopulateMethod(trapFile);
@@ -37,6 +39,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
ContainingType.PopulateGenerics();
Overrides(trapFile);
}
public override bool NeedsPopulation => Context.Defines(Symbol) || IsImplicitOperator(out _);

View File

@@ -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
@@ -286,54 +282,60 @@ namespace Semmle.Extraction.CSharp
public static IEnumerable<IFieldSymbol?> GetTupleElementsMaybeNull(this INamedTypeSymbol type) =>
type.TupleElements;
private static void BuildQualifierAndName(INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined)
{
if (named.ContainingType is not null)
{
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
trapFile.Write('.');
}
else if (named.ContainingNamespace is not null)
{
if (cx.ShouldAddAssemblyTrapPrefix && named.ContainingAssembly is not null)
BuildAssembly(named.ContainingAssembly, trapFile);
named.ContainingNamespace.BuildNamespace(cx, trapFile);
}
var name = named.IsFileLocal ? named.MetadataName : named.Name;
trapFile.Write(name);
}
private static void BuildTupleId(INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined)
{
trapFile.Write('(');
trapFile.BuildList(",", named.GetTupleElementsMaybeNull(),
(i, f) =>
{
if (f is null)
{
trapFile.Write($"null({i})");
}
else
{
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
trapFile.Write(":");
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
}
}
);
trapFile.Write(")");
}
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
{
if (!constructUnderlyingTupleType && named.IsTupleType)
{
trapFile.Write('(');
trapFile.BuildList(",", named.GetTupleElementsMaybeNull(),
(i, f) =>
{
if (f is null)
{
trapFile.Write($"null({i})");
}
else
{
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
trapFile.Write(":");
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
}
}
);
trapFile.Write(")");
BuildTupleId(named, cx, trapFile, symbolBeingDefined);
return;
}
void AddContaining()
{
if (named.ContainingType is not null)
{
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
trapFile.Write('.');
}
else if (named.ContainingNamespace is not null)
{
if (cx.ShouldAddAssemblyTrapPrefix && named.ContainingAssembly is not null)
BuildAssembly(named.ContainingAssembly, trapFile);
named.ContainingNamespace.BuildNamespace(cx, trapFile);
}
}
if (named.TypeParameters.IsEmpty)
{
AddContaining();
trapFile.Write(named.Name);
BuildQualifierAndName(named, cx, trapFile, symbolBeingDefined);
}
else if (named.IsReallyUnbound())
{
AddContaining();
trapFile.Write(named.Name);
BuildQualifierAndName(named, cx, trapFile, symbolBeingDefined);
trapFile.Write("`");
trapFile.Write(named.TypeParameters.Length);
}

View File

@@ -1,4 +1,4 @@
namespace Semmle.Autobuild.Shared
namespace Semmle.Util
{
public sealed class Language
{

View File

@@ -15,6 +15,7 @@
<ItemGroup>
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,242 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace Semmle.Util
{
/// <summary>
/// Represents diagnostic messages for the tool status page.
/// </summary>
public class DiagnosticMessage
{
/// <summary>
/// Represents sources of diagnostic messages.
/// </summary>
public class TspSource
{
/// <summary>
/// An identifier under which it makes sense to group this diagnostic message.
/// This is used to build the SARIF reporting descriptor object.
/// </summary>
public string Id { get; }
/// <summary>
/// Display name for the ID. This is used to build the SARIF reporting descriptor object.
/// </summary>
public string Name { get; }
/// <summary>
/// Name of the CodeQL extractor. This is used to identify which tool component the reporting descriptor object should be nested under in SARIF.
/// </summary>
public string? ExtractorName { get; }
public TspSource(string id, string name, string? extractorName = null)
{
Id = id;
Name = name;
ExtractorName = extractorName;
}
}
/// <summary>
/// Enumerates severity levels for diagnostics.
/// </summary>
[JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))]
public enum TspSeverity
{
Note,
Warning,
Error
}
/// <summary>
/// Stores flags indicating where the diagnostic should be displayed.
/// </summary>
public class TspVisibility
{
/// <summary>
/// A read-only instance of <see cref="TspVisibility" /> which indicates that the
/// diagnostic should be used in all supported locations.
/// </summary>
public static readonly TspVisibility All = new(true, true, true);
/// <summary>
/// True if the message should be displayed on the status page (defaults to false).
/// </summary>
public bool? StatusPage { get; }
/// <summary>
/// True if the message should be counted in the diagnostics summary table printed by
/// <c>codeql database analyze</c> (defaults to false).
/// </summary>
public bool? CLISummaryTable { get; }
/// <summary>
/// True if the message should be sent to telemetry (defaults to false).
/// </summary>
public bool? Telemetry { get; }
public TspVisibility(bool? statusPage = null, bool? cliSummaryTable = null, bool? telemetry = null)
{
this.StatusPage = statusPage;
this.CLISummaryTable = cliSummaryTable;
this.Telemetry = telemetry;
}
}
/// <summary>
/// Represents source code locations for diagnostic messages.
/// </summary>
public class TspLocation
{
/// <summary>
/// Path to the affected file if appropriate, relative to the source root.
/// </summary>
public string? File { get; }
/// <summary>
/// The line where the range to which the diagnostic relates to starts.
/// </summary>
public int? StartLine { get; }
/// <summary>
/// The column where the range to which the diagnostic relates to starts.
/// </summary>
public int? StartColumn { get; }
/// <summary>
/// The line where the range to which the diagnostic relates to ends.
/// </summary>
public int? EndLine { get; }
/// <summary>
/// The column where the range to which the diagnostic relates to ends.
/// </summary>
public int? EndColumn { get; }
public TspLocation(string? file = null, int? startLine = null, int? startColumn = null, int? endLine = null, int? endColumn = null)
{
this.File = file;
this.StartLine = startLine;
this.StartColumn = startColumn;
this.EndLine = endLine;
this.EndColumn = endColumn;
}
}
/// <summary>
/// ISO 8601 timestamp.
/// </summary>
public string Timestamp { get; }
/// <summary>
/// The source of the diagnostic message.
/// </summary>
public TspSource Source { get; }
/// <summary>
/// GitHub flavored Markdown formatted message. Should include inline links to any help pages.
/// </summary>
public string? MarkdownMessage { get; }
/// <summary>
/// Plain text message. Used by components where the string processing needed to support
/// Markdown is cumbersome.
/// </summary>
public string? PlaintextMessage { get; }
/// <summary>
/// List of help links intended to supplement <see cref="PlaintextMessage" />.
/// </summary>
public List<string> HelpLinks { get; }
/// <summary>
/// SARIF severity.
/// </summary>
public TspSeverity? Severity { get; }
/// <summary>
/// If true, then this message won't be presented to users.
/// </summary>
public bool Internal { get; }
public TspVisibility Visibility { get; }
public TspLocation Location { get; }
/// <summary>
/// Structured metadata about the diagnostic message.
/// </summary>
public Dictionary<string, object> Attributes { get; }
public DiagnosticMessage(
Language language, string id, string name, string? markdownMessage = null, string? plaintextMessage = null,
TspVisibility? visibility = null, TspLocation? location = null, TspSeverity? severity = TspSeverity.Error,
DateTime? timestamp = null, bool? intrnl = null
)
{
this.Source = new TspSource(
id: $"{language.UpperCaseName.ToLower()}/autobuilder/{id}",
name: name,
extractorName: language.UpperCaseName.ToLower()
);
this.Timestamp = (timestamp ?? DateTime.UtcNow).ToString("o", CultureInfo.InvariantCulture);
this.HelpLinks = new List<string>();
this.Attributes = new Dictionary<string, object>();
this.Severity = severity;
this.Visibility = visibility ?? TspVisibility.All;
this.Location = location ?? new TspLocation();
this.Internal = intrnl ?? false;
this.MarkdownMessage = markdownMessage;
this.PlaintextMessage = plaintextMessage;
}
}
/// <summary>
/// Provides the ability to write diagnostic messages to some output.
/// </summary>
public interface IDiagnosticsWriter
{
/// <summary>
/// Adds <paramref name="message" /> as a new diagnostics entry.
/// </summary>
/// <param name="message">The diagnostics entry to add.</param>
void AddEntry(DiagnosticMessage message);
}
/// <summary>
/// A wrapper around an underlying <see cref="StreamWriter" /> which allows
/// <see cref="DiagnosticMessage" /> objects to be serialized to it.
/// </summary>
public sealed class DiagnosticsStream : IDiagnosticsWriter, IDisposable
{
private readonly JsonSerializer serializer;
private readonly StreamWriter writer;
/// <summary>
/// Initialises a new <see cref="DiagnosticsStream" /> for a file at <paramref name="path" />.
/// </summary>
/// <param name="path">The path to the file that should be created.</param>
public DiagnosticsStream(string path)
{
this.writer = File.CreateText(path);
var contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
serializer = new JsonSerializer
{
ContractResolver = contractResolver,
NullValueHandling = NullValueHandling.Ignore
};
}
/// <summary>
/// Adds <paramref name="message" /> as a new diagnostics entry.
/// </summary>
/// <param name="message">The diagnostics entry to add.</param>
public void AddEntry(DiagnosticMessage message)
{
serializer.Serialize(writer, message);
writer.Flush();
}
/// <summary>
/// Releases all resources used by the <see cref="DiagnosticsStream" /> object.
/// </summary>
public void Dispose()
{
writer.Dispose();
}
}
}

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.4.3
version: 1.4.4-dev
groups:
- csharp
- solorigate

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.4.3
version: 1.4.4-dev
groups:
- csharp
- solorigate

Some files were not shown because too many files have changed in this diff Show More