Compare commits

..

603 Commits

Author SHA1 Message Date
Asger F
7e4fbe2f14 Merge pull request #18326 from asgerf/js/shared-dataflow-bump
JS: Merge 'main' into shared dataflow branch
2025-01-03 11:24:37 +01:00
Asger F
942ba189f7 JS: Minor test output change in nodes/edges
I suspect this is due to some fixes in the DeduplicatePathGraph module
2024-12-19 15:25:49 +01:00
Asger F
f8dc7eb25b JS: Update output from tests that changed on main 2024-12-19 15:25:47 +01:00
Asger F
4a6030c592 JS: Update expected with some absent result sets 2024-12-19 15:25:46 +01:00
Asger F
cd6ebb103e JS: Make test not assume implicit through for maps 2024-12-19 15:25:45 +01:00
Asger F
dc2f39c399 JS: Add model of Map#groupBy 2024-12-19 15:25:43 +01:00
Asger F
de5e6ddeed JS: Update with changes in TaintTracking test 2024-12-19 15:25:42 +01:00
Asger F
c204527c08 JS: Update Array test output (new tests added on main) 2024-12-19 15:25:41 +01:00
Asger F
33e8bd5032 JS: Update testUtilities import 2024-12-19 15:25:39 +01:00
Asger F
3acd4814de Merge branch 'main' into js/shared-dataflow-merge-main 2024-12-19 10:14:38 +01:00
Paolo Tranquilli
b392391138 Merge pull request #18319 from github/redsun82/rust-fetch-ungram
Rust: fetch ungram and rust-analyzer code instead of checking it in
2024-12-19 08:16:09 +01:00
Paolo Tranquilli
c4a7abda0a Bazel: resync 3rd party dependencies and skip buildifier on them 2024-12-18 17:33:39 +01:00
Paolo Tranquilli
d6b8d42936 Bazel: fix 3rdparty update script 2024-12-18 17:20:05 +01:00
Paolo Tranquilli
290a1043b1 Rust: fetch ungram and rust-analyzer code instead of checking it in
* The ungram file is now taken from the rust-analyzer dependencies
  pulled in by bazel
* the grammar parsing code is not published, so it must be taken
  directly from rust-analyzer code. That part should be less prone to be
  updated than the ungram file, so it does not necessarily need to be
  in sync with the rust-analyzer version is used elsewhere.
* both need some patches. The former is patched during build, the latter
  during loading in `MODULE.bazel`.
2024-12-18 16:37:24 +01:00
Arthur Baars
023f48ff1c Merge pull request #18295 from github/aibaars/update-rust-ungram
Rust: update rust-analyzer
2024-12-18 16:01:50 +01:00
Simon Friis Vindum
508c7e6e85 Merge pull request #18314 from paldepind/rust-tuple-ref-patterns
Rust: Add read steps for tuple and reference patterns
2024-12-18 14:13:08 +01:00
Asger F
be939dca29 Merge pull request #14350 from asgerf/shared/deduplicate-path-graph
Shared: Add DataFlow::DeduplicatePathGraph
2024-12-18 14:04:29 +01:00
Tom Hvitved
00688ebd79 Merge pull request #18312 from hvitved/rust/operator-overloading-test
Rust: Add data flow tests for operator overloading
2024-12-18 13:58:39 +01:00
Simon Friis Vindum
09fd27af80 Rust: Add read steps for tuple and reference patterns 2024-12-18 13:22:05 +01:00
Mathias Vorreiter Pedersen
927d359cfa Merge pull request #18310 from MathiasVP/fix-recursion-through-forex-in-sign-analysis
C++: Fix `forex` recursion in sign analysis
2024-12-18 12:19:33 +00:00
Simon Friis Vindum
b5b8af3aa2 Rust: Add data flow tests for borrows 2024-12-18 13:00:38 +01:00
Arthur Baars
a6ec51a951 Rust: update expected output 2024-12-18 13:00:14 +01:00
Arthur Baars
71959f5faa Rust: address clippy warnings 2024-12-18 13:00:13 +01:00
Tom Hvitved
3a63dbcd5d Apply suggestions from code review
Co-authored-by: Simon Friis Vindum <paldepind@github.com>
2024-12-18 12:46:11 +01:00
Mathias Vorreiter Pedersen
4ffe70dd3b C++: Respond to review comments. 2024-12-18 11:26:41 +00:00
Simon Friis Vindum
87b9e6001d Merge pull request #18291 from paldepind/rust-data-flow-models
Rust: Data flow improvements to unlock flow in sqlx test
2024-12-18 11:53:26 +01:00
Michael Nebel
ef2215dd53 Merge pull request #18303 from michaelnebel/refactorlibrarylocations
C#: Move external api declarations to the library pack.
2024-12-18 11:43:35 +01:00
Simon Friis Vindum
049fab4c72 Rust: Remove taint steps 2024-12-18 11:22:56 +01:00
Jeroen Ketema
66b2b5df8d Merge pull request #18308 from jketema/template-parameters
C++: Introduce a new base class for template parameters
2024-12-18 10:38:03 +01:00
Jeroen Ketema
ccd3681f83 C++: Expand QLDoc of TemplateParameterBase 2024-12-18 09:45:51 +01:00
Tom Hvitved
025a67384f Rust: Add data flow tests for operator overloading 2024-12-18 09:26:17 +01:00
Mathias Vorreiter Pedersen
0b2b341283 C++: Work around suboptimal codegen for recursive 'forex'. 2024-12-17 23:58:57 +00:00
Jeroen Ketema
b7d1da8741 C++: Introduce a new base class for template parameters
This will enable us to support non-type template parameters, which we
currently do not support, and error template parameters, which might
become relevant in the `build-mode: none` context.
2024-12-17 20:25:41 +01:00
Mathias Vorreiter Pedersen
dfb34832fd Merge pull request #18307 from MathiasVP/fix-more-join-orders-in-dataflow
C++: Fix two more dataflow-related joins
2024-12-17 18:56:12 +00:00
Mathias Vorreiter Pedersen
2cc6ffbd28 C++: Fix ql-for-ql findings. 2024-12-17 16:55:52 +00:00
Simon Friis Vindum
c1e21974c6 Rust: Address review comments 2024-12-17 17:24:42 +01:00
Mathias Vorreiter Pedersen
5ed0222b1a C++: Sync identical files. 2024-12-17 15:28:04 +00:00
Mathias Vorreiter Pedersen
f351558547 C++: While here, let's avoid materializing 'ensuresEq' and 'ensuresLt' when computing unreachable nodes in dataflow. 2024-12-17 15:27:54 +00:00
Mathias Vorreiter Pedersen
9b6f39c1fe C++: Apply similar join order fixes to the other cases. 2024-12-17 15:26:49 +00:00
Mathias Vorreiter Pedersen
eea7804b62 C++: Join with value number only after joining with 'controls'. 2024-12-17 15:25:16 +00:00
Simon Friis Vindum
d8c301a96b Merge branch 'main' into rust-data-flow-models 2024-12-17 16:09:59 +01:00
Michael Nebel
1ef5b595ae C#: Add change-note. 2024-12-17 15:11:27 +01:00
Michael Nebel
bd9f656be2 C#: Add ql doc to TestLibrary. 2024-12-17 14:40:01 +01:00
Michael Nebel
a91c1dc715 C#: Move external api declarations to the library pack. 2024-12-17 14:39:59 +01:00
Asger F
729efff6a4 Merge pull request #18265 from asgerf/jss/flow-labels2
JS: Migrate all queries to proper flow states and deprecate FlowLabel
2024-12-17 14:37:11 +01:00
Arthur Baars
23e6a825aa Rust: fix QL code 2024-12-17 14:07:48 +01:00
Arthur Baars
029e2604a3 Rust: //rust/codegen 2024-12-17 14:07:44 +01:00
Arthur Baars
c13e173681 Rust: fix codegeneration for AsmOptions 2024-12-17 14:05:53 +01:00
Arthur Baars
93972fcb2e Run: misc/bazel/3rdparty/update_cargo_deps.sh 2024-12-17 14:05:51 +01:00
Arthur Baars
8e7eedc172 Update codegen/grammar 2024-12-17 14:05:50 +01:00
Arthur Baars
3928efe05f Rust: update rust.ungram 2024-12-17 14:05:12 +01:00
Tom Hvitved
8efd870192 Merge pull request #18292 from hvitved/rust/never-skip-lhs
Rust: Never skip assignment LHS in data flow
2024-12-17 13:18:17 +01:00
Tom Hvitved
d8c05b5388 Merge pull request #18290 from hvitved/rust/perf-fixes
Rust: Fix two bad joins
2024-12-17 13:18:05 +01:00
Simon Friis Vindum
ee87d4c948 Merge branch 'main' into rust-data-flow-models 2024-12-17 13:12:32 +01:00
Asger F
e34fbc8bd1 Shared: autoformat 2024-12-17 11:26:56 +01:00
Asger F
8340841d54 Shared: Fix propagation of call bit 2024-12-17 11:16:04 +01:00
Asger F
950ae44d03 Shared: Show test failures 2024-12-17 11:15:57 +01:00
Michael Nebel
132dbd7517 Merge pull request #18285 from github/workflow/coverage/update
Update CSV framework coverage reports
2024-12-17 09:17:33 +01:00
github-actions[bot]
f9d739c173 Add changed framework coverage reports 2024-12-17 00:22:24 +00:00
Jeroen Ketema
fa5cc90167 Merge pull request #18281 from jketema/changenote
C++: Add word missing from change note
2024-12-16 20:23:47 +01:00
Mathias Vorreiter Pedersen
a3ef0b94b9 Merge pull request #18207 from MathiasVP/fix-fp-in-missing-check-scanf-fixing-take-3
C++: Fix some FPs in cpp/missing-check-scanf (third attempt!)
2024-12-16 16:55:44 +00:00
Paolo Tranquilli
d6246707e4 Merge pull request #18294 from github/redsun82/extract-self-param-ref
Rust: extract `isRef` for `SelfParam`
2024-12-16 17:00:47 +01:00
Simon Friis Vindum
402d4e11c4 Rust: Re-add inline expectations query tags 2024-12-16 16:36:30 +01:00
Edward Minnix III
9a80c403a0 Merge pull request #18278 from egregius313/egregius313/csharp/markup-string
C#: Add `html-injection` sinks for Blazor `MarkupString`
2024-12-16 10:21:04 -05:00
Edward Minnix III
360398481b Merge pull request #18280 from egregius313/egregius313/csharp/blazor/runtime-helpers/typecheck
C#: Add summary for `Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelper::TypeCheck<T>`
2024-12-16 10:19:38 -05:00
Asger F
e5ae7e0231 JS: Fix bad join in isOptionallySanitizedEdgeInternal
This was previously called from isBarrier(node, state) but without restricting the state. The call was therefore moved to isBarrier(node), but this caused some optimisation changes resulting in a bad join.
2024-12-16 15:35:54 +01:00
Asger F
947b785d47 JS: Remove reference to deprecated step relation that's empty anyway 2024-12-16 15:35:53 +01:00
Asger F
0b2914ff13 JS: A few more deprecation updates 2024-12-16 15:35:50 +01:00
Asger F
db00dad033 JS: Avoid deprecation warnings in some tests 2024-12-16 15:35:49 +01:00
Asger F
cf6d166d29 JS: Also update tutorial code 2024-12-16 15:35:47 +01:00
Asger F
079294e55f JS: Mass rename to node1,state1,node2,state2 naming convention 2024-12-16 15:35:46 +01:00
Asger F
ac6da6c2b1 JS: Add some missing qldoc 2024-12-16 15:35:44 +01:00
Asger F
d993c888b1 JS: Deprecate the FlowLabel class 2024-12-16 15:35:43 +01:00
Asger F
69b361ae70 JS: Migrate a test to use flow state 2024-12-16 15:35:42 +01:00
Asger F
73af3f3536 JS: Migrate PrototypePollutingFunction 2024-12-16 15:35:40 +01:00
Asger F
ebe596f227 JS: Migrate CorsPermissiveConfiguration 2024-12-16 15:35:39 +01:00
Asger F
d83ddfabaa JS: Migrate an experimental CodeInjection query 2024-12-16 15:35:38 +01:00
Asger F
a398599bfb JS: Rename an experimental query
Having the same name as a standard query is just confusing
2024-12-16 15:35:36 +01:00
Asger F
c951a29e2a JS: Migrate UnvalidatedDynamicMethodCall 2024-12-16 15:35:34 +01:00
Tom Hvitved
ddd05b5d1b Rust: Never skip match scrutinee/patterns in data flow 2024-12-16 15:12:16 +01:00
Tom Hvitved
9f2b436d35 Rust: Never skip assignment LHS in data flow 2024-12-16 15:12:15 +01:00
Paolo Tranquilli
4975e7b739 Merge branch 'main' into redsun82/extract-self-param-ref 2024-12-16 15:06:16 +01:00
Mathias Vorreiter Pedersen
913357b70d C++: Fix incorrect QLDoc. 2024-12-16 14:02:50 +00:00
Mathias Vorreiter Pedersen
5a90b25c45 C++: Remove the released change note and add a new change note. 2024-12-16 14:02:48 +00:00
Mathias Vorreiter Pedersen
5327847744 C++: No need to exclude static and global initializers now that we inline the predicates. 2024-12-16 14:02:46 +00:00
Mathias Vorreiter Pedersen
3bdfdd0573 C++: Change all the 'ensures' and (and most 'compares') predicates to be inlined to prevent explosions. Also remove the caching since this is't necessary now that the main recursion is cached. 2024-12-16 14:02:44 +00:00
Mathias Vorreiter Pedersen
404dd33498 C++: Move the main recursion into to a cached module. 2024-12-16 14:02:42 +00:00
Mathias Vorreiter Pedersen
6f73aa552d C++: Convert IRGuards to use final abstract classes. 2024-12-16 14:02:40 +00:00
Mathias Vorreiter Pedersen
20dfbdc5cc Revert "Merge pull request #18057 from jketema/codeql-cli-2.19.4"
This reverts commit ed922f6519, reversing
changes made to aa4cc72f30.
2024-12-16 14:02:38 +00:00
Jeroen Ketema
da3fcda4fc C++: Address review comments 2024-12-16 14:25:41 +01:00
Paolo Tranquilli
4c4a8d7619 Rust: extract isRef for SelfParam 2024-12-16 14:24:56 +01:00
Asger F
f2968f4e14 Shared: Ensure subpath-induced edges are handled properly
Argument-passing and flow-through edges are present in 'edges' in addition to 'subpaths', but the implementation didn't take this into account.
2024-12-16 13:21:43 +01:00
Simon Friis Vindum
cad4f39aee Rust: Database name capitalization 2024-12-16 13:15:42 +01:00
Asger F
0edb30638a Apply suggestions from code review
Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com>
2024-12-16 13:14:27 +01:00
Simon Friis Vindum
defbbb2a24 Rust: Add additional models for stdlib and sqlx 2024-12-16 11:46:57 +01:00
Simon Friis Vindum
aab3428bc7 Rust: Model address-of and dereference as stores and loads 2024-12-16 11:31:15 +01:00
Simon Friis Vindum
df0375103c Rust: Add data flow tests 2024-12-16 11:09:22 +01:00
Tom Hvitved
aabcc108dd Rust: Fix bad join
```
[2024-12-16 10:10:36] (247s) Tuple counts for DataFlowImpl::RustDataFlow::storeStep/3#98e80e57/3@0618fdm6 after 3m8s:
                      33711       ~0%        {3} r1 = SCAN `DataFlowImpl::VariableCapture::storeStep/3#cb0fdcf6` OUTPUT In.1, In.0 'node1', In.2 'node2'
                      33711       ~6%        {3}    | JOIN WITH DataFlowImpl::TSingletonContentSet#9b15eaba ON FIRST 1 OUTPUT Lhs.1 'node1', Rhs.1 'cs', Lhs.2 'node2'

                      0           ~0%        {3} r2 = JOIN `FlowSummaryImpl::Private::Steps::summaryStoreStep/3#2c853d0d` WITH DataFlowImpl::TFlowSummaryNode#2b28ecb7 ON FIRST 1 OUTPUT Lhs.2, Lhs.1 'cs', Rhs.1 'node1'
                      0           ~0%        {3}    | JOIN WITH DataFlowImpl::TFlowSummaryNode#2b28ecb7 ON FIRST 1 OUTPUT Lhs.2 'node1', Lhs.1 'cs', Rhs.1 'node1'

                      1554        ~0%        {3} r3 = JOIN _DataFlowImpl::TExprNode#83a34c2e__DataFlowImpl::TArrayElement#b9fb9b7b_DataFlowImpl::TSingletonCont__#shared WITH `CfgNodes::ArrayRepeatExprCfgNode.getRepeatOperand/0#dispred#b264e402_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2 'node1'
                      1554        ~0%        {3}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Lhs.2 'node1', Lhs.1 'cs', Rhs.1 'node2'

                      870         ~2%        {3} r4 = SCAN `DataFlowImpl::RustDataFlow::tupleAssignment/3#bf3c8690` OUTPUT In.2, In.0 'node1', In.1
                      870         ~0%        {3}    | JOIN WITH DataFlowImpl::TSingletonContentSet#9b15eaba ON FIRST 1 OUTPUT Lhs.2, Rhs.1 'cs', Lhs.1 'node1'
                      870         ~0%        {3}    | JOIN WITH `DataFlowImpl::Node::PostUpdateNode.getPreUpdateNode/0#dispred#53daedc2_10#join_rhs` ON FIRST 1 OUTPUT Lhs.2 'node1', Lhs.1 'cs', Rhs.1 'node2'

                      40037       ~4%        {3} r5 = JOIN _DataFlowImpl::TExprNode#83a34c2e__DataFlowImpl::TArrayElement#b9fb9b7b_DataFlowImpl::TSingletonCont__#shared WITH `CfgNodes::ArrayExprCfgNode.getAnExpr/0#dispred#9d00a6f1_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2 'node1'
                      36929       ~4%        {3}    | JOIN WITH CfgNodes::ArrayListExprCfgNode#07eee614 ON FIRST 1 OUTPUT Lhs.0, Lhs.1 'cs', Lhs.2 'node1'
                      36929       ~0%        {3}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Lhs.2 'node1', Lhs.1 'cs', Rhs.1 'node2'

                      14          ~0%        {2} r6 = JOIN DataFlowImpl::TTuplePositionContent#f1d90606_10#join_rhs WITH DataFlowImpl::TSingletonContentSet#9b15eaba ON FIRST 1 OUTPUT Lhs.1, Rhs.1 'cs'
                      47949       ~0%        {3}    | JOIN WITH `CfgNodes::TupleExprCfgNode.getField/1#dispred#9f7c9c63_102#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Rhs.2
                      47949       ~0%        {3}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Lhs.2, Lhs.1 'cs', Rhs.1 'node2'
                      47949       ~2%        {3}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Rhs.1 'node2', Lhs.1 'cs', Lhs.2 'node2'

                      59801       ~0%        {3} r7 = JOIN _DataFlowImpl::TSingletonContentSet#9b15eaba_DataFlowImpl::TVariantPositionContent#ca6baca0_201#join__#shared WITH `DataFlowImpl::RustDataFlow::tupleVariantConstruction/2#10613c55_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2
                      45509       ~0%        {3}    | JOIN WITH CfgNodes::CallExprCfgNode#9c2a4686_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2
                      45509       ~2%        {4}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Lhs.0, Lhs.2, Lhs.1 'cs', Rhs.1 'node2'
                      45509       ~0%        {3}    | JOIN WITH `CfgNodes::CallExprBaseCfgNode.getArgument/1#dispred#9ebb27c0` ON FIRST 2 OUTPUT Rhs.2, Lhs.2 'cs', Lhs.3 'node2'
                      45509       ~0%        {3}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Rhs.1 'node2', Lhs.1 'cs', Lhs.2 'node2'

                      75147       ~1%        {3} r8 = JOIN _DataFlowImpl::TSingletonContentSet#9b15eaba_DataFlowImpl::TStructFieldContent#1d6d7b05_201#join_rhs#shared WITH `DataFlowImpl::RustDataFlow::structConstruction/2#a9656db0_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2
                      59186       ~3%        {3}    | JOIN WITH `CfgNodes::RecordExprCfgNode.getRecordExpr/0#dispred#659ad1af_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2

                      5641        ~2%        {3} r9 = JOIN _DataFlowImpl::TSingletonContentSet#9b15eaba_DataFlowImpl::TVariantFieldContent#4e05bcf1_201#join_rh__#shared WITH `DataFlowImpl::RustDataFlow::recordVariantConstruction/2#34b016f6_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2
                      5268        ~0%        {3}    | JOIN WITH `CfgNodes::RecordExprCfgNode.getRecordExpr/0#dispred#659ad1af_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2

                      64454       ~1%        {3} r10 = r8 UNION r9
                      64454       ~0%        {4}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Lhs.0, Lhs.2, Lhs.1 'cs', Rhs.1 'node2'
                      25923       ~0%        {3}    | JOIN WITH `CfgNodes::RecordExprCfgNode.getFieldExpr/1#d72dca6e` ON FIRST 2 OUTPUT Rhs.2, Lhs.2 'cs', Lhs.3 'node2'
                      25923       ~0%        {3}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Rhs.1 'node2', Lhs.1 'cs', Lhs.2 'node2'

                      67759289500 ~251%      {4} r11 = JOIN DataFlowImpl::TSingletonContentSet#9b15eaba WITH DataFlowImpl::TExprNode#83a34c2e CARTESIAN PRODUCT OUTPUT Lhs.0, Lhs.1 'cs', Rhs.0, Rhs.1 'node2'
                      3568000     ~1488%     {3}    | JOIN WITH DataFlowImpl::TArrayElement#b9fb9b7b ON FIRST 1 OUTPUT Lhs.3, Lhs.1 'cs', Lhs.2
                      1223000     ~1291%     {3}    | JOIN WITH `DataFlowImpl::Node::PostUpdateNode.getPreUpdateNode/0#dispred#53daedc2_10#join_rhs` ON FIRST 1 OUTPUT Lhs.2, Lhs.1 'cs', Rhs.1 'node2'
                      11500       ~0%        {3}    | JOIN WITH `CfgNodes::IndexExprCfgNode.getBase/0#dispred#19aba7d8_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2 'node2'
                      1000        ~3%        {3}    | JOIN WITH `CfgNodes::BinaryExprCfgNode.getLhs/0#dispred#bd1c02e7_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2 'node2'
                      500         ~3%        {3}    | JOIN WITH CfgNodes::AssignmentExprCfgNode#a9a5c022 ON FIRST 1 OUTPUT Lhs.0, Lhs.1 'cs', Lhs.2 'node2'
                      0           ~0%        {3}    | JOIN WITH `CfgNodes::BinaryExprCfgNode.getRhs/0#dispred#4a1146e4` ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'cs', Lhs.2 'node2'
                      0           ~0%        {3}    | JOIN WITH DataFlowImpl::TExprNode#83a34c2e ON FIRST 1 OUTPUT Rhs.1 'node2', Lhs.1 'cs', Lhs.2 'node2'

                      192445      ~1%        {3} r12 = r1 UNION r2 UNION r3 UNION r4 UNION r5 UNION r6 UNION r7 UNION r10 UNION r11
                                             return r12
```
2024-12-16 10:20:30 +01:00
Tom Hvitved
2d16b5276d Rust: Fix bad join
```
Evaluated relational algebra for predicate DataFlowImpl::RustDataFlow::pathResolveToVariantCanonicalPath/2#dc73aca0@34414869 with tuple counts:
          422639   ~3%    {3} r1 = JOIN `DataFlowImpl::resolveExtendedCanonicalPath/3#0454a346` WITH Synth::Synth::TPathAstNode#a7913307 ON FIRST 1 OUTPUT Lhs.1, Lhs.0, Lhs.2
        73033499   ~7%    {6}    | JOIN WITH DataFlowImpl::MkVariantCanonicalPath#ab1ecb00 ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Rhs.3, _, Rhs.1, Rhs.2
                          {4}    | REWRITE WITH Tmp.3 := "::", Out.3 := (In.4 ++ Tmp.3 ++ In.5), TEST Out.3 = InOut.1 KEEPING 4
          170993   ~1%    {2}    | SCAN OUTPUT In.0, In.2
                          return r1
```
2024-12-16 10:20:01 +01:00
Ed Minnix
129388c78a Fix change note 2024-12-13 12:48:01 -05:00
Ed Minnix
4ee60138b7 Fix test results 2024-12-13 12:44:57 -05:00
Asger F
820f81fc10 JS: Migrate UnsafeDynamicMethodAccess 2024-12-13 11:32:25 +01:00
Asger F
a9e89ed8e3 JS: Migrate PrototypePollutingAssignment 2024-12-13 11:23:31 +01:00
Asger F
bcc1669f4c JS: Migrate InsecureDownload 2024-12-13 11:10:14 +01:00
Asger F
4e25036cdc JS: Follow naming convention in InsecureModuleFlow module 2024-12-13 11:09:59 +01:00
Asger F
d381ab1260 JS: Migrate IncompleteHtmlAttributeSanitization 2024-12-13 10:55:00 +01:00
Jeroen Ketema
d6964ff755 C++: Add word missing from change note 2024-12-13 10:48:46 +01:00
Asger F
2112ecc44d JS: Migrate HardcodedDataInterpretedAsCode 2024-12-13 10:48:43 +01:00
Asger F
dc3d7a0159 Update ExceptionXssCustomizations.qll 2024-12-13 10:47:04 +01:00
Asger F
42a7208704 JS: Migrate ExceptionXss 2024-12-13 10:29:32 +01:00
Asger F
d9a43dbd85 JS: Migrate UnsafeHtmlConstruction 2024-12-13 10:08:17 +01:00
Asger F
8907252814 JS: Migrate TemplateObjectInjection 2024-12-13 10:08:16 +01:00
Asger F
3573f0b065 JS: Migrate SecondOrderCommandInjection 2024-12-13 10:08:15 +01:00
Asger F
355f7cdd54 JS: Migrate PrototypePollutingMergeCall 2024-12-13 10:08:13 +01:00
Asger F
c38e3a23eb JS: Migrate NoSqlInjection 2024-12-13 10:08:12 +01:00
Asger F
8e8de5cf23 JS: Migrate LoopBoundInjection 2024-12-13 10:08:11 +01:00
Asger F
daddff0dc6 JS: Avoid deprecation warning in XssThroughDom 2024-12-13 10:08:10 +01:00
Asger F
15d999a9dc JS: Migrate DeepObjectResourceExhaustion 2024-12-13 10:08:09 +01:00
Asger F
5f42a715f6 JS: Migrate TaintedObject to a CommonFlowState 2024-12-13 10:08:08 +01:00
Asger F
14ca1c134b JS: Update TaintedUrlSuffix test 2024-12-13 10:08:07 +01:00
Asger F
12289d4c39 JS: Migrate DomBasedXssQuery to FlowState 2024-12-13 10:08:06 +01:00
Asger F
114d4a141a JS: Move FlowState definition into CommonFlowState
Needed for migrating the XSS query
2024-12-13 10:08:05 +01:00
Asger F
3cf14d8506 JS: Migrate ClientSideUrlRedirect to flow state 2024-12-13 10:08:03 +01:00
Asger F
cca980298f JS: Use flow state in barrier and step relations 2024-12-13 10:08:02 +01:00
Asger F
a8fdd759f9 JS: Add FlowState class to TaintedUrlSuffix 2024-12-13 10:08:01 +01:00
Ed Minnix
68e2f27180 Add summary Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers::TypeCheck<T> 2024-12-12 22:10:15 -05:00
Ed Minnix
8e37a5cd55 Fix test case 2024-12-12 22:05:26 -05:00
Ed Minnix
0a967325e7 Change note 2024-12-12 16:22:09 -05:00
Ed Minnix
40ea5f582c MarkupString models 2024-12-12 16:18:29 -05:00
Asger F
a53d294d91 Merge pull request #18203 from asgerf/jss/document-url
JS: Use TaintedUrlSuffix in ClientSideUrlRedirect
2024-12-12 15:47:51 +01:00
Asger F
97b78e752b JS: Added more qldoc 2024-12-12 13:10:52 +01:00
Asger F
f8abc5afee Merge pull request #18204 from asgerf/jss/flow-labels
JS: Migrate away from FlowLabel class in TaintedPath
2024-12-11 13:20:48 +01:00
Asger F
889100a243 Java: update test output with provenance 2024-12-11 13:19:47 +01:00
Asger F
afdbf2c3c6 Java: update test to account for key,val 2024-12-11 13:19:36 +01:00
Asger F
736388809d Java: MethodAccess -> MethodCall 2024-12-11 13:19:25 +01:00
Asger F
f9c0ba3826 Ruby: use DeduplicatePathGraph in CodeInjection query 2024-12-11 11:48:15 +01:00
Asger F
815581dc11 JS: Update to account for key,val pairs on edges 2024-12-11 11:48:13 +01:00
Asger F
5aa1242117 Shared: use a call bit when tracking reachability to/from a discriminator 2024-12-11 11:29:14 +01:00
Asger F
0eb543e0a9 Java: add test for spurious flow from path graph deduplication 2024-12-11 11:29:13 +01:00
Asger F
8efdc2df7b Shared: change note 2024-12-11 11:29:11 +01:00
Asger F
cba7b98f7a Shared: Add DataFlow::DeduplicatePathGraph 2024-12-11 11:29:10 +01:00
Asger F
77f8e8ef4e JS: Use FlowState::fromFlowLabel instead of Label::toFlowState
This works better for other queries where we don't already have a module named Label
2024-12-10 11:57:18 +01:00
Asger F
38c9023dd9 JS: FlowLabel -> FlowState in ZipSlip 2024-12-10 11:16:07 +01:00
Asger F
0cd01cb96f JS: Use node1,state1,node2,state2 naming convention in tainted path 2024-12-10 11:16:05 +01:00
Asger F
0802107d9a JS: Flow label -> flow state in TaintedPath 2024-12-10 11:16:04 +01:00
Asger F
66eb458134 JS: Handle match/matchAll and unknown regexps 2024-12-09 15:38:36 +01:00
Asger F
6e7c5a3707 JS: Slightly more general getRoot() 2024-12-09 15:05:45 +01:00
Asger F
be617cee4a JS: More precise handling of .exec() 2024-12-09 15:03:51 +01:00
Asger F
703cad9e95 Expand test case 2024-12-09 15:00:56 +01:00
Asger F
2a2a4d2b67 JS: Add TaintedUrlSuffixCustomizations
Importing TaintedUrlSuffix.qll causes the flow label to materialised in unrelated queries, so:

- Renames TaintedUrlSuffix.qll to TaintedUrlSuffixCustomizations.qll
- Make the flow label class abstract
- Adds a new TaintedUrlSuffix.qll that re-exports the above file and also materialises the flow label
- Import the *Customizations.qll file from contexts where we don't want to materialise the flow label
2024-12-09 14:59:29 +01:00
Asger F
d1694013ff JS: Update test showing accidental flow label materialisation
This wouldn't be an issue once FlowLabel is completely deprecated but it will cause perf issues in the interim, so this is fixed in the next commit
2024-12-09 14:59:28 +01:00
Asger F
8fe39bdd38 JS: Update query's own output after test changes 2024-12-09 14:59:27 +01:00
Asger F
71a6a47713 JS: Fix issue with new RegExp().exec() 2024-12-09 14:59:25 +01:00
Asger F
f6d0835c64 JS: Show problem with new RegExp().exec() 2024-12-09 14:59:24 +01:00
Asger F
ef833de60e JS: Replace DocumentUrl with TaintedUrlSuffix 2024-12-09 14:59:23 +01:00
Asger F
e2b2d1c9ab JS: Allow arbitrary comments in ConsistencyChecking
Because line comments cannot be used inside JSX elements
2024-12-09 14:59:21 +01:00
Asger F
712c69ebc8 JS: Fixup the test expectations 2024-12-09 14:59:19 +01:00
Asger F
f8ff504f5c JS: Add ClientSideUrlRedirect test consistency
Update Consistency.ql again
2024-12-09 14:59:18 +01:00
Asger F
b8d652c5b2 Merge pull request #18132 from asgerf/jss/deprecation
JS: Deprecations and related refactorings
2024-12-06 13:23:26 +01:00
Asger F
3f0d0e3a05 JS: Deprecate DataFlow::BarrierGuardNode 2024-12-03 14:30:50 +01:00
Asger F
b3461989b1 JS: Remove use of SanitizerGuardNode in experimental SSRF query
Makes a quick effort attempt to restore the original behaviour, though
it is not exactly the same due to lack of recursion.
2024-12-03 14:30:36 +01:00
Asger F
0d79c7141c JS: Update two more uses of SanitizerGuardNode 2024-12-03 14:30:35 +01:00
Asger F
62c17d3f4e JS: Update SanitizerGuardNode use in BasicTaintTracking test 2024-12-03 14:30:34 +01:00
Asger F
f620191da4 JS: Deprecate SanitizerGuardNode 2024-12-03 14:30:33 +01:00
Asger F
2ae7386775 JS: Also apply new BarrierGuardLegacy pattern in Xss.qll 2024-12-03 14:30:32 +01:00
Asger F
2ef652da2c JS: Add more deprecation annotations in tests 2024-12-03 14:30:31 +01:00
Asger F
21494fbdff JS: Refactor BarrierGuardLegacy pattern to not depend on SanitizerGuardNode
Previously our barrier guard classes were direct descendents of SanitizerGuardNode which made it hard to deprecate that class.

Now our barrier guards are not descending from any shared class. Instead they are contributed to SanitizerGuardNode via a private helper class we can remove in the future.
2024-12-03 14:30:29 +01:00
Asger F
a574ff1669 JS: Remove use of MakeLegacyBarrierGuard in experimental SSRF 2024-12-03 14:30:28 +01:00
Asger F
08d25c122d JS: Deprecate more uses of ConsistencyConfiguration 2024-12-03 14:30:27 +01:00
Asger F
75ab4856b8 Remove unsupported features from PoI 2024-12-03 14:30:25 +01:00
Asger F
e6680dec8f JS: Avoid use of LabeledSanitizerGuardNode in TaintedObject
Drive-by bugfix: Rename sanitizes -> blocksExpr.
This fixes a bug that caused the sanitizer guard not to work in df2.

The test output reflects the fact that the barrier guard works now.
2024-12-03 14:30:24 +01:00
Asger F
0ce1fe767d JS: Deprecate ConsistencyChecking to avoid deprecation warnings 2024-12-03 14:30:23 +01:00
Asger F
04a3a6707f JS: Update a reference to AdditionalSanitizerGuardNode
Unlike most other references to this class, we're not subclassing it here, we're
just trying to reuse some standard barrier guards but with a different flow state.
2024-12-03 14:30:22 +01:00
Asger F
834d35bc42 JS: Port experimental DecompressionBombs to ConfigSig 2024-12-03 14:30:21 +01:00
Asger F
871bc3b84a JS: Port experimental CorsPermissiveConfiguration to ConfigSig
The tests show a new (source, sink) pair for an already-flagged sink.

Not sure why it was not flagged originally since the data flow path seems valid, given the steps provided by our models.
2024-12-03 14:30:20 +01:00
Asger F
f5a6485ef2 JS: Port experimental decodeJwtWithoutVerificationLocalSource 2024-12-03 14:30:19 +01:00
Asger F
72e522631d JS: Port experimental jwtDecodeWithoutVerification to ConfigSig 2024-12-03 14:30:18 +01:00
Asger F
7e162f5451 JS: Port experimental EnvValueInjection to ConfigSig 2024-12-03 14:30:17 +01:00
Asger F
4f839070a0 JS: Port experimental EnvValueAndKeyInjection to ConfigSig 2024-12-03 14:30:16 +01:00
Asger F
8887ca1722 JS: Port an experimental CodeInjection variant to ConfigSig 2024-12-03 14:30:15 +01:00
Asger F
1832e93766 JS: Port FormParsers test to ConfigSig 2024-12-03 14:30:14 +01:00
Asger F
4d7401a074 JS: Deprecate tests for deprecated APIs
Mainly adds 'deprecated' in front of a bunch of tests for deprecated APIs.
2024-12-03 14:30:12 +01:00
Asger F
3548544970 JS: Avoid some uses of deprecated guard classes in tests 2024-12-03 14:30:11 +01:00
Asger F
a568d8c086 JS: Port threat-model test to ConfigSig 2024-12-03 14:30:10 +01:00
Asger F
f758b67d30 JS: Openly recommend SummarizedCallable 2024-12-03 14:30:09 +01:00
Asger F
249104b8ae JS: Update comments referring to old Configuration style
Also avoid the term "analysis-specific" because it's not a term we use anywhere else.
2024-12-03 14:30:08 +01:00
Asger F
13ee597848 JS: Add some proper documentation to SummarizedCallable 2024-12-03 14:30:07 +01:00
Asger F
988fa9c0ef JS: Deprecate AdditionalSanitizerGuardNode
We're deprecating the class through an alias, but it is still the base class for a non-deprecated class, for backwards compatibility. For this reason we're also deprecating all of its member predicates so we can remove those in the future.
2024-12-03 14:30:06 +01:00
Asger F
0b1e859e70 JS: Remove uses of AdditionalSanitizerGuardNode 2024-12-03 14:30:05 +01:00
Asger F
c2abb0fbd0 JS: Remove reference to AdditionalSanitizerGuard from CachedStages 2024-12-03 14:30:04 +01:00
Asger F
82682d9a62 JS: Remove a non-deprecated reference to SanitizerGuardNode 2024-12-03 14:30:03 +01:00
Asger F
bc7753de29 JS: Remove non-deprecated reference to AdditionalBarrierGuardNode 2024-12-03 14:30:02 +01:00
Asger F
0cd2e3f9eb JS: Deprecate old data flow library, except some guard-related nodes 2024-12-03 14:30:01 +01:00
Asger F
071189a9e9 Merge pull request #18175 from asgerf/jss/documentation
JS: Update data flow documentation and tutorials for JavaScript
2024-12-03 14:23:29 +01:00
Asger F
e1aff15f29 Merge pull request #18125 from asgerf/jss/summary-type-tracker
JS: Derive type-tracking steps from flow summaries
2024-12-03 12:40:56 +01:00
Asger F
27e61a1f3d JS: Also update cheat sheet 2024-12-03 12:00:30 +01:00
Asger F
89463d73f5 JS: Remove mention of isAdditionalTaintStep 2024-12-03 11:51:46 +01:00
Asger F
935e1c065a Update docs/codeql/codeql-language-guides/using-flow-labels-for-precise-data-flow-analysis.rst
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2024-12-03 11:49:45 +01:00
Asger F
89849fae87 Update docs/codeql/codeql-language-guides/using-flow-labels-for-precise-data-flow-analysis.rst
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2024-12-03 11:49:34 +01:00
Asger F
5e27257405 Update docs/codeql/codeql-language-guides/analyzing-data-flow-in-javascript-and-typescript.rst
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2024-12-03 11:49:22 +01:00
Asger F
054558d7b5 JS: Include content properties in type-tracker properties
Reminder: we have two PropertyName classes because the one in Contents.qll can't depend on DataFlow::Node.
2024-12-03 09:58:54 +01:00
Asger F
8bca66493f JS: Add test showing lack of inclusion in PropertyName 2024-12-03 09:57:02 +01:00
Asger F
404b0f24f2 JS: Fix another stray reference to BarrierGuardNode/SanitizerGuardNode 2024-12-02 13:29:52 +01:00
Asger F
422c089a39 JS: Remove redundant base class in TruthinessCheck 2024-12-02 13:26:37 +01:00
Asger F
628f60d2e3 JS: Update flow label tutorial 2024-12-02 10:34:02 +01:00
Asger F
2db89c1b02 JS: Update query17 from intro tutorial 2024-12-02 10:04:09 +01:00
Asger F
2722c45737 JS: Update global data flow tutorial .rst file 2024-12-02 10:04:08 +01:00
Asger F
103a6ea8a6 JS: Port tutorial query5 2024-12-02 10:04:07 +01:00
Asger F
02c5e49de8 JS: Port tutorial query4 2024-12-02 10:04:05 +01:00
Asger F
1f6335f9ba JS: Port tutorial query3 2024-12-02 10:04:04 +01:00
Asger F
3319870d00 JS: Port tutorial query2 2024-12-02 10:04:02 +01:00
Asger F
32f020ee6f JS: Port tutorial query1 2024-12-02 10:04:00 +01:00
Asger F
cab8a40d00 JS: Fix accidental recursion 2024-11-29 14:23:57 +01:00
Asger F
9c6b6981e2 JS: Add test to restrict dependencies 2024-11-29 14:23:56 +01:00
Asger F
2f0c80a98b JS: Include summary steps in type tracking 2024-11-29 14:23:55 +01:00
Asger F
440cbb7f0a JS: Add inline-expectation test for type tracking 2024-11-29 14:23:54 +01:00
Asger F
6349903110 JS: Move FlowSummary/Summaries.qll into testUtilities 2024-11-29 14:23:52 +01:00
Asger F
e34064e3b5 JS: Initial instantiation of sumamry type tracking
Instantiates the library without using it yet.
2024-11-29 14:23:50 +01:00
Asger F
df12f255ac JS: Rename propagatesFlowExt -> propagatesFlow 2024-11-29 14:23:49 +01:00
Asger F
66d6bda716 Merge pull request #18044 from asgerf/js/shared-dataflow-bump
JS: Merge 'main' and implement 'speculativeTaintStep'
2024-11-27 15:43:27 +01:00
Asger F
805fd0b46e JS: Refine speculative step definition 2024-11-26 15:56:56 +01:00
Asger F
8818fcc207 JS: Benign test output changes 2024-11-26 15:47:13 +01:00
Asger F
c94a01e6b6 JS: Remove reference to argsParseStep
This was removed as part of the PR that introduced threat models.
2024-11-26 15:36:47 +01:00
Asger F
bf62582f53 JS: Implement 'speculativeTaintStep'
It is a mandatory part of the interface now; just providing a bare-bones implementation for rather than 'none()'
2024-11-26 15:36:46 +01:00
Asger F
82d61e4194 Merge branch 'js/shared-dataflow-branch' into js/shared-dataflow-merge-main 2024-11-26 15:36:16 +01:00
Asger F
c2e9dca1de Merge pull request #18043 from asgerf/jss/jump-and-test-exclusion
JS: Fix jump steps generated by IIFEs and exception flow
2024-11-26 14:33:42 +01:00
Asger F
f073f3b791 JS: Rename file to foo.test.js 2024-11-26 13:44:00 +01:00
Asger F
65da9b41b5 JS: Add cross-file test in InsecureRandom 2024-11-26 13:43:24 +01:00
Asger F
b4bd8e701c JS: Add test for file classification change 2024-11-26 12:33:39 +01:00
Asger F
930a7b6e28 JS: Update output changes to nodes/edges/subpaths 2024-11-21 13:33:39 +01:00
Asger F
7a77432024 JS: Update lost result in insecure-download
The VariableCapture library consumes one component of the access path limit, which means we lose this result
2024-11-21 13:33:10 +01:00
Asger F
1ac7591faf JS: Update missed flow in capture-flow.js
We previously caught this flow because of a heuristic in capture flow. We'll have to fix it properly later.
2024-11-21 12:57:34 +01:00
Asger F
9dad2d62d7 JS: Update DataFlowConsistency 2024-11-21 12:54:11 +01:00
Asger F
ce00bd2cc9 JS: More docs 2024-11-21 11:06:43 +01:00
Asger F
4e62a512c5 JS: Only apply exception propagator when no other summary applies
Previously a few Promise-related methods were special-cased, which is no longer needed.
2024-11-21 11:01:05 +01:00
Asger F
84820adf3c Add test for exception flow out of finally() 2024-11-21 11:01:03 +01:00
Asger F
948d21ca07 JS: Propagate exceptions from summarized callables by default 2024-11-21 10:24:31 +01:00
Asger F
dcdb2e5133 JS: Fix callback check so it works without parameters 2024-11-21 10:24:29 +01:00
Asger F
b7dd455aff JS: Add test case 2024-11-21 09:21:36 +01:00
Asger F
d52bc971b8 Merge branch 'main' into js/shared-dataflow-merge-main 2024-11-20 14:05:03 +01:00
Asger F
d1c9e47d23 JS: More aggressive test file classification 2024-11-19 13:23:32 +01:00
Asger F
01669908f2 JS: Block InsecureRandomness flow into test files 2024-11-19 13:23:31 +01:00
Asger F
80a5a5909e JS: Use getUnderlyingValue() a few places in VariableCapture 2024-11-19 13:23:29 +01:00
Asger F
d2daec4c66 JS: Add tests explaining why the IIFE in f2 didn't work 2024-11-19 13:23:24 +01:00
Asger F
023dcce400 JS: Disable variable capture heuristic
Bailing out can be more expensive as the resulting jump steps themselves
cause perf issues. The limit of 100 variables per scope has also been
added in the interim, which handles the cases that this needed to cover.
2024-11-18 13:44:10 +01:00
Asger F
37676f41aa JS: Remove jump steps from IIFE steps 2024-11-18 13:38:34 +01:00
Asger F
7f2eae0966 JS: Add test case for false flow through IIFEs
We generate local flow steps into and out of IIFEs, but these come jump steps automatically, resulting in FPs.
2024-11-18 13:34:35 +01:00
Asger F
7acc5689cf JS: Port exception steps to a universal summary 2024-11-18 13:27:58 +01:00
Asger F
5ed362f7d6 JS: Add exception test case 2024-11-18 13:23:09 +01:00
Asger F
33b7ba41ca Merge pull request #17535 from asgerf/jss/use-use-flow
JS: Follow use-use flow after a post-update
2024-11-18 12:48:58 +01:00
Asger F
80ee372ddf JS: Replace an unused value with _ 2024-11-12 11:24:17 +01:00
Asger F
637baabe37 JS: Clarify why there are no SSA definitions 2024-11-12 11:23:35 +01:00
Asger F
2fb108419c JS: Only parameter-calls as lambda calls 2024-10-29 08:32:15 +01:00
Asger F
1e9e57e46e JS: Fix missing qldoc 2024-10-29 08:32:14 +01:00
Asger F
52ba91a7f8 JS: Updates to nodes/edges in tests
Only changes to nodes/edges for various reasons, no actual result changes
2024-10-29 08:32:13 +01:00
Asger F
1243188825 JS: Update CleartextLogging with fixed FP 2024-10-29 08:32:11 +01:00
Asger F
18b39460f5 JS: Add regained results in UnsafeJQueryPlugin
These were marked as 'NOT OK' in the test file, but weren't previously flagged for some reason
2024-10-29 08:32:10 +01:00
Asger F
d3e70c1e97 JS: Add in-barrier to XSS query
This is a bit of a bandaid to cover issues with the push() method on next/router being
treated as an array push, which causes it to flow into other taint sources.
2024-10-29 08:32:08 +01:00
Asger F
1b85feb1fa JS: Add imprecise post-update steps for when a captured var/this is not tracked precisely
With the capture library we sometimes bails out of handling certain functions for scalability reasons.

This means we have a notion of "captured but imprecisely-tracked" variables and 'this'. In these cases we go back to propagating flow from a post-update node to the local source.
2024-10-29 08:32:07 +01:00
Asger F
d557c7689c JS: Update a test that now has more precise output 2024-10-29 08:32:06 +01:00
Asger F
1efef2ca3c JS: Change rule for getPostUpdateForStore
This causes less wobbles in test outputs
2024-10-29 08:32:05 +01:00
Asger F
ad52b71922 JS: Update immutable.js test to clarify why it stopped working
The Immutable model uses the 'd' and 'f' properties to model Map content, but the test doesn't actually mention those properties, so they were missing from the PropertyName class.

The flow was previously found spuriously by the regular Map model, which also adds flow through the  get/set calls. This flow is however no longer found since it relied on a step from post-update back to getALocalSource which is no longer present.
2024-10-29 08:32:03 +01:00
Asger F
c0997c28cb JS: Reveal issue with immutable.js test
Fixed in the next commit
2024-10-29 08:32:02 +01:00
Asger F
4473e6d977 JS: Update test with some post-update consistency checks gone
For a constructor call, the return value acts as the post-update node for the 'this' argument. The fact that constructor calls are sometimes PostUpdateNodes causes some of these harmless alerts.

The warnings have disappeared in some cases because we no longer target getALocalSource() so the target is no longer the constructor call.
2024-10-29 08:32:01 +01:00
Asger F
cb874945bf Test updates from introduction of implicit 'this' 2024-10-29 08:31:59 +01:00
Asger F
bd94fe1574 JS: Explain false positive in test case 2024-10-29 08:31:58 +01:00
Asger F
e05e077b33 JS: Block jump steps through 'this' now that the capture lib handles 'this' 2024-10-29 08:31:57 +01:00
Asger F
16b08b74eb JS: Add test showing potential for FPs when handling refinement guards 2024-10-29 08:31:55 +01:00
Asger F
958602e43e JS: Cache getARead (as per instructions in the SSA library) 2024-10-22 12:46:20 +02:00
Asger F
e784813c3b JS: Make barrier guards work with use-use flow 2024-10-22 12:46:19 +02:00
Asger F
67fdd864c9 JS: Add TODO 2024-10-22 12:46:18 +02:00
Asger F
81af9a1658 Fix missing flow through super calls 2024-10-22 12:46:17 +02:00
Asger F
12370e9210 JS: Use VariableOrThis in variable capture as well 2024-10-22 12:46:16 +02:00
Asger F
0ebe8bdd91 JS: Add test for missing capture flow for 'this' 2024-10-22 12:46:15 +02:00
Asger F
d31499d727 JS: introduce implicit this uses in general 2024-10-22 12:46:14 +02:00
Asger F
8dc0505f84 JS: Add test for missing flow into 'this' in field initializers 2024-10-22 12:46:13 +02:00
Asger F
c3c003b275 JS: Fix post-update flow into 'this' 2024-10-22 12:46:11 +02:00
Asger F
9fc99d6f9d JS: Fix store into object literals that have a post-update node 2024-10-22 12:46:11 +02:00
Asger F
d626e79ed3 JS: Add two test cases for missing flow 2024-10-22 12:46:10 +02:00
Asger F
992c144559 JS: Add qldoc to file 2024-10-22 12:46:09 +02:00
Asger F
beaacf96b3 JS: Rename Internal -> Cached since whole file is internal now 2024-10-22 12:46:08 +02:00
Asger F
3fca27bee2 JS: Fix indentation
Only formatting changes
2024-10-22 12:46:07 +02:00
Asger F
ed0af958a9 JS: Add Public module and only expose that
Indentation will be fixed in next commit
2024-10-22 12:46:06 +02:00
Asger F
3b663bd2f6 JS: Remove BasicBlockInternal module and mark relevant predicates as public
This exposes the predicates publicly, but will be hidden again in the next commit.
2024-10-22 12:46:04 +02:00
Asger F
211b42d0ce JS: Move BasicBlocks.qll -> internal/BasicBlocksInternal.qll 2024-10-22 12:46:03 +02:00
Asger F
9e600424cc JS: Remove unused predicate 2024-10-22 12:46:02 +02:00
Asger F
78e961cef3 JS: Add use-use flow 2024-10-22 12:46:01 +02:00
Asger F
81e74d8bb5 JS: Add test case for spurious flow from lack of use-use 2024-10-22 12:46:00 +02:00
Asger F
7363b578b1 JS: Instantiate shared SSA library
JS: Remove with statement comment
2024-10-22 12:45:58 +02:00
Asger F
a258489551 JS: Refactor some internal methods to make them easier to alias
We need these to return the dominator instead of declaring it in the parameter list, so that we can use it directly to fulfill part of the signature for the SSA library.

We can't rewrite it with an inline predicate since the SSA module calls with a transitive closure '*', which does not permit inline predicates.
2024-10-22 12:45:57 +02:00
Asger F
443987b484 Merge branch 'main' into js/shared-dataflow-merge-main 2024-10-22 10:30:53 +02:00
Asger F
12e316b99d JS: Update test output after merging in 'main'
- Paths are now relative to the test case, not the qlpack
- Paths going through an implicit reads have changed slightly
2024-10-08 10:11:15 +02:00
Asger F
e2e91ac7d9 Merge branch 'main' into js/shared-dataflow-merge-main 2024-10-08 09:28:26 +02:00
Asger F
72daa980a0 Merge pull request #17643 from asgerf/jss/cached-barriers
JS: Fix bug causing re-evaluation of cached barriers
2024-10-03 12:59:53 +02:00
Asger F
5d2ce172eb JS: Update a test to handle AdditionalSanitizerGuardNode 2024-10-02 14:44:42 +02:00
Asger F
6cbe04dcb7 JS: Consistently use the shared XSS barrier guards in the XSS queries
Previously only reflected XSS used shared barrier guards.
2024-10-02 14:44:17 +02:00
Asger F
341bacfe55 JS: Fix bug causing re-evaluation of cached barriers 2024-10-02 14:43:18 +02:00
Asger F
1cd00a118c Merge branch 'main' into js/shared-dataflow-merge-main 2024-09-18 14:57:50 +02:00
Asger F
5e4c0906d8 Merge pull request #17412 from asgerf/jss/array-index-constant
JS: Fix handling of constant array index reads, and fix the fallout
2024-09-18 12:28:44 +02:00
Asger F
7ba6995854 JS: Clarify a comment 2024-09-17 15:59:04 +02:00
Asger F
1df69ec1d2 JS: Actually don't propagate into array element 0
Preserving tainted-url-suffix into array element 0 seemed like a good idea, but didn't work out so well.
2024-09-12 13:42:36 +02:00
Asger F
0e4e0f4fdd JS: Preverse tainted-url-suffix when stepping into prefix
A URL of form https://example.com?evil#bar will contain '?evil' after splitting out the '#' suffix, and vice versa.
2024-09-12 13:42:28 +02:00
Asger F
74ab346348 JS: Do not include taint steps in TaintedUrlSuffix::step
TaintedUrlSuffix is currently only used in TaintTracking configs meaning it is already propagated
by taint steps. The inclusion of these taint steps here however meant that implicit reads could appear prior to any of these steps.

This was is problematic for PropRead steps as an expression like x[0] could spuriously read from array element 1 via the path:

x [element 1]
x [empty access path] (after implicit read)
x[0] (taint step through PropRead)
2024-09-12 13:42:25 +02:00
Asger F
2712bf821a JS: Fix a bug in isSafeClientSideUrlProperty 2024-09-12 13:42:23 +02:00
Asger F
bc04131c72 JS: Disallow implicit reads before an optional step 2024-09-12 13:42:22 +02:00
Asger F
e1bed42481 JS: Add inline expectation test specifically for TaintedUrlSuffix 2024-09-12 13:42:20 +02:00
Asger F
cf90c83604 JS: Accept changes to nodes/edges results 2024-09-12 13:42:19 +02:00
Asger F
3b09bc548e JS: Add taint step for shift() 2024-09-12 13:42:17 +02:00
Asger F
3ea1134cc1 JS: Add inline test for .shift() method 2024-09-12 13:42:16 +02:00
Asger F
3fcf4ef7a1 JS: More precise model of .shift()
Array.prototype.shift only returns the first array element.

The mutation of Argument[this] is not yet modelled, and is better handled when we have use-use flow.
2024-09-12 13:42:15 +02:00
Asger F
e4f7560bcd JS: Add missing qldoc 2024-09-12 13:42:14 +02:00
Asger F
15fc450a9e JS: Add reminder to update ClientSideUrlRedirect 2024-09-12 13:42:13 +02:00
Asger F
da696817a3 JS: Convert 'split' taint step to legacy taint step 2024-09-12 13:42:05 +02:00
Asger F
133b016c7c JS: Remove old 'split' handling from TaintedUrlSuffix 2024-09-12 13:41:56 +02:00
Asger F
e87e543850 JS: Ensure optional steps/barriers are computed in the correct stage 2024-09-12 13:35:38 +02:00
Asger F
7790f68fe2 JS: Make the TaintedUrlSuffix library use optional steps/barriers 2024-09-12 13:35:36 +02:00
Asger F
3b34cd72f2 JS: Handle split() with '#' or '?' separator in a separate summary
This summary uses the notion of optional steps/barriers so it becomes configurable whether there is flow into the zero'th array element.

Also makes sure we handle the second-argument version of split().
2024-09-12 13:35:33 +02:00
Asger F
24983a5836 JS: Add OptionalStep and OptionalBarrier MaD tokens
OptionalStep[foo] and OptionalBarrier[foo] contribute steps/barriers that are not active by default, but can be opted into by specific queries or for specific flow states.

(Will be used in the following commits)
2024-09-12 13:30:39 +02:00
Asger F
87454a4f11 JS: Remove unused predicate 2024-09-10 14:44:49 +02:00
Asger F
0ddb1c87f5 JS: Test update indicating a problem with .split() 2024-09-10 13:14:37 +02:00
Asger F
e0ca1b0482 JS: Benign test updates 2024-09-10 13:07:24 +02:00
Asger F
3d4287b7cc JS: Remove ContentSet#asArrayIndex()
For ContentSet it is ambiguous whether asArrayIndex() should get a singleton content set, or the KnownArrayElement content set. The user will now have to choose between asSingleton().asArrayIndex() or ContentSet::arrayElementKnown.
2024-09-09 13:28:32 +02:00
Asger F
013d226ae3 JS: Update comment 2024-09-09 13:26:27 +02:00
Asger F
55d4e7e742 JS: Use ArrayElementKnown when reading a constant array index 2024-09-09 13:26:25 +02:00
Asger F
094112c905 Merge pull request #17213 from asgerf/jss/spread-argument
JS: Improve handling of spread arguments and rest parameters [shared data flow branch]
2024-09-09 13:15:22 +02:00
Asger F
fb9732a33f JS: Add another test and TODO about an issue with constant array indices 2024-09-06 08:43:11 +02:00
Asger F
1da68aac73 JS: Benign test output change
This happened as a result of the bugfix in the previous commit
2024-09-06 08:43:10 +02:00
Asger F
a9a8351cce JS: Fix one case of missing handling of unknown array index 2024-09-06 08:43:09 +02:00
Asger F
379c7ef20a JS: Add test to show lack of unknown array element being propagated 2024-09-06 08:43:08 +02:00
Asger F
92bb4b3da8 JS: Address some comments from hvitved 2024-09-05 11:32:07 +02:00
Asger F
4568967a76 JS: Do not use legacy taint steps in TaintedUrlSuffix
Tainted URL suffix steps are added as configuration-specific additional
steps, which means implicit reads may occur before any of these steps.

These steps accidentally included the legacy taint steps which include
a step from 'arguments' to all positional parameters. Combined with the
implicit read, arguments could escape their array index and flow to
any parameter while in the tainted-url flow state.
2024-08-29 13:48:30 +02:00
Asger F
65a36b0b3b JS: Add regression test for argument position confusion 2024-08-29 13:42:28 +02:00
Asger F
f65879eef1 JS: Update a test that no longer fails 2024-08-27 11:35:37 +02:00
Asger F
cb5dbb919d JS: Update test to reflect implicit read flow has been fixed
Shows the effect of https://github.com/github/codeql/pull/17262
2024-08-27 11:35:36 +02:00
Asger F
a2d53c261b JS: Update test output and add related TODO in model of 'async' 2024-08-27 11:35:35 +02:00
Asger F
837a8be1b8 JS: Update test output and add related TODO in 'markdown-table' model 2024-08-27 11:35:34 +02:00
Asger F
2e2181be2c JS: Update test output that only affects nodes/edges/subpaths 2024-08-27 11:35:33 +02:00
Asger F
3e196f83f1 JS: Update Promises/flow2 test 2024-08-27 11:35:32 +02:00
Asger F
aa8bd332bf JS: Add a few more tests 2024-08-27 11:35:31 +02:00
Asger F
371f7ef551 JS: Add implicit taint read of array elements 2024-08-27 11:35:31 +02:00
Asger F
df42e7c527 JS: Add test showing lack of implicit reads for ArrayElement 2024-08-27 11:35:30 +02:00
Asger F
4e7bd9ddd8 JS: Update Arrays test now that array elements do not taint the whole array 2024-08-27 11:35:29 +02:00
Asger F
4389b5c999 JS: Fix issue for .apply() calls 2024-08-27 11:35:28 +02:00
Asger F
34e6864fa3 JS: Note issue with .apply() calls 2024-08-27 11:35:27 +02:00
Asger F
ac1dd1850e JS: Remove taint step from array element to whole array 2024-08-27 11:35:26 +02:00
Asger F
5084d0260f Update tests.expected
The 'arguments' node is only materialised for functions that use 'arguments
2024-08-27 11:35:25 +02:00
Asger F
895cb872ad JS: Add taint into dynamic argument array 2024-08-27 11:35:24 +02:00
Asger F
079a622cf9 JS: Add tests showing missing taint flow
When the spread argument itself is tained and not
inside any content, the read steps currently fail
to propagate the data.
2024-08-27 11:35:23 +02:00
Asger F
6a083136d7 JS: Hide some nodes 2024-08-27 11:35:22 +02:00
Asger F
acdc896c04 JS: Support for dynamic args to flow summaries 2024-08-27 11:35:21 +02:00
Asger F
53a2a66dd0 Add new nodes to early stage 2024-08-27 11:35:20 +02:00
Asger F
5c7e623c47 JS: Add some tests for missing handling of dynamic args in flow summaries 2024-08-27 11:35:19 +02:00
Asger F
c04f0beb8a Update DataFlowConsistency.expected 2024-08-27 11:35:18 +02:00
Asger F
60c3d077b2 Update DataFlowImplConsistency.qll 2024-08-27 11:35:17 +02:00
Asger F
bbb1c8c374 Remove old arguments-array position 2024-08-27 11:35:16 +02:00
Asger F
ed33a6e91b JS: Add explicit model of .join() 2024-08-27 11:35:15 +02:00
Asger F
fa7ad03068 JS: Add store/load steps for the new argument arrays 2024-08-27 11:35:15 +02:00
Asger F
623dbda77d Do not pass regular positional args into the rest parameter 2024-08-27 11:35:14 +02:00
Asger F
a72f79576a JS: Add corresponding argument positions 2024-08-27 11:35:13 +02:00
Asger F
6c7d745a2b JS: Add nodes for static/dynamic argument/parameter arrays 2024-08-27 11:35:12 +02:00
Asger F
5d77c336fc Test case for spread and rest args/params 2024-08-27 11:35:11 +02:00
Asger F
4cdaccd22e JS: Add InlineFlowTest 2024-08-27 11:35:10 +02:00
Asger F
2adaf0f935 Merge pull request #17261 from asgerf/jss/dynamic-import-step
JS: Port step for dynamic imports
2024-08-27 08:27:16 +02:00
Asger F
47c519fc0a JS: Add test for flow through dynamic imports 2024-08-26 15:15:49 +02:00
Asger F
4b8ae2a4f3 Merge branch 'main' into js/shared-dataflow-merge-main 2024-08-26 12:43:16 +02:00
Asger F
7cfe3dae85 JS: Port step for dynamic imports 2024-08-23 10:07:28 +02:00
Asger F
379952febc Merge pull request #17285 from asgerf/js/shared-dataflow-bump
JS: Resolve conflicts after merging 'main' into shared data flow branch
2024-08-23 09:58:27 +02:00
Asger F
a2dd47aeb2 JS: Update test output
These files conflicted and have been regenerated.
2024-08-22 14:27:15 +02:00
Asger F
423fd04545 JS: Update new xsjs-specific code to respect TEarlyStageNode 2024-08-22 13:22:35 +02:00
Asger F
c54f5858b1 Merge branch 'main' into js/shared-dataflow-merge-main 2024-08-22 13:22:05 +02:00
Asger F
c66000d2fa Merge pull request #17136 from asgerf/js/shared-dataflow-bump
JS: Merge 'main' into shared dataflow branch
2024-08-06 14:14:47 +02:00
Asger F
2d814428d6 JS: Update expected output with provenance 2024-08-06 12:45:08 +02:00
Asger F
0a143a5f52 JS: Do not include type in path explanation 2024-08-06 12:45:07 +02:00
Asger F
1a532dac29 JS: Update VariableCapture instantiation after merge 2024-08-06 12:45:06 +02:00
Asger F
c8bbad6c4d Merge branch 'main' into js/shared-dataflow-merge-main 2024-08-06 12:43:13 +02:00
Asger F
df64388d79 Merge branch 'main' into js/shared-dataflow-merge-main 2024-08-02 13:18:38 +02:00
Asger F
5c222f7b05 Merge pull request #14412 from asgerf/js/shared-dataflow
[Feature branch] JS: Migrate to shared dataflow library
2024-08-02 12:48:01 +02:00
Asger F
1d267efb6b JS: Fix missing qldoc 2024-06-28 14:30:56 +02:00
Asger F
e5924c1f84 JS: Another messy test update 2024-06-28 13:08:38 +02:00
Asger F
14fc790617 Update DataFlowConsistency.expected 2024-06-28 13:08:09 +02:00
Asger F
1c730bc66e JS: Fix compilation error in DataFlowImplConsistency.qll 2024-06-27 12:47:15 +02:00
Asger F
c3806a2210 JS: Messy test output updates
These initially got messed up by a merge conflict where I couldn't rerun the tests due to breaking
changes in the data flow library. I wanted the breaking-change updates to live in their own commits,
not just eaten by a merge resolution commit, so the test output became broken for a while.

The '#select' result set is unchanged in all of these, so they should be safe to accept.
2024-06-27 11:59:56 +02:00
Asger F
90f0e07e49 JS: Benign update after fixing PropertyName charpred 2024-06-27 11:56:22 +02:00
Asger F
ee10702e73 JS: Another provanance test output update 2024-06-27 11:56:01 +02:00
Asger F
df0488a470 Ensure Member tokens from flow summaries are seen in PropertyName 2024-06-27 10:22:14 +02:00
Asger F
c52a4b0621 JS: Provide RenderSummarizedCallable 2024-06-27 09:44:45 +02:00
Asger F
e53c0cdce7 Fix unknown Parameter/Argument decoding 2024-06-27 09:39:06 +02:00
Asger F
2473274681 JS: Benign test output changes 2024-06-27 09:06:45 +02:00
Asger F
af7b4e3063 Accept flow difference due to added test cases
New library gets FN for spread arguments in a call to splice(), which
was added to the old version in this PR:
  https://github.com/github/codeql/pull/16739
2024-06-26 13:52:27 +02:00
Asger F
53efb5837b JS: Update some tests with provenance columns
Only includes the changes that purely contain the new provenance columns
2024-06-26 13:51:44 +02:00
Asger F
88edc06517 Avoid bad join in compatibleTypesCached
This is identical to the code in Ruby and seems to prevent a bad join ordering
in a cached version of this predicate in DataFlowCommon
2024-06-26 13:51:41 +02:00
Asger F
fc7c2c5b17 Remove unused code 2024-06-26 13:51:40 +02:00
Asger F
e67e89dd70 Implement decodeUnknownArgument/ParameterPosition 2024-06-26 13:51:39 +02:00
Asger F
3bebd709b3 Handle AnyMemberDeep and ArrayElementDeep in encodeContent 2024-06-26 13:51:38 +02:00
Asger F
6c0c67dce4 Implement encodeWith/WithoutContent 2024-06-26 13:51:37 +02:00
Asger F
b0ea81276b Implement encodeReturn 2024-06-26 13:51:36 +02:00
Asger F
5811a3c5a6 Port getMadStringFromContentSet -> encodeContent 2024-06-26 13:51:35 +02:00
Asger F
8c4e5e8876 Boilerplate implementation of default predicates from FlowSummaryImpl.qll 2024-06-26 13:51:34 +02:00
Asger F
6b35a766a6 Migrate to shared FlowSummary library 2024-06-25 14:43:29 +02:00
Asger F
dd7aff555d Instantiate shared FlowSummary library 2024-06-25 13:35:49 +02:00
Asger F
f0d7c3a7f0 Remove bindingsets 2024-06-25 13:33:06 +02:00
Asger F
6e32f27652 Rename predicates to be consistent with qlpack
In preparation for migrating to the FlowSummary module in the qlpack,
rename predicates to be consistent with the qlpack.
2024-06-25 13:30:33 +02:00
Asger F
6c8fb61f60 Js: Update FlowSummaryImpl.qll to make things compile 2024-06-25 13:10:24 +02:00
Asger F
64a9598b89 JS: Update interface for isUnreachableInCall 2024-06-25 13:01:23 +02:00
Asger F
505c532af7 JS: Implement totalorder() 2024-06-25 12:58:35 +02:00
Asger F
102ca77acf Switch to getLocation() in DataFlowCall 2024-06-25 11:49:19 +02:00
Asger F
ecf418b8f6 Merge branch 'main' into js/shared-dataflow 2024-06-25 11:48:41 +02:00
Asger F
bd3fccd1a8 JS: Update test output with provenance column 2024-06-25 10:30:56 +02:00
Asger F
20df5adbaa JS: Bugfix in DeduplicatePathGraph
This was introduced after a quick fix to handle the addition of
provenance.
2024-06-25 10:30:14 +02:00
Asger F
f43a189f06 JS: Make CaptureNode.toString() more explicit 2024-06-25 09:56:39 +02:00
Asger F
536c115c1c JS: Fix location override in CaptureNode 2024-05-06 13:51:25 +02:00
Asger F
23d28fc098 Shared: add location for 'this' nodes 2024-05-06 13:50:40 +02:00
Asger F
5a2260b481 JS: Update to match changes to API 2024-05-06 10:13:25 +02:00
Asger F
19f14622f3 JS: Update use of Locations 2024-05-06 10:13:24 +02:00
Asger F
2de9af2236 JS: Update to getLocation() in DeduplicatePathGraph 2024-05-06 10:13:07 +02:00
Asger F
c408ab9e6a Merge branch 'main' into js/shared-dataflow 2024-05-02 19:43:34 +02:00
Asger F
711a08b0d4 JS: Add TODO about switching to the shared library 2024-03-15 09:26:19 +01:00
Asger F
eff5f3b7d6 JS: Remove duplicate dependency from qlpack.yml 2024-03-13 20:43:44 +01:00
Asger F
ddf6eb3a04 JS: Quick fix to make DeduplicatePathGraph compile
There's an open PR for this where a real fix should be written
2024-03-13 15:24:53 +01:00
Asger F
8ecdb5cefe Update VariableCapture.qll 2024-03-13 15:24:20 +01:00
Asger F
82abd867a0 JS: Update uses of AccessPathSyntax
This doesn't yet migrate to the FlowSummaryImpl.qll in a qlpack, just trying to make things compile first
2024-03-13 15:17:58 +01:00
Asger F
e5bc8db2f0 JS: Fix conflicting default for visbleImplInCallContext 2024-03-13 15:17:08 +01:00
Asger F
bb1f729a3f Update VariableCapture.qll 2024-03-13 15:16:37 +01:00
Asger F
97567f412e JS: Update VariableCapture.qll after changes to API 2024-03-13 14:53:00 +01:00
Asger F
5e7d1d5c2c Merge branch 'main' into js/shared-dataflow-merged 2024-03-13 14:27:16 +01:00
Asger F
fa8933eb41 JS: Reduce duplication in UnsafeDynamicMethodAccessQuery 2024-03-13 12:30:05 +01:00
Asger F
ea4bc9cdbb JS: Comment about manually applying taint steps 2024-03-13 12:30:05 +01:00
Asger F
406b080ce3 JS: Add comment about allowImplicitRead in PostMessageStar 2024-03-13 11:30:52 +01:00
Asger F
0a2050bc42 JS: Deduplicate predicate in HostHeaderPoisoningQuery 2024-03-13 11:27:18 +01:00
Asger F
11983faccf JS: Remove out-commented code 2024-03-13 11:26:56 +01:00
Asger F
b31f20a64e JS: Explain why ObjetWrapperFlowLabel is deprecated 2024-03-13 11:08:25 +01:00
Asger F
e0aae53ac7 JS: Remove unnecessary BarrierGuardLegacy class 2024-03-13 11:05:23 +01:00
Asger F
fce2be0af3 JS: Use BarrierGuardLegacy in TaintedPath 2024-03-13 11:02:09 +01:00
Asger F
e640154048 JS: Be backwards compatible with AdditionalBarrierGuardNode
I've confirmed that the 'legacyBarrier' predicate does not occur in the DIL
2024-03-13 10:54:02 +01:00
Asger F
14e75be510 JS: Expand comments and synthetic node name in ForOfLoops 2024-03-13 09:27:00 +01:00
Asger F
e66f27cfe3 JS: Move hasWildcardReplaceRegExp to a shared place 2024-03-13 09:19:26 +01:00
Asger F
4043bc13ab JS: Explicit mark comment as a TODO 2024-03-13 09:19:03 +01:00
Asger F
858c79e395 JS: Add plain taint step through Promise.all() 2024-03-13 08:57:42 +01:00
Asger F
13a8e0fbf0 JS: Add failing test for Promise.all() 2024-03-13 08:54:06 +01:00
Asger F
2c1aa08f79 JS: Rename Strings2 -> Strings 2024-03-12 21:18:14 +01:00
Asger F
478dd25f3e JS: Rename Sets2 -> Sets 2024-03-12 21:17:29 +01:00
Asger F
433489478d JS: Rename Promise2 -> Promise 2024-03-12 21:16:43 +01:00
Asger F
e2f3565227 JS: Rename Maps2 -> Maps 2024-03-12 21:14:29 +01:00
Asger F
b3fad7a8dc JS: Rename Iterators2 -> Iterators 2024-03-12 15:12:07 +01:00
Asger F
5aafd33cec JS: Rename Arrays2 -> Arrays 2024-03-12 15:11:29 +01:00
Asger F
76e0445af0 JS: Be consistent about caching in PreCallGraphStep 2024-03-12 15:08:59 +01:00
Asger F
28fc8ba0c1 JS: Remove EmptyType 2024-03-12 14:59:04 +01:00
Asger F
f94aa2ceec Update javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll 2024-03-12 14:41:11 +01:00
Asger F
a02ab2ad88 JS: Port heuristic versions of standard queries 2023-10-13 13:15:08 +02:00
Asger F
3c7c5377ec JS: Add content approximation
This seems to fix a performance issue for RegExpInjection in angular
2023-10-13 13:15:08 +02:00
Asger F
5775fe6d6e JS: Use TAnyType in FlowSummaryPrivate 2023-10-13 13:15:08 +02:00
Asger F
9faf300dd0 JS: Use type-pruning to restrict callback flow 2023-10-13 13:15:08 +02:00
Asger F
e738b5d125 JS: Expand callback test case
Type-based pruning is confused by the different tests being interleaved, so we additionally want to have a test that is independent from the other parts of this test.
2023-10-13 13:15:08 +02:00
Asger F
d3f5169e66 JS: Lower field-flow branch limit on Polynomial ReDoS 2023-10-13 13:15:08 +02:00
Asger F
51dec79401 JS: Lower access path limit to 2 2023-10-13 13:15:08 +02:00
Asger F
24bab27ffe JS: Add TODO for dynamic import step 2023-10-13 13:15:08 +02:00
Asger F
7c5eb89491 JS: Add tests for captured 'this' (genuine FN) 2023-10-13 13:15:08 +02:00
Asger F
98c79e7674 JS: Update test output showing lack of global flow (geniune FN) 2023-10-13 13:15:08 +02:00
Asger F
9b46c4596c JS: Update HeuristicSoruceCodeInjection test 2023-10-13 13:15:08 +02:00
Asger F
bab639f23c JS: Update ReflectedXssWithCustomSanitizer test 2023-10-13 13:15:08 +02:00
Asger F
85e8998067 JS: Update ImportEquals test 2023-10-13 13:15:08 +02:00
Asger F
2eff07f476 JS: Update TaintTracking test 2023-10-13 13:15:08 +02:00
Asger F
b5ad36686e JS: Block flow into window.location 2023-10-13 13:15:08 +02:00
Asger F
75c915b2a3 JS: Update Spife test 2023-10-13 13:15:07 +02:00
Asger F
c2f66c0f93 JS: Update Restify2 test 2023-10-13 13:15:07 +02:00
Asger F
b304fb4337 JS: Reorder result sets in ReactJS test output 2023-10-13 13:15:07 +02:00
Asger F
32eddd3c07 JS: Update ReactJS test output 2023-10-13 13:15:07 +02:00
Asger F
b8a0afbb9f JS: Make overriding ConsistencyChecking.getATestFile() optional 2023-10-13 13:15:07 +02:00
Asger F
6c9f4a10ac JS: Port TaintBarriers test 2023-10-13 13:15:07 +02:00
Asger F
e5946bf43b JS: Port HeuristicSource test 2023-10-13 13:15:07 +02:00
Asger F
771519bbc5 JS: Port Routing test 2023-10-13 13:15:07 +02:00
Asger F
2364bd84e0 JS: Fix whitespace in a test (trivial change) 2023-10-13 13:15:07 +02:00
Asger F
98d1bb3826 JS: Reorder result sets in a test (trivial change) 2023-10-13 13:15:07 +02:00
Asger F
81bd292a16 JS: Port Promises test
Result changes are benign
2023-10-13 13:15:07 +02:00
Asger F
dd8a24c6c0 JS: Port LabelledBarrierGuards test 2023-10-13 13:15:07 +02:00
Asger F
458f0a077c JS: Port InterProceduralFlow test
All the new results are benign
2023-10-13 13:15:07 +02:00
Asger F
0d10aba67d Revert "JS: Add global post-update steps"
This resulted in huge performance issues from too much global flow
2023-10-13 13:15:07 +02:00
Asger F
50aace3fa3 JS: Add global post-update steps 2023-10-13 13:15:07 +02:00
Asger F
9372f7993d JS: Update Generators test
Data flow difference is benign
2023-10-13 13:15:07 +02:00
Asger F
995df41532 JS: Update Vuex test 2023-10-13 13:15:07 +02:00
Asger F
3983530983 JS: Update Templating/Xss test 2023-10-13 13:15:07 +02:00
Asger F
b9344134d3 JS: Update Redux test 2023-10-13 13:15:07 +02:00
Asger F
d2053445a7 JS: Update frameworks/PropertyProjection test 2023-10-13 13:15:07 +02:00
Asger F
2eec47b52c JS: Update frameworks/Next test 2023-10-13 13:15:07 +02:00
Asger F
644f9683b1 JS: Update frameworks/immutable test 2023-10-13 13:15:07 +02:00
Asger F
a2d4a03c0e JS: Update framework/data test 2023-10-13 13:15:06 +02:00
Asger F
6600fe9d51 JS: Port ComposedFunctions test 2023-10-13 13:15:06 +02:00
Asger F
09892279e6 JS: Port Collections test 2023-10-13 13:15:06 +02:00
Asger F
466ffdf8f5 JS: Port AsyncTaintTracking test 2023-10-13 13:15:06 +02:00
Asger F
09b0ba0c1f JS: Port Angular2 test 2023-10-13 13:15:06 +02:00
Asger F
92812eee78 JS: Add test for flow summaries 2023-10-13 13:15:06 +02:00
Asger F
af05789cbf JS: Remove noise from data flow test 2023-10-13 13:15:06 +02:00
Asger F
c652470e2f JS: Do not port CustomLoadStoreStep test 2023-10-13 13:15:06 +02:00
Asger F
1a95961bac JS: Port Classes test 2023-10-13 13:15:06 +02:00
Asger F
9a15a557b4 JS: Port SimpleBarrierGuard test 2023-10-13 13:15:06 +02:00
Asger F
ff086377cb JS: Port Arrays test 2023-10-13 13:15:06 +02:00
Asger F
d35959a098 JS: Add utility for comparing results in tests 2023-10-13 13:15:06 +02:00
Asger F
43be45207d JS: Port meta queries 2023-10-13 13:15:06 +02:00
Asger F
c55300d4b0 JS: Port PolynomialReDoS 2023-10-13 13:15:06 +02:00
Asger F
b8847dbc5d JS: Port Xxe 2023-10-13 13:15:06 +02:00
Asger F
c2d170b4fd JS: Port XpathInjection 2023-10-13 13:15:06 +02:00
Asger F
03f8c0fc5e JS: Port XmlBomb 2023-10-13 13:15:06 +02:00
Asger F
83095535f9 JS: Port UnvalidatedDynamicMethodCall 2023-10-13 13:15:06 +02:00
Asger F
ba9edb4e54 JS: Port UnsafeShellCommandConstruction 2023-10-13 13:15:06 +02:00
Asger F
d08e4504ff JS: Port UnsafeJQueryPlugin 2023-10-13 13:15:06 +02:00
Asger F
6e3f4bd7d8 JS: Port UnsafeHtmlConstruction 2023-10-13 13:15:06 +02:00
Asger F
7f4d42ddcd JS: Port UnsafeDynamicMethodAccess 2023-10-13 13:15:06 +02:00
Asger F
758f42495c JS: Port UnsafeDeserialization 2023-10-13 13:15:05 +02:00
Asger F
32022ccbda JS: Port UnsafeCodeConstruction 2023-10-13 13:15:05 +02:00
Asger F
5af608c937 JS: Port TypeConfusionThroughParameterTampering 2023-10-13 13:15:05 +02:00
Asger F
25962a9ba6 JS: Port TemplateObjectInjection 2023-10-13 13:15:05 +02:00
Asger F
51624c02a2 JS: Port TaintedFormatString 2023-10-13 13:15:05 +02:00
Asger F
63343b1ba4 JS: Port StackTraceExposure 2023-10-13 13:15:05 +02:00
Asger F
d446444667 JS: Port ShellCommandInjectionFromEnvironment 2023-10-13 13:15:05 +02:00
Asger F
06835a800c JS: Port SecondOrderCommandInjection 2023-10-13 13:15:05 +02:00
Asger F
4af7694309 JS: Port ResourceExhaustion 2023-10-13 13:15:05 +02:00
Asger F
b9bd0520e2 JS: Port RemotePropertyInjection 2023-10-13 13:15:05 +02:00
Asger F
dcc73a7f90 JS: Port RegExpInjection 2023-10-13 13:15:05 +02:00
Asger F
2400af4bc3 JS: Port PostMessageStar 2023-10-13 13:15:05 +02:00
Asger F
e1fae3d16d JS: Port InsufficientPasswordHash 2023-10-13 13:15:05 +02:00
Asger F
fd98b2546d JS: Port InsecureTemporaryFile 2023-10-13 13:15:05 +02:00
Asger F
cd1a1e25ae JS: Port InsecureRandomness 2023-10-13 13:15:05 +02:00
Asger F
99f63b1cfa JS: Port InsecureDownload 2023-10-13 13:15:05 +02:00
Asger F
8c001916b6 JS: Port IndirectCommandInjection 2023-10-13 13:15:05 +02:00
Asger F
e3ab5bdd16 JS: Port IncompleteHtmlAttributeSanitization 2023-10-13 13:15:05 +02:00
Asger F
9128722627 JS: Port ImproperCodeSanitization 2023-10-13 13:15:05 +02:00
Asger F
8715c1b324 JS: Port HostHeaderPoisoningInEmailGeneration 2023-10-13 13:15:05 +02:00
Asger F
bc88f50a5f JS: Port HardcodedDataInterpretedAsCode 2023-10-13 13:15:04 +02:00
Asger F
4bac90252c JS: Port HardcodedCredentials 2023-10-13 13:15:04 +02:00
Asger F
f4d62c3225 JS: Port HttpToFileAccess 2023-10-13 13:15:04 +02:00
Asger F
2935aac559 JS: Port FileAccessToHttp 2023-10-13 13:15:04 +02:00
Asger F
8e95a90d03 JS: Port UntrustedDataToExternalAPI 2023-10-13 13:15:04 +02:00
Asger F
abd937a49d JS: Port DifferentKindsComparisonBypass 2023-10-13 13:15:04 +02:00
Asger F
d324e554f3 JS: Port DeepObjectResourceExhaustion 2023-10-13 13:15:04 +02:00
Asger F
30f1fbc10d JS: Port CorsMisconfigurationForCredentials 2023-10-13 13:15:04 +02:00
Asger F
f14303acea JS: Port ConditionalBypass 2023-10-13 13:15:04 +02:00
Asger F
2296a273c4 JS: Port BuildArtifactLeak 2023-10-13 13:15:04 +02:00
Asger F
85617c292e JS: Port BrokenCryptoAlgorithm 2023-10-13 13:15:04 +02:00
Asger F
395f52303c JS: Port barriers in UrlConcatenation.qll 2023-10-13 13:15:04 +02:00
Asger F
7a1aead831 JS: Port ZipSlip 2023-10-13 13:15:04 +02:00
Asger F
e9189f965f JS: Port LogInjection 2023-10-13 13:15:04 +02:00
Asger F
ae680e747b JS: Port LoopBoundInjection 2023-10-13 13:15:04 +02:00
Asger F
40d68cb4dc JS: Port CleartextStorage 2023-10-13 13:15:04 +02:00
Asger F
b8a6f81669 JS: Port CleartextLogging 2023-10-13 13:15:04 +02:00
Asger F
a5c221fcfc JS: Port PrototypePollutingMergeCall 2023-10-13 13:15:04 +02:00
Asger F
adf7d5409d JS: Port PrototypePollutingFunction 2023-10-13 13:15:04 +02:00
Asger F
f1f45927b1 JS: Port PrototypePollutingAssignment 2023-10-13 13:15:04 +02:00
Asger F
81d2721248 JS: Port ClientSideUrlRedirect 2023-10-13 13:15:04 +02:00
Asger F
46fd727a55 JS: Port ServerSideUrlRedirect 2023-10-13 13:15:04 +02:00
Asger F
92816b1c9a JS: Port ClientSideRequestForgery 2023-10-13 13:15:03 +02:00
Asger F
b2216627be JS: Port RequestForgery 2023-10-13 13:15:03 +02:00
Asger F
d7b4e0c206 JS: Port ExceptionXss 2023-10-13 13:15:03 +02:00
Asger F
cf5450dbd5 JS: Port XssThroughDom 2023-10-13 13:15:03 +02:00
Asger F
5f05232e02 JS: Port StoredXss 2023-10-13 13:15:03 +02:00
Asger F
46b90e51fc JS: Port ReflectedXss 2023-10-13 13:15:03 +02:00
Asger F
e091fdefa4 JS: Port DomBasedXss 2023-10-13 13:15:03 +02:00
Asger F
2818fa62d6 JS: Updates to shared Xss.qll 2023-10-13 13:15:03 +02:00
Asger F
547a8a958a JS: Port SqlInjection 2023-10-13 13:15:03 +02:00
Asger F
65e9706c8e JS: Port TaintedPath 2023-10-13 13:15:03 +02:00
Asger F
fcfab5238e JS: Port CodeInjection 2023-10-13 13:15:03 +02:00
Asger F
17233a6749 JS: Port CommandInjection 2023-10-13 13:15:03 +02:00
Asger F
ccd6d3dcd7 JS: Port example queries 2023-10-13 13:15:03 +02:00
Asger F
449ec72dbe JS: Port experimental queries 2023-10-13 13:15:03 +02:00
Asger F
aa5a2836f5 JS: Update barriers in TaintedObject 2023-10-13 13:15:03 +02:00
Asger F
bc68b6a7f8 JS: Add AdHocWhitelistSanitizer::getABarrierNode()
This sanitizer guard is opt-in, i.e. not an AdditionalSanitizerGuardNode.
2023-10-13 13:15:03 +02:00
Asger F
26f7f94246 JS: Expose default taint steps/sanitizers
We need access to these in order to port taint-tracking configurations
where only some flow labels should use taint steps. This isn't supported
by the shared data flow library.

Such queries must therefore be converted to plain data-flow
configurations that explicitly add taint steps to the relevant flow
states.
2023-10-13 13:15:03 +02:00
Asger F
c924b4a220 JS: Expose shared API in DataFlow/TaintTracking modules 2023-10-13 13:15:03 +02:00
Asger F
1ed3235639 JS: use BarrierGuards 2023-10-13 13:15:03 +02:00
Asger F
277292e3b9 JS: Improve performance of barrier guards without pruning 2023-10-13 13:15:03 +02:00
Asger F
06fd9c2359 JS: Add barrier guard library 2023-10-13 13:14:43 +02:00
Asger F
46e4cdc623 JS: Disallow consecutive captured contents 2023-10-13 13:14:43 +02:00
Asger F
7bcf8b858b JS: Capture flow 2023-10-13 13:14:43 +02:00
Asger F
16df2c31bb Create DataFlowImplConsistency.qll 2023-10-13 12:42:41 +02:00
Asger F
3ef478669b JS: Collapse some cached stages 2023-10-13 12:42:41 +02:00
Asger F
9fef8803ed JS: Avoid BarrierGuardNode's range from depending on Configuration 2023-10-13 12:42:41 +02:00
Asger F
e31ae3a1bf JS: Model JSON.stringify with "deep" read operators 2023-10-13 12:42:41 +02:00
Asger F
0c2e52baba JS: Summary/steps for iterators and generators 2023-10-13 12:42:41 +02:00
Asger F
da3a0de814 JS: Port String#replace to flow summary 2023-10-13 12:42:41 +02:00
Asger F
f0c2afe39e JS: Add flow summaries for maps and sets 2023-10-13 12:42:40 +02:00
Asger F
5054c43b18 JS: Add flow summaries/steps for promises and async/await 2023-10-13 12:42:40 +02:00
Asger F
4319b07798 JS: Add flow summaries for Arrays 2023-10-13 12:42:40 +02:00
Asger F
a31e251529 JS: Add flow summaries for core methods 2023-10-13 12:42:40 +02:00
Asger F
46fec8ea7e JS: Add AdditionalFlowInternal
This provides access to more features than we want to expose publicly at the moment, but is useful for modelling certain language features.
2023-10-13 12:42:40 +02:00
Asger F
3f20d71a9b JS: Add legacy post-update step
This is to ensure getALocalSource() can be replaced by getPostUpdateNode() as the base of a store
2023-10-13 12:42:40 +02:00
Asger F
6037ff553c JS: Add LegacyPreUpdateStep
This contributes to both LegacyFlowStep and SharedTypeTrackingStep.

That is, this is for steps that are used by type-tracking and the old data flow library, but not the new data flow library.
2023-10-13 12:42:40 +02:00
Asger F
27c7d5004a JS: Do the same for additional taint steps 2023-10-13 12:42:40 +02:00
Asger F
1afe06e3a5 JS: Add "additional" and "legacy" steps
See the comment at the top of AdditionalFlowSteps.qll
2023-10-13 12:42:40 +02:00
Asger F
c24a0e00f5 JS: Move SharedTaintStep to AdditionalTaintSteps.qll
NOTE that this commit only moves around code. There are no changes.
2023-10-13 12:42:40 +02:00
Asger F
5bccc652c8 JS: Move SharedFlowStep to AdditionalFlowSteps.qll
NOTE that this commit only moves around code. There are no changes.
2023-10-13 12:42:40 +02:00
Asger F
293899d648 JS: Add 'Awaited' token 2023-10-13 12:42:40 +02:00
Asger F
32070abb27 JS: Implicitly treat array steps as taint steps 2023-10-13 12:42:40 +02:00
Asger F
60101f5e6a JS: Instantiate flow summary library 2023-10-13 12:42:40 +02:00
Asger F
8dc0800526 JS: Add the shared FlowSummaryImpl.qll file 2023-10-13 12:42:40 +02:00
Asger F
f316da78d2 JS: Add FunctionSelfReferenceNode 2023-10-13 12:42:40 +02:00
Asger F
760873c01c JS: Basic instantiation of shared library 2023-10-13 12:42:40 +02:00
Asger F
3455463e71 JS: Add instantiation boilerplate
Note that this commit won't compile on its own, but putting the boilerplate in its own commit
2023-10-13 12:42:40 +02:00
Asger F
c839822eb9 JS: Add PostUpdateNode 2023-10-13 12:42:40 +02:00
Asger F
01952f17bf JS: Add some missing getContainer() predicates 2023-10-13 12:42:40 +02:00
Asger F
21300eef4c JS:Add ConstructorThisArgumentNode 2023-10-13 12:42:40 +02:00
Asger F
b499c6075a JS: Add Contents.qll 2023-10-13 12:42:40 +02:00
Asger F
79e7aae9f6 JS: Add TEarlyStageNode 2023-10-13 12:42:39 +02:00
Asger F
51ef0e5836 JS: Move TNode into a cached module 2023-10-13 12:42:39 +02:00
Asger F
60b179bda2 Shared: add DeduplicatePathGraph
Note that there is a separate PR open with this library
2023-10-13 12:42:39 +02:00
1062 changed files with 49831 additions and 57100 deletions

422
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@ bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True
# the versions there are canonical, the versions here are used for CI in github/codeql, as well as for the vendoring of dependencies.
RUST_EDITION = "2021"
RUST_VERSION = "1.81.0"
RUST_VERSION = "1.82.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
@@ -70,7 +70,22 @@ use_repo(py_deps, "vendor__anyhow-1.0.44", "vendor__cc-1.0.70", "vendor__clap-2.
# deps for ruby+rust
# keep in sync by running `misc/bazel/3rdparty/update_cargo_deps.sh`
tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r")
use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.93", "vendor__argfile-0.2.1", "vendor__chrono-0.4.38", "vendor__clap-4.5.20", "vendor__dunce-1.0.5", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.34", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.10.5", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.89", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.232", "vendor__ra_ap_cfg-0.0.232", "vendor__ra_ap_hir-0.0.232", "vendor__ra_ap_hir_def-0.0.232", "vendor__ra_ap_hir_expand-0.0.232", "vendor__ra_ap_ide_db-0.0.232", "vendor__ra_ap_intern-0.0.232", "vendor__ra_ap_load-cargo-0.0.232", "vendor__ra_ap_parser-0.0.232", "vendor__ra_ap_paths-0.0.232", "vendor__ra_ap_project_model-0.0.232", "vendor__ra_ap_span-0.0.232", "vendor__ra_ap_syntax-0.0.232", "vendor__ra_ap_vfs-0.0.232", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.214", "vendor__serde_json-1.0.133", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.87", "vendor__tracing-0.1.40", "vendor__tracing-subscriber-0.3.18", "vendor__tree-sitter-0.24.4", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1")
use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.94", "vendor__argfile-0.2.1", "vendor__chrono-0.4.39", "vendor__clap-4.5.23", "vendor__dunce-1.0.5", "vendor__either-1.13.0", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.35", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.12.1", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.92", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.248", "vendor__ra_ap_cfg-0.0.248", "vendor__ra_ap_hir-0.0.248", "vendor__ra_ap_hir_def-0.0.248", "vendor__ra_ap_hir_expand-0.0.248", "vendor__ra_ap_ide_db-0.0.248", "vendor__ra_ap_intern-0.0.248", "vendor__ra_ap_load-cargo-0.0.248", "vendor__ra_ap_parser-0.0.248", "vendor__ra_ap_paths-0.0.248", "vendor__ra_ap_project_model-0.0.248", "vendor__ra_ap_span-0.0.248", "vendor__ra_ap_stdx-0.0.248", "vendor__ra_ap_syntax-0.0.248", "vendor__ra_ap_vfs-0.0.248", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.216", "vendor__serde_json-1.0.133", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.90", "vendor__tracing-0.1.41", "vendor__tracing-subscriber-0.3.19", "vendor__tree-sitter-0.24.5", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1")
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# rust-analyzer sources needed by the rust ast-generator (see `rust/ast-generator/README.md`)
http_archive(
name = "rust-analyzer-src",
build_file = "//rust/ast-generator:BUILD.rust-analyzer-src.bazel",
integrity = "sha256-jl4KJmZku+ilMLnuX2NU+qa1v10IauSiDiz23sZo360=",
patch_args = ["-p1"],
patches = [
"//rust/ast-generator:patches/rust-analyzer.patch",
],
strip_prefix = "rust-analyzer-2024-12-16",
url = "https://github.com/rust-lang/rust-analyzer/archive/refs/tags/2024-12-16.tar.gz",
)
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
dotnet.toolchain(dotnet_version = "9.0.100")

View File

@@ -6,7 +6,7 @@
### Deprecated APIs
* The `NonThrowing` class (`semmle.code.cpp.models.interfaces.NonThrowing`) has been deprecated. Please use the `NonCppThrowingFunction` class instead.
* The `NonThrowingFunction` class (`semmle.code.cpp.models.interfaces.NonThrowing.NonThrowingFunction`) has been deprecated. Please use the `NonCppThrowingFunction` class instead.
## 2.1.1

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `Guards` library (`semmle.code.cpp.controlflow.Guards`) has been improved to recognize more guard conditions.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* A new class `TemplateParameterBase` was introduced, which represents C++ non-type template parameters, type template parameters, and template template parameters.

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `TemplateParameter` class, representing C++ type template parameters has been deprecated. Use `TypeTemplateParameter` instead.

View File

@@ -6,4 +6,4 @@
### Deprecated APIs
* The `NonThrowing` class (`semmle.code.cpp.models.interfaces.NonThrowing`) has been deprecated. Please use the `NonCppThrowingFunction` class instead.
* The `NonThrowingFunction` class (`semmle.code.cpp.models.interfaces.NonThrowing.NonThrowingFunction`) has been deprecated. Please use the `NonCppThrowingFunction` class instead.

View File

@@ -952,7 +952,7 @@ class ClassTemplateSpecialization extends Class {
result.getNamespace() = this.getNamespace() and
// It is distinguished by the fact that each of its template arguments
// is a distinct template parameter.
count(TemplateParameter tp | tp = result.getATemplateArgument()) =
count(TemplateParameterBase tp | tp = result.getATemplateArgument()) =
count(int i | exists(result.getTemplateArgument(i)))
}
@@ -1006,7 +1006,7 @@ private predicate isPartialClassTemplateSpecialization(Class c) {
*/
exists(Type ta | ta = c.getATemplateArgument() and ta.involvesTemplateParameter()) and
count(TemplateParameter tp | tp = c.getATemplateArgument()) !=
count(TemplateParameterBase tp | tp = c.getATemplateArgument()) !=
count(int i | exists(c.getTemplateArgument(i)))
}
@@ -1091,7 +1091,7 @@ class ProxyClass extends UserType {
override Location getLocation() { result = this.getTemplateParameter().getDefinitionLocation() }
/** Gets the template parameter for which this is the proxy class. */
TemplateParameter getTemplateParameter() {
TypeTemplateParameter getTemplateParameter() {
is_proxy_class_for(underlyingElement(this), unresolveElement(result))
}
}

View File

@@ -187,7 +187,7 @@ class Declaration extends Locatable, @declaration {
this instanceof Parameter or
this instanceof ProxyClass or
this instanceof LocalVariable or
this instanceof TemplateParameter or
this instanceof TypeTemplateParameter or
this.(UserType).isLocal()
)
}

View File

@@ -33,7 +33,7 @@ private string getScopePrefix(Declaration decl) {
result = "(" + type.getEnclosingFunction().(DumpFunction).getIdentityString() + ")::"
)
or
decl instanceof TemplateParameter and result = ""
decl instanceof TypeTemplateParameter and result = ""
}
/**

View File

@@ -1666,6 +1666,28 @@ class RoutineType extends Type, @routinetype {
}
}
abstract private class TemplateParameterImpl extends Locatable {
override string getAPrimaryQlClass() { result = "TemplateParameterImpl" }
}
/**
* A C++ template parameter.
*
* In the example below, `T`, `TT`, and `I` are template parameters:
* ```
* template <class T, template<typename> TT, int I>
* class C { };
* ```
*/
final class TemplateParameterBase = TemplateParameterImpl;
/**
* A C++ `typename` (or `class`) template parameter.
*
* DEPRECATED: Use `TypeTemplateParameter` instead.
*/
deprecated class TemplateParameter = TypeTemplateParameter;
/**
* A C++ `typename` (or `class`) template parameter.
*
@@ -1675,12 +1697,12 @@ class RoutineType extends Type, @routinetype {
* class C { };
* ```
*/
class TemplateParameter extends UserType {
TemplateParameter() {
class TypeTemplateParameter extends UserType, TemplateParameterImpl {
TypeTemplateParameter() {
usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8)
}
override string getAPrimaryQlClass() { result = "TemplateParameter" }
override string getAPrimaryQlClass() { result = "TypeTemplateParameter" }
override predicate involvesTemplateParameter() { any() }
}
@@ -1695,7 +1717,7 @@ class TemplateParameter extends UserType {
* void foo(const Container<Elem> &value) { }
* ```
*/
class TemplateTemplateParameter extends TemplateParameter {
class TemplateTemplateParameter extends TypeTemplateParameter {
TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) }
override string getAPrimaryQlClass() { result = "TemplateTemplateParameter" }
@@ -1707,7 +1729,7 @@ class TemplateTemplateParameter extends TemplateParameter {
* auto val = some_typed_expr();
* ```
*/
class AutoType extends TemplateParameter {
class AutoType extends TypeTemplateParameter {
AutoType() { usertypes(underlyingElement(this), "auto", 7) }
override string getAPrimaryQlClass() { result = "AutoType" }

View File

@@ -66,7 +66,7 @@ class Symbol extends DependsSource {
not this.(TypeDeclarationEntry).getType() instanceof LocalEnum and
not this.(TypeDeclarationEntry).getType() instanceof LocalClass and
not this.(TypeDeclarationEntry).getType() instanceof LocalTypedefType and
not this.(TypeDeclarationEntry).getType() instanceof TemplateParameter
not this.(TypeDeclarationEntry).getType() instanceof TypeTemplateParameter
or
this instanceof NamespaceDeclarationEntry
)

File diff suppressed because it is too large Load Diff

View File

@@ -504,7 +504,7 @@ private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remain
result = getParameterTypeWithoutTemplateArguments(templateFunction, n)
)
or
exists(string mid, TemplateParameter tp, Function templateFunction |
exists(string mid, TypeTemplateParameter tp, Function templateFunction |
mid = getTypeNameWithoutFunctionTemplates(f, n, remaining + 1) and
templateFunction = getFullyTemplatedFunction(f) and
tp = templateFunction.getTemplateArgument(remaining) and
@@ -529,7 +529,7 @@ private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining
remaining = 0 and
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
or
exists(string mid, TemplateParameter tp, Class template |
exists(string mid, TypeTemplateParameter tp, Class template |
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
isClassConstructedFrom(f.getDeclaringType(), template) and
tp = template.getTemplateArgument(remaining) and

View File

@@ -130,7 +130,7 @@ class Declaration extends @declaration {
this instanceof Parameter or
this instanceof ProxyClass or
this instanceof LocalVariable or
this instanceof TemplateParameter or
this instanceof TypeTemplateParameter or
this.(UserType).isLocal()
)
}
@@ -226,8 +226,8 @@ class ProxyClass extends UserType {
ProxyClass() { usertypes(this, _, 9) }
}
class TemplateParameter extends UserType {
TemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) }
class TypeTemplateParameter extends UserType {
TypeTemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) }
}
class TemplateClass extends UserType {

View File

@@ -1237,12 +1237,14 @@ module IsUnreachableInCall {
int getValue() { result = value }
}
pragma[nomagic]
bindingset[right]
pragma[inline_late]
private predicate ensuresEq(Operand left, Operand right, int k, IRBlock block, boolean areEqual) {
any(G::IRGuardCondition guard).ensuresEq(left, right, k, block, areEqual)
}
pragma[nomagic]
bindingset[right]
pragma[inline_late]
private predicate ensuresLt(Operand left, Operand right, int k, IRBlock block, boolean areEqual) {
any(G::IRGuardCondition guard).ensuresLt(left, right, k, block, areEqual)
}

View File

@@ -2275,7 +2275,7 @@ private predicate guardControlsPhiInput(
*/
signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch);
bindingset[g, n]
bindingset[g]
pragma[inline_late]
private predicate controls(IRGuardCondition g, Node n, boolean edge) {
g.controls(n.getBasicBlock(), edge)
@@ -2288,6 +2288,15 @@ private predicate controls(IRGuardCondition g, Node n, boolean edge) {
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
bindingset[value, n]
pragma[inline_late]
private predicate convertedExprHasValueNumber(ValueNumber value, Node n) {
exists(Expr e |
e = value.getAnInstruction().getConvertedResultExpression() and
n.asConvertedExpr() = e
)
}
/**
* Gets an expression node that is safely guarded by the given guard check.
*
@@ -2321,9 +2330,8 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
*/
Node getABarrierNode() {
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
e = value.getAnInstruction().getConvertedResultExpression() and
result.asConvertedExpr() = e and
exists(IRGuardCondition g, ValueNumber value, boolean edge |
convertedExprHasValueNumber(value, result) and
guardChecks(g,
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and
controls(g, result, edge)
@@ -2374,6 +2382,17 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*/
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
bindingset[value, n]
pragma[inline_late]
private predicate indirectConvertedExprHasValueNumber(
int indirectionIndex, ValueNumber value, Node n
) {
exists(Expr e |
e = value.getAnInstruction().getConvertedResultExpression() and
n.asIndirectConvertedExpr(indirectionIndex) = e
)
}
/**
* Gets an indirect expression node with indirection index `indirectionIndex` that is
* safely guarded by the given guard check.
@@ -2409,9 +2428,8 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/
Node getAnIndirectBarrierNode(int indirectionIndex) {
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
e = value.getAnInstruction().getConvertedResultExpression() and
result.asIndirectConvertedExpr(indirectionIndex) = e and
exists(IRGuardCondition g, ValueNumber value, boolean edge |
indirectConvertedExprHasValueNumber(indirectionIndex, value, result) and
guardChecks(g,
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and
controls(g, result, edge)
@@ -2450,12 +2468,20 @@ private EdgeKind getConditionalEdge(boolean branch) {
* in data flow and taint tracking.
*/
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
bindingset[value, n]
pragma[inline_late]
private predicate operandHasValueNumber(ValueNumber value, Node n) {
exists(Operand use |
use = value.getAnInstruction().getAUse() and
n.asOperand() = use
)
}
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() {
exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use |
exists(IRGuardCondition g, ValueNumber value, boolean edge |
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge) and
use = value.getAnInstruction().getAUse() and
result.asOperand() = use and
operandHasValueNumber(value, result) and
controls(g, result, edge)
)
or

View File

@@ -51,6 +51,7 @@ class ValueNumber extends TValueNumber {
/**
* Gets an `Operand` whose definition is exact and has this value number.
*/
pragma[nomagic]
final Operand getAUse() { this = valueNumber(result.getDef()) }
final string getKind() {

View File

@@ -51,6 +51,7 @@ class ValueNumber extends TValueNumber {
/**
* Gets an `Operand` whose definition is exact and has this value number.
*/
pragma[nomagic]
final Operand getAUse() { this = valueNumber(result.getDef()) }
final string getKind() {

View File

@@ -51,6 +51,7 @@ class ValueNumber extends TValueNumber {
/**
* Gets an `Operand` whose definition is exact and has this value number.
*/
pragma[nomagic]
final Operand getAUse() { this = valueNumber(result.getDef()) }
final string getKind() {

View File

@@ -437,6 +437,78 @@ module SignAnalysis<DeltaSig D> {
not hasGuard(v, pos, result)
}
private SemExpr posBoundGetElement(int i, SemSsaVariable v, SsaReadPosition pos) {
result =
rank[i + 1](SemExpr bound, SemBasicBlock b, int blockOrder, int indexOrder |
posBound(bound, v, pos) and
b = bound.getBasicBlock() and
blockOrder = b.getUniqueId() and
bound = b.getInstruction(indexOrder)
|
bound order by blockOrder, indexOrder
)
}
private predicate posBoundOkFromIndex(int i, SemSsaVariable v, SsaReadPosition pos) {
i = 0 and
posBoundOk(posBoundGetElement(i, v, pos), v, pos)
or
posBoundOkFromIndex(i - 1, v, pos) and
posBoundOk(posBoundGetElement(i, v, pos), v, pos)
}
private predicate posBoundGuardedSsaSignOk(SemSsaVariable v, SsaReadPosition pos) {
posBoundOkFromIndex(max(int i | exists(posBoundGetElement(i, v, pos))), v, pos)
}
private SemExpr negBoundGetElement(int i, SemSsaVariable v, SsaReadPosition pos) {
result =
rank[i + 1](SemExpr bound, SemBasicBlock b, int blockOrder, int indexOrder |
negBound(bound, v, pos) and
b = bound.getBasicBlock() and
blockOrder = b.getUniqueId() and
bound = b.getInstruction(indexOrder)
|
bound order by blockOrder, indexOrder
)
}
private predicate negBoundOkFromIndex(int i, SemSsaVariable v, SsaReadPosition pos) {
i = 0 and
negBoundOk(negBoundGetElement(i, v, pos), v, pos)
or
negBoundOkFromIndex(i - 1, v, pos) and
negBoundOk(negBoundGetElement(i, v, pos), v, pos)
}
private predicate negBoundGuardedSsaSignOk(SemSsaVariable v, SsaReadPosition pos) {
negBoundOkFromIndex(max(int i | exists(negBoundGetElement(i, v, pos))), v, pos)
}
private SemExpr zeroBoundGetElement(int i, SemSsaVariable v, SsaReadPosition pos) {
result =
rank[i + 1](SemExpr bound, SemBasicBlock b, int blockOrder, int indexOrder |
zeroBound(bound, v, pos) and
b = bound.getBasicBlock() and
blockOrder = b.getUniqueId() and
bound = b.getInstruction(indexOrder)
|
bound order by blockOrder, indexOrder
)
}
private predicate zeroBoundOkFromIndex(int i, SemSsaVariable v, SsaReadPosition pos) {
i = 0 and
zeroBoundOk(zeroBoundGetElement(i, v, pos), v, pos)
or
zeroBoundOkFromIndex(i - 1, v, pos) and
zeroBoundOk(zeroBoundGetElement(i, v, pos), v, pos)
}
private predicate zeroBoundGuardedSsaSignOk(SemSsaVariable v, SsaReadPosition pos) {
zeroBoundOkFromIndex(max(int i | exists(zeroBoundGetElement(i, v, pos))), v, pos)
}
/**
* Gets a possible sign of `v` at read position `pos`, where a guard could have
* ruled out the sign but does not.
@@ -444,13 +516,19 @@ module SignAnalysis<DeltaSig D> {
*/
private Sign guardedSsaSignOk(SemSsaVariable v, SsaReadPosition pos) {
result = TPos() and
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
// optimised version of
// `forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))`
posBoundGuardedSsaSignOk(v, pos)
or
result = TNeg() and
forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))
// optimised version of
// `forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))`
negBoundGuardedSsaSignOk(v, pos)
or
result = TZero() and
forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))
// optimised version of
// `forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))`
zeroBoundGuardedSsaSignOk(v, pos)
}
/** Gets a possible sign for `v` at `pos`. */

View File

@@ -26,7 +26,7 @@ import cpp
*/
class TemplateDependentType extends Type {
TemplateDependentType() {
this instanceof TemplateParameter
this instanceof TypeTemplateParameter
or
exists(TemplateDependentType t |
this.refersToDirectly(t) and

View File

@@ -49,7 +49,7 @@ predicate nanTest(EqualityOperation cmp) {
pointlessSelfComparison(cmp) and
exists(Type t | t = cmp.getLeftOperand().getUnspecifiedType() |
t instanceof FloatingPointType or
t instanceof TemplateParameter
t instanceof TypeTemplateParameter
)
}

View File

@@ -2,7 +2,7 @@ import cpp
private predicate mightHaveConstMethods(Type t) {
t instanceof Class or
t instanceof TemplateParameter
t instanceof TypeTemplateParameter
}
predicate hasSuperfluousConstReturn(Function f) {

View File

@@ -26,7 +26,7 @@ predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) {
exists(Type returnType |
returnType = f.getUnspecifiedType() and
not returnType instanceof VoidType and
not returnType instanceof TemplateParameter
not returnType instanceof TypeTemplateParameter
) and
exists(ReturnStmt s |
f.getAPredecessor() = s and

View File

@@ -915,7 +915,7 @@ VacuousDestructorCall.cpp:
# 2| [TemplateFunction,TopLevelFunction] void CallDestructor<T>(T, T*)
# 2| <params>:
# 2| getParameter(0): [Parameter] x
# 2| Type = [TemplateParameter] T
# 2| Type = [TypeTemplateParameter] T
# 2| getParameter(1): [Parameter] y
# 2| Type = [PointerType] T *
# 2| getEntryPoint(): [BlockStmt] { ... }
@@ -927,7 +927,7 @@ VacuousDestructorCall.cpp:
# 3| Type = [UnknownType] unknown
# 3| ValueCategory = prvalue
# 3| getChild(-1): [VariableAccess] x
# 3| Type = [TemplateParameter] T
# 3| Type = [TypeTemplateParameter] T
# 3| ValueCategory = lvalue
# 4| getStmt(1): [ExprStmt] ExprStmt
# 4| getExpr(): [ExprCall] call to expression

View File

@@ -17,6 +17,7 @@
| test.cpp:49:12:49:12 | Load: x | test.cpp:46:22:46:22 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 |
| test.cpp:49:12:49:12 | Load: x | test.cpp:46:29:46:29 | ValueNumberBound | -2 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 |
| test.cpp:54:12:54:12 | Load: x | test.cpp:46:22:46:22 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:52:7:52:11 | test.cpp:52:7:52:11 |
| test.cpp:54:12:54:12 | Load: x | test.cpp:46:29:46:29 | ValueNumberBound | -2 | true | CompareLT: ... < ... | test.cpp:52:7:52:11 | test.cpp:52:7:52:11 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 3 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:39:61:51 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |

View File

@@ -51,7 +51,7 @@ int test5(int x, int y, int z) {
}
if (x < y) {
if (y < z) {
sink(x); // x < z is not inferred here
sink(x); // x < z is inferred here
}
}
}

View File

@@ -42,6 +42,8 @@ astGuards
astGuardsCompare
| 7 | 0 < x+0 when ... > ... is true |
| 7 | 0 >= x+0 when ... > ... is false |
| 7 | ... > ... != 0 when ... > ... is true |
| 7 | ... > ... == 0 when ... > ... is false |
| 7 | x < 0+1 when ... > ... is false |
| 7 | x >= 0+1 when ... > ... is true |
| 17 | 0 < x+1 when ... < ... is false |
@@ -50,6 +52,12 @@ astGuardsCompare
| 17 | 1 < y+0 when ... && ... is true |
| 17 | 1 < y+0 when ... > ... is true |
| 17 | 1 >= y+0 when ... > ... is false |
| 17 | ... < ... != 0 when ... && ... is true |
| 17 | ... < ... != 0 when ... < ... is true |
| 17 | ... < ... == 0 when ... < ... is false |
| 17 | ... > ... != 0 when ... && ... is true |
| 17 | ... > ... != 0 when ... > ... is true |
| 17 | ... > ... == 0 when ... > ... is false |
| 17 | x < 0+0 when ... && ... is true |
| 17 | x < 0+0 when ... < ... is true |
| 17 | x >= 0+0 when ... < ... is false |
@@ -60,30 +68,42 @@ astGuardsCompare
| 18 | call to get == 0 when call to get is false |
| 26 | 0 < x+0 when ... > ... is true |
| 26 | 0 >= x+0 when ... > ... is false |
| 26 | ... > ... != 0 when ... > ... is true |
| 26 | ... > ... == 0 when ... > ... is false |
| 26 | x < 0+1 when ... > ... is false |
| 26 | x >= 0+1 when ... > ... is true |
| 31 | - ... != x+0 when ... == ... is false |
| 31 | - ... == x+0 when ... == ... is true |
| 31 | ... == ... != 0 when ... == ... is true |
| 31 | ... == ... == 0 when ... == ... is false |
| 31 | x != -1 when ... == ... is false |
| 31 | x != - ...+0 when ... == ... is false |
| 31 | x == -1 when ... == ... is true |
| 31 | x == - ...+0 when ... == ... is true |
| 34 | 10 < j+1 when ... < ... is false |
| 34 | 10 >= j+1 when ... < ... is true |
| 34 | ... < ... != 0 when ... < ... is true |
| 34 | ... < ... == 0 when ... < ... is false |
| 34 | j < 10+0 when ... < ... is true |
| 34 | j >= 10+0 when ... < ... is false |
| 42 | 10 < j+1 when ... < ... is false |
| 42 | 10 >= j+1 when ... < ... is true |
| 42 | ... < ... != 0 when ... < ... is true |
| 42 | ... < ... == 0 when ... < ... is false |
| 42 | call to getABool != 0 when call to getABool is true |
| 42 | call to getABool == 0 when call to getABool is false |
| 42 | j < 10+0 when ... < ... is true |
| 42 | j >= 10+0 when ... < ... is false |
| 44 | 0 < z+0 when ... > ... is true |
| 44 | 0 >= z+0 when ... > ... is false |
| 44 | ... > ... != 0 when ... > ... is true |
| 44 | ... > ... == 0 when ... > ... is false |
| 44 | z < 0+1 when ... > ... is false |
| 44 | z >= 0+1 when ... > ... is true |
| 45 | 0 < y+0 when ... > ... is true |
| 45 | 0 >= y+0 when ... > ... is false |
| 45 | ... > ... != 0 when ... > ... is true |
| 45 | ... > ... == 0 when ... > ... is false |
| 45 | y < 0+1 when ... > ... is false |
| 45 | y >= 0+1 when ... > ... is true |
| 58 | 0 != x+0 when ... == ... is false |
@@ -92,6 +112,12 @@ astGuardsCompare
| 58 | 0 < y+1 when ... \|\| ... is false |
| 58 | 0 == x+0 when ... == ... is true |
| 58 | 0 >= y+1 when ... < ... is true |
| 58 | ... < ... != 0 when ... < ... is true |
| 58 | ... < ... == 0 when ... < ... is false |
| 58 | ... < ... == 0 when ... \|\| ... is false |
| 58 | ... == ... != 0 when ... == ... is true |
| 58 | ... == ... == 0 when ... == ... is false |
| 58 | ... == ... == 0 when ... \|\| ... is false |
| 58 | x != 0 when ... == ... is false |
| 58 | x != 0 when ... \|\| ... is false |
| 58 | x != 0+0 when ... == ... is false |
@@ -103,6 +129,8 @@ astGuardsCompare
| 58 | y >= 0+0 when ... \|\| ... is false |
| 75 | 0 != x+0 when ... == ... is false |
| 75 | 0 == x+0 when ... == ... is true |
| 75 | ... == ... != 0 when ... == ... is true |
| 75 | ... == ... == 0 when ... == ... is false |
| 75 | x != 0 when ... == ... is false |
| 75 | x != 0+0 when ... == ... is false |
| 75 | x == 0 when ... == ... is true |
@@ -113,6 +141,12 @@ astGuardsCompare
| 85 | 0 == x+0 when ... && ... is true |
| 85 | 0 == x+0 when ... == ... is true |
| 85 | 0 == y+0 when ... != ... is false |
| 85 | ... != ... != 0 when ... != ... is true |
| 85 | ... != ... != 0 when ... && ... is true |
| 85 | ... != ... == 0 when ... != ... is false |
| 85 | ... == ... != 0 when ... && ... is true |
| 85 | ... == ... != 0 when ... == ... is true |
| 85 | ... == ... == 0 when ... == ... is false |
| 85 | x != 0 when ... == ... is false |
| 85 | x != 0+0 when ... == ... is false |
| 85 | x == 0 when ... && ... is true |
@@ -127,12 +161,16 @@ astGuardsCompare
| 85 | y == 0+0 when ... != ... is false |
| 94 | 0 != x+0 when ... != ... is true |
| 94 | 0 == x+0 when ... != ... is false |
| 94 | ... != ... != 0 when ... != ... is true |
| 94 | ... != ... == 0 when ... != ... is false |
| 94 | x != 0 when ... != ... is true |
| 94 | x != 0+0 when ... != ... is true |
| 94 | x == 0 when ... != ... is false |
| 94 | x == 0+0 when ... != ... is false |
| 102 | 10 < j+1 when ... < ... is false |
| 102 | 10 >= j+1 when ... < ... is true |
| 102 | ... < ... != 0 when ... < ... is true |
| 102 | ... < ... == 0 when ... < ... is false |
| 102 | j < 10+0 when ... < ... is true |
| 102 | j >= 10+0 when ... < ... is false |
| 109 | 0 != x+0 when ... == ... is false |
@@ -141,6 +179,12 @@ astGuardsCompare
| 109 | 0 < y+1 when ... \|\| ... is false |
| 109 | 0 == x+0 when ... == ... is true |
| 109 | 0 >= y+1 when ... < ... is true |
| 109 | ... < ... != 0 when ... < ... is true |
| 109 | ... < ... == 0 when ... < ... is false |
| 109 | ... < ... == 0 when ... \|\| ... is false |
| 109 | ... == ... != 0 when ... == ... is true |
| 109 | ... == ... == 0 when ... == ... is false |
| 109 | ... == ... == 0 when ... \|\| ... is false |
| 109 | x != 0 when ... == ... is false |
| 109 | x != 0 when ... \|\| ... is false |
| 109 | x != 0+0 when ... == ... is false |
@@ -173,6 +217,8 @@ astGuardsCompare
| 152 | y == 0 when y is false |
| 156 | ... + ... != x+0 when ... == ... is false |
| 156 | ... + ... == x+0 when ... == ... is true |
| 156 | ... == ... != 0 when ... == ... is true |
| 156 | ... == ... == 0 when ... == ... is false |
| 156 | x != ... + ...+0 when ... == ... is false |
| 156 | x != y+42 when ... == ... is false |
| 156 | x == ... + ...+0 when ... == ... is true |
@@ -181,6 +227,8 @@ astGuardsCompare
| 156 | y == x+-42 when ... == ... is true |
| 159 | ... - ... != x+0 when ... == ... is false |
| 159 | ... - ... == x+0 when ... == ... is true |
| 159 | ... == ... != 0 when ... == ... is true |
| 159 | ... == ... == 0 when ... == ... is false |
| 159 | x != ... - ...+0 when ... == ... is false |
| 159 | x != y+-42 when ... == ... is false |
| 159 | x == ... - ...+0 when ... == ... is true |
@@ -189,6 +237,8 @@ astGuardsCompare
| 159 | y == x+42 when ... == ... is true |
| 162 | ... + ... < x+1 when ... < ... is false |
| 162 | ... + ... >= x+1 when ... < ... is true |
| 162 | ... < ... != 0 when ... < ... is true |
| 162 | ... < ... == 0 when ... < ... is false |
| 162 | x < ... + ...+0 when ... < ... is true |
| 162 | x < y+42 when ... < ... is true |
| 162 | x >= ... + ...+0 when ... < ... is false |
@@ -197,6 +247,8 @@ astGuardsCompare
| 162 | y >= x+-41 when ... < ... is true |
| 165 | ... - ... < x+1 when ... < ... is false |
| 165 | ... - ... >= x+1 when ... < ... is true |
| 165 | ... < ... != 0 when ... < ... is true |
| 165 | ... < ... == 0 when ... < ... is false |
| 165 | x < ... - ...+0 when ... < ... is true |
| 165 | x < y+-42 when ... < ... is true |
| 165 | x >= ... - ...+0 when ... < ... is false |
@@ -205,6 +257,8 @@ astGuardsCompare
| 165 | y >= x+43 when ... < ... is true |
| 175 | 0 != call to foo+0 when ... == ... is false |
| 175 | 0 == call to foo+0 when ... == ... is true |
| 175 | ... == ... != 0 when ... == ... is true |
| 175 | ... == ... == 0 when ... == ... is false |
| 175 | call to foo != 0 when ... == ... is false |
| 175 | call to foo != 0+0 when ... == ... is false |
| 175 | call to foo == 0 when ... == ... is true |
@@ -414,10 +468,20 @@ astGuardsEnsure
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:75:14:75:14 | 0 | != | test.c:75:9:75:9 | x | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:8 | x | != | test.c:85:13:85:13 | 0 | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:85:13:85:13 | 0 | != | test.c:85:8:85:8 | x | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 75 | 77 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:18 | y | != | test.c:85:23:85:23 | 0 | 0 | 86 | 86 |
@@ -491,16 +555,81 @@ astGuardsEnsure
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 31 | 32 |
astGuardsEnsure_const
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:13 | ... > ... | != | 0 | 7 | 9 |
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:13 | ... > ... | == | 0 | 10 | 11 |
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:12 | ... < ... | != | 0 | 17 | 17 |
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:12 | ... < ... | != | 0 | 18 | 18 |
| test.c:17:8:17:21 | ... && ... | test.c:17:8:17:12 | ... < ... | != | 0 | 18 | 18 |
| test.c:17:8:17:21 | ... && ... | test.c:17:17:17:21 | ... > ... | != | 0 | 18 | 18 |
| test.c:17:17:17:21 | ... > ... | test.c:17:17:17:21 | ... > ... | != | 0 | 18 | 18 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | != | 0 | 26 | 28 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 2 | 2 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 31 | 34 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 34 | 34 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 39 | 42 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 42 | 42 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 42 | 44 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 45 | 45 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 45 | 47 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 51 | 53 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 56 | 58 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 58 | 58 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 58 | 66 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 62 | 62 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | != | 0 | 34 | 34 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 2 | 2 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 39 | 42 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 42 | 42 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 42 | 44 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 45 | 45 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 45 | 47 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 51 | 53 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 56 | 58 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 58 | 58 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 58 | 66 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 62 | 62 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 42 | 42 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 42 | 44 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 45 | 45 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 45 | 47 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:16 | ... > ... | != | 0 | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:16 | ... > ... | != | 0 | 45 | 47 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:16 | ... > ... | == | 0 | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:16 | ... > ... | == | 0 | 51 | 53 |
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:20 | ... > ... | != | 0 | 45 | 47 |
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | 0 | 58 | 58 |
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | 0 | 62 | 62 |
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:14 | ... == ... | == | 0 | 58 | 58 |
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:14 | ... == ... | == | 0 | 62 | 62 |
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:9:58:9 | x | != | 0 | 62 | 62 |
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:9:58:14 | ... == ... | == | 0 | 62 | 62 |
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:19:58:23 | ... < ... | == | 0 | 62 | 62 |
| test.c:58:19:58:23 | ... < ... | test.c:58:19:58:23 | ... < ... | == | 0 | 62 | 62 |
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | != | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | == | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:14 | ... == ... | != | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:14 | ... == ... | == | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:8 | x | != | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:13 | ... == ... | != | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:13 | ... == ... | == | 0 | 78 | 79 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:9 | x | == | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:9 | x | == | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:14 | ... == ... | != | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:14 | ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:13 | ... == ... | != | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:13 | ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:75:9:75:9 | x | == | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:75:9:75:14 | ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:8 | x | == | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:13 | ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:18 | y | != | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:23 | ... != ... | != | 0 | 86 | 86 |
| test.c:85:18:85:23 | ... != ... | test.c:85:18:85:18 | y | != | 0 | 86 | 86 |
| test.c:85:18:85:23 | ... != ... | test.c:85:18:85:23 | ... != ... | != | 0 | 86 | 86 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | != | 0 | 94 | 96 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 70 | 70 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 99 | 102 |
@@ -509,16 +638,41 @@ astGuardsEnsure_const
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 109 | 109 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 109 | 117 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 113 | 113 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | != | 0 | 94 | 96 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 70 | 70 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 99 | 102 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 102 | 102 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 107 | 109 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 109 | 109 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 109 | 117 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 113 | 113 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | != | 0 | 102 | 102 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 70 | 70 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 107 | 109 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 109 | 109 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 109 | 117 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 113 | 113 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:14 | ... == ... | == | 0 | 109 | 109 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:14 | ... == ... | == | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:14 | ... == ... | == | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:23 | ... < ... | == | 0 | 113 | 113 |
| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:23 | ... < ... | == | 0 | 113 | 113 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 131 | 132 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 134 | 123 |
| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
| test.c:126:7:126:28 | ... && ... | test.c:127:9:127:9 | 1 | != | 0 | 126 | 128 |
| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
@@ -529,8 +683,14 @@ astGuardsEnsure_const
| test.c:152:10:152:15 | ... && ... | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
| test.c:152:10:152:15 | ... && ... | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
| test.c:152:15:152:15 | y | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
| test.c:156:9:156:19 | ... == ... | test.c:156:9:156:19 | ... == ... | != | 0 | 156 | 157 |
| test.c:159:9:159:19 | ... == ... | test.c:159:9:159:19 | ... == ... | != | 0 | 159 | 160 |
| test.c:162:9:162:18 | ... < ... | test.c:162:9:162:18 | ... < ... | != | 0 | 162 | 163 |
| test.c:165:9:165:18 | ... < ... | test.c:165:9:165:18 | ... < ... | != | 0 | 165 | 166 |
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | != | 0 | 175 | 175 |
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | == | 0 | 175 | 175 |
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:32 | ... == ... | != | 0 | 175 | 175 |
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:32 | ... == ... | == | 0 | 175 | 175 |
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 181 | 182 |
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 186 | 180 |
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | == | 0 | 183 | 184 |
@@ -539,6 +699,10 @@ astGuardsEnsure_const
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:13 | ... == ... | != | 0 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:13 | ... == ... | != | 0 | 31 | 32 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:13 | ... == ... | == | 0 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:13 | ... == ... | == | 0 | 34 | 34 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
irGuards
@@ -579,6 +743,8 @@ irGuards
irGuardsCompare
| 7 | 0 < x+0 when CompareGT: ... > ... is true |
| 7 | 0 >= x+0 when CompareGT: ... > ... is false |
| 7 | ... > ... != 0 when CompareGT: ... > ... is true |
| 7 | ... > ... == 0 when CompareGT: ... > ... is false |
| 7 | x < 0+1 when CompareGT: ... > ... is false |
| 7 | x < 1 when CompareGT: ... > ... is false |
| 7 | x >= 0+1 when CompareGT: ... > ... is true |
@@ -587,6 +753,10 @@ irGuardsCompare
| 17 | 0 >= x+1 when CompareLT: ... < ... is true |
| 17 | 1 < y+0 when CompareGT: ... > ... is true |
| 17 | 1 >= y+0 when CompareGT: ... > ... is false |
| 17 | ... < ... != 0 when CompareLT: ... < ... is true |
| 17 | ... < ... == 0 when CompareLT: ... < ... is false |
| 17 | ... > ... != 0 when CompareGT: ... > ... is true |
| 17 | ... > ... == 0 when CompareGT: ... > ... is false |
| 17 | x < 0 when CompareLT: ... < ... is true |
| 17 | x < 0+0 when CompareLT: ... < ... is true |
| 17 | x >= 0 when CompareLT: ... < ... is false |
@@ -599,24 +769,32 @@ irGuardsCompare
| 18 | call to get == 0 when CompareNE: (bool)... is false |
| 26 | 0 < x+0 when CompareGT: ... > ... is true |
| 26 | 0 >= x+0 when CompareGT: ... > ... is false |
| 26 | ... > ... != 0 when CompareGT: ... > ... is true |
| 26 | ... > ... == 0 when CompareGT: ... > ... is false |
| 26 | x < 0+1 when CompareGT: ... > ... is false |
| 26 | x < 1 when CompareGT: ... > ... is false |
| 26 | x >= 0+1 when CompareGT: ... > ... is true |
| 26 | x >= 1 when CompareGT: ... > ... is true |
| 31 | - ... != x+0 when CompareEQ: ... == ... is false |
| 31 | - ... == x+0 when CompareEQ: ... == ... is true |
| 31 | ... == ... != 0 when CompareEQ: ... == ... is true |
| 31 | ... == ... == 0 when CompareEQ: ... == ... is false |
| 31 | x != -1 when CompareEQ: ... == ... is false |
| 31 | x != - ...+0 when CompareEQ: ... == ... is false |
| 31 | x == -1 when CompareEQ: ... == ... is true |
| 31 | x == - ...+0 when CompareEQ: ... == ... is true |
| 34 | 10 < j+1 when CompareLT: ... < ... is false |
| 34 | 10 >= j+1 when CompareLT: ... < ... is true |
| 34 | ... < ... != 0 when CompareLT: ... < ... is true |
| 34 | ... < ... == 0 when CompareLT: ... < ... is false |
| 34 | j < 10 when CompareLT: ... < ... is true |
| 34 | j < 10+0 when CompareLT: ... < ... is true |
| 34 | j >= 10 when CompareLT: ... < ... is false |
| 34 | j >= 10+0 when CompareLT: ... < ... is false |
| 42 | 10 < j+1 when CompareLT: ... < ... is false |
| 42 | 10 >= j+1 when CompareLT: ... < ... is true |
| 42 | ... < ... != 0 when CompareLT: ... < ... is true |
| 42 | ... < ... == 0 when CompareLT: ... < ... is false |
| 42 | call to getABool != 0 when Call: call to getABool is true |
| 42 | call to getABool == 0 when Call: call to getABool is false |
| 42 | j < 10 when CompareLT: ... < ... is true |
@@ -625,12 +803,16 @@ irGuardsCompare
| 42 | j >= 10+0 when CompareLT: ... < ... is false |
| 44 | 0 < z+0 when CompareGT: ... > ... is true |
| 44 | 0 >= z+0 when CompareGT: ... > ... is false |
| 44 | ... > ... != 0 when CompareGT: ... > ... is true |
| 44 | ... > ... == 0 when CompareGT: ... > ... is false |
| 44 | z < 0+1 when CompareGT: ... > ... is false |
| 44 | z < 1 when CompareGT: ... > ... is false |
| 44 | z >= 0+1 when CompareGT: ... > ... is true |
| 44 | z >= 1 when CompareGT: ... > ... is true |
| 45 | 0 < y+0 when CompareGT: ... > ... is true |
| 45 | 0 >= y+0 when CompareGT: ... > ... is false |
| 45 | ... > ... != 0 when CompareGT: ... > ... is true |
| 45 | ... > ... == 0 when CompareGT: ... > ... is false |
| 45 | y < 0+1 when CompareGT: ... > ... is false |
| 45 | y < 1 when CompareGT: ... > ... is false |
| 45 | y >= 0+1 when CompareGT: ... > ... is true |
@@ -639,6 +821,10 @@ irGuardsCompare
| 58 | 0 < y+1 when CompareLT: ... < ... is false |
| 58 | 0 == x+0 when CompareEQ: ... == ... is true |
| 58 | 0 >= y+1 when CompareLT: ... < ... is true |
| 58 | ... < ... != 0 when CompareLT: ... < ... is true |
| 58 | ... < ... == 0 when CompareLT: ... < ... is false |
| 58 | ... == ... != 0 when CompareEQ: ... == ... is true |
| 58 | ... == ... == 0 when CompareEQ: ... == ... is false |
| 58 | x != 0 when CompareEQ: ... == ... is false |
| 58 | x != 0+0 when CompareEQ: ... == ... is false |
| 58 | x == 0 when CompareEQ: ... == ... is true |
@@ -649,6 +835,8 @@ irGuardsCompare
| 58 | y >= 0+0 when CompareLT: ... < ... is false |
| 75 | 0 != x+0 when CompareEQ: ... == ... is false |
| 75 | 0 == x+0 when CompareEQ: ... == ... is true |
| 75 | ... == ... != 0 when CompareEQ: ... == ... is true |
| 75 | ... == ... == 0 when CompareEQ: ... == ... is false |
| 75 | x != 0 when CompareEQ: ... == ... is false |
| 75 | x != 0+0 when CompareEQ: ... == ... is false |
| 75 | x == 0 when CompareEQ: ... == ... is true |
@@ -657,6 +845,10 @@ irGuardsCompare
| 85 | 0 != y+0 when CompareNE: ... != ... is true |
| 85 | 0 == x+0 when CompareEQ: ... == ... is true |
| 85 | 0 == y+0 when CompareNE: ... != ... is false |
| 85 | ... != ... != 0 when CompareNE: ... != ... is true |
| 85 | ... != ... == 0 when CompareNE: ... != ... is false |
| 85 | ... == ... != 0 when CompareEQ: ... == ... is true |
| 85 | ... == ... == 0 when CompareEQ: ... == ... is false |
| 85 | x != 0 when CompareEQ: ... == ... is false |
| 85 | x != 0+0 when CompareEQ: ... == ... is false |
| 85 | x == 0 when CompareEQ: ... == ... is true |
@@ -667,12 +859,16 @@ irGuardsCompare
| 85 | y == 0+0 when CompareNE: ... != ... is false |
| 94 | 0 != x+0 when CompareNE: ... != ... is true |
| 94 | 0 == x+0 when CompareNE: ... != ... is false |
| 94 | ... != ... != 0 when CompareNE: ... != ... is true |
| 94 | ... != ... == 0 when CompareNE: ... != ... is false |
| 94 | x != 0 when CompareNE: ... != ... is true |
| 94 | x != 0+0 when CompareNE: ... != ... is true |
| 94 | x == 0 when CompareNE: ... != ... is false |
| 94 | x == 0+0 when CompareNE: ... != ... is false |
| 102 | 10 < j+1 when CompareLT: ... < ... is false |
| 102 | 10 >= j+1 when CompareLT: ... < ... is true |
| 102 | ... < ... != 0 when CompareLT: ... < ... is true |
| 102 | ... < ... == 0 when CompareLT: ... < ... is false |
| 102 | j < 10 when CompareLT: ... < ... is true |
| 102 | j < 10+0 when CompareLT: ... < ... is true |
| 102 | j >= 10 when CompareLT: ... < ... is false |
@@ -681,6 +877,10 @@ irGuardsCompare
| 109 | 0 < y+1 when CompareLT: ... < ... is false |
| 109 | 0 == x+0 when CompareEQ: ... == ... is true |
| 109 | 0 >= y+1 when CompareLT: ... < ... is true |
| 109 | ... < ... != 0 when CompareLT: ... < ... is true |
| 109 | ... < ... == 0 when CompareLT: ... < ... is false |
| 109 | ... == ... != 0 when CompareEQ: ... == ... is true |
| 109 | ... == ... == 0 when CompareEQ: ... == ... is false |
| 109 | x != 0 when CompareEQ: ... == ... is false |
| 109 | x != 0+0 when CompareEQ: ... == ... is false |
| 109 | x == 0 when CompareEQ: ... == ... is true |
@@ -708,6 +908,8 @@ irGuardsCompare
| 152 | y == 0 when Load: y is false |
| 156 | ... + ... != x+0 when CompareEQ: ... == ... is false |
| 156 | ... + ... == x+0 when CompareEQ: ... == ... is true |
| 156 | ... == ... != 0 when CompareEQ: ... == ... is true |
| 156 | ... == ... == 0 when CompareEQ: ... == ... is false |
| 156 | x != ... + ...+0 when CompareEQ: ... == ... is false |
| 156 | x != y+42 when CompareEQ: ... == ... is false |
| 156 | x == ... + ...+0 when CompareEQ: ... == ... is true |
@@ -716,6 +918,8 @@ irGuardsCompare
| 156 | y == x+-42 when CompareEQ: ... == ... is true |
| 159 | ... - ... != x+0 when CompareEQ: ... == ... is false |
| 159 | ... - ... == x+0 when CompareEQ: ... == ... is true |
| 159 | ... == ... != 0 when CompareEQ: ... == ... is true |
| 159 | ... == ... == 0 when CompareEQ: ... == ... is false |
| 159 | x != ... - ...+0 when CompareEQ: ... == ... is false |
| 159 | x != y+-42 when CompareEQ: ... == ... is false |
| 159 | x == ... - ...+0 when CompareEQ: ... == ... is true |
@@ -724,6 +928,8 @@ irGuardsCompare
| 159 | y == x+42 when CompareEQ: ... == ... is true |
| 162 | ... + ... < x+1 when CompareLT: ... < ... is false |
| 162 | ... + ... >= x+1 when CompareLT: ... < ... is true |
| 162 | ... < ... != 0 when CompareLT: ... < ... is true |
| 162 | ... < ... == 0 when CompareLT: ... < ... is false |
| 162 | x < ... + ...+0 when CompareLT: ... < ... is true |
| 162 | x < y+42 when CompareLT: ... < ... is true |
| 162 | x >= ... + ...+0 when CompareLT: ... < ... is false |
@@ -732,6 +938,8 @@ irGuardsCompare
| 162 | y >= x+-41 when CompareLT: ... < ... is true |
| 165 | ... - ... < x+1 when CompareLT: ... < ... is false |
| 165 | ... - ... >= x+1 when CompareLT: ... < ... is true |
| 165 | ... < ... != 0 when CompareLT: ... < ... is true |
| 165 | ... < ... == 0 when CompareLT: ... < ... is false |
| 165 | x < ... - ...+0 when CompareLT: ... < ... is true |
| 165 | x < y+-42 when CompareLT: ... < ... is true |
| 165 | x >= ... - ...+0 when CompareLT: ... < ... is false |
@@ -740,6 +948,8 @@ irGuardsCompare
| 165 | y >= x+43 when CompareLT: ... < ... is true |
| 175 | 0 != call to foo+0 when CompareEQ: ... == ... is false |
| 175 | 0 == call to foo+0 when CompareEQ: ... == ... is true |
| 175 | ... == ... != 0 when CompareEQ: ... == ... is true |
| 175 | ... == ... == 0 when CompareEQ: ... == ... is false |
| 175 | call to foo != 0 when CompareEQ: ... == ... is false |
| 175 | call to foo != 0+0 when CompareEQ: ... == ... is false |
| 175 | call to foo == 0 when CompareEQ: ... == ... is true |
@@ -930,6 +1140,14 @@ irGuardsEnsure
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | == | test.c:75:14:75:14 | Constant: 0 | 0 | 76 | 76 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:14:75:14 | Constant: 0 | != | test.c:75:9:75:9 | Load: x | 0 | 79 | 79 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:14:75:14 | Constant: 0 | == | test.c:75:9:75:9 | Load: x | 0 | 76 | 76 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | != | test.c:85:13:85:13 | Constant: 0 | 0 | 79 | 79 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | test.c:85:13:85:13 | Constant: 0 | 0 | 76 | 76 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:85:13:85:13 | Constant: 0 | != | test.c:85:8:85:8 | Load: x | 0 | 79 | 79 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:85:13:85:13 | Constant: 0 | == | test.c:85:8:85:8 | Load: x | 0 | 76 | 76 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | == | test.c:75:14:75:14 | Constant: 0 | 0 | 85 | 85 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | == | test.c:75:14:75:14 | Constant: 0 | 0 | 86 | 86 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:75:14:75:14 | Constant: 0 | == | test.c:75:9:75:9 | Load: x | 0 | 85 | 85 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:75:14:75:14 | Constant: 0 | == | test.c:75:9:75:9 | Load: x | 0 | 86 | 86 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | test.c:85:13:85:13 | Constant: 0 | 0 | 85 | 85 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | test.c:85:13:85:13 | Constant: 0 | 0 | 86 | 86 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:13:85:13 | Constant: 0 | == | test.c:85:8:85:8 | Load: x | 0 | 85 | 85 |
@@ -1003,9 +1221,14 @@ irGuardsEnsure
irGuardsEnsure_const
| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:9:7:9 | Load: x | < | 1 | 11 | 11 |
| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:9:7:9 | Load: x | >= | 1 | 8 | 8 |
| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:9:7:13 | CompareGT: ... > ... | != | 0 | 8 | 8 |
| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:9:7:13 | CompareGT: ... > ... | == | 0 | 11 | 11 |
| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:8:17:8 | Load: x | < | 0 | 17 | 17 |
| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:8:17:8 | Load: x | < | 0 | 18 | 18 |
| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:8:17:12 | CompareLT: ... < ... | != | 0 | 17 | 17 |
| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:8:17:12 | CompareLT: ... < ... | != | 0 | 18 | 18 |
| test.c:17:17:17:21 | CompareGT: ... > ... | test.c:17:17:17:17 | Load: y | >= | 2 | 18 | 18 |
| test.c:17:17:17:21 | CompareGT: ... > ... | test.c:17:17:17:21 | CompareGT: ... > ... | != | 0 | 18 | 18 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | 1 | 2 | 2 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | 1 | 31 | 31 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | 1 | 34 | 34 |
@@ -1021,6 +1244,21 @@ irGuardsEnsure_const
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | 1 | 59 | 59 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | 1 | 62 | 62 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | >= | 1 | 27 | 27 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | != | 0 | 27 | 27 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 2 | 2 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 31 | 31 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 34 | 34 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 35 | 35 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 39 | 39 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 42 | 42 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 43 | 43 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 45 | 45 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 46 | 46 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 52 | 52 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 56 | 56 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 58 | 58 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 59 | 59 |
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:15 | CompareGT: ... > ... | == | 0 | 62 | 62 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | < | 10 | 35 | 35 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | 10 | 2 | 2 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | 10 | 39 | 39 |
@@ -1033,22 +1271,58 @@ irGuardsEnsure_const
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | 10 | 58 | 58 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | 10 | 59 | 59 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | 10 | 62 | 62 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | != | 0 | 35 | 35 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 2 | 2 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 39 | 39 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 42 | 42 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 43 | 43 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 45 | 45 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 46 | 46 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 52 | 52 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 56 | 56 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 58 | 58 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 59 | 59 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:21 | CompareLT: ... < ... | == | 0 | 62 | 62 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | 10 | 43 | 43 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | 10 | 45 | 45 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | 10 | 46 | 46 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | 10 | 52 | 52 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:21 | CompareLT: ... < ... | != | 0 | 43 | 43 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:21 | CompareLT: ... < ... | != | 0 | 45 | 45 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:21 | CompareLT: ... < ... | != | 0 | 46 | 46 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:21 | CompareLT: ... < ... | != | 0 | 52 | 52 |
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | < | 1 | 52 | 52 |
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | >= | 1 | 45 | 45 |
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | >= | 1 | 46 | 46 |
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:16 | CompareGT: ... > ... | != | 0 | 45 | 45 |
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:16 | CompareGT: ... > ... | != | 0 | 46 | 46 |
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:16 | CompareGT: ... > ... | == | 0 | 52 | 52 |
| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:16:45:16 | Load: y | >= | 1 | 46 | 46 |
| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:16:45:20 | CompareGT: ... > ... | != | 0 | 46 | 46 |
| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:9:58:9 | Load: x | != | 0 | 58 | 58 |
| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:9:58:9 | Load: x | != | 0 | 62 | 62 |
| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:9:58:14 | CompareEQ: ... == ... | == | 0 | 58 | 58 |
| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:9:58:14 | CompareEQ: ... == ... | == | 0 | 62 | 62 |
| test.c:58:19:58:23 | CompareLT: ... < ... | test.c:58:19:58:19 | Load: y | >= | 0 | 62 | 62 |
| test.c:58:19:58:23 | CompareLT: ... < ... | test.c:58:19:58:23 | CompareLT: ... < ... | == | 0 | 62 | 62 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | != | 0 | 79 | 79 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | == | 0 | 76 | 76 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:14 | CompareEQ: ... == ... | != | 0 | 76 | 76 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:14 | CompareEQ: ... == ... | == | 0 | 79 | 79 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | != | 0 | 79 | 79 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | 0 | 76 | 76 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:85:8:85:13 | CompareEQ: ... == ... | != | 0 | 76 | 76 |
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:85:8:85:13 | CompareEQ: ... == ... | == | 0 | 79 | 79 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | == | 0 | 85 | 85 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | == | 0 | 86 | 86 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:75:9:75:14 | CompareEQ: ... == ... | != | 0 | 85 | 85 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:75:9:75:14 | CompareEQ: ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | 0 | 85 | 85 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | 0 | 86 | 86 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:13 | CompareEQ: ... == ... | != | 0 | 85 | 85 |
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:13 | CompareEQ: ... == ... | != | 0 | 86 | 86 |
| test.c:85:18:85:23 | CompareNE: ... != ... | test.c:85:18:85:18 | Load: y | != | 0 | 86 | 86 |
| test.c:85:18:85:23 | CompareNE: ... != ... | test.c:85:18:85:23 | CompareNE: ... != ... | != | 0 | 86 | 86 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | != | 0 | 95 | 95 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | 0 | 70 | 70 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | 0 | 99 | 99 |
@@ -1058,34 +1332,78 @@ irGuardsEnsure_const
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | 0 | 109 | 109 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | 0 | 110 | 110 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | 0 | 113 | 113 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | != | 0 | 95 | 95 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | == | 0 | 70 | 70 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | == | 0 | 99 | 99 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | == | 0 | 102 | 102 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | == | 0 | 103 | 103 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | == | 0 | 107 | 107 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | == | 0 | 109 | 109 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | == | 0 | 110 | 110 |
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:16 | CompareNE: ... != ... | == | 0 | 113 | 113 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | < | 10 | 103 | 103 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | 10 | 70 | 70 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | 10 | 107 | 107 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | 10 | 109 | 109 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | 10 | 110 | 110 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | 10 | 113 | 113 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:21 | CompareLT: ... < ... | != | 0 | 103 | 103 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:21 | CompareLT: ... < ... | == | 0 | 70 | 70 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:21 | CompareLT: ... < ... | == | 0 | 107 | 107 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:21 | CompareLT: ... < ... | == | 0 | 109 | 109 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:21 | CompareLT: ... < ... | == | 0 | 110 | 110 |
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:21 | CompareLT: ... < ... | == | 0 | 113 | 113 |
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 109 | 109 |
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 113 | 113 |
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:14 | CompareEQ: ... == ... | == | 0 | 109 | 109 |
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:14 | CompareEQ: ... == ... | == | 0 | 113 | 113 |
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | 0 | 113 | 113 |
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:23 | CompareLT: ... < ... | == | 0 | 113 | 113 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 127 | 127 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 132 | 132 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 134 | 134 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:5:127:9 | Store: ... = ... | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:5:127:9 | Store: ... = ... | != | 0 | 127 | 127 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:5:127:9 | Store: ... = ... | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:5:127:9 | Store: ... = ... | != | 0 | 132 | 132 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:5:127:9 | Store: ... = ... | != | 0 | 134 | 134 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:9:127:9 | Constant: 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:9:127:9 | Constant: 1 | != | 0 | 127 | 127 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:9:127:9 | Constant: 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:9:127:9 | Constant: 1 | != | 0 | 132 | 132 |
| test.c:126:7:126:7 | Constant: 1 | test.c:127:9:127:9 | Constant: 1 | != | 0 | 134 | 134 |
| test.c:126:12:126:26 | Call: call to test3_condition | test.c:126:12:126:26 | Call: call to test3_condition | != | 0 | 127 | 127 |
| test.c:131:7:131:7 | Load: b | test.c:131:7:131:7 | Load: b | != | 0 | 132 | 132 |
| test.c:131:7:131:7 | Load: b | test.c:131:7:131:7 | Phi: b | != | 0 | 132 | 132 |
| test.c:137:7:137:7 | Constant: 0 | test.c:137:7:137:7 | Constant: 0 | == | 0 | 142 | 142 |
| test.c:146:7:146:8 | LogicalNot: ! ... | test.c:146:7:146:8 | LogicalNot: ! ... | != | 0 | 147 | 147 |
| test.c:146:8:146:8 | Load: x | test.c:145:16:145:16 | InitializeParameter: x | == | 0 | 147 | 147 |
| test.c:146:8:146:8 | Load: x | test.c:146:8:146:8 | Load: x | == | 0 | 147 | 147 |
| test.c:152:10:152:10 | Load: x | test.c:151:16:151:16 | InitializeParameter: x | != | 0 | 152 | 152 |
| test.c:152:10:152:10 | Load: x | test.c:152:10:152:10 | Load: x | != | 0 | 152 | 152 |
| test.c:152:15:152:15 | Load: y | test.c:151:23:151:23 | InitializeParameter: y | != | 0 | 152 | 152 |
| test.c:152:15:152:15 | Load: y | test.c:152:15:152:15 | Load: y | != | 0 | 152 | 152 |
| test.c:156:9:156:19 | CompareEQ: ... == ... | test.c:156:9:156:19 | CompareEQ: ... == ... | != | 0 | 156 | 157 |
| test.c:159:9:159:19 | CompareEQ: ... == ... | test.c:159:9:159:19 | CompareEQ: ... == ... | != | 0 | 159 | 160 |
| test.c:162:9:162:18 | CompareLT: ... < ... | test.c:162:9:162:18 | CompareLT: ... < ... | != | 0 | 162 | 163 |
| test.c:165:9:165:18 | CompareLT: ... < ... | test.c:165:9:165:18 | CompareLT: ... < ... | != | 0 | 165 | 166 |
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | != | 0 | 175 | 175 |
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | == | 0 | 175 | 175 |
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:32 | CompareEQ: ... == ... | != | 0 | 175 | 175 |
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:32 | CompareEQ: ... == ... | == | 0 | 175 | 175 |
| test.c:181:9:181:9 | Load: x | test.c:180:20:180:20 | InitializeParameter: x | != | 0 | 182 | 182 |
| test.c:181:9:181:9 | Load: x | test.c:180:20:180:20 | InitializeParameter: x | == | 0 | 184 | 184 |
| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | != | 0 | 182 | 182 |
| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | == | 0 | 184 | 184 |
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | 0 | 19 | 19 |
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:12 | CompareNE: (bool)... | != | 0 | 19 | 19 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:13 | CompareEQ: ... == ... | != | 0 | 30 | 30 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:13 | CompareEQ: ... == ... | != | 0 | 32 | 32 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:13 | CompareEQ: ... == ... | == | 0 | 34 | 34 |
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | != | 0 | 44 | 44 |
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | == | 0 | 53 | 53 |

View File

@@ -1,5 +1,7 @@
| 7 | 0 < x+0 when ... > ... is true |
| 7 | 0 >= x+0 when ... > ... is false |
| 7 | ... > ... != 0 when ... > ... is true |
| 7 | ... > ... == 0 when ... > ... is false |
| 7 | x < 0+1 when ... > ... is false |
| 7 | x < 1 when ... > ... is false |
| 7 | x >= 0+1 when ... > ... is true |
@@ -10,6 +12,12 @@
| 17 | 1 < y+0 when ... && ... is true |
| 17 | 1 < y+0 when ... > ... is true |
| 17 | 1 >= y+0 when ... > ... is false |
| 17 | ... < ... != 0 when ... && ... is true |
| 17 | ... < ... != 0 when ... < ... is true |
| 17 | ... < ... == 0 when ... < ... is false |
| 17 | ... > ... != 0 when ... && ... is true |
| 17 | ... > ... != 0 when ... > ... is true |
| 17 | ... > ... == 0 when ... > ... is false |
| 17 | x < 0 when ... && ... is true |
| 17 | x < 0 when ... < ... is true |
| 17 | x < 0+0 when ... && ... is true |
@@ -26,24 +34,32 @@
| 18 | call to get == 0 when call to get is false |
| 26 | 0 < x+0 when ... > ... is true |
| 26 | 0 >= x+0 when ... > ... is false |
| 26 | ... > ... != 0 when ... > ... is true |
| 26 | ... > ... == 0 when ... > ... is false |
| 26 | x < 0+1 when ... > ... is false |
| 26 | x < 1 when ... > ... is false |
| 26 | x >= 0+1 when ... > ... is true |
| 26 | x >= 1 when ... > ... is true |
| 31 | - ... != x+0 when ... == ... is false |
| 31 | - ... == x+0 when ... == ... is true |
| 31 | ... == ... != 0 when ... == ... is true |
| 31 | ... == ... == 0 when ... == ... is false |
| 31 | x != -1 when ... == ... is false |
| 31 | x != - ...+0 when ... == ... is false |
| 31 | x == -1 when ... == ... is true |
| 31 | x == - ...+0 when ... == ... is true |
| 34 | 10 < j+1 when ... < ... is false |
| 34 | 10 >= j+1 when ... < ... is true |
| 34 | ... < ... != 0 when ... < ... is true |
| 34 | ... < ... == 0 when ... < ... is false |
| 34 | j < 10 when ... < ... is true |
| 34 | j < 10+0 when ... < ... is true |
| 34 | j >= 10 when ... < ... is false |
| 34 | j >= 10+0 when ... < ... is false |
| 42 | 10 < j+1 when ... < ... is false |
| 42 | 10 >= j+1 when ... < ... is true |
| 42 | ... < ... != 0 when ... < ... is true |
| 42 | ... < ... == 0 when ... < ... is false |
| 42 | call to getABool != 0 when call to getABool is true |
| 42 | call to getABool == 0 when call to getABool is false |
| 42 | j < 10 when ... < ... is true |
@@ -52,12 +68,16 @@
| 42 | j >= 10+0 when ... < ... is false |
| 44 | 0 < z+0 when ... > ... is true |
| 44 | 0 >= z+0 when ... > ... is false |
| 44 | ... > ... != 0 when ... > ... is true |
| 44 | ... > ... == 0 when ... > ... is false |
| 44 | z < 0+1 when ... > ... is false |
| 44 | z < 1 when ... > ... is false |
| 44 | z >= 0+1 when ... > ... is true |
| 44 | z >= 1 when ... > ... is true |
| 45 | 0 < y+0 when ... > ... is true |
| 45 | 0 >= y+0 when ... > ... is false |
| 45 | ... > ... != 0 when ... > ... is true |
| 45 | ... > ... == 0 when ... > ... is false |
| 45 | y < 0+1 when ... > ... is false |
| 45 | y < 1 when ... > ... is false |
| 45 | y >= 0+1 when ... > ... is true |
@@ -68,6 +88,12 @@
| 58 | 0 < y+1 when ... \|\| ... is false |
| 58 | 0 == x+0 when ... == ... is true |
| 58 | 0 >= y+1 when ... < ... is true |
| 58 | ... < ... != 0 when ... < ... is true |
| 58 | ... < ... == 0 when ... < ... is false |
| 58 | ... < ... == 0 when ... \|\| ... is false |
| 58 | ... == ... != 0 when ... == ... is true |
| 58 | ... == ... == 0 when ... == ... is false |
| 58 | ... == ... == 0 when ... \|\| ... is false |
| 58 | x != 0 when ... == ... is false |
| 58 | x != 0 when ... \|\| ... is false |
| 58 | x != 0+0 when ... == ... is false |
@@ -89,6 +115,8 @@
| 74 | i >= 11 when i is Case[11..20] |
| 75 | 0 != x+0 when ... == ... is false |
| 75 | 0 == x+0 when ... == ... is true |
| 75 | ... == ... != 0 when ... == ... is true |
| 75 | ... == ... == 0 when ... == ... is false |
| 75 | x != 0 when ... == ... is false |
| 75 | x != 0+0 when ... == ... is false |
| 75 | x == 0 when ... == ... is true |
@@ -99,6 +127,12 @@
| 85 | 0 == x+0 when ... && ... is true |
| 85 | 0 == x+0 when ... == ... is true |
| 85 | 0 == y+0 when ... != ... is false |
| 85 | ... != ... != 0 when ... != ... is true |
| 85 | ... != ... != 0 when ... && ... is true |
| 85 | ... != ... == 0 when ... != ... is false |
| 85 | ... == ... != 0 when ... && ... is true |
| 85 | ... == ... != 0 when ... == ... is true |
| 85 | ... == ... == 0 when ... == ... is false |
| 85 | x != 0 when ... == ... is false |
| 85 | x != 0+0 when ... == ... is false |
| 85 | x == 0 when ... && ... is true |
@@ -115,18 +149,26 @@
| 93 | c == 0 when c is false |
| 94 | 0 != x+0 when ... != ... is true |
| 94 | 0 == x+0 when ... != ... is false |
| 94 | ... != ... != 0 when ... != ... is true |
| 94 | ... != ... == 0 when ... != ... is false |
| 94 | x != 0 when ... != ... is true |
| 94 | x != 0+0 when ... != ... is true |
| 94 | x == 0 when ... != ... is false |
| 94 | x == 0+0 when ... != ... is false |
| 99 | f != 0 when f is true |
| 99 | f == 0 when f is false |
| 102 | 10 < j+1 when ... < ... is false |
| 102 | 10 >= j+1 when ... < ... is true |
| 102 | ... < ... != 0 when ... < ... is true |
| 102 | ... < ... == 0 when ... < ... is false |
| 102 | j < 10 when ... < ... is true |
| 102 | j < 10+0 when ... < ... is true |
| 102 | j >= 10 when ... < ... is false |
| 102 | j >= 10+0 when ... < ... is false |
| 105 | 0.0 != f+0 when ... != ... is true |
| 105 | 0.0 == f+0 when ... != ... is false |
| 105 | ... != ... != 0 when ... != ... is true |
| 105 | ... != ... == 0 when ... != ... is false |
| 105 | f != 0.0+0 when ... != ... is true |
| 105 | f == 0.0+0 when ... != ... is false |
| 109 | 0 != x+0 when ... == ... is false |
@@ -135,6 +177,12 @@
| 109 | 0 < y+1 when ... \|\| ... is false |
| 109 | 0 == x+0 when ... == ... is true |
| 109 | 0 >= y+1 when ... < ... is true |
| 109 | ... < ... != 0 when ... < ... is true |
| 109 | ... < ... == 0 when ... < ... is false |
| 109 | ... < ... == 0 when ... \|\| ... is false |
| 109 | ... == ... != 0 when ... == ... is true |
| 109 | ... == ... == 0 when ... == ... is false |
| 109 | ... == ... == 0 when ... \|\| ... is false |
| 109 | x != 0 when ... == ... is false |
| 109 | x != 0 when ... \|\| ... is false |
| 109 | x != 0+0 when ... == ... is false |
@@ -149,6 +197,8 @@
| 109 | y >= 0+0 when ... \|\| ... is false |
| 111 | 0.0 != i+0 when ... != ... is true |
| 111 | 0.0 == i+0 when ... != ... is false |
| 111 | ... != ... != 0 when ... != ... is true |
| 111 | ... != ... == 0 when ... != ... is false |
| 111 | i != 0.0+0 when ... != ... is true |
| 111 | i == 0.0+0 when ... != ... is false |
| 122 | b != 0 when b is true |
@@ -166,6 +216,8 @@
| 126 | call to test3_condition == 0 when call to test3_condition is false |
| 131 | ... + ... != a+0 when call to __builtin_expect is false |
| 131 | ... + ... == a+0 when call to __builtin_expect is true |
| 131 | ... == ... != 0 when call to __builtin_expect is true |
| 131 | ... == ... == 0 when call to __builtin_expect is false |
| 131 | a != ... + ...+0 when call to __builtin_expect is false |
| 131 | a != b+42 when call to __builtin_expect is false |
| 131 | a == ... + ...+0 when call to __builtin_expect is true |
@@ -176,6 +228,8 @@
| 131 | b == a+-42 when call to __builtin_expect is true |
| 131 | call to __builtin_expect != 0 when call to __builtin_expect is true |
| 131 | call to __builtin_expect == 0 when call to __builtin_expect is false |
| 135 | ... != ... != 0 when call to __builtin_expect is true |
| 135 | ... != ... == 0 when call to __builtin_expect is false |
| 135 | ... + ... != a+0 when call to __builtin_expect is true |
| 135 | ... + ... == a+0 when call to __builtin_expect is false |
| 135 | a != ... + ...+0 when call to __builtin_expect is true |
@@ -190,6 +244,8 @@
| 137 | 0 == 0 when 0 is false |
| 141 | 42 != a+0 when call to __builtin_expect is false |
| 141 | 42 == a+0 when call to __builtin_expect is true |
| 141 | ... == ... != 0 when call to __builtin_expect is true |
| 141 | ... == ... == 0 when call to __builtin_expect is false |
| 141 | a != 42 when call to __builtin_expect is false |
| 141 | a != 42+0 when call to __builtin_expect is false |
| 141 | a == 42 when call to __builtin_expect is true |
@@ -198,6 +254,8 @@
| 141 | call to __builtin_expect == 0 when call to __builtin_expect is false |
| 145 | 42 != a+0 when call to __builtin_expect is true |
| 145 | 42 == a+0 when call to __builtin_expect is false |
| 145 | ... != ... != 0 when call to __builtin_expect is true |
| 145 | ... != ... == 0 when call to __builtin_expect is false |
| 145 | a != 42 when call to __builtin_expect is true |
| 145 | a != 42+0 when call to __builtin_expect is true |
| 145 | a == 42 when call to __builtin_expect is false |

View File

@@ -99,10 +99,20 @@ binary
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:75:14:75:14 | 0 | != | test.c:75:9:75:9 | x | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:8 | x | != | test.c:85:13:85:13 | 0 | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:85:13:85:13 | 0 | != | test.c:85:8:85:8 | x | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 75 | 77 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:18 | y | != | test.c:85:23:85:23 | 0 | 0 | 86 | 86 |
@@ -174,11 +184,18 @@ binary
unary
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | 1 | 10 | 11 |
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | 1 | 7 | 9 |
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:13 | ... > ... | != | 0 | 7 | 9 |
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:13 | ... > ... | == | 0 | 10 | 11 |
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | 0 | 17 | 17 |
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | 0 | 18 | 18 |
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:12 | ... < ... | != | 0 | 17 | 17 |
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:12 | ... < ... | != | 0 | 18 | 18 |
| test.c:17:8:17:21 | ... && ... | test.c:17:8:17:8 | x | < | 0 | 18 | 18 |
| test.c:17:8:17:21 | ... && ... | test.c:17:8:17:12 | ... < ... | != | 0 | 18 | 18 |
| test.c:17:8:17:21 | ... && ... | test.c:17:17:17:17 | y | >= | 2 | 18 | 18 |
| test.c:17:8:17:21 | ... && ... | test.c:17:17:17:21 | ... > ... | != | 0 | 18 | 18 |
| test.c:17:17:17:21 | ... > ... | test.c:17:17:17:17 | y | >= | 2 | 18 | 18 |
| test.c:17:17:17:21 | ... > ... | test.c:17:17:17:21 | ... > ... | != | 0 | 18 | 18 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 2 | 2 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 31 | 34 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 34 | 34 |
@@ -193,6 +210,20 @@ unary
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 58 | 66 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 62 | 62 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | >= | 1 | 26 | 28 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | != | 0 | 26 | 28 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 2 | 2 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 31 | 34 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 34 | 34 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 39 | 42 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 42 | 42 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 42 | 44 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 45 | 45 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 45 | 47 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 51 | 53 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 56 | 58 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 58 | 58 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 58 | 66 |
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:15 | ... > ... | == | 0 | 62 | 62 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | < | 10 | 34 | 34 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 2 | 2 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 39 | 42 |
@@ -205,28 +236,72 @@ unary
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 58 | 58 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 58 | 66 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 62 | 62 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | != | 0 | 34 | 34 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 2 | 2 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 39 | 42 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 42 | 42 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 42 | 44 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 45 | 45 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 45 | 47 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 51 | 53 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 56 | 58 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 58 | 58 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 58 | 66 |
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:21 | ... < ... | == | 0 | 62 | 62 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 42 | 42 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 42 | 44 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 45 | 45 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 45 | 47 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 51 | 53 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 42 | 42 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 42 | 44 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 45 | 45 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 45 | 47 |
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:21 | ... < ... | != | 0 | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | 1 | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | 1 | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | 1 | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | 1 | 45 | 47 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:16 | ... > ... | != | 0 | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:16 | ... > ... | != | 0 | 45 | 47 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:16 | ... > ... | == | 0 | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:16 | ... > ... | == | 0 | 51 | 53 |
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | >= | 1 | 45 | 47 |
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:20 | ... > ... | != | 0 | 45 | 47 |
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | 0 | 58 | 58 |
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | 0 | 62 | 62 |
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:14 | ... == ... | == | 0 | 58 | 58 |
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:14 | ... == ... | == | 0 | 62 | 62 |
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:9:58:9 | x | != | 0 | 62 | 62 |
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:9:58:14 | ... == ... | == | 0 | 62 | 62 |
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:19:58:19 | y | >= | 0 | 62 | 62 |
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:19:58:23 | ... < ... | == | 0 | 62 | 62 |
| test.c:58:19:58:23 | ... < ... | test.c:58:19:58:19 | y | >= | 0 | 62 | 62 |
| test.c:58:19:58:23 | ... < ... | test.c:58:19:58:23 | ... < ... | == | 0 | 62 | 62 |
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | != | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | == | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:14 | ... == ... | != | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:14 | ... == ... | == | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:8 | x | != | 0 | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:13 | ... == ... | != | 0 | 75 | 77 |
| test.c:75:9:75:14 | ... == ... | test.c:85:8:85:13 | ... == ... | == | 0 | 78 | 79 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:9 | x | == | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:9 | x | == | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:14 | ... == ... | != | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:75:9:75:14 | ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 86 | 86 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:13 | ... == ... | != | 0 | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:13 | ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:75:9:75:9 | x | == | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:75:9:75:14 | ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:8 | x | == | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:13 | ... == ... | != | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:18 | y | != | 0 | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:23 | ... != ... | != | 0 | 86 | 86 |
| test.c:85:18:85:23 | ... != ... | test.c:85:18:85:18 | y | != | 0 | 86 | 86 |
| test.c:85:18:85:23 | ... != ... | test.c:85:18:85:23 | ... != ... | != | 0 | 86 | 86 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | != | 0 | 94 | 96 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 70 | 70 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 99 | 102 |
@@ -235,24 +310,49 @@ unary
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 109 | 109 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 109 | 117 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 113 | 113 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | != | 0 | 94 | 96 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 70 | 70 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 99 | 102 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 102 | 102 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 107 | 109 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 109 | 109 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 109 | 117 |
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:16 | ... != ... | == | 0 | 113 | 113 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | < | 10 | 102 | 102 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 70 | 70 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 107 | 109 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 109 | 109 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 109 | 117 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 113 | 113 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | != | 0 | 102 | 102 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 70 | 70 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 107 | 109 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 109 | 109 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 109 | 117 |
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:21 | ... < ... | == | 0 | 113 | 113 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:14 | ... == ... | == | 0 | 109 | 109 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:14 | ... == ... | == | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:14 | ... == ... | == | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:23 | ... < ... | == | 0 | 113 | 113 |
| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:23 | ... < ... | == | 0 | 113 | 113 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 131 | 132 |
| test.c:126:7:126:7 | 1 | test.c:127:9:127:9 | 1 | != | 0 | 134 | 123 |
| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
| test.c:126:7:126:28 | ... && ... | test.c:127:9:127:9 | 1 | != | 0 | 126 | 128 |
| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
@@ -269,6 +369,10 @@ unary
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:13 | ... == ... | != | 0 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:13 | ... == ... | != | 0 | 31 | 32 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:13 | ... == ... | == | 0 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:13 | ... == ... | == | 0 | 34 | 34 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 0 | 62 | 64 |
@@ -278,13 +382,20 @@ unary
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 0 | 75 | 77 |
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 |
| test.cpp:93:6:93:6 | c | test.cpp:93:6:93:6 | c | != | 0 | 93 | 94 |
| test.cpp:99:6:99:6 | f | test.cpp:99:6:99:6 | f | != | 0 | 99 | 100 |
| test.cpp:105:6:105:14 | ... != ... | test.cpp:105:6:105:14 | ... != ... | != | 0 | 105 | 106 |
| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:6:111:14 | ... != ... | != | 0 | 111 | 112 |
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 123 | 125 |
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 125 | 125 |
| test.cpp:125:13:125:20 | ! ... | test.cpp:125:13:125:20 | ! ... | != | 0 | 125 | 125 |
| test.cpp:125:14:125:17 | call to safe | test.cpp:125:14:125:17 | call to safe | == | 0 | 125 | 125 |
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:6:131:21 | call to __builtin_expect | != | 0 | 131 | 132 |
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:23:131:33 | ... == ... | != | 0 | 131 | 132 |
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:6:135:21 | call to __builtin_expect | != | 0 | 135 | 136 |
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:23:135:33 | ... != ... | != | 0 | 135 | 136 |
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:6:141:21 | call to __builtin_expect | != | 0 | 141 | 142 |
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:23:141:23 | a | == | 42 | 141 | 142 |
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:23:141:29 | ... == ... | != | 0 | 141 | 142 |
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:6:145:21 | call to __builtin_expect | != | 0 | 145 | 146 |
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:23:145:23 | a | != | 42 | 145 | 146 |
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:23:145:29 | ... != ... | != | 0 | 145 | 146 |

View File

@@ -56,7 +56,7 @@ union MyUnion0 {
// Typedef
typedef MyClass0 *MyClassPtr;
// TemplateClass, TemplateParameter (UserType)
// TemplateClass, TypeTemplateParameter (UserType)
template <typename T>
class myTemplateClass
@@ -113,7 +113,7 @@ public:
// Typedef
typedef MyClass1 *MyClassPtr;
// TemplateClass, TemplateParameter (UserType)
// TemplateClass, TypeTemplateParameter (UserType)
template <typename T>
class myTemplateClass

View File

@@ -9016,9 +9016,9 @@ ir.cpp:
# 704| [TemplateFunction,TopLevelFunction] T min<T>(T, T)
# 704| <params>:
# 704| getParameter(0): [Parameter] x
# 704| Type = [TemplateParameter] T
# 704| Type = [TypeTemplateParameter] T
# 704| getParameter(1): [Parameter] y
# 704| Type = [TemplateParameter] T
# 704| Type = [TypeTemplateParameter] T
# 704| getEntryPoint(): [BlockStmt] { ... }
# 705| getStmt(0): [ReturnStmt] return ...
# 705| getExpr(): [ConditionalExpr] ... ? ... : ...
@@ -9028,16 +9028,16 @@ ir.cpp:
# 705| Type = [UnknownType] unknown
# 705| ValueCategory = prvalue
# 705| getLesserOperand(): [VariableAccess] x
# 705| Type = [TemplateParameter] T
# 705| Type = [TypeTemplateParameter] T
# 705| ValueCategory = lvalue
# 705| getGreaterOperand(): [VariableAccess] y
# 705| Type = [TemplateParameter] T
# 705| Type = [TypeTemplateParameter] T
# 705| ValueCategory = lvalue
# 705| getThen(): [VariableAccess] x
# 705| Type = [TemplateParameter] T
# 705| Type = [TypeTemplateParameter] T
# 705| ValueCategory = lvalue
# 705| getElse(): [VariableAccess] y
# 705| Type = [TemplateParameter] T
# 705| Type = [TypeTemplateParameter] T
# 705| ValueCategory = lvalue
# 705| getCondition().getFullyConverted(): [CStyleCast] (bool)...
# 705| Conversion = [BoolConversion] conversion to bool
@@ -9095,24 +9095,24 @@ ir.cpp:
# 715| [MemberFunction,TemplateFunction] T Outer<T>::Func<U, V>(U, V)
# 715| <params>:
# 715| getParameter(0): [Parameter] x
# 715| Type = [TemplateParameter] U
# 715| Type = [TypeTemplateParameter] U
# 715| getParameter(1): [Parameter] y
# 715| Type = [TemplateParameter] V
# 715| Type = [TypeTemplateParameter] V
# 715| getEntryPoint(): [BlockStmt] { ... }
# 716| getStmt(0): [ReturnStmt] return ...
# 716| getExpr(): [Literal] 0
# 716| Type = [TemplateParameter] T
# 716| Type = [TypeTemplateParameter] T
# 716| Value = [Literal] 0
# 716| ValueCategory = prvalue
# 716| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 716| Type = [TemplateParameter] T
# 716| Type = [TypeTemplateParameter] T
# 716| ValueCategory = prvalue(load)
# 715| [MemberFunction,TemplateFunction] long Outer<long>::Func<U, V>(U, V)
# 715| <params>:
# 715| getParameter(0): [Parameter] x
# 715| Type = [TemplateParameter] U
# 715| Type = [TypeTemplateParameter] U
# 715| getParameter(1): [Parameter] y
# 715| Type = [TemplateParameter] V
# 715| Type = [TypeTemplateParameter] V
# 715| [FunctionTemplateInstantiation,MemberFunction] long Outer<long>::Func<void*, char>(void*, char)
# 715| <params>:
# 715| getParameter(0): [Parameter] x
@@ -12559,7 +12559,7 @@ ir.cpp:
# 1109| [Constructor] void std::vector<T>::vector(T)
# 1109| <params>:
# 1109| getParameter(0): [Parameter] (unnamed parameter 0)
# 1109| Type = [TemplateParameter] T
# 1109| Type = [TypeTemplateParameter] T
# 1109| [Constructor] void std::vector<char>::vector(char)
# 1109| <params>:
# 1109| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -12601,15 +12601,15 @@ ir.cpp:
# 1120| [Operator,TemplateFunction,TopLevelFunction] bool std::operator==<T>(iterator, iterator)
# 1120| <params>:
# 1120| getParameter(0): [Parameter] left
# 1120| Type = [TemplateParameter] iterator
# 1120| Type = [TypeTemplateParameter] iterator
# 1120| getParameter(1): [Parameter] right
# 1120| Type = [TemplateParameter] iterator
# 1120| Type = [TypeTemplateParameter] iterator
# 1122| [Operator,TemplateFunction,TopLevelFunction] bool std::operator!=<T>(iterator, iterator)
# 1122| <params>:
# 1122| getParameter(0): [Parameter] left
# 1122| Type = [TemplateParameter] iterator
# 1122| Type = [TypeTemplateParameter] iterator
# 1122| getParameter(1): [Parameter] right
# 1122| Type = [TemplateParameter] iterator
# 1122| Type = [TypeTemplateParameter] iterator
# 1126| [TopLevelFunction] void RangeBasedFor(std::vector<int> const&)
# 1126| <params>:
# 1126| getParameter(0): [Parameter] v
@@ -14129,11 +14129,11 @@ ir.cpp:
# 1375| getEntryPoint(): [BlockStmt] { ... }
# 1376| getStmt(0): [ReturnStmt] return ...
# 1376| getExpr(): [Literal] 0
# 1376| Type = [TemplateParameter] T
# 1376| Type = [TypeTemplateParameter] T
# 1376| Value = [Literal] 0
# 1376| ValueCategory = prvalue
# 1376| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 1376| Type = [TemplateParameter] T
# 1376| Type = [TypeTemplateParameter] T
# 1376| ValueCategory = prvalue(load)
# 1375| [FunctionTemplateInstantiation,TopLevelFunction] copy_constructor defaultConstruct<copy_constructor>()
# 1375| <params>:
@@ -14223,7 +14223,7 @@ ir.cpp:
# 1409| [TemplateFunction,TopLevelFunction] void acceptValue<T>(T)
# 1409| <params>:
# 1409| getParameter(0): [Parameter] v
# 1409| Type = [TemplateParameter] T
# 1409| Type = [TypeTemplateParameter] T
# 1409| [FunctionTemplateInstantiation,TopLevelFunction] void acceptValue<copy_constructor>(copy_constructor)
# 1409| <params>:
# 1409| getParameter(0): [Parameter] v
@@ -20584,7 +20584,7 @@ ir.cpp:
# 2256| Type = [LValueReferenceType] T &
# 2256| ValueCategory = prvalue(load)
# 2256| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2256| Type = [TemplateParameter] T
# 2256| Type = [TypeTemplateParameter] T
# 2256| ValueCategory = lvalue
# 2256| [FunctionTemplateInstantiation,TopLevelFunction] int& vacuous_destructor_call::get<int>(int&)
# 2256| <params>:
@@ -20648,7 +20648,7 @@ ir.cpp:
# 2260| Type = [LValueReferenceType] T &
# 2260| ValueCategory = prvalue(load)
# 2260| getArgument(0).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2260| Type = [TemplateParameter] T
# 2260| Type = [TypeTemplateParameter] T
# 2260| ValueCategory = lvalue
# 2261| getStmt(1): [ReturnStmt] return ...
# 2259| [FunctionTemplateInstantiation,TopLevelFunction] void vacuous_destructor_call::call_destructor<int>(int&)

View File

@@ -1,4 +1,4 @@
| proxy_class.cpp:1:8:1:11 | Base | Struct |
| proxy_class.cpp:3:20:3:20 | T | ProxyClass |
| proxy_class.cpp:3:20:3:20 | T | TemplateParameter |
| proxy_class.cpp:3:20:3:20 | T | TypeTemplateParameter |
| proxy_class.cpp:4:8:4:14 | Derived<Base> | Struct |

View File

@@ -3,7 +3,7 @@ import cpp
string clazz(Declaration d) {
d instanceof ProxyClass and result = "ProxyClass"
or
d instanceof TemplateParameter and result = "TemplateParameter"
d instanceof TypeTemplateParameter and result = "TypeTemplateParameter"
or
d instanceof Struct and result = "Struct"
}

View File

@@ -52,6 +52,9 @@ edges
| test.cpp:541:39:541:40 | sscanf output argument | test.cpp:549:8:549:8 | e | provenance | |
| test.cpp:541:43:541:44 | sscanf output argument | test.cpp:545:8:545:8 | f | provenance | |
| test.cpp:541:43:541:44 | sscanf output argument | test.cpp:550:8:550:8 | f | provenance | |
| test.cpp:559:30:559:31 | scanf output argument | test.cpp:561:9:561:9 | i | provenance | |
| test.cpp:567:35:567:36 | scanf output argument | test.cpp:569:9:569:9 | i | provenance | |
| test.cpp:575:30:575:31 | scanf output argument | test.cpp:577:9:577:9 | i | provenance | |
nodes
| test.cpp:34:15:34:16 | scanf output argument | semmle.label | scanf output argument |
| test.cpp:35:7:35:7 | i | semmle.label | i |
@@ -154,6 +157,12 @@ nodes
| test.cpp:548:8:548:8 | d | semmle.label | d |
| test.cpp:549:8:549:8 | e | semmle.label | e |
| test.cpp:550:8:550:8 | f | semmle.label | f |
| test.cpp:559:30:559:31 | scanf output argument | semmle.label | scanf output argument |
| test.cpp:561:9:561:9 | i | semmle.label | i |
| test.cpp:567:35:567:36 | scanf output argument | semmle.label | scanf output argument |
| test.cpp:569:9:569:9 | i | semmle.label | i |
| test.cpp:575:30:575:31 | scanf output argument | semmle.label | scanf output argument |
| test.cpp:577:9:577:9 | i | semmle.label | i |
subpaths
#select
| test.cpp:35:7:35:7 | i | test.cpp:34:15:34:16 | scanf output argument | test.cpp:35:7:35: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:34:3:34:7 | call to scanf | call to scanf |
@@ -177,3 +186,5 @@ subpaths
| test.cpp:484:9:484:9 | i | test.cpp:480:25:480:26 | scanf output argument | test.cpp:484:9:484:9 | 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:480:13:480:17 | call to scanf | call to scanf |
| test.cpp:495:8:495:8 | i | test.cpp:491:25:491:26 | scanf output argument | test.cpp:495:8:495:8 | 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:491:13:491:17 | call to scanf | call to scanf |
| test.cpp:545:8:545:8 | f | test.cpp:541:43:541:44 | sscanf output argument | test.cpp:545:8:545:8 | f | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 3. | test.cpp:541:10:541:15 | call to sscanf | call to sscanf |
| test.cpp:569:9:569:9 | i | test.cpp:567:35:567:36 | scanf output argument | test.cpp:569:9:569:9 | 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:567:23:567:27 | call to scanf | call to scanf |
| test.cpp:577:9:577:9 | i | test.cpp:575:30:575:31 | scanf output argument | test.cpp:577:9:577:9 | 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:575:18:575:22 | call to scanf | call to scanf |

View File

@@ -553,3 +553,27 @@ void switch_cases(const char *data) {
break;
}
}
void test_scanf_compared_right_away() {
int i;
bool success = scanf("%d", &i) == 1;
if(success) {
use(i); // GOOD
}
}
void test_scanf_compared_in_conjunct_right(bool b) {
int i;
bool success = b && scanf("%d", &i) == 1;
if(success) {
use(i); // GOOD [FALSE POSITIVE]
}
}
void test_scanf_compared_in_conjunct_left(bool b) {
int i;
bool success = scanf("%d", &i) == 1 && b;
if(success) {
use(i); // GOOD [FALSE POSITIVE]
}
}

View File

@@ -13,7 +13,7 @@ JsonToItemsTaskFactory,,,11,,,,,,,,,,,,,,,,,,,1,10
Microsoft.Android.Build,,1,14,,,,,,,,,,,,,1,,,,,,12,2
Microsoft.Apple.Build,,,7,,,,,,,,,,,,,,,,,,,7,
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,,,28,,,,,,,,,,
Microsoft.AspNetCore.Components,,2,1,,,,,,,,,,,,,,,,2,,,1,
Microsoft.AspNetCore.Components,2,2,2,,,,,,,2,,,,,,,,,2,,,1,1
Microsoft.AspNetCore.Mvc,,,2,,,,,,,,,,,,,,,,,,,,2
Microsoft.AspNetCore.WebUtilities,,,2,,,,,,,,,,,,,,,,,,,2,
Microsoft.CSharp,,,2,,,,,,,,,,,,,,,,,,,2,
1 package sink source summary sink:code-injection sink:encryption-decryptor sink:encryption-encryptor sink:encryption-keyprop sink:encryption-symmetrickey sink:file-content-store sink:html-injection sink:js-injection sink:log-injection sink:sql-injection source:commandargs source:database source:environment source:file source:file-write source:remote source:stdin source:windows-registry summary:taint summary:value
13 Microsoft.Android.Build 1 14 1 12 2
14 Microsoft.Apple.Build 7 7
15 Microsoft.ApplicationBlocks.Data 28 28
16 Microsoft.AspNetCore.Components 2 2 1 2 2 2 1 1
17 Microsoft.AspNetCore.Mvc 2 2
18 Microsoft.AspNetCore.WebUtilities 2 2
19 Microsoft.CSharp 2 2

View File

@@ -9,6 +9,6 @@ C# framework & library support
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
System,"``System.*``, ``System``",47,10819,54,5
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.Mvc``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.Sdk.WebAssembly``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",59,2073,150,2
Totals,,106,12899,398,7
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.Mvc``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.Sdk.WebAssembly``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",59,2074,152,4
Totals,,106,12900,400,9

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added the constructor and explicit cast operator of `Microsoft.AspNetCore.Components.MarkupString` as an `html-injection` sink. This will help catch cross-site scripting resulting from using `MarkupString`.

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/csharp-all
extensible: summaryModel
data:
- ["Microsoft.AspNetCore.Components.CompilerServices", "RuntimeHelpers", False, "TypeCheck<T>", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"]

View File

@@ -10,3 +10,9 @@ extensions:
extensible: summaryModel
data:
- ["Microsoft.AspNetCore.Components", "NagivationManager", True, "ToAbsoluteUri", "(System.String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- addsTo:
pack: codeql/csharp-all
extensible: sinkModel
data:
- ["Microsoft.AspNetCore.Components", "MarkupString", False, "MarkupString", "(System.String)", "", "Argument[0]", "html-injection", "manual"]
- ["Microsoft.AspNetCore.Components", "MarkupString", False, "op_Explicit", "(System.String)", "", "Argument[0]", "html-injection", "manual"]

View File

@@ -0,0 +1,163 @@
/** Provides classes and predicates related to handling APIs from external libraries. */
private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.dataflow.FlowSummary
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
private import semmle.code.csharp.dataflow.internal.ExternalFlow
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
private import semmle.code.csharp.security.dataflow.flowsources.ApiSources as ApiSources
private import semmle.code.csharp.security.dataflow.flowsinks.ApiSinks as ApiSinks
private import TestLibrary
/** Holds if the given callable is not worth supporting. */
private predicate isUninteresting(Callable c) {
c.getDeclaringType() instanceof TestLibrary
or
c.(Constructor).isParameterless()
or
// The data flow library uses read/store steps for properties, so we don't need to model them,
// if both a getter and a setter exist.
c.(Accessor).getDeclaration().(Property).isReadWrite()
}
/**
* An external API from either the C# Standard Library or a 3rd party library.
*/
class ExternalApi extends Callable {
ExternalApi() {
this.isUnboundDeclaration() and
this.fromLibrary() and
this.(Modifiable).isEffectivelyPublic() and
not isUninteresting(this)
}
/**
* Gets the unbound type, name and parameter types of this API.
*/
bindingset[this]
private string getSignature() {
result =
nestedName(this.getDeclaringType().getUnboundDeclaration()) + "." + this.getName() + "(" +
parameterQualifiedTypeNamesToString(this) + ")"
}
/**
* Gets the namespace of this API.
*/
bindingset[this]
string getNamespace() { this.getDeclaringType().hasFullyQualifiedName(result, _) }
/**
* Gets the namespace and signature of this API.
*/
bindingset[this]
string getApiName() { result = this.getNamespace() + "#" + this.getSignature() }
/** Gets a node that is an input to a call to this API. */
private ArgumentNode getAnInput() {
result
.getCall()
.(DataFlowDispatch::NonDelegateDataFlowCall)
.getATarget(_)
.getUnboundDeclaration() = this
}
/** Gets a node that is an output from a call to this API. */
private DataFlow::Node getAnOutput() {
exists(Call c, DataFlowDispatch::NonDelegateDataFlowCall dc |
dc.getDispatchCall().getCall() = c and
c.getTarget().getUnboundDeclaration() = this
|
result = DataFlowDispatch::getAnOutNode(dc, _)
)
}
/** Holds if this API has a supported summary. */
pragma[nomagic]
predicate hasSummary() {
this instanceof SummarizedCallable
or
defaultAdditionalTaintStep(this.getAnInput(), _, _)
}
/** Holds if this API is a known source. */
pragma[nomagic]
predicate isSource() { this.getAnOutput() instanceof ApiSources::SourceNode }
/** Holds if this API is a known sink. */
pragma[nomagic]
predicate isSink() { this.getAnInput() instanceof ApiSinks::SinkNode }
/** Holds if this API is a known neutral. */
pragma[nomagic]
predicate isNeutral() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
/**
* Holds if this API is supported by existing CodeQL libraries, that is, it is either a
* recognized source, sink or neutral or it has a flow summary.
*/
predicate isSupported() {
this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral()
}
}
/**
* Gets the nested name of the type `t`.
*
* If the type is not a nested type, the result is the same as \`getName()\`.
* Otherwise the name of the nested type is prefixed with a \`+\` and appended to
* the name of the enclosing type, which might be a nested type as well.
*/
private string nestedName(Type t) {
not exists(t.getDeclaringType().getUnboundDeclaration()) and
result = t.getName()
or
nestedName(t.getDeclaringType().getUnboundDeclaration()) + "+" + t.getName() = result
}
/**
* Gets the limit for the number of results produced by a telemetry query.
*/
int resultLimit() { result = 100 }
/**
* Holds if it is relevant to count usages of `api`.
*/
signature predicate relevantApi(ExternalApi api);
/**
* Given a predicate to count relevant API usages, this module provides a predicate
* for restricting the number or returned results based on a certain limit.
*/
module Results<relevantApi/1 getRelevantUsages> {
private int getUsages(string apiName) {
result =
strictcount(Call c, ExternalApi api |
c.getTarget().getUnboundDeclaration() = api and
apiName = api.getApiName() and
getRelevantUsages(api) and
c.fromSource()
)
}
private int getOrder(string apiName) {
apiName =
rank[result](string name, int usages |
usages = getUsages(name)
|
name order by usages desc, name
)
}
/**
* Holds if there exists an API with `apiName` that is being used `usages` times
* and if it is in the top results (guarded by resultLimit).
*/
predicate restrict(string apiName, int usages) {
usages = getUsages(apiName) and
getOrder(apiName) <= resultLimit()
}
}

View File

@@ -0,0 +1,18 @@
/** Provides classes and predicates related to handling test libraries. */
private import csharp
pragma[nomagic]
private predicate isTestNamespace(Namespace ns) {
ns.getFullName()
.matches([
"NUnit.Framework%", "Xunit%", "Microsoft.VisualStudio.TestTools.UnitTesting%", "Moq%"
])
}
/**
* A test library.
*/
class TestLibrary extends RefType {
TestLibrary() { isTestNamespace(this.getNamespace()) }
}

View File

@@ -1,163 +1,4 @@
/** Provides classes and predicates related to handling APIs from external libraries. */
// Use `semmle.code.csharp.telemetry.ExternalApi` instead.
deprecated module;
private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.dataflow.FlowSummary
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
private import semmle.code.csharp.dataflow.internal.ExternalFlow
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
private import semmle.code.csharp.security.dataflow.flowsources.ApiSources as ApiSources
private import semmle.code.csharp.security.dataflow.flowsinks.ApiSinks as ApiSinks
private import TestLibrary
/** Holds if the given callable is not worth supporting. */
private predicate isUninteresting(Callable c) {
c.getDeclaringType() instanceof TestLibrary
or
c.(Constructor).isParameterless()
or
// The data flow library uses read/store steps for properties, so we don't need to model them,
// if both a getter and a setter exist.
c.(Accessor).getDeclaration().(Property).isReadWrite()
}
/**
* An external API from either the C# Standard Library or a 3rd party library.
*/
class ExternalApi extends Callable {
ExternalApi() {
this.isUnboundDeclaration() and
this.fromLibrary() and
this.(Modifiable).isEffectivelyPublic() and
not isUninteresting(this)
}
/**
* Gets the unbound type, name and parameter types of this API.
*/
bindingset[this]
private string getSignature() {
result =
nestedName(this.getDeclaringType().getUnboundDeclaration()) + "." + this.getName() + "(" +
parameterQualifiedTypeNamesToString(this) + ")"
}
/**
* Gets the namespace of this API.
*/
bindingset[this]
string getNamespace() { this.getDeclaringType().hasFullyQualifiedName(result, _) }
/**
* Gets the namespace and signature of this API.
*/
bindingset[this]
string getApiName() { result = this.getNamespace() + "#" + this.getSignature() }
/** Gets a node that is an input to a call to this API. */
private ArgumentNode getAnInput() {
result
.getCall()
.(DataFlowDispatch::NonDelegateDataFlowCall)
.getATarget(_)
.getUnboundDeclaration() = this
}
/** Gets a node that is an output from a call to this API. */
private DataFlow::Node getAnOutput() {
exists(Call c, DataFlowDispatch::NonDelegateDataFlowCall dc |
dc.getDispatchCall().getCall() = c and
c.getTarget().getUnboundDeclaration() = this
|
result = DataFlowDispatch::getAnOutNode(dc, _)
)
}
/** Holds if this API has a supported summary. */
pragma[nomagic]
predicate hasSummary() {
this instanceof SummarizedCallable
or
defaultAdditionalTaintStep(this.getAnInput(), _, _)
}
/** Holds if this API is a known source. */
pragma[nomagic]
predicate isSource() { this.getAnOutput() instanceof ApiSources::SourceNode }
/** Holds if this API is a known sink. */
pragma[nomagic]
predicate isSink() { this.getAnInput() instanceof ApiSinks::SinkNode }
/** Holds if this API is a known neutral. */
pragma[nomagic]
predicate isNeutral() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
/**
* Holds if this API is supported by existing CodeQL libraries, that is, it is either a
* recognized source, sink or neutral or it has a flow summary.
*/
predicate isSupported() {
this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral()
}
}
/**
* Gets the nested name of the type `t`.
*
* If the type is not a nested type, the result is the same as \`getName()\`.
* Otherwise the name of the nested type is prefixed with a \`+\` and appended to
* the name of the enclosing type, which might be a nested type as well.
*/
private string nestedName(Type t) {
not exists(t.getDeclaringType().getUnboundDeclaration()) and
result = t.getName()
or
nestedName(t.getDeclaringType().getUnboundDeclaration()) + "+" + t.getName() = result
}
/**
* Gets the limit for the number of results produced by a telemetry query.
*/
int resultLimit() { result = 100 }
/**
* Holds if it is relevant to count usages of `api`.
*/
signature predicate relevantApi(ExternalApi api);
/**
* Given a predicate to count relevant API usages, this module provides a predicate
* for restricting the number or returned results based on a certain limit.
*/
module Results<relevantApi/1 getRelevantUsages> {
private int getUsages(string apiName) {
result =
strictcount(Call c, ExternalApi api |
c.getTarget().getUnboundDeclaration() = api and
apiName = api.getApiName() and
getRelevantUsages(api) and
c.fromSource()
)
}
private int getOrder(string apiName) {
apiName =
rank[result](string name, int usages |
usages = getUsages(name)
|
name order by usages desc, name
)
}
/**
* Holds if there exists an API with `apiName` that is being used `usages` times
* and if it is in the top results (guarded by resultLimit).
*/
predicate restrict(string apiName, int usages) {
usages = getUsages(apiName) and
getOrder(apiName) <= resultLimit()
}
}
import semmle.code.csharp.telemetry.ExternalApi

View File

@@ -8,7 +8,7 @@
private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi
private import semmle.code.csharp.telemetry.ExternalApi
private predicate getRelevantUsages(string namespace, int usages) {
usages =

View File

@@ -8,7 +8,7 @@
private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi
private import semmle.code.csharp.telemetry.ExternalApi
private predicate relevant(ExternalApi api) { api.isSupported() }

View File

@@ -8,7 +8,7 @@
private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi
private import semmle.code.csharp.telemetry.ExternalApi
private predicate relevant(ExternalApi api) { api.isSink() }

View File

@@ -8,7 +8,7 @@
private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi
private import semmle.code.csharp.telemetry.ExternalApi
private predicate relevant(ExternalApi api) { api.isSource() }

View File

@@ -8,7 +8,7 @@
private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi
private import semmle.code.csharp.telemetry.ExternalApi
private predicate relevant(ExternalApi api) { api.hasSummary() }

View File

@@ -1,16 +1,4 @@
private import csharp
// Use `semmle.code.csharp.telemetry.TestLibrary` instead.
deprecated module;
pragma[nomagic]
private predicate isTestNamespace(Namespace ns) {
ns.getFullName()
.matches([
"NUnit.Framework%", "Xunit%", "Microsoft.VisualStudio.TestTools.UnitTesting%", "Moq%"
])
}
/**
* A test library.
*/
class TestLibrary extends RefType {
TestLibrary() { isTestNamespace(this.getNamespace()) }
}
import semmle.code.csharp.telemetry.TestLibrary

View File

@@ -7,7 +7,7 @@
*/
private import csharp
private import ExternalApi
private import semmle.code.csharp.telemetry.ExternalApi
private predicate relevant(ExternalApi api) { not api.isSupported() }

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `ExternalApi` and `TestLibrary` modules have been moved to the library pack.

View File

@@ -9,7 +9,7 @@
*/
private import csharp
private import Telemetry.ExternalApi
private import semmle.code.csharp.telemetry.ExternalApi
from Call c, ExternalApi api
where

View File

@@ -5,7 +5,7 @@ private import semmle.code.csharp.dataflow.FlowSummary
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.dataflow.internal.ExternalFlow
private import semmle.code.csharp.frameworks.Test
private import Telemetry.TestLibrary
private import semmle.code.csharp.telemetry.TestLibrary
/** Holds if the given callable is not worth supporting. */
private predicate isUninteresting(Callable c) {

View File

@@ -250,6 +250,8 @@ sink
| Dapper;SqlMapper;QuerySingleOrDefaultAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable<System.Int32>,System.Nullable<System.Data.CommandType>);Argument[1];sql-injection;manual |
| Dapper;SqlMapper;QuerySingleOrDefaultAsync;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable<System.Int32>,System.Nullable<System.Data.CommandType>);Argument[2];sql-injection;manual |
| Dapper;SqlMapper;QuerySingleOrDefaultAsync<T>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable<System.Int32>,System.Nullable<System.Data.CommandType>);Argument[1];sql-injection;manual |
| Microsoft.AspNetCore.Components;MarkupString;MarkupString;(System.String);Argument[0];html-injection;manual |
| Microsoft.AspNetCore.Components;MarkupString;op_Explicit;(System.String);Argument[0];html-injection;manual |
| Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;ExecuteSqlRaw;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Collections.Generic.IEnumerable<System.Object>);Argument[1];sql-injection;manual |
| Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;ExecuteSqlRaw;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Object[]);Argument[1];sql-injection;manual |
| Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;ExecuteSqlRawAsync;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Collections.Generic.IEnumerable<System.Object>,System.Threading.CancellationToken);Argument[1];sql-injection;manual |
@@ -951,6 +953,7 @@ summary
| Microsoft.AspNetCore.Components.CompilerServices;RuntimeHelpers;InvokeAsynchronousDelegate;(System.Action);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.CompilerServices;RuntimeHelpers;InvokeAsynchronousDelegate;(System.Func<System.Threading.Tasks.Task>);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.CompilerServices;RuntimeHelpers;InvokeSynchronousDelegate;(System.Action);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.CompilerServices;RuntimeHelpers;TypeCheck<T>;(T);Argument[0];ReturnValue;value;manual |
| Microsoft.AspNetCore.Components.Forms.Mapping;FormValueMappingContext;set_MapErrorToContainer;(System.Action<System.String,System.Object>);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.Forms.Mapping;FormValueMappingContext;set_OnError;(System.Action<System.String,System.FormattableString,System.String>);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.Forms;EditContext;GetValidationMessages;(System.Linq.Expressions.Expression<System.Func<System.Object>>);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |

View File

@@ -164,6 +164,7 @@
| Microsoft.AspNetCore.Components.CompilerServices;RuntimeHelpers;InvokeAsynchronousDelegate;(System.Action);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.CompilerServices;RuntimeHelpers;InvokeAsynchronousDelegate;(System.Func<System.Threading.Tasks.Task>);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.CompilerServices;RuntimeHelpers;InvokeSynchronousDelegate;(System.Action);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.CompilerServices;RuntimeHelpers;TypeCheck<T>;(T);Argument[0];ReturnValue;value;manual |
| Microsoft.AspNetCore.Components.Forms.Mapping;FormValueMappingContext;set_MapErrorToContainer;(System.Action<System.String,System.Object>);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.Forms.Mapping;FormValueMappingContext;set_OnError;(System.Action<System.String,System.FormattableString,System.String>);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |
| Microsoft.AspNetCore.Components.Forms;EditContext;GetValidationMessages;(System.Linq.Expressions.Expression<System.Func<System.Object>>);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated |

View File

@@ -204,58 +204,45 @@ data flow solver that can check whether there is (global) data flow from a sourc
Optionally, configurations may specify extra data flow edges to be added to the data flow graph, and may also specify `barriers`. Barriers are data flow nodes or edges through
which data should not be tracked for the purposes of this analysis.
To define a configuration, extend the class ``DataFlow::Configuration`` as follows:
To define a configuration, add a module that implements the signature ``DataFlow::ConfigSig`` and pass it to ``DataFlow::Global`` as follows:
.. code-block:: ql
class MyDataFlowConfiguration extends DataFlow::Configuration {
MyDataFlowConfiguration() { this = "MyDataFlowConfiguration" }
module MyAnalysisConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { /* ... */ }
override predicate isSource(DataFlow::Node source) { /* ... */ }
predicate isSink(DataFlow::Node sink) { /* ... */ }
override predicate isSink(DataFlow::Node sink) { /* ... */ }
// optional overrides:
override predicate isBarrier(DataFlow::Node nd) { /* ... */ }
override predicate isBarrierEdge(DataFlow::Node pred, DataFlow::Node succ) { /* ... */ }
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { /* ... */ }
// optional predicates:
predicate isBarrier(DataFlow::Node nd) { /* ... */ }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { /* ... */ }
}
The characteristic predicate ``MyDataFlowConfiguration()`` defines the name of the configuration, so ``"MyDataFlowConfiguration"`` should be replaced by a suitable
name describing your particular analysis configuration.
module MyAnalysisFlow = DataFlow::Global<MyAnalysisConfig>
The data flow analysis is performed using the predicate ``hasFlow(source, sink)``:
The data flow analysis is performed using the predicate ``MyAnalysisFlow::flow(source, sink)``:
.. code-block:: ql
from MyDataFlowConfiguration dataflow, DataFlow::Node source, DataFlow::Node sink
where dataflow.hasFlow(source, sink)
from DataFlow::Node source, DataFlow::Node sink
where MyAnalysisFlow::flow(source, sink)
select source, "Data flow from $@ to $@.", source, source.toString(), sink, sink.toString()
Using global taint tracking
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Global taint tracking extends global data flow with additional non-value-preserving steps, such as flow through string-manipulating operations. To use it, simply extend
``TaintTracking::Configuration`` instead of ``DataFlow::Configuration``:
Global taint tracking extends global data flow with additional non-value-preserving steps, such as flow through string-manipulating operations. To use it, simply
use ``TaintTracking::Global<...>`` instead of ``DataFlow::Global<...>``:
.. code-block:: ql
class MyTaintTrackingConfiguration extends TaintTracking::Configuration {
MyTaintTrackingConfiguration() { this = "MyTaintTrackingConfiguration" }
override predicate isSource(DataFlow::Node source) { /* ... */ }
override predicate isSink(DataFlow::Node sink) { /* ... */ }
module MyAnalysisConfig implements DataFlow::ConfigSig {
/* ... */
}
Analogous to ``isAdditionalFlowStep``, there is a predicate ``isAdditionalTaintStep`` that you can override to specify custom flow steps to consider in the analysis.
Instead of the ``isBarrier`` and ``isBarrierEdge`` predicates, the taint tracking configuration includes ``isSanitizer`` and ``isSanitizerEdge`` predicates that specify
data flow nodes or edges that act as taint sanitizers and hence stop flow from a source to a sink.
module MyAnalysisFlow = TaintTracking::Global<MyAnalysisConfig>
Similar to global data flow, the characteristic predicate ``MyTaintTrackingConfiguration()`` defines the unique name of the configuration, so ``"MyTaintTrackingConfiguration"``
should be replaced by an appropriate descriptive name.
The taint tracking analysis is again performed using the predicate ``hasFlow(source, sink)``.
The taint tracking analysis is again performed using the predicate ``MyAnalysisFlow::flow(source, sink)``.
Examples
~~~~~~~~
@@ -267,20 +254,20 @@ time using global taint tracking.
import javascript
class CommandLineFileNameConfiguration extends TaintTracking::Configuration {
CommandLineFileNameConfiguration() { this = "CommandLineFileNameConfiguration" }
override predicate isSource(DataFlow::Node source) {
module CommandLineFileNameConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
DataFlow::globalVarRef("process").getAPropertyRead("argv").getAPropertyRead() = source
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
DataFlow::moduleMember("fs", "readFile").getACall().getArgument(0) = sink
}
}
from CommandLineFileNameConfiguration cfg, DataFlow::Node source, DataFlow::Node sink
where cfg.hasFlow(source, sink)
module CommandLineFileNameFlow = TaintTracking::Global<CommandLineFileNameConfig>;
from DataFlow::Node source, DataFlow::Node sink
where CommandLineFileNameFlow::flow(source, sink)
select source, sink
This query will now find flows that involve inter-procedural steps, like in the following example (where the individual steps have been marked with comments
@@ -325,15 +312,15 @@ with an error if it does not. We could then use that function in ``readFileHelpe
}
For the purposes of our above analysis, ``checkPath`` is a `sanitizer`: its output is always untainted, even if its input is tainted. To model this
we can add an override of ``isSanitizer`` to our taint-tracking configuration like this:
we can add an ``isBarrier`` predicate to our taint-tracking configuration like this:
.. code-block:: ql
class CommandLineFileNameConfiguration extends TaintTracking::Configuration {
module CommandLineFileNameConfig implements DataFlow::ConfigSig {
// ...
override predicate isSanitizer(DataFlow::Node nd) {
predicate isBarrier(DataFlow::Node nd) {
nd.(DataFlow::CallNode).getCalleeName() = "checkPath"
}
}
@@ -359,36 +346,36 @@ Note that ``checkPath`` is now no longer a sanitizer in the sense described abov
through ``checkPath`` any more. The flow is, however, `guarded` by ``checkPath`` in the sense that the expression ``checkPath(p)`` has to evaluate
to ``true`` (or, more precisely, to a truthy value) in order for the flow to happen.
Such sanitizer guards can be supported by defining a new subclass of ``TaintTracking::SanitizerGuardNode`` and overriding the predicate
``isSanitizerGuard`` in the taint-tracking configuration class to add all instances of this class as sanitizer guards to the configuration.
Such sanitizer guards can be supported by defining a class with a ``blocksExpr`` predicate and using the `DataFlow::MakeBarrierGuard`` module
to implement the ``isBarrier`` predicate.
For our above example, we would begin by defining a subclass of ``SanitizerGuardNode`` that identifies guards of the form ``checkPath(...)``:
For our above example, we would begin by defining a subclass of ``DataFlow::CallNode`` that identifies guards of the form ``checkPath(...)``:
.. code-block:: ql
class CheckPathSanitizerGuard extends TaintTracking::SanitizerGuardNode, DataFlow::CallNode {
class CheckPathSanitizerGuard extends DataFlow::CallNode {
CheckPathSanitizerGuard() { this.getCalleeName() = "checkPath" }
override predicate sanitizes(boolean outcome, Expr e) {
predicate blocksExpr(boolean outcome, Expr e) {
outcome = true and
e = getArgument(0).asExpr()
e = this.getArgument(0).asExpr()
}
}
The characteristic predicate of this class checks that the sanitizer guard is a call to a function named ``checkPath``. The overriding definition
of ``sanitizes`` says such a call sanitizes its first argument (that is, ``getArgument(0)``) if it evaluates to ``true`` (or rather, a truthy
The characteristic predicate of this class checks that the sanitizer guard is a call to a function named ``checkPath``. The definition
of ``blocksExpr`` says such a call sanitizes its first argument (that is, ``getArgument(0)``) if it evaluates to ``true`` (or rather, a truthy
value).
Now we can override ``isSanitizerGuard`` to add these sanitizer guards to our configuration:
Now we can implement ``isBarrier`` to add this sanitizer guard to our configuration:
.. code-block:: ql
class CommandLineFileNameConfiguration extends TaintTracking::Configuration {
module CommandLineFileNameConfig implements DataFlow::ConfigSig {
// ...
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode nd) {
nd instanceof CheckPathSanitizerGuard
predicate isBarrier(DataFlow::Node node) {
node = DataFlow::MakeBarrierGuard<CheckPathSanitizerGuard>::getABarrierNode()
}
}
@@ -399,7 +386,7 @@ reach there if ``checkPath(p)`` evaluates to a truthy value. Consequently, there
Additional taint steps
~~~~~~~~~~~~~~~~~~~~~~
Sometimes the default data flow and taint steps provided by ``DataFlow::Configuration`` and ``TaintTracking::Configuration`` are not sufficient
Sometimes the default data flow and taint steps provided by the data flow library are not sufficient
and we need to add additional flow or taint steps to our configuration to make it find the expected flow. For example, this can happen because
the analyzed program uses a function from an external library whose source code is not available to the analysis, or because it uses a function
that is too difficult to analyze.
@@ -420,20 +407,20 @@ to resolve any symlinks in the path ``p`` before passing it to ``readFile``:
Resolving symlinks does not make an unsafe path any safer, so we would still like our query to flag this, but since the standard library does
not have a model of ``resolve-symlinks`` it will no longer return any results.
We can fix this quite easily by adding an overriding definition of the ``isAdditionalTaintStep`` predicate to our configuration, introducing an
We can fix this quite easily by adding a definition of the ``isAdditionalFlowStep`` predicate to our configuration, introducing an
additional taint step from the first argument of ``resolveSymlinks`` to its result:
.. code-block:: ql
class CommandLineFileNameConfiguration extends TaintTracking::Configuration {
module CommandLineFileNameConfig implements DataFlow::ConfigSig {
// ...
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::CallNode c |
c = DataFlow::moduleImport("resolve-symlinks").getACall() and
pred = c.getArgument(0) and
succ = c
node1 = c.getArgument(0) and
node2 = c
)
}
}
@@ -444,11 +431,11 @@ to wrap it in a new subclass of ``TaintTracking::SharedTaintStep`` like this:
.. code-block:: ql
class StepThroughResolveSymlinks extends TaintTracking::SharedTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::CallNode c |
c = DataFlow::moduleImport("resolve-symlinks").getACall() and
pred = c.getArgument(0) and
succ = c
node1 = c.getArgument(0) and
node2 = c
)
}
}
@@ -494,18 +481,18 @@ Exercise 2
import javascript
class HardCodedTagNameConfiguration extends DataFlow::Configuration {
HardCodedTagNameConfiguration() { this = "HardCodedTagNameConfiguration" }
module HardCodedTagNameConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof ConstantString }
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof ConstantString }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
sink = DataFlow::globalVarRef("document").getAMethodCall("createElement").getArgument(0)
}
}
from HardCodedTagNameConfiguration cfg, DataFlow::Node source, DataFlow::Node sink
where cfg.hasFlow(source, sink)
module HardCodedTagNameFlow = DataFlow::Global<HardCodedTagNameConfig>;
from DataFlow::Node source, DataFlow::Node sink
where HardCodedTagNameFlow::flow(source, sink)
select source, sink
Exercise 3
@@ -540,18 +527,18 @@ Exercise 4
}
}
class HardCodedTagNameConfiguration extends DataFlow::Configuration {
HardCodedTagNameConfiguration() { this = "HardCodedTagNameConfiguration" }
module HardCodedTagNameConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof ArrayEntryCallResult }
override predicate isSource(DataFlow::Node source) { source instanceof ArrayEntryCallResult }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
sink = DataFlow::globalVarRef("document").getAMethodCall("createElement").getArgument(0)
}
}
from HardCodedTagNameConfiguration cfg, DataFlow::Node source, DataFlow::Node sink
where cfg.hasFlow(source, sink)
module HardCodedTagNameFlow = DataFlow::Global<HardCodedTagNameConfig>;
from DataFlow::Node source, DataFlow::Node sink
where HardCodedTagNameFlow::flow(source, sink)
select source, sink
Further reading

View File

@@ -700,19 +700,16 @@ The data flow graph-based analyses described so far are all intraprocedural: the
We distinguish here between data flow proper, and *taint tracking*: the latter not only considers value-preserving flow (such as from variable definitions to uses), but also cases where one value influences ("taints") another without determining it entirely. For example, in the assignment ``s2 = s1.substring(i)``, the value of ``s1`` influences the value of ``s2``, because ``s2`` is assigned a substring of ``s1``. In general, ``s2`` will not be assigned ``s1`` itself, so there is no data flow from ``s1`` to ``s2``, but ``s1`` still taints ``s2``.
It is a common pattern that we wish to specify data flow or taint analysis in terms of its *sources* (where flow starts), *sinks* (where it should be tracked), and *barriers* or *sanitizers* (where flow is interrupted). Sanitizers they are very common in security analyses: for example, an analysis that tracks the flow of untrusted user input into, say, a SQL query has to keep track of code that validates the input, thereby making it safe to use. Such a validation step is an example of a sanitizer.
It is a common pattern that we wish to specify data flow or taint analysis in terms of its *sources* (where flow starts), *sinks* (where it should be tracked), and *barriers* (also called *sanitizers*) where flow is interrupted. Sanitizers they are very common in security analyses: for example, an analysis that tracks the flow of untrusted user input into, say, a SQL query has to keep track of code that validates the input, thereby making it safe to use. Such a validation step is an example of a sanitizer.
The classes ``DataFlow::Configuration`` and ``TaintTracking::Configuration`` allow specifying a data flow or taint analysis, respectively, by overriding the following predicates:
A module implementing the signature `DataFlow::ConfigSig` may specify a data flow or taint analysis by implementing the following predicates:
- ``isSource(DataFlow::Node nd)`` selects all nodes ``nd`` from where flow tracking starts.
- ``isSink(DataFlow::Node nd)`` selects all nodes ``nd`` to which the flow is tracked.
- ``isBarrier(DataFlow::Node nd)`` selects all nodes ``nd`` that act as a barrier for data flow; ``isSanitizer`` is the corresponding predicate for taint tracking configurations.
- ``isBarrierEdge(DataFlow::Node src, DataFlow::Node trg)`` is a variant of ``isBarrier(nd)`` that allows specifying barrier *edges* in addition to barrier nodes; again, ``isSanitizerEdge`` is the corresponding predicate for taint tracking;
- ``isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg)`` allows specifying custom additional flow steps for this analysis; ``isAdditionalTaintStep`` is the corresponding predicate for taint tracking configurations.
- ``isBarrier(DataFlow::Node nd)`` selects all nodes ``nd`` that act as a barrier/sanitizer for data flow.
- ``isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg)`` allows specifying custom additional flow steps for this analysis.
Since for technical reasons both ``Configuration`` classes are subtypes of ``string``, you have to choose a unique name for each flow configuration and equate ``this`` with it in the characteristic predicate (as in the example below).
The predicate ``Configuration.hasFlow`` performs the actual flow tracking, starting at a source and looking for flow to a sink that does not pass through a barrier node or edge.
Such a module can be passed to ``DataFlow::Global<...>``. This will produce a module with a ``flow`` predicate that performs the actual flow tracking, starting at a source and looking for flow to a sink that does not pass through a barrier node.
For example, suppose that we are developing an analysis to find hard-coded passwords. We might write a simple query that looks for string constants flowing into variables named ``"password"``.
@@ -720,35 +717,27 @@ For example, suppose that we are developing an analysis to find hard-coded passw
import javascript
class PasswordTracker extends DataFlow::Configuration {
PasswordTracker() {
// unique identifier for this configuration
this = "PasswordTracker"
}
module PasswordConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node nd) { nd.asExpr() instanceof StringLiteral }
override predicate isSource(DataFlow::Node nd) {
nd.asExpr() instanceof StringLiteral
}
override predicate isSink(DataFlow::Node nd) {
passwordVarAssign(_, nd)
}
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
v.getAnAssignedExpr() = nd.asExpr() and
v.getName().toLowerCase() = "password"
}
predicate isSink(DataFlow::Node nd) { passwordVarAssign(_, nd) }
}
Now we can rephrase our query to use ``Configuration.hasFlow``:
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
v.getAnAssignedExpr() = nd.asExpr() and
v.getName().toLowerCase() = "password"
}
module PasswordFlow = DataFlow::Global<PasswordConfig>;
Now we can rephrase our query to use ``PasswordFlow::flow``:
.. code-block:: ql
from PasswordTracker pt, DataFlow::Node source, DataFlow::Node sink, Variable v
where pt.hasFlow(source, sink) and pt.passwordVarAssign(v, sink)
from DataFlow::Node source, DataFlow::Node sink, Variable v
where PasswordFlow::flow(_, sink) and passwordVarAssign(v, sink)
select sink, "Password variable " + v + " is assigned a constant string."
Syntax errors
~~~~~~~~~~~~~

View File

@@ -16,18 +16,17 @@ Use the following template to create a taint tracking path query:
* @kind path-problem
*/
import javascript
import DataFlow
import DataFlow::PathGraph
class MyConfig extends TaintTracking::Configuration {
MyConfig() { this = "MyConfig" }
override predicate isSource(Node node) { ... }
override predicate isSink(Node node) { ... }
override predicate isAdditionalTaintStep(Node pred, Node succ) { ... }
module MyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { ... }
predicate isSink(DataFlow::Node node) { ... }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { ... }
}
from MyConfig cfg, PathNode source, PathNode sink
where cfg.hasFlowPath(source, sink)
module MyFlow = TaintTracking::Global<MyConfig>;
from MyFlow::PathNode source, MyFlow::PathNode sink
where MyFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "taint from $@.", source.getNode(), "here"
This query reports flow paths which:

View File

@@ -1,9 +1,9 @@
.. _using-flow-labels-for-precise-data-flow-analysis:
Using flow labels for precise data flow analysis
Using flow state for precise data flow analysis
================================================
You can associate flow labels with each value tracked by the flow analysis to determine whether the flow contains potential vulnerabilities.
You can associate a flow state with each value tracked by the flow analysis to determine whether the flow contains potential vulnerabilities.
Overview
--------
@@ -16,9 +16,9 @@ program, and associates a flag with every data value telling us whether it might
source node.
In some cases, you may want to track more detailed information about data values. This can be done
by associating flow labels with data values, as shown in this tutorial. We will first discuss the
general idea behind flow labels and then show how to use them in practice. Finally, we will give an
overview of the API involved and provide some pointers to standard queries that use flow labels.
by associating flow states with data values, as shown in this tutorial. We will first discuss the
general idea behind flow states and then show how to use them in practice. Finally, we will give an
overview of the API involved and provide some pointers to standard queries that use flow states.
Limitations of basic data-flow analysis
---------------------------------------
@@ -47,22 +47,21 @@ contain ``..`` components. Untrusted user input has both bits set initially, ind
off individual bits, and if a value that has at least one bit set is interpreted as a path, a
potential vulnerability is flagged.
Using flow labels
Using flow states
-----------------
You can handle these cases and others like them by associating a set of `flow labels` (sometimes
also referred to as `taint kinds`) with each value being tracked by the analysis. Value-preserving
You can handle these cases and others like them by associating a set of `flow states` (sometimes
also referred to as `flow labels` or `taint kinds`) with each value being tracked by the analysis. Value-preserving
data-flow steps (such as flow steps from writes to a variable to its reads) preserve the set of flow
labels, but other steps may add or remove flow labels. Sanitizers, in particular, are simply flow
steps that remove some or all flow labels. The initial set of flow labels for a value is determined
states, but other steps may add or remove flow states. The initial set of flow states for a value is determined
by the source node that gives rise to it. Similarly, sink nodes can specify that an incoming value
needs to have a certain flow label (or one of a set of flow labels) in order for the flow to be
needs to have a certain flow state (or one of a set of flow states) in order for the flow to be
flagged as a potential vulnerability.
Example
-------
As an example of using flow labels, we will show how to write a query that flags property accesses
As an example of using flow state, we will show how to write a query that flags property accesses
on JSON values that come from user-controlled input where we have not checked whether the value is
``null``, so that the property access may cause a runtime exception.
@@ -88,8 +87,8 @@ This code, on the other hand, should not be flagged:
}
}
We will first try to write a query to find this kind of problem without flow labels, and use the
difficulties we encounter as a motivation for bringing flow labels into play, which will make the
We will first try to write a query to find this kind of problem without flow state, and use the
difficulties we encounter as a motivation for bringing flow state into play, which will make the
query much easier to implement.
To get started, let's write a query that simply flags any flow from ``JSON.parse`` into the base of
@@ -99,24 +98,24 @@ a property access:
import javascript
class JsonTrackingConfig extends DataFlow::Configuration {
JsonTrackingConfig() { this = "JsonTrackingConfig" }
override predicate isSource(DataFlow::Node nd) {
module JsonTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node nd) {
exists(JsonParserCall jpc |
nd = jpc.getOutput()
)
}
override predicate isSink(DataFlow::Node nd) {
predicate isSink(DataFlow::Node nd) {
exists(DataFlow::PropRef pr |
nd = pr.getBase()
)
}
}
from JsonTrackingConfig cfg, DataFlow::Node source, DataFlow::Node sink
where cfg.hasFlow(source, sink)
module JsonTrackingFlow = DataFlow::Global<JsonTrackingConfig>;
from DataFlow::Node source, DataFlow::Node sink
where JsonTrackingFlow::flow(source, sink)
select sink, "Property access on JSON value originating $@.", source, "here"
Note that we use the ``JsonParserCall`` class from the standard library to model various JSON
@@ -127,8 +126,7 @@ introduced any sanitizers yet.
There are many ways of checking for nullness directly or indirectly. Since this is not the main
focus of this tutorial, we will only show how to model one specific case: if some variable ``v`` is
known to be truthy, it cannot be ``null``. This kind of condition is easily expressed using a
``BarrierGuardNode`` (or its counterpart ``SanitizerGuardNode`` for taint-tracking configurations).
known to be truthy, it cannot be ``null``. This kind of condition is expressed using a "barrier guard".
A barrier guard node is a data-flow node ``b`` that blocks flow through some other node ``nd``,
provided that some condition checked at ``b`` is known to hold, that is, evaluate to a truthy value.
@@ -139,29 +137,29 @@ is a barrier guard blocking flow through the use of ``data`` on the right-hand s
At this point we know that ``data`` has evaluated to a truthy value, so it cannot be ``null``
anymore.
Implementing this additional condition is easy. We implement a subclass of ``DataFlow::BarrierGuardNode``:
Implementing this additional condition is easy. We implement a class with a predicate called ``blocksExpr``:
.. code-block:: ql
class TruthinessCheck extends DataFlow::BarrierGuardNode, DataFlow::ValueNode {
class TruthinessCheck extends DataFlow::ValueNode {
SsaVariable v;
TruthinessCheck() {
astNode = v.getAUse()
}
override predicate blocks(boolean outcome, Expr e) {
predicate blocksExpr(boolean outcome, Expr e) {
outcome = true and
e = astNode
}
}
and then use it to override predicate ``isBarrierGuard`` in our configuration class:
and then use it to implement the predicate ``isBarrier`` in our configuration module:
.. code-block:: ql
override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) {
guard instanceof TruthinessCheck
predicate isBarrier(DataFlow::Node node) {
node = DataFlow::MakeBarrierGuard<TruthinessCheck>::getABarrierNode()
}
With this change, we now flag the problematic case and don't flag the unproblematic case above.
@@ -182,11 +180,11 @@ checked for null-guardedness:
}
}
We could try to remedy the situation by overriding ``isAdditionalFlowStep`` in our configuration class to track values through property reads:
We could try to remedy the situation by adding ``isAdditionalFlowStep`` in our configuration module to track values through property reads:
.. code-block:: ql
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
succ.(DataFlow::PropRead).getBase() = pred
}
@@ -199,79 +197,86 @@ altogether, it should simply record the fact that ``root`` itself is known to be
Any property read from ``root``, on the other hand, may well be null and needs to be checked
separately.
We can achieve this by introducing two different flow labels, ``json`` and ``maybe-null``. The former
We can achieve this by introducing two different flow states, ``json`` and ``maybe-null``. The former
means that the value we are dealing with comes from a JSON object, the latter that it may be
``null``. The result of any call to ``JSON.parse`` has both labels. A property read from a value
with label ``json`` also has both labels. Checking truthiness removes the ``maybe-null`` label.
Accessing a property on a value that has the ``maybe-null`` label should be flagged.
``null``. The result of any call to ``JSON.parse`` has both states. A property read from a value
with state ``json`` also results in a value with both states. Checking truthiness removes the ``maybe-null`` state.
Accessing a property on a value that has the ``maybe-null`` state should be flagged.
To implement this, we start by defining two new subclasses of the class ``DataFlow::FlowLabel``:
To implement this, we first change the signature of our configuration module to ``DataFlow::StateConfigSig``, and
replace ``DataFlow::Global<...>`` with ``DataFlow::GlobalWithState<...>``:
.. code-block:: ql
class JsonLabel extends DataFlow::FlowLabel {
JsonLabel() {
this = "json"
}
module JsonTrackingConfig implements DataFlow::StateConfigSig {
/* ... */
}
class MaybeNullLabel extends DataFlow::FlowLabel {
MaybeNullLabel() {
this = "maybe-null"
}
}
module JsonTrackingFlow = DataFlow::GlobalWithState<JsonTrackingConfig>;
Then we extend our ``isSource`` predicate from above to track flow labels by overriding the two-argument version instead of the one-argument version:
We then add a class called ``FlowState`` which has one value for each flow state:
.. code-block:: ql
override predicate isSource(DataFlow::Node nd, DataFlow::FlowLabel lbl) {
module JsonTrackingConfig implements DataFlow::StateConfigSig {
class FlowState extends string {
FlowState() {
this = ["json", "maybe-null"]
}
}
/* ... */
}
Then we extend our ``isSource`` predicate with an additional parameter to specify the flow state:
.. code-block:: ql
predicate isSource(DataFlow::Node nd, FlowState state) {
exists(JsonParserCall jpc |
nd = jpc.getOutput() and
(lbl instanceof JsonLabel or lbl instanceof MaybeNullLabel)
state = ["json", "maybe-null"] // start in either state
)
}
Similarly, we make ``isSink`` flow-label aware and require the base of the property read to have the ``maybe-null`` label:
Similarly, we update ``isSink`` and require the base of the property read to have the ``maybe-null`` state:
.. code-block:: ql
override predicate isSink(DataFlow::Node nd, DataFlow::FlowLabel lbl) {
predicate isSink(DataFlow::Node nd, FlowState state) {
exists(DataFlow::PropRef pr |
nd = pr.getBase() and
lbl instanceof MaybeNullLabel
state = "maybe-null"
)
}
Our overriding definition of ``isAdditionalFlowStep`` now needs to specify two flow labels, a
predecessor label ``predlbl`` and a successor label ``succlbl``. In addition to specifying flow from
the predecessor node ``pred`` to the successor node ``succ``, it requires that ``pred`` has label
``predlbl``, and adds label ``succlbl`` to ``succ``. In our case, we use this to add both the
``json`` label and the ``maybe-null`` label to any property read from a value labeled with ``json``
(no matter whether it has the ``maybe-null`` label):
Our definition of ``isAdditionalFlowStep`` now needs to specify two flow states, a
predecessor state ``predState`` and a successor state ``succState``. In addition to specifying flow from
the predecessor node ``pred`` to the successor node ``succ``, it requires that ``pred`` has state
``predState``, and adds state ``succState`` to ``succ``. In our case, we use this to add both the
``json`` state and the ``maybe-null`` state to any property read from a value in the ``json`` state
(no matter whether it has the ``maybe-null`` state):
.. code-block:: ql
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ,
DataFlow::FlowLabel predlbl, DataFlow::FlowLabel succlbl) {
predicate isAdditionalFlowStep(DataFlow::Node pred, FlowState predState,
DataFlow::Node succ, FlowState succState) {
succ.(DataFlow::PropRead).getBase() = pred and
predlbl instanceof JsonLabel and
(succlbl instanceof JsonLabel or succlbl instanceof MaybeNullLabel)
predState = "json" and
succState = ["json", "maybe-null"]
}
Finally, we turn ``TruthinessCheck`` from a ``BarrierGuardNode`` into a ``LabeledBarrierGuardNode``,
specifying that it only removes the ``maybe-null`` label (but not the ``json`` label) from the
sanitized value:
Finally, we add an additional parameter to the ``isBarrier`` predicate to specify the flow state
to block at the ``TruthinessCheck`` barrier.
.. code-block:: ql
class TruthinessCheck extends DataFlow::LabeledBarrierGuardNode, DataFlow::ValueNode {
...
module JsonTrackingConfig implements DataFlow::StateConfigSig {
/* ... */
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) {
outcome = true and
e = astNode and
lbl instanceof MaybeNullLabel
predicate isBarrier(DataFlow::Node node, FlowState state) {
node = DataFlow::MakeBarrierGuard<TruthinessCheck>::getABarrierNode() and
state = "maybe-null"
}
}
@@ -283,66 +288,60 @@ step by step in the UI:
/** @kind path-problem */
import javascript
import DataFlow::PathGraph
class JsonLabel extends DataFlow::FlowLabel {
JsonLabel() {
this = "json"
}
}
class MaybeNullLabel extends DataFlow::FlowLabel {
MaybeNullLabel() {
this = "maybe-null"
}
}
class TruthinessCheck extends DataFlow::LabeledBarrierGuardNode, DataFlow::ValueNode {
class TruthinessCheck extends DataFlow::ValueNode {
SsaVariable v;
TruthinessCheck() {
astNode = v.getAUse()
}
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) {
predicate blocksExpr(boolean outcome, Expr e, JsonTrackingConfig::FlowState state) {
outcome = true and
e = astNode and
lbl instanceof MaybeNullLabel
state = "maybe-null"
}
}
class JsonTrackingConfig extends DataFlow::Configuration {
JsonTrackingConfig() { this = "JsonTrackingConfig" }
module JsonTrackingConfig implements DataFlow::StateConfigSig {
class FlowState extends string {
FlowState() {
this = ["json", "maybe-null"]
}
}
override predicate isSource(DataFlow::Node nd, DataFlow::FlowLabel lbl) {
predicate isSource(DataFlow::Node nd, FlowState state) {
exists(JsonParserCall jpc |
nd = jpc.getOutput() and
(lbl instanceof JsonLabel or lbl instanceof MaybeNullLabel)
state = ["json", "maybe-null"] // start in either state
)
}
override predicate isSink(DataFlow::Node nd, DataFlow::FlowLabel lbl) {
predicate isSink(DataFlow::Node nd, FlowState state) {
exists(DataFlow::PropRef pr |
nd = pr.getBase() and
lbl instanceof MaybeNullLabel
state = "maybe-null"
)
}
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ,
DataFlow::FlowLabel predlbl, DataFlow::FlowLabel succlbl) {
predicate isAdditionalFlowStep(DataFlow::Node pred, FlowState predState,
DataFlow::Node succ, FlowState succState) {
succ.(DataFlow::PropRead).getBase() = pred and
predlbl instanceof JsonLabel and
(succlbl instanceof JsonLabel or succlbl instanceof MaybeNullLabel)
predState = "json" and
succState = ["json", "maybe-null"]
}
override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) {
guard instanceof TruthinessCheck
predicate isBarrier(DataFlow::Node node, FlowState state) {
node = DataFlow::MakeBarrierGuard<TruthinessCheck>::getABarrierNode() and
state = "maybe-null"
}
}
from JsonTrackingConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "Property access on JSON value originating $@.", source, "here"
module JsonTrackingFlow = DataFlow::GlobalWithState<JsonTrackingConfig>;
from DataFlow::Node source, DataFlow::Node sink
where JsonTrackingFlow::flow(source, sink)
select sink, "Property access on JSON value originating $@.", source, "here"
We ran this query on the https://github.com/finos/plexus-interop repository. Many of the
results were false positives since the query does not currently model many ways in which we can check
@@ -354,52 +353,30 @@ this tutorial.
API
---
Plain data-flow configurations implicitly use a single flow label "data", which indicates that a
data value originated from a source. You can use the predicate ``DataFlow::FlowLabel::data()``,
which returns this flow label, as a symbolic name for it.
Flow state can be used in modules implementing the ``DataFlow::StateConfigSig`` signature. Compared to a ``DataFlow::ConfigSig`` the main differences are:
Taint-tracking configurations add a second flow label "taint" (``DataFlow::FlowLabel::taint()``),
which is similar to "data", but includes values that have passed through non-value preserving steps
such as string operations.
- The module must be passed to ``DataFlow::GlobalWithState<...>`` or ``TaintTracking::GlobalWithState<...>``.
instead of ``DataFlow::Global<...>`` or ``TaintTracking::Global<...>``.
- The module must contain a type named ``FlowState``.
- ``isSource`` expects an additional parameter specifying the flow state.
- ``isSink`` optionally can take an additional parameter specifying the flow state.
If omitted, the sinks are in effect for all flow states.
- ``isAdditionalFlowStep`` optionally can take two additional parameters specifying the predecessor and successor flow states.
If omitted, the generated steps apply for any flow state and preserve the current flow state.
- ``isBarrier`` optionally can take an additional parameter specifying the flow state to block.
If omitted, the barriers block all flow states.
Each of the three member predicates ``isSource``, ``isSink`` and
``isAdditionalFlowStep``/``isAdditionalTaintStep`` has one version that uses the default flow
labels, and one version that allows specifying custom flow labels through additional arguments.
For ``isSource``, there is one additional argument specifying which flow label(s) should be
associated with values originating from this source. If multiple flow labels are specified, each
value is associated with `all` of them.
For ``isSink``, the additional argument specifies which flow label(s) a value that flows into this
source may be associated with. If multiple flow labels are specified, then any value that is
associated with `at least one` of them will be considered by the configuration.
For ``isAdditionalFlowStep`` there are two additional arguments ``predlbl`` and ``succlbl``, which
allow flow steps to act as flow label transformers. If a value associated with ``predlbl`` arrives
at the start node of the additional step, it is propagated to the end node and associated with
``succlbl``. Of course, ``predlbl`` and ``succlbl`` may be the same, indicating that the flow step
preserves this label. There can also be multiple values of ``succlbl`` for a single ``predlbl`` or
vice versa.
Note that if you do not restrict ``succlbl`` then it will be allowed to range over all flow labels.
This may cause labels that were previously blocked on a path to reappear, which is not usually what
you want.
The flow label-aware version of ``isBarrier`` is called ``isLabeledBarrier``: unlike ``isBarrier``,
which prevents any flow past the given node, it only blocks flow of values associated with one of
the specified flow labels.
Standard queries using flow labels
Standard queries using flow state
----------------------------------
Some of our standard security queries use flow labels. You can look at their implementation
to get a feeling for how to use flow labels in practice.
Some of our standard security queries use flow state. You can look at their implementation
to get a feeling for how to use flow state in practice.
In particular, both of the examples mentioned in the section on limitations of basic data flow above
are from standard security queries that use flow labels. The `Prototype-polluting merge call
<https://codeql.github.com/codeql-query-help/javascript/js-prototype-pollution/>`_ query uses two flow labels to distinguish completely
are from standard security queries that use flow state. The `Prototype-polluting merge call
<https://codeql.github.com/codeql-query-help/javascript/js-prototype-pollution/>`_ query uses two flow states to distinguish completely
tainted objects from partially tainted objects. The `Uncontrolled data used in path expression
<https://codeql.github.com/codeql-query-help/javascript/js-path-injection/>`_ query uses four flow labels to track whether a user-controlled
<https://codeql.github.com/codeql-query-help/javascript/js-path-injection/>`_ query uses four flow states to track whether a user-controlled
string may be an absolute path and whether it may contain ``..`` components.
Further reading

View File

@@ -1,142 +1,142 @@
package,sink,source,summary,sink:command-injection,sink:credentials-key,sink:jwt,sink:log-injection,sink:nosql-injection,sink:path-injection,sink:regex-use[0],sink:regex-use[1],sink:regex-use[c],sink:request-forgery,sink:request-forgery[TCP Addr + Port],sink:sql-injection,sink:url-redirection,sink:url-redirection[0],sink:url-redirection[receiver],sink:xpath-injection,source:environment,source:file,source:remote,source:stdin,summary:taint,summary:value
,,,8,,,,,,,,,,,,,,,,,,,,,3,5
archive/tar,,,5,,,,,,,,,,,,,,,,,,,,,5,
archive/zip,,,6,,,,,,,,,,,,,,,,,,,,,6,
bufio,,,17,,,,,,,,,,,,,,,,,,,,,17,
bytes,,,43,,,,,,,,,,,,,,,,,,,,,43,
clevergo.tech/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,,
compress/bzip2,,,1,,,,,,,,,,,,,,,,,,,,,1,
compress/flate,,,4,,,,,,,,,,,,,,,,,,,,,4,
compress/gzip,,,3,,,,,,,,,,,,,,,,,,,,,3,
compress/lzw,,,1,,,,,,,,,,,,,,,,,,,,,1,
compress/zlib,,,4,,,,,,,,,,,,,,,,,,,,,4,
container/heap,,,5,,,,,,,,,,,,,,,,,,,,,5,
container/list,,,20,,,,,,,,,,,,,,,,,,,,,20,
container/ring,,,5,,,,,,,,,,,,,,,,,,,,,5,
context,,,5,,,,,,,,,,,,,,,,,,,,,5,
crypto,,,10,,,,,,,,,,,,,,,,,,,,,10,
database/sql,30,,11,,,,,,,,,,,,30,,,,,,,,,11,
encoding,,,77,,,,,,,,,,,,,,,,,,,,,77,
errors,,,3,,,,,,,,,,,,,,,,,,,,,3,
expvar,,,6,,,,,,,,,,,,,,,,,,,,,6,
fmt,3,,16,,,,3,,,,,,,,,,,,,,,,,16,
github.com/ChrisTrenkamp/goxpath,3,,,,,,,,,,,,,,,,,,3,,,,,,
github.com/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
github.com/Sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,,
github.com/antchfx/htmlquery,4,,,,,,,,,,,,,,,,,,4,,,,,,
github.com/antchfx/jsonquery,4,,,,,,,,,,,,,,,,,,4,,,,,,
github.com/antchfx/xmlquery,8,,,,,,,,,,,,,,,,,,8,,,,,,
github.com/antchfx/xpath,4,,,,,,,,,,,,,,,,,,4,,,,,,
github.com/appleboy/gin-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
github.com/astaxie/beego,71,21,21,,,,34,,5,,,,,,30,2,,,,,,21,,21,
github.com/beego/beego,142,42,42,,,,68,,10,,,,,,60,4,,,,,,42,,42,
github.com/caarlos0/env,,5,2,,,,,,,,,,,,,,,,,5,,,,1,1
github.com/clevergo/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,,
github.com/codeskyblue/go-sh,4,,,4,,,,,,,,,,,,,,,,,,,,,
github.com/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
github.com/couchbaselabs/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
github.com/crankycoder/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
github.com/cristalhq/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
github.com/davecgh/go-spew/spew,9,,,,,,9,,,,,,,,,,,,,,,,,,
github.com/dgrijalva/jwt-go,3,,9,,2,1,,,,,,,,,,,,,,,,,,9,
github.com/elazarl/goproxy,2,2,2,,,,2,,,,,,,,,,,,,,,2,,2,
github.com/emicklei/go-restful,,7,,,,,,,,,,,,,,,,,,,,7,,,
github.com/evanphx/json-patch,,,12,,,,,,,,,,,,,,,,,,,,,12,
github.com/form3tech-oss/jwt-go,2,,,,2,,,,,,,,,,,,,,,,,,,,
github.com/gin-gonic/gin,3,46,2,,,,,,3,,,,,,,,,,,,,46,,2,
github.com/go-chi/chi,,3,,,,,,,,,,,,,,,,,,,,3,,,
github.com/go-chi/jwtauth,1,,,,1,,,,,,,,,,,,,,,,,,,,
github.com/go-gorm/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
github.com/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
github.com/go-kit/kit/auth/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
github.com/go-pg/pg/orm,,,6,,,,,,,,,,,,,,,,,,,,,6,
github.com/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
github.com/go-xorm/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,
github.com/gobuffalo/envy,,7,,,,,,,,,,,,,,,,,,7,,,,,
github.com/gobwas/ws,,2,,,,,,,,,,,,,,,,,,,,2,,,
github.com/gofiber/fiber,5,,,,,,,,4,,,,,,,,,1,,,,,,,
github.com/gogf/gf-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
github.com/gogf/gf/database/gdb,51,,,,,,,,,,,,,,51,,,,,,,,,,
github.com/going/toolkit/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
github.com/golang-jwt/jwt,3,,11,,2,1,,,,,,,,,,,,,,,,,,11,
github.com/golang/glog,90,,,,,,90,,,,,,,,,,,,,,,,,,
github.com/golang/protobuf/proto,,,4,,,,,,,,,,,,,,,,,,,,,4,
github.com/gorilla/mux,,1,,,,,,,,,,,,,,,,,,,,1,,,
github.com/gorilla/websocket,,3,,,,,,,,,,,,,,,,,,,,3,,,
github.com/hashicorp/go-envparse,,1,,,,,,,,,,,,,,,,,,1,,,,,
github.com/jbowtie/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,,
github.com/jbowtie/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,,
github.com/jinzhu/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
github.com/jmoiron/sqlx,12,,,,,,,,,,,,,,12,,,,,,,,,,
github.com/joho/godotenv,,4,,,,,,,,,,,,,,,,,,4,,,,,
github.com/json-iterator/go,,,4,,,,,,,,,,,,,,,,,,,,,4,
github.com/kataras/iris/context,6,,,,,,,,6,,,,,,,,,,,,,,,,
github.com/kataras/iris/middleware/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,,
github.com/kataras/iris/server/web/context,6,,,,,,,,6,,,,,,,,,,,,,,,,
github.com/kataras/jwt,5,,,,5,,,,,,,,,,,,,,,,,,,,
github.com/kelseyhightower/envconfig,,6,,,,,,,,,,,,,,,,,,6,,,,,
github.com/labstack/echo,3,12,2,,,,,,2,,,,,,,1,,,,,,12,,2,
github.com/lann/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
github.com/lestrrat-go/jwx,2,,,,2,,,,,,,,,,,,,,,,,,,,
github.com/lestrrat-go/libxml2/parser,3,,,,,,,,,,,,,,,,,,3,,,,,,
github.com/lestrrat/go-jwx/jwk,1,,,,1,,,,,,,,,,,,,,,,,,,,
github.com/masterzen/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
github.com/moovweb/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,,
github.com/moovweb/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,,
github.com/ory/fosite/token/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,,
github.com/raindog308/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,,
github.com/revel/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,23,,10,
github.com/robfig/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,23,,10,
github.com/rqlite/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,,
github.com/santhosh-tekuri/xpathparser,2,,,,,,,,,,,,,,,,,,2,,,,,,
github.com/sendgrid/sendgrid-go/helpers/mail,,,1,,,,,,,,,,,,,,,,,,,,,1,
github.com/sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,,
github.com/spf13/afero,34,,,,,,,,34,,,,,,,,,,,,,,,,
github.com/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
github.com/uptrace/bun,63,,,,,,,,,,,,,,63,,,,,,,,,,
github.com/valyala/fasthttp,35,50,5,,,,,,8,,,,17,8,,2,,,,,,50,,5,
go.mongodb.org/mongo-driver/mongo,14,,,,,,,14,,,,,,,,,,,,,,,,,
go.uber.org/zap,33,,11,,,,33,,,,,,,,,,,,,,,,,11,
golang.org/x/crypto/ssh,4,,,4,,,,,,,,,,,,,,,,,,,,,
golang.org/x/net/context,,,5,,,,,,,,,,,,,,,,,,,,,5,
golang.org/x/net/html,,,16,,,,,,,,,,,,,,,,,,,,,16,
golang.org/x/net/websocket,,2,,,,,,,,,,,,,,,,,,,,2,,,
google.golang.org/protobuf/internal/encoding/text,,,1,,,,,,,,,,,,,,,,,,,,,1,
google.golang.org/protobuf/internal/impl,,,2,,,,,,,,,,,,,,,,,,,,,2,
google.golang.org/protobuf/proto,,,8,,,,,,,,,,,,,,,,,,,,,8,
google.golang.org/protobuf/reflect/protoreflect,,,1,,,,,,,,,,,,,,,,,,,,,1,
gopkg.in/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
gopkg.in/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
gopkg.in/glog,90,,,,,,90,,,,,,,,,,,,,,,,,,
gopkg.in/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
gopkg.in/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
gopkg.in/macaron,1,12,1,,,,,,,,,,,,,,,1,,,,12,,1,
gopkg.in/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
gopkg.in/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
gopkg.in/yaml,,,9,,,,,,,,,,,,,,,,,,,,,9,
gorm.io/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
html,,,8,,,,,,,,,,,,,,,,,,,,,8,
io,5,4,34,,,,,,5,,,,,,,,,,,,4,,,34,
k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,,,,,10,
k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,,,,,47,
k8s.io/klog,90,,,,,,90,,,,,,,,,,,,,,,,,,
launchpad.net/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
log,20,,3,,,,20,,,,,,,,,,,,,,,,,3,
math/big,,,1,,,,,,,,,,,,,,,,,,,,,1,
mime,,,14,,,,,,,,,,,,,,,,,,,,,14,
net,2,16,100,,,,,,1,,,,,,,,1,,,,,16,,100,
nhooyr.io/websocket,,2,,,,,,,,,,,,,,,,,,,,2,,,
os,29,11,6,3,,,,,26,,,,,,,,,,,7,3,,1,6,
path,,,18,,,,,,,,,,,,,,,,,,,,,18,
reflect,,,37,,,,,,,,,,,,,,,,,,,,,37,
regexp,10,,20,,,,,,,3,3,4,,,,,,,,,,,,20,
slices,,,17,,,,,,,,,,,,,,,,,,,,,,17
sort,,,1,,,,,,,,,,,,,,,,,,,,,1,
strconv,,,9,,,,,,,,,,,,,,,,,,,,,9,
strings,,,34,,,,,,,,,,,,,,,,,,,,,34,
sync,,,34,,,,,,,,,,,,,,,,,,,,,34,
syscall,5,2,8,5,,,,,,,,,,,,,,,,2,,,,8,
text/scanner,,,3,,,,,,,,,,,,,,,,,,,,,3,
text/tabwriter,,,1,,,,,,,,,,,,,,,,,,,,,1,
text/template,,,6,,,,,,,,,,,,,,,,,,,,,6,
xorm.io/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,
package,sink,source,summary,sink:command-injection,sink:credentials-key,sink:jwt,sink:log-injection,sink:nosql-injection,sink:path-injection,sink:regex-use[0],sink:regex-use[1],sink:regex-use[c],sink:request-forgery,sink:request-forgery[TCP Addr + Port],sink:sql-injection,sink:url-redirection,sink:url-redirection[0],sink:url-redirection[receiver],sink:xpath-injection,source:commandargs,source:environment,source:file,source:remote,source:stdin,summary:taint,summary:value
,,,8,,,,,,,,,,,,,,,,,,,,,,3,5
archive/tar,,,5,,,,,,,,,,,,,,,,,,,,,,5,
archive/zip,,,6,,,,,,,,,,,,,,,,,,,,,,6,
bufio,,,17,,,,,,,,,,,,,,,,,,,,,,17,
bytes,,,43,,,,,,,,,,,,,,,,,,,,,,43,
clevergo.tech/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,,,
compress/bzip2,,,1,,,,,,,,,,,,,,,,,,,,,,1,
compress/flate,,,4,,,,,,,,,,,,,,,,,,,,,,4,
compress/gzip,,,3,,,,,,,,,,,,,,,,,,,,,,3,
compress/lzw,,,1,,,,,,,,,,,,,,,,,,,,,,1,
compress/zlib,,,4,,,,,,,,,,,,,,,,,,,,,,4,
container/heap,,,5,,,,,,,,,,,,,,,,,,,,,,5,
container/list,,,20,,,,,,,,,,,,,,,,,,,,,,20,
container/ring,,,5,,,,,,,,,,,,,,,,,,,,,,5,
context,,,5,,,,,,,,,,,,,,,,,,,,,,5,
crypto,,,10,,,,,,,,,,,,,,,,,,,,,,10,
database/sql,30,,11,,,,,,,,,,,,30,,,,,,,,,,11,
encoding,,,77,,,,,,,,,,,,,,,,,,,,,,77,
errors,,,3,,,,,,,,,,,,,,,,,,,,,,3,
expvar,,,6,,,,,,,,,,,,,,,,,,,,,,6,
fmt,3,,16,,,,3,,,,,,,,,,,,,,,,,,16,
github.com/ChrisTrenkamp/goxpath,3,,,,,,,,,,,,,,,,,,3,,,,,,,
github.com/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,,
github.com/Sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,,,
github.com/antchfx/htmlquery,4,,,,,,,,,,,,,,,,,,4,,,,,,,
github.com/antchfx/jsonquery,4,,,,,,,,,,,,,,,,,,4,,,,,,,
github.com/antchfx/xmlquery,8,,,,,,,,,,,,,,,,,,8,,,,,,,
github.com/antchfx/xpath,4,,,,,,,,,,,,,,,,,,4,,,,,,,
github.com/appleboy/gin-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,,
github.com/astaxie/beego,71,21,21,,,,34,,5,,,,,,30,2,,,,,,,21,,21,
github.com/beego/beego,142,42,42,,,,68,,10,,,,,,60,4,,,,,,,42,,42,
github.com/caarlos0/env,,5,2,,,,,,,,,,,,,,,,,,5,,,,1,1
github.com/clevergo/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,,,
github.com/codeskyblue/go-sh,4,,,4,,,,,,,,,,,,,,,,,,,,,,
github.com/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,,18,
github.com/couchbaselabs/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,,18,
github.com/crankycoder/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,,
github.com/cristalhq/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,,
github.com/davecgh/go-spew/spew,9,,,,,,9,,,,,,,,,,,,,,,,,,,
github.com/dgrijalva/jwt-go,3,,9,,2,1,,,,,,,,,,,,,,,,,,,9,
github.com/elazarl/goproxy,2,2,2,,,,2,,,,,,,,,,,,,,,,2,,2,
github.com/emicklei/go-restful,,7,,,,,,,,,,,,,,,,,,,,,7,,,
github.com/evanphx/json-patch,,,12,,,,,,,,,,,,,,,,,,,,,,12,
github.com/form3tech-oss/jwt-go,2,,,,2,,,,,,,,,,,,,,,,,,,,,
github.com/gin-gonic/gin,3,46,2,,,,,,3,,,,,,,,,,,,,,46,,2,
github.com/go-chi/chi,,3,,,,,,,,,,,,,,,,,,,,,3,,,
github.com/go-chi/jwtauth,1,,,,1,,,,,,,,,,,,,,,,,,,,,
github.com/go-gorm/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,,
github.com/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,,4,
github.com/go-kit/kit/auth/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,,
github.com/go-pg/pg/orm,,,6,,,,,,,,,,,,,,,,,,,,,,6,
github.com/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,,
github.com/go-xorm/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,,
github.com/gobuffalo/envy,,7,,,,,,,,,,,,,,,,,,,7,,,,,
github.com/gobwas/ws,,2,,,,,,,,,,,,,,,,,,,,,2,,,
github.com/gofiber/fiber,5,,,,,,,,4,,,,,,,,,1,,,,,,,,
github.com/gogf/gf-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,,
github.com/gogf/gf/database/gdb,51,,,,,,,,,,,,,,51,,,,,,,,,,,
github.com/going/toolkit/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,,
github.com/golang-jwt/jwt,3,,11,,2,1,,,,,,,,,,,,,,,,,,,11,
github.com/golang/glog,90,,,,,,90,,,,,,,,,,,,,,,,,,,
github.com/golang/protobuf/proto,,,4,,,,,,,,,,,,,,,,,,,,,,4,
github.com/gorilla/mux,,1,,,,,,,,,,,,,,,,,,,,,1,,,
github.com/gorilla/websocket,,3,,,,,,,,,,,,,,,,,,,,,3,,,
github.com/hashicorp/go-envparse,,1,,,,,,,,,,,,,,,,,,,1,,,,,
github.com/jbowtie/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,,,
github.com/jbowtie/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,,,
github.com/jinzhu/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,,
github.com/jmoiron/sqlx,12,,,,,,,,,,,,,,12,,,,,,,,,,,
github.com/joho/godotenv,,4,,,,,,,,,,,,,,,,,,,4,,,,,
github.com/json-iterator/go,,,4,,,,,,,,,,,,,,,,,,,,,,4,
github.com/kataras/iris/context,6,,,,,,,,6,,,,,,,,,,,,,,,,,
github.com/kataras/iris/middleware/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,,,
github.com/kataras/iris/server/web/context,6,,,,,,,,6,,,,,,,,,,,,,,,,,
github.com/kataras/jwt,5,,,,5,,,,,,,,,,,,,,,,,,,,,
github.com/kelseyhightower/envconfig,,6,,,,,,,,,,,,,,,,,,,6,,,,,
github.com/labstack/echo,3,12,2,,,,,,2,,,,,,,1,,,,,,,12,,2,
github.com/lann/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,,
github.com/lestrrat-go/jwx,2,,,,2,,,,,,,,,,,,,,,,,,,,,
github.com/lestrrat-go/libxml2/parser,3,,,,,,,,,,,,,,,,,,3,,,,,,,
github.com/lestrrat/go-jwx/jwk,1,,,,1,,,,,,,,,,,,,,,,,,,,,
github.com/masterzen/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,,
github.com/moovweb/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,,,
github.com/moovweb/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,,,
github.com/ory/fosite/token/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,,,
github.com/raindog308/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,,,
github.com/revel/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,,23,,10,
github.com/robfig/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,,23,,10,
github.com/rqlite/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,,,
github.com/santhosh-tekuri/xpathparser,2,,,,,,,,,,,,,,,,,,2,,,,,,,
github.com/sendgrid/sendgrid-go/helpers/mail,,,1,,,,,,,,,,,,,,,,,,,,,,1,
github.com/sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,,,
github.com/spf13/afero,34,,,,,,,,34,,,,,,,,,,,,,,,,,
github.com/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,,4,
github.com/uptrace/bun,63,,,,,,,,,,,,,,63,,,,,,,,,,,
github.com/valyala/fasthttp,35,50,5,,,,,,8,,,,17,8,,2,,,,,,,50,,5,
go.mongodb.org/mongo-driver/mongo,14,,,,,,,14,,,,,,,,,,,,,,,,,,
go.uber.org/zap,33,,11,,,,33,,,,,,,,,,,,,,,,,,11,
golang.org/x/crypto/ssh,4,,,4,,,,,,,,,,,,,,,,,,,,,,
golang.org/x/net/context,,,5,,,,,,,,,,,,,,,,,,,,,,5,
golang.org/x/net/html,,,16,,,,,,,,,,,,,,,,,,,,,,16,
golang.org/x/net/websocket,,2,,,,,,,,,,,,,,,,,,,,,2,,,
google.golang.org/protobuf/internal/encoding/text,,,1,,,,,,,,,,,,,,,,,,,,,,1,
google.golang.org/protobuf/internal/impl,,,2,,,,,,,,,,,,,,,,,,,,,,2,
google.golang.org/protobuf/proto,,,8,,,,,,,,,,,,,,,,,,,,,,8,
google.golang.org/protobuf/reflect/protoreflect,,,1,,,,,,,,,,,,,,,,,,,,,,1,
gopkg.in/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,,
gopkg.in/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,,18,
gopkg.in/glog,90,,,,,,90,,,,,,,,,,,,,,,,,,,
gopkg.in/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,,4,
gopkg.in/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,,
gopkg.in/macaron,1,12,1,,,,,,,,,,,,,,,1,,,,,12,,1,
gopkg.in/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,,4,
gopkg.in/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,,
gopkg.in/yaml,,,9,,,,,,,,,,,,,,,,,,,,,,9,
gorm.io/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,,
html,,,8,,,,,,,,,,,,,,,,,,,,,,8,
io,5,4,34,,,,,,5,,,,,,,,,,,,,4,,,34,
k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,,,,,,10,
k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,,,,,,47,
k8s.io/klog,90,,,,,,90,,,,,,,,,,,,,,,,,,,
launchpad.net/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,,
log,20,,3,,,,20,,,,,,,,,,,,,,,,,,3,
math/big,,,1,,,,,,,,,,,,,,,,,,,,,,1,
mime,,,14,,,,,,,,,,,,,,,,,,,,,,14,
net,2,16,100,,,,,,1,,,,,,,,1,,,,,,16,,100,
nhooyr.io/websocket,,2,,,,,,,,,,,,,,,,,,,,,2,,,
os,29,12,6,3,,,,,26,,,,,,,,,,,1,7,3,,1,6,
path,,,18,,,,,,,,,,,,,,,,,,,,,,18,
reflect,,,37,,,,,,,,,,,,,,,,,,,,,,37,
regexp,10,,20,,,,,,,3,3,4,,,,,,,,,,,,,20,
slices,,,17,,,,,,,,,,,,,,,,,,,,,,,17
sort,,,1,,,,,,,,,,,,,,,,,,,,,,1,
strconv,,,9,,,,,,,,,,,,,,,,,,,,,,9,
strings,,,34,,,,,,,,,,,,,,,,,,,,,,34,
sync,,,34,,,,,,,,,,,,,,,,,,,,,,34,
syscall,5,2,8,5,,,,,,,,,,,,,,,,,2,,,,8,
text/scanner,,,3,,,,,,,,,,,,,,,,,,,,,,3,
text/tabwriter,,,1,,,,,,,,,,,,,,,,,,,,,,1,
text/template,,,6,,,,,,,,,,,,,,,,,,,,,,6,
xorm.io/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,,
1 package sink source summary sink:command-injection sink:credentials-key sink:jwt sink:log-injection sink:nosql-injection sink:path-injection sink:regex-use[0] sink:regex-use[1] sink:regex-use[c] sink:request-forgery sink:request-forgery[TCP Addr + Port] sink:sql-injection sink:url-redirection sink:url-redirection[0] sink:url-redirection[receiver] sink:xpath-injection source:commandargs source:environment source:file source:remote source:stdin summary:taint summary:value
2 8 3 5
3 archive/tar 5 5
4 archive/zip 6 6
5 bufio 17 17
6 bytes 43 43
7 clevergo.tech/clevergo 1 1
8 compress/bzip2 1 1
9 compress/flate 4 4
10 compress/gzip 3 3
11 compress/lzw 1 1
12 compress/zlib 4 4
13 container/heap 5 5
14 container/list 20 20
15 container/ring 5 5
16 context 5 5
17 crypto 10 10
18 database/sql 30 11 30 11
19 encoding 77 77
20 errors 3 3
21 expvar 6 6
22 fmt 3 16 3 16
23 github.com/ChrisTrenkamp/goxpath 3 3
24 github.com/Masterminds/squirrel 32 32
25 github.com/Sirupsen/logrus 145 145
26 github.com/antchfx/htmlquery 4 4
27 github.com/antchfx/jsonquery 4 4
28 github.com/antchfx/xmlquery 8 8
29 github.com/antchfx/xpath 4 4
30 github.com/appleboy/gin-jwt 1 1
31 github.com/astaxie/beego 71 21 21 34 5 30 2 21 21
32 github.com/beego/beego 142 42 42 68 10 60 4 42 42
33 github.com/caarlos0/env 5 2 5 1 1
34 github.com/clevergo/clevergo 1 1
35 github.com/codeskyblue/go-sh 4 4
36 github.com/couchbase/gocb 8 18 8 18
37 github.com/couchbaselabs/gocb 8 18 8 18
38 github.com/crankycoder/xmlpath 2 2
39 github.com/cristalhq/jwt 1 1
40 github.com/davecgh/go-spew/spew 9 9
41 github.com/dgrijalva/jwt-go 3 9 2 1 9
42 github.com/elazarl/goproxy 2 2 2 2 2 2
43 github.com/emicklei/go-restful 7 7
44 github.com/evanphx/json-patch 12 12
45 github.com/form3tech-oss/jwt-go 2 2
46 github.com/gin-gonic/gin 3 46 2 3 46 2
47 github.com/go-chi/chi 3 3
48 github.com/go-chi/jwtauth 1 1
49 github.com/go-gorm/gorm 13 13
50 github.com/go-jose/go-jose 3 4 2 1 4
51 github.com/go-kit/kit/auth/jwt 1 1
52 github.com/go-pg/pg/orm 6 6
53 github.com/go-xmlpath/xmlpath 2 2
54 github.com/go-xorm/xorm 34 34
55 github.com/gobuffalo/envy 7 7
56 github.com/gobwas/ws 2 2
57 github.com/gofiber/fiber 5 4 1
58 github.com/gogf/gf-jwt 1 1
59 github.com/gogf/gf/database/gdb 51 51
60 github.com/going/toolkit/xmlpath 2 2
61 github.com/golang-jwt/jwt 3 11 2 1 11
62 github.com/golang/glog 90 90
63 github.com/golang/protobuf/proto 4 4
64 github.com/gorilla/mux 1 1
65 github.com/gorilla/websocket 3 3
66 github.com/hashicorp/go-envparse 1 1
67 github.com/jbowtie/gokogiri/xml 4 4
68 github.com/jbowtie/gokogiri/xpath 1 1
69 github.com/jinzhu/gorm 13 13
70 github.com/jmoiron/sqlx 12 12
71 github.com/joho/godotenv 4 4
72 github.com/json-iterator/go 4 4
73 github.com/kataras/iris/context 6 6
74 github.com/kataras/iris/middleware/jwt 2 2
75 github.com/kataras/iris/server/web/context 6 6
76 github.com/kataras/jwt 5 5
77 github.com/kelseyhightower/envconfig 6 6
78 github.com/labstack/echo 3 12 2 2 1 12 2
79 github.com/lann/squirrel 32 32
80 github.com/lestrrat-go/jwx 2 2
81 github.com/lestrrat-go/libxml2/parser 3 3
82 github.com/lestrrat/go-jwx/jwk 1 1
83 github.com/masterzen/xmlpath 2 2
84 github.com/moovweb/gokogiri/xml 4 4
85 github.com/moovweb/gokogiri/xpath 1 1
86 github.com/ory/fosite/token/jwt 2 2
87 github.com/raindog308/gorqlite 24 24
88 github.com/revel/revel 2 23 10 1 1 23 10
89 github.com/robfig/revel 2 23 10 1 1 23 10
90 github.com/rqlite/gorqlite 24 24
91 github.com/santhosh-tekuri/xpathparser 2 2
92 github.com/sendgrid/sendgrid-go/helpers/mail 1 1
93 github.com/sirupsen/logrus 145 145
94 github.com/spf13/afero 34 34
95 github.com/square/go-jose 3 4 2 1 4
96 github.com/uptrace/bun 63 63
97 github.com/valyala/fasthttp 35 50 5 8 17 8 2 50 5
98 go.mongodb.org/mongo-driver/mongo 14 14
99 go.uber.org/zap 33 11 33 11
100 golang.org/x/crypto/ssh 4 4
101 golang.org/x/net/context 5 5
102 golang.org/x/net/html 16 16
103 golang.org/x/net/websocket 2 2
104 google.golang.org/protobuf/internal/encoding/text 1 1
105 google.golang.org/protobuf/internal/impl 2 2
106 google.golang.org/protobuf/proto 8 8
107 google.golang.org/protobuf/reflect/protoreflect 1 1
108 gopkg.in/Masterminds/squirrel 32 32
109 gopkg.in/couchbase/gocb 8 18 8 18
110 gopkg.in/glog 90 90
111 gopkg.in/go-jose/go-jose 3 4 2 1 4
112 gopkg.in/go-xmlpath/xmlpath 2 2
113 gopkg.in/macaron 1 12 1 1 12 1
114 gopkg.in/square/go-jose 3 4 2 1 4
115 gopkg.in/xmlpath 2 2
116 gopkg.in/yaml 9 9
117 gorm.io/gorm 13 13
118 html 8 8
119 io 5 4 34 5 4 34
120 k8s.io/api/core 10 10
121 k8s.io/apimachinery/pkg/runtime 47 47
122 k8s.io/klog 90 90
123 launchpad.net/xmlpath 2 2
124 log 20 3 20 3
125 math/big 1 1
126 mime 14 14
127 net 2 16 100 1 1 16 100
128 nhooyr.io/websocket 2 2
129 os 29 11 12 6 3 26 1 7 3 1 6
130 path 18 18
131 reflect 37 37
132 regexp 10 20 3 3 4 20
133 slices 17 17
134 sort 1 1
135 strconv 9 9
136 strings 34 34
137 sync 34 34
138 syscall 5 2 8 5 2 8
139 text/scanner 3 3
140 text/tabwriter 1 1
141 text/template 6 6
142 xorm.io/xorm 34 34

View File

@@ -26,7 +26,7 @@ Go framework & library support
`Macaron <https://gopkg.in/macaron.v1>`_,``gopkg.in/macaron*``,12,1,1
`Revel <http://revel.github.io/>`_,"``github.com/revel/revel*``, ``github.com/robfig/revel*``",46,20,4
`SendGrid <https://github.com/sendgrid/sendgrid-go>`_,``github.com/sendgrid/sendgrid-go*``,,1,
`Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",33,604,104
`Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",34,604,104
`XPath <https://github.com/antchfx/xpath>`_,``github.com/antchfx/xpath*``,,,4
`appleboy/gin-jwt <https://github.com/appleboy/gin-jwt>`_,``github.com/appleboy/gin-jwt*``,,,1
`beego <https://beego.me/>`_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",63,63,213
@@ -61,5 +61,5 @@ Go framework & library support
`yaml <https://gopkg.in/yaml.v3>`_,``gopkg.in/yaml*``,,9,
`zap <https://go.uber.org/zap>`_,``go.uber.org/zap*``,,11,33
Others,"``github.com/Masterminds/squirrel``, ``github.com/caarlos0/env``, ``github.com/go-gorm/gorm``, ``github.com/go-xorm/xorm``, ``github.com/gobuffalo/envy``, ``github.com/gogf/gf/database/gdb``, ``github.com/hashicorp/go-envparse``, ``github.com/jinzhu/gorm``, ``github.com/jmoiron/sqlx``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``, ``github.com/lann/squirrel``, ``github.com/raindog308/gorqlite``, ``github.com/rqlite/gorqlite``, ``github.com/uptrace/bun``, ``go.mongodb.org/mongo-driver/mongo``, ``gopkg.in/Masterminds/squirrel``, ``gorm.io/gorm``, ``xorm.io/xorm``",23,2,391
Totals,,307,928,1532
Totals,,308,928,1532

View File

@@ -0,0 +1,34 @@
import java.util.function.Function;
class A {
String source() { return ""; }
void sink(String s) { }
String propagateState(String s, String state) {
return "";
}
void foo() {
Function<String, String> lambda = Math.random() > 0.5
? x -> propagateState(x, "A")
: x -> propagateState(x, "B");
String step0 = source();
String step1 = lambda.apply(step0);
String step2 = lambda.apply(step1);
sink(step2);
}
void bar() {
Function<String, String> lambda =
(x -> Math.random() > 0.5 ? propagateState(x, "A") : propagateState(x, "B"));
String step0 = source();
String step1 = lambda.apply(step0);
String step2 = lambda.apply(step1);
sink(step2);
}
}

View File

@@ -0,0 +1,79 @@
nodes
| A.java:14:9:14:9 | x : String | semmle.label | x : String |
| A.java:14:14:14:35 | propagateState(...) : String | semmle.label | propagateState(...) : String |
| A.java:14:29:14:29 | x : String | semmle.label | x : String |
| A.java:15:9:15:9 | x : String | semmle.label | x : String |
| A.java:15:14:15:35 | propagateState(...) : String | semmle.label | propagateState(...) : String |
| A.java:15:29:15:29 | x : String | semmle.label | x : String |
| A.java:17:20:17:27 | source(...) : String | semmle.label | source(...) : String |
| A.java:18:20:18:38 | apply(...) : String | semmle.label | apply(...) : String |
| A.java:18:20:18:38 | apply(...) : String | semmle.label | apply(...) : String |
| A.java:18:33:18:37 | step0 : String | semmle.label | step0 : String |
| A.java:19:20:19:38 | apply(...) : String | semmle.label | apply(...) : String |
| A.java:19:33:19:37 | step1 : String | semmle.label | step1 : String |
| A.java:19:33:19:37 | step1 : String | semmle.label | step1 : String |
| A.java:21:10:21:14 | step2 | semmle.label | step2 |
| A.java:26:8:26:8 | x : String | semmle.label | x : String |
| A.java:26:8:26:8 | x : String | semmle.label | x : String |
| A.java:26:13:26:81 | ...?...:... : String | semmle.label | ...?...:... : String |
| A.java:26:13:26:81 | ...?...:... : String | semmle.label | ...?...:... : String |
| A.java:26:35:26:56 | propagateState(...) : String | semmle.label | propagateState(...) : String |
| A.java:26:50:26:50 | x : String | semmle.label | x : String |
| A.java:26:60:26:81 | propagateState(...) : String | semmle.label | propagateState(...) : String |
| A.java:26:75:26:75 | x : String | semmle.label | x : String |
| A.java:28:20:28:27 | source(...) : String | semmle.label | source(...) : String |
| A.java:29:20:29:38 | apply(...) : String | semmle.label | apply(...) : String |
| A.java:29:20:29:38 | apply(...) : String | semmle.label | apply(...) : String |
| A.java:29:33:29:37 | step0 : String | semmle.label | step0 : String |
| A.java:30:20:30:38 | apply(...) : String | semmle.label | apply(...) : String |
| A.java:30:33:30:37 | step1 : String | semmle.label | step1 : String |
| A.java:30:33:30:37 | step1 : String | semmle.label | step1 : String |
| A.java:32:10:32:14 | step2 | semmle.label | step2 |
edges
| A.java:14:9:14:9 | x : String | A.java:14:29:14:29 | x : String | provenance | |
| A.java:14:29:14:29 | x : String | A.java:14:14:14:35 | propagateState(...) : String | provenance | Config |
| A.java:15:9:15:9 | x : String | A.java:15:29:15:29 | x : String | provenance | |
| A.java:15:29:15:29 | x : String | A.java:15:14:15:35 | propagateState(...) : String | provenance | Config |
| A.java:17:20:17:27 | source(...) : String | A.java:18:33:18:37 | step0 : String | provenance | |
| A.java:18:20:18:38 | apply(...) : String | A.java:19:33:19:37 | step1 : String | provenance | |
| A.java:18:20:18:38 | apply(...) : String | A.java:19:33:19:37 | step1 : String | provenance | |
| A.java:18:33:18:37 | step0 : String | A.java:14:9:14:9 | x : String | provenance | |
| A.java:18:33:18:37 | step0 : String | A.java:15:9:15:9 | x : String | provenance | |
| A.java:18:33:18:37 | step0 : String | A.java:18:20:18:38 | apply(...) : String | provenance | Config |
| A.java:18:33:18:37 | step0 : String | A.java:18:20:18:38 | apply(...) : String | provenance | Config |
| A.java:19:20:19:38 | apply(...) : String | A.java:21:10:21:14 | step2 | provenance | |
| A.java:19:33:19:37 | step1 : String | A.java:14:9:14:9 | x : String | provenance | |
| A.java:19:33:19:37 | step1 : String | A.java:15:9:15:9 | x : String | provenance | |
| A.java:19:33:19:37 | step1 : String | A.java:19:20:19:38 | apply(...) : String | provenance | Config |
| A.java:19:33:19:37 | step1 : String | A.java:19:20:19:38 | apply(...) : String | provenance | Config |
| A.java:26:8:26:8 | x : String | A.java:26:50:26:50 | x : String | provenance | |
| A.java:26:8:26:8 | x : String | A.java:26:75:26:75 | x : String | provenance | |
| A.java:26:35:26:56 | propagateState(...) : String | A.java:26:13:26:81 | ...?...:... : String | provenance | |
| A.java:26:50:26:50 | x : String | A.java:26:35:26:56 | propagateState(...) : String | provenance | Config |
| A.java:26:60:26:81 | propagateState(...) : String | A.java:26:13:26:81 | ...?...:... : String | provenance | |
| A.java:26:75:26:75 | x : String | A.java:26:60:26:81 | propagateState(...) : String | provenance | Config |
| A.java:28:20:28:27 | source(...) : String | A.java:29:33:29:37 | step0 : String | provenance | |
| A.java:29:20:29:38 | apply(...) : String | A.java:30:33:30:37 | step1 : String | provenance | |
| A.java:29:20:29:38 | apply(...) : String | A.java:30:33:30:37 | step1 : String | provenance | |
| A.java:29:33:29:37 | step0 : String | A.java:26:8:26:8 | x : String | provenance | |
| A.java:29:33:29:37 | step0 : String | A.java:26:8:26:8 | x : String | provenance | |
| A.java:29:33:29:37 | step0 : String | A.java:29:20:29:38 | apply(...) : String | provenance | Config |
| A.java:29:33:29:37 | step0 : String | A.java:29:20:29:38 | apply(...) : String | provenance | Config |
| A.java:30:20:30:38 | apply(...) : String | A.java:32:10:32:14 | step2 | provenance | |
| A.java:30:33:30:37 | step1 : String | A.java:26:8:26:8 | x : String | provenance | |
| A.java:30:33:30:37 | step1 : String | A.java:26:8:26:8 | x : String | provenance | |
| A.java:30:33:30:37 | step1 : String | A.java:30:20:30:38 | apply(...) : String | provenance | Config |
| A.java:30:33:30:37 | step1 : String | A.java:30:20:30:38 | apply(...) : String | provenance | Config |
subpaths
| A.java:18:33:18:37 | step0 : String | A.java:14:9:14:9 | x : String | A.java:14:14:14:35 | propagateState(...) : String | A.java:18:20:18:38 | apply(...) : String |
| A.java:18:33:18:37 | step0 : String | A.java:15:9:15:9 | x : String | A.java:15:14:15:35 | propagateState(...) : String | A.java:18:20:18:38 | apply(...) : String |
| A.java:19:33:19:37 | step1 : String | A.java:14:9:14:9 | x : String | A.java:14:14:14:35 | propagateState(...) : String | A.java:19:20:19:38 | apply(...) : String |
| A.java:19:33:19:37 | step1 : String | A.java:15:9:15:9 | x : String | A.java:15:14:15:35 | propagateState(...) : String | A.java:19:20:19:38 | apply(...) : String |
| A.java:29:33:29:37 | step0 : String | A.java:26:8:26:8 | x : String | A.java:26:13:26:81 | ...?...:... : String | A.java:29:20:29:38 | apply(...) : String |
| A.java:29:33:29:37 | step0 : String | A.java:26:8:26:8 | x : String | A.java:26:13:26:81 | ...?...:... : String | A.java:29:20:29:38 | apply(...) : String |
| A.java:30:33:30:37 | step1 : String | A.java:26:8:26:8 | x : String | A.java:26:13:26:81 | ...?...:... : String | A.java:30:20:30:38 | apply(...) : String |
| A.java:30:33:30:37 | step1 : String | A.java:26:8:26:8 | x : String | A.java:26:13:26:81 | ...?...:... : String | A.java:30:20:30:38 | apply(...) : String |
spuriousFlow
#select
| A.java:17:20:17:27 | source(...) : String | A.java:17:20:17:27 | source(...) : String | A.java:21:10:21:14 | step2 | Flow |
| A.java:28:20:28:27 | source(...) : String | A.java:28:20:28:27 | source(...) : String | A.java:32:10:32:14 | step2 | Flow |

View File

@@ -0,0 +1,84 @@
/**
* @kind path-problem
*/
import java
import semmle.code.java.dataflow.DataFlow
import DataFlow
MethodCall propagateCall(string state) {
result.getMethod().getName() = "propagateState" and
state = result.getArgument(1).(StringLiteral).getValue()
}
module TestConfig implements StateConfigSig {
class FlowState = string;
predicate isSource(Node n, FlowState state) {
n.asExpr().(MethodCall).getMethod().getName() = "source" and state = ["A", "B"]
}
predicate isSink(Node n, FlowState state) {
n.asExpr() = any(MethodCall acc | acc.getMethod().getName() = "sink").getAnArgument() and
state = ["A", "B"]
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
exists(MethodCall call |
call = propagateCall(state1) and
state2 = state1 and
node1.asExpr() = call.getArgument(0) and
node2.asExpr() = call
)
}
}
module TestFlow = DataFlow::GlobalWithState<TestConfig>;
module Graph = DataFlow::DeduplicatePathGraph<TestFlow::PathNode, TestFlow::PathGraph>;
/**
* Holds if `node` is reachable from a call to `propagateState` with the given `state` argument.
* `call` indicates if a call step was taken (i.e. into a subpath).
*
* We use this to check if one `propagateState` can flow out of another, which is not allowed.
*/
predicate reachableFromPropagate(Graph::PathNode node, string state, boolean call) {
node.getNode().asExpr() = propagateCall(state) and call = false
or
exists(Graph::PathNode prev | reachableFromPropagate(prev, state, call) |
Graph::edges(prev, node, _, _) and
not Graph::subpaths(prev, node, _, _) // argument-passing edges are handled separately
or
Graph::subpaths(prev, _, _, node) // arg -> out (should be included in 'edges' but handle the case here for clarity)
)
or
exists(Graph::PathNode prev |
reachableFromPropagate(prev, state, _) and
Graph::subpaths(prev, node, _, _) and // arg -> parameter
call = true
)
or
exists(Graph::PathNode prev |
reachableFromPropagate(prev, state, call) and
Graph::subpaths(_, _, prev, node) and // return -> out
call = false
)
}
/**
* Holds if `node` is the return value of a `propagateState` call that appears to be reachable
* with a different state than the one propagated by the call, indicating spurious flow resulting from
* merging path nodes.
*/
query predicate spuriousFlow(Graph::PathNode node, string state1, string state2) {
reachableFromPropagate(node, state1, _) and
node.getNode().asExpr() = propagateCall(state2) and
state1 != state2
}
import Graph::PathGraph
from Graph::PathNode source, Graph::PathNode sink
where TestFlow::flowPath(source.getAnOriginalPathNode(), sink.getAnOriginalPathNode())
select source, source, sink, "Flow"

View File

@@ -9,42 +9,42 @@
*/
import javascript
import DataFlow
import DataFlow::PathGraph
/**
* A taint-tracking configuration that tracks user-controlled values into a 'userId' property sent to a backend service.
*/
class IdorTaint extends TaintTracking::Configuration {
IdorTaint() { this = "IdorTaint" }
module IdorTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
override predicate isSource(Node node) { node instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node node) { exists(ClientRequest req | node = req.getADataNode()) }
override predicate isSink(Node node) { exists(ClientRequest req | node = req.getADataNode()) }
override predicate isAdditionalTaintStep(Node pred, Node succ) {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
// Step from x -> { userId: x }
succ.(SourceNode).getAPropertyWrite("userId").getRhs() = pred
node2.(DataFlow::SourceNode).getAPropertyWrite("userId").getRhs() = node1
}
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode node) {
predicate isBarrier(DataFlow::Node node) {
// After a check like `if (userId === session.user.id)`, the userId is considered safe.
node instanceof EqualityGuard
node = DataFlow::MakeBarrierGuard<EqualityGuard>::getABarrierNode()
}
}
/**
* A sanitizer for values that have successfully been compared to another value.
*/
class EqualityGuard extends TaintTracking::SanitizerGuardNode, ValueNode {
class EqualityGuard extends DataFlow::ValueNode {
override EqualityTest astNode;
override predicate sanitizes(boolean outcome, Expr e) {
predicate blocksExpr(boolean outcome, Expr e) {
e = astNode.getAnOperand() and
outcome = astNode.getPolarity()
}
}
from IdorTaint cfg, PathNode source, PathNode sink
where cfg.hasFlowPath(source, sink)
module IdorTaintFlow = TaintTracking::Global<IdorTaintConfig>;
import IdorTaintFlow::PathGraph
from IdorTaintFlow::PathNode source, IdorTaintFlow::PathNode sink
where IdorTaintFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Unauthenticated user ID from $@.", source.getNode(), "here"

View File

@@ -9,23 +9,25 @@
*/
import javascript
import DataFlow
import DataFlow::PathGraph
class DecodingAfterSanitization extends TaintTracking::Configuration {
DecodingAfterSanitization() { this = "DecodingAfterSanitization" }
module DecodingAfterSanitizationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
node.(DataFlow::CallNode).getCalleeName() = "escapeHtml"
}
override predicate isSource(Node node) { node.(CallNode).getCalleeName() = "escapeHtml" }
override predicate isSink(Node node) {
exists(CallNode call |
predicate isSink(DataFlow::Node node) {
exists(DataFlow::CallNode call |
call.getCalleeName().matches("decodeURI%") and
node = call.getArgument(0)
)
}
}
from DecodingAfterSanitization cfg, PathNode source, PathNode sink
where cfg.hasFlowPath(source, sink)
module DecodingAfterSanitizationFlow = TaintTracking::Global<DecodingAfterSanitizationConfig>;
import DecodingAfterSanitizationFlow::PathGraph
from DecodingAfterSanitizationFlow::PathNode source, DecodingAfterSanitizationFlow::PathNode sink
where DecodingAfterSanitizationFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "URI decoding invalidates the HTML sanitization performed $@.",
source.getNode(), "here"

View File

@@ -9,16 +9,14 @@
*/
import javascript
import DataFlow
import DataFlow::PathGraph
/**
* A call to a function that may introduce HTML meta-characters by
* replacing `%3C` or `\u003C` with `<`.
*/
class DecodingCall extends CallNode {
class DecodingCall extends DataFlow::CallNode {
string kind;
Node input;
DataFlow::Node input;
DecodingCall() {
this.getCalleeName().matches("decodeURI%") and
@@ -33,20 +31,24 @@ class DecodingCall extends CallNode {
string getKind() { result = kind }
/** Gets the input being decoded. */
Node getInput() { result = input }
DataFlow::Node getInput() { result = input }
}
class DecodingAfterSanitization extends TaintTracking::Configuration {
DecodingAfterSanitization() { this = "DecodingAfterSanitization" }
module DecodingAfterSanitizationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof HtmlSanitizerCall }
override predicate isSource(Node node) { node instanceof HtmlSanitizerCall }
override predicate isSink(Node node) { node = any(DecodingCall c).getInput() }
predicate isSink(DataFlow::Node node) { node = any(DecodingCall c).getInput() }
}
from DecodingAfterSanitization cfg, PathNode source, PathNode sink, DecodingCall decoder
module DecodingAfterSanitizationFlow = TaintTracking::Global<DecodingAfterSanitizationConfig>;
import DecodingAfterSanitizationFlow::PathGraph
from
DecodingAfterSanitizationFlow::PathNode source, DecodingAfterSanitizationFlow::PathNode sink,
DecodingCall decoder
where
cfg.hasFlowPath(source, sink) and
DecodingAfterSanitizationFlow::flowPath(source, sink) and
decoder.getInput() = sink.getNode()
select sink.getNode(), source, sink, decoder.getKind() + " invalidates $@.", source.getNode(),
"this HTML sanitization"

View File

@@ -8,16 +8,17 @@
*/
import javascript
import DataFlow
class EvalTaint extends TaintTracking::Configuration {
EvalTaint() { this = "EvalTaint" }
module EvalTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
override predicate isSource(Node node) { node instanceof RemoteFlowSource }
override predicate isSink(Node node) { node = globalVarRef("eval").getACall().getArgument(0) }
predicate isSink(DataFlow::Node node) {
node = DataFlow::globalVarRef("eval").getACall().getArgument(0)
}
}
from EvalTaint cfg, Node source, Node sink
where cfg.hasFlow(source, sink)
module EvalTaintFlow = TaintTracking::Global<EvalTaintConfig>;
from DataFlow::Node source, DataFlow::Node sink
where EvalTaintFlow::flow(source, sink)
select sink, "Eval with user-controlled input from $@.", source, "here"

View File

@@ -9,18 +9,20 @@
*/
import javascript
import DataFlow
import DataFlow::PathGraph
class EvalTaint extends TaintTracking::Configuration {
EvalTaint() { this = "EvalTaint" }
module EvalTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
override predicate isSource(Node node) { node instanceof RemoteFlowSource }
override predicate isSink(Node node) { node = globalVarRef("eval").getACall().getArgument(0) }
predicate isSink(DataFlow::Node node) {
node = DataFlow::globalVarRef("eval").getACall().getArgument(0)
}
}
from EvalTaint cfg, PathNode source, PathNode sink
where cfg.hasFlowPath(source, sink)
module EvalTaintFlow = TaintTracking::Global<EvalTaintConfig>;
import EvalTaintFlow::PathGraph
from EvalTaintFlow::PathNode source, EvalTaintFlow::PathNode sink
where EvalTaintFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Eval with user-controlled input from $@.", source.getNode(),
"here"

View File

@@ -9,8 +9,6 @@
*/
import javascript
import DataFlow
import DataFlow::PathGraph
/**
* A dataflow configuration that tracks authentication tokens ("authKey")
@@ -26,33 +24,37 @@ import DataFlow::PathGraph
* }), '*');
* ```
*/
class AuthKeyTracking extends DataFlow::Configuration {
AuthKeyTracking() { this = "AuthKeyTracking" }
module AuthKeyTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
node.(DataFlow::PropRead).getPropertyName() = "authKey"
}
override predicate isSource(Node node) { node.(PropRead).getPropertyName() = "authKey" }
override predicate isSink(Node node) {
exists(MethodCallNode call |
predicate isSink(DataFlow::Node node) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = "postMessage" and
call.getArgument(1).getStringValue() = "*" and // no restriction on target origin
call.getArgument(0) = node
)
}
override predicate isAdditionalFlowStep(Node pred, Node succ) {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
// Step into objects: x -> { f: x }
succ.(SourceNode).getAPropertyWrite().getRhs() = pred
node2.(DataFlow::SourceNode).getAPropertyWrite().getRhs() = node1
or
// Step through JSON serialization: x -> JSON.stringify(x)
// Note: TaintTracking::Configuration includes this step by default, but not DataFlow::Configuration
exists(CallNode call |
call = globalVarRef("JSON").getAMethodCall("stringify") and
pred = call.getArgument(0) and
succ = call
exists(DataFlow::CallNode call |
call = DataFlow::globalVarRef("JSON").getAMethodCall("stringify") and
node1 = call.getArgument(0) and
node2 = call
)
}
}
from AuthKeyTracking cfg, PathNode source, PathNode sink
where cfg.hasFlowPath(source, sink)
module AuthKeyTracking = DataFlow::Global<AuthKeyTrackingConfig>;
import AuthKeyTracking::PathGraph
from AuthKeyTracking::PathNode source, AuthKeyTracking::PathNode sink
where AuthKeyTracking::flowPath(source, sink)
select sink.getNode(), source, sink, "Message leaks the authKey from $@.", source.getNode(), "here"

View File

@@ -9,7 +9,7 @@
import javascript
import semmle.javascript.security.dataflow.StoredXssQuery
import DataFlow::PathGraph
import StoredXssFlow::PathGraph
/**
* The data returned from a MySQL query, such as the `data` parameter in this example:
@@ -31,6 +31,6 @@ class MysqlSource extends Source {
}
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
from StoredXssFlow::PathNode source, StoredXssFlow::PathNode sink
where StoredXssFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Stored XSS from $@.", source.getNode(), "database value."

View File

@@ -10,7 +10,7 @@
import javascript
import semmle.javascript.security.dataflow.StoredXssQuery
import DataFlow::PathGraph
import StoredXssFlow::PathGraph
/**
* Gets an instance of `mysql.createConnection()`, tracked globally.
@@ -45,6 +45,6 @@ class MysqlSource extends Source {
MysqlSource() { this = mysqlConnection().getAMethodCall("query").getCallback(1).getParameter(1) }
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
from StoredXssFlow::PathNode source, StoredXssFlow::PathNode sink
where StoredXssFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Stored XSS from $@.", source.getNode(), "database value."

View File

@@ -8,8 +8,6 @@
*/
import javascript
import DataFlow
import DataFlow::PathGraph
/**
* Gets the name of an unescaped placeholder in a lodash template.
@@ -21,13 +19,11 @@ string getAPlaceholderInString(string s) {
result = s.regexpCapture(".*<%=\\s*([a-zA-Z0-9_]+)\\s*%>.*", 1)
}
class TemplateInjection extends TaintTracking::Configuration {
TemplateInjection() { this = "TemplateInjection" }
module TemplateInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
override predicate isSource(Node node) { node instanceof RemoteFlowSource }
override predicate isSink(Node node) {
exists(CallNode call, string placeholder |
predicate isSink(DataFlow::Node node) {
exists(DataFlow::CallNode call, string placeholder |
call = LodashUnderscore::member("template").getACall() and
placeholder = getAPlaceholderInString(call.getArgument(0).getStringValue()) and
node = call.getOptionArgument(1, placeholder)
@@ -35,7 +31,11 @@ class TemplateInjection extends TaintTracking::Configuration {
}
}
from TemplateInjection cfg, PathNode source, PathNode sink
where cfg.hasFlowPath(source, sink)
module TemplateInjectionFlow = TaintTracking::Global<TemplateInjectionConfig>;
import TemplateInjectionFlow::PathGraph
from TemplateInjectionFlow::PathNode source, TemplateInjectionFlow::PathNode sink
where TemplateInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink,
"User-controlled value from $@ occurs unescaped in a lodash template.", source.getNode(), "here."

View File

@@ -9,8 +9,10 @@ dependencies:
codeql/dataflow: ${workspace}
codeql/mad: ${workspace}
codeql/regex: ${workspace}
codeql/ssa: ${workspace}
codeql/threat-models: ${workspace}
codeql/tutorial: ${workspace}
codeql/typetracking: ${workspace}
codeql/util: ${workspace}
codeql/xml: ${workspace}
codeql/yaml: ${workspace}

View File

@@ -6,6 +6,7 @@
import javascript
private import semmle.javascript.internal.CachedStages
private import Expressions.ExprHasNoEffect
private import semmle.javascript.dataflow.internal.DataFlowNode
/**
* Companion module to the `AmdModuleDefinition` class.
@@ -84,10 +85,15 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
result instanceof DataFlow::ValueNode
}
private DataFlow::Node getFactoryNodeInternal() {
// To avoid recursion, this should not depend on `SourceNode`.
result = DataFlow::valueNode(this.getLastArgument()) or
result = this.getFactoryNodeInternal().getAPredecessor()
/**
* Gets the factory function of this module definition.
*/
Function getFactoryFunction() { TValueNode(result) = this.getFactoryNodeInternal() }
private EarlyStageNode getFactoryNodeInternal() {
result = TValueNode(this.getLastArgument())
or
DataFlow::localFlowStep(result, this.getFactoryNodeInternal())
}
/** Gets the expression defining this module. */
@@ -139,7 +145,10 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
* Gets the `i`th parameter of the factory function of this module.
*/
private Parameter getFactoryParameter(int i) {
this.getFactoryNodeInternal().asExpr().(Function).getParameter(i) = result
exists(Function fun |
this.getFactoryNodeInternal() = TValueNode(fun) and
result = fun.getParameter(i)
)
}
/**

View File

@@ -9,7 +9,7 @@ module ArrayTaintTracking {
/**
* A taint propagating data flow edge caused by the builtin array functions.
*/
private class ArrayFunctionTaintStep extends TaintTracking::SharedTaintStep {
private class ArrayFunctionTaintStep extends TaintTracking::LegacyTaintStep {
override predicate arrayStep(DataFlow::Node pred, DataFlow::Node succ) {
arrayFunctionTaintStep(pred, succ, _)
}
@@ -130,7 +130,7 @@ private module ArrayDataFlow {
* A step modeling the creation of an Array using the `Array.from(x)` method.
* The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
*/
private class ArrayFrom extends PreCallGraphStep {
private class ArrayFrom extends LegacyPreCallGraphStep {
override predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp
) {
@@ -150,7 +150,7 @@ private module ArrayDataFlow {
*
* Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
*/
private class ArrayCopySpread extends PreCallGraphStep {
private class ArrayCopySpread extends LegacyPreCallGraphStep {
override predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp
) {
@@ -171,7 +171,7 @@ private module ArrayDataFlow {
/**
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
*/
private class ArrayAppendStep extends PreCallGraphStep {
private class ArrayAppendStep extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
prop = arrayElement() and
exists(DataFlow::MethodCallNode call |
@@ -202,7 +202,7 @@ private module ArrayDataFlow {
* A step for reading/writing an element from an array inside a for-loop.
* E.g. a read from `foo[i]` to `bar` in `for(var i = 0; i < arr.length; i++) {bar = foo[i]}`.
*/
private class ArrayIndexingStep extends PreCallGraphStep {
private class ArrayIndexingStep extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
exists(ArrayIndexingAccess access |
prop = arrayElement() and
@@ -224,7 +224,7 @@ private module ArrayDataFlow {
* A step for retrieving an element from an array using `.pop()`, `.shift()`, or `.at()`.
* E.g. `array.pop()`.
*/
private class ArrayPopStep extends PreCallGraphStep {
private class ArrayPopStep extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = ["pop", "shift", "at"] and
@@ -245,7 +245,7 @@ private module ArrayDataFlow {
*
* And the second parameter in the callback is the array ifself, so there is a `loadStoreStep` from the array to that second parameter.
*/
private class ArrayIteration extends PreCallGraphStep {
private class ArrayIteration extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = ["map", "forEach"] and
@@ -277,7 +277,7 @@ private module ArrayDataFlow {
/**
* A step for creating an array and storing the elements in the array.
*/
private class ArrayCreationStep extends PreCallGraphStep {
private class ArrayCreationStep extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
exists(DataFlow::ArrayCreationNode array, int i |
element = array.getElement(i) and
@@ -291,7 +291,7 @@ private module ArrayDataFlow {
* A step modeling that `splice` can insert elements into an array.
* For example in `array.splice(i, del, e1, e2, ...)`: if any item is tainted, then so is `array`
*/
private class ArraySpliceStep extends PreCallGraphStep {
private class ArraySpliceStep extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = ["splice", "toSpliced"] and
@@ -319,7 +319,7 @@ private module ArrayDataFlow {
* A step for modeling `concat`.
* For example in `e = arr1.concat(arr2, arr3)`: if any of the `arr` is tainted, then so is `e`.
*/
private class ArrayConcatStep extends PreCallGraphStep {
private class ArrayConcatStep extends LegacyPreCallGraphStep {
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = "concat" and
@@ -333,7 +333,7 @@ private module ArrayDataFlow {
/**
* A step for modeling that elements from an array `arr` also appear in the result from calling `slice`/`splice`/`filter`/`toSpliced`.
*/
private class ArraySliceStep extends PreCallGraphStep {
private class ArraySliceStep extends LegacyPreCallGraphStep {
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = ["slice", "splice", "filter", "toSpliced"] and
@@ -347,7 +347,7 @@ private module ArrayDataFlow {
/**
* A step modeling that elements from an array `arr` are received by calling `find`.
*/
private class ArrayFindStep extends PreCallGraphStep {
private class ArrayFindStep extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
exists(DataFlow::CallNode call |
call = arrayFindCall(pred) and
@@ -397,7 +397,7 @@ private module ArrayLibraries {
/**
* A taint step through the `arrify` library, or other libraries that (maybe) convert values into arrays.
*/
private class ArrayifyStep extends TaintTracking::SharedTaintStep {
private class ArrayifyStep extends TaintTracking::LegacyTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(API::CallNode call | call = API::moduleImport(["arrify", "array-ify"]).getACall() |
pred = call.getArgument(0) and succ = call
@@ -417,7 +417,7 @@ private module ArrayLibraries {
/**
* A taint step for a library that copies the elements of an array into another array.
*/
private class ArrayCopyTaint extends TaintTracking::SharedTaintStep {
private class ArrayCopyTaint extends TaintTracking::LegacyTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::CallNode call |
call = arrayCopyCall(pred) and
@@ -429,7 +429,7 @@ private module ArrayLibraries {
/**
* A loadStoreStep for a library that copies the elements of an array into another array.
*/
private class ArrayCopyLoadStore extends PreCallGraphStep {
private class ArrayCopyLoadStore extends LegacyPreCallGraphStep {
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
exists(DataFlow::CallNode call |
call = arrayCopyCall(pred) and
@@ -442,7 +442,7 @@ private module ArrayLibraries {
/**
* A taint step through a call to `Array.prototype.flat` or a polyfill implementing array flattening.
*/
private class ArrayFlatStep extends TaintTracking::SharedTaintStep {
private class ArrayFlatStep extends TaintTracking::LegacyTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::CallNode call | succ = call |
call.(DataFlow::MethodCallNode).getMethodName() = "flat" and

View File

@@ -3,356 +3,4 @@
* liveness information for local variables.
*/
import javascript
private import internal.StmtContainers
private import semmle.javascript.internal.CachedStages
/**
* Holds if `nd` starts a new basic block.
*/
private predicate startsBB(ControlFlowNode nd) {
not exists(nd.getAPredecessor()) and exists(nd.getASuccessor())
or
nd.isJoin()
or
nd.getAPredecessor().isBranch()
}
/**
* Holds if the first node of basic block `succ` is a control flow
* successor of the last node of basic block `bb`.
*/
private predicate succBB(BasicBlock bb, BasicBlock succ) { succ = bb.getLastNode().getASuccessor() }
/**
* Holds if the first node of basic block `bb` is a control flow
* successor of the last node of basic block `pre`.
*/
private predicate predBB(BasicBlock bb, BasicBlock pre) { succBB(pre, bb) }
/** Holds if `bb` is an entry basic block. */
private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof ControlFlowEntryNode }
/** Holds if `bb` is an exit basic block. */
private predicate exitBB(BasicBlock bb) { bb.getLastNode() instanceof ControlFlowExitNode }
cached
private module Internal {
/**
* Holds if `succ` is a control flow successor of `nd` within the same basic block.
*/
private predicate intraBBSucc(ControlFlowNode nd, ControlFlowNode succ) {
succ = nd.getASuccessor() and
not succ instanceof BasicBlock
}
/**
* Holds if `nd` is the `i`th node in basic block `bb`.
*
* In other words, `i` is the shortest distance from a node `bb`
* that starts a basic block to `nd` along the `intraBBSucc` relation.
*/
cached
predicate bbIndex(BasicBlock bb, ControlFlowNode nd, int i) =
shortestDistances(startsBB/1, intraBBSucc/2)(bb, nd, i)
cached
int bbLength(BasicBlock bb) { result = strictcount(ControlFlowNode nd | bbIndex(bb, nd, _)) }
cached
predicate useAt(BasicBlock bb, int i, Variable v, VarUse u) {
Stages::BasicBlocks::ref() and
v = u.getVariable() and
bbIndex(bb, u, i)
}
cached
predicate defAt(BasicBlock bb, int i, Variable v, VarDef d) {
exists(VarRef lhs |
lhs = d.getTarget().(BindingPattern).getABindingVarRef() and
v = lhs.getVariable()
|
lhs = d.getTarget() and
bbIndex(bb, d, i)
or
exists(PropertyPattern pp |
lhs = pp.getValuePattern() and
bbIndex(bb, pp, i)
)
or
exists(ObjectPattern op |
lhs = op.getRest() and
bbIndex(bb, lhs, i)
)
or
exists(ArrayPattern ap |
lhs = ap.getAnElement() and
bbIndex(bb, lhs, i)
)
)
}
cached
predicate reachableBB(BasicBlock bb) {
entryBB(bb)
or
exists(BasicBlock predBB | succBB(predBB, bb) | reachableBB(predBB))
}
}
private import Internal
/** Holds if `dom` is an immediate dominator of `bb`. */
cached
private predicate bbIDominates(BasicBlock dom, BasicBlock bb) =
idominance(entryBB/1, succBB/2)(_, dom, bb)
/** Holds if `dom` is an immediate post-dominator of `bb`. */
cached
private predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
idominance(exitBB/1, predBB/2)(_, dom, bb)
/**
* A basic block, that is, a maximal straight-line sequence of control flow nodes
* without branches or joins.
*
* At the database level, a basic block is represented by its first control flow node.
*/
class BasicBlock extends @cfg_node, NodeInStmtContainer {
cached
BasicBlock() { Stages::BasicBlocks::ref() and startsBB(this) }
/** Gets a basic block succeeding this one. */
BasicBlock getASuccessor() { succBB(this, result) }
/** Gets a basic block preceding this one. */
BasicBlock getAPredecessor() { result.getASuccessor() = this }
/** Gets a node in this block. */
ControlFlowNode getANode() { result = this.getNode(_) }
/** Gets the node at the given position in this block. */
ControlFlowNode getNode(int pos) { bbIndex(this, result, pos) }
/** Gets the first node in this block. */
ControlFlowNode getFirstNode() { result = this }
/** Gets the last node in this block. */
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
/** Gets the length of this block. */
int length() { result = bbLength(this) }
/** Holds if this basic block uses variable `v` in its `i`th node `u`. */
predicate useAt(int i, Variable v, VarUse u) { useAt(this, i, v, u) }
/** Holds if this basic block defines variable `v` in its `i`th node `d`. */
predicate defAt(int i, Variable v, VarDef d) { defAt(this, i, v, d) }
/**
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
* witnessing the liveness.
*
* In other words, `u` is a use of `v` that is reachable from the
* entry node of this basic block without going through a redefinition
* of `v`. The use `u` may either be in this basic block, or in another
* basic block reachable from this one.
*/
predicate isLiveAtEntry(Variable v, VarUse u) {
// restrict `u` to be reachable from this basic block
u = this.getASuccessor*().getANode() and
(
// shortcut: if `v` is never defined, then it must be live
this.isDefinedInSameContainer(v)
implies
// otherwise, do full liveness computation
this.isLiveAtEntryImpl(v, u)
)
}
/**
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
* witnessing the liveness, where `v` is defined at least once in the enclosing
* function or script.
*/
private predicate isLiveAtEntryImpl(Variable v, VarUse u) {
this.isLocallyLiveAtEntry(v, u)
or
this.isDefinedInSameContainer(v) and
not this.defAt(_, v, _) and
this.getASuccessor().isLiveAtEntryImpl(v, u)
}
/**
* Holds if `v` is defined at least once in the function or script to which
* this basic block belongs.
*/
private predicate isDefinedInSameContainer(Variable v) {
exists(VarDef def | def.getAVariable() = v and def.getContainer() = this.getContainer())
}
/**
* Holds if `v` is a variable that is live at entry to this basic block.
*
* Note that this is equivalent to `bb.isLiveAtEntry(v, _)`, but may
* be more efficient on large databases.
*/
predicate isLiveAtEntry(Variable v) {
this.isLocallyLiveAtEntry(v, _)
or
not this.defAt(_, v, _) and this.getASuccessor().isLiveAtEntry(v)
}
/**
* Holds if local variable `v` is live at entry to this basic block and
* `u` is a use of `v` witnessing the liveness.
*/
predicate localIsLiveAtEntry(LocalVariable v, VarUse u) {
this.isLocallyLiveAtEntry(v, u)
or
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v, u)
}
/**
* Holds if local variable `v` is live at entry to this basic block.
*/
predicate localIsLiveAtEntry(LocalVariable v) {
this.isLocallyLiveAtEntry(v, _)
or
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v)
}
/**
* Holds if `d` is a definition of `v` that is reachable from the beginning of
* this basic block without going through a redefinition of `v`.
*/
predicate localMayBeOverwritten(LocalVariable v, VarDef d) {
this.isLocallyOverwritten(v, d)
or
not this.defAt(_, v, _) and this.getASuccessor().localMayBeOverwritten(v, d)
}
/**
* Gets the next index after `i` in this basic block at which `v` is
* defined or used, provided that `d` is a definition of `v` at index `i`.
* If there are no further uses or definitions of `v` after `i`, the
* result is the length of this basic block.
*/
private int nextDefOrUseAfter(PurelyLocalVariable v, int i, VarDef d) {
this.defAt(i, v, d) and
result =
min(int j |
(this.defAt(j, v, _) or this.useAt(j, v, _) or j = this.length()) and
j > i
)
}
/**
* Holds if `d` defines variable `v` at the `i`th node of this basic block, and
* the definition is live, that is, the variable may be read after this
* definition and before a re-definition.
*/
predicate localLiveDefAt(PurelyLocalVariable v, int i, VarDef d) {
exists(int j | j = this.nextDefOrUseAfter(v, i, d) |
this.useAt(j, v, _)
or
j = this.length() and this.getASuccessor().localIsLiveAtEntry(v)
)
}
/**
* Holds if `u` is a use of `v` in this basic block, and there are
* no definitions of `v` before it.
*/
private predicate isLocallyLiveAtEntry(Variable v, VarUse u) {
exists(int n | this.useAt(n, v, u) | not exists(int m | m < n | this.defAt(m, v, _)))
}
/**
* Holds if `d` is a definition of `v` in this basic block, and there are
* no other definitions of `v` before it.
*/
private predicate isLocallyOverwritten(Variable v, VarDef d) {
exists(int n | this.defAt(n, v, d) | not exists(int m | m < n | this.defAt(m, v, _)))
}
/**
* Gets the basic block that immediately dominates this basic block.
*/
ReachableBasicBlock getImmediateDominator() { bbIDominates(result, this) }
}
/**
* An unreachable basic block, that is, a basic block
* whose first node is unreachable.
*/
class UnreachableBlock extends BasicBlock {
UnreachableBlock() { this.getFirstNode().isUnreachable() }
}
/**
* An entry basic block, that is, a basic block
* whose first node is the entry node of a statement container.
*/
class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
}
/**
* A basic block that is reachable from an entry basic block.
*/
class ReachableBasicBlock extends BasicBlock {
ReachableBasicBlock() { reachableBB(this) }
/**
* Holds if this basic block strictly dominates `bb`.
*/
pragma[inline]
predicate strictlyDominates(ReachableBasicBlock bb) { bbIDominates+(this, bb) }
/**
* Holds if this basic block dominates `bb`.
*
* This predicate is reflexive: each reachable basic block dominates itself.
*/
pragma[inline]
predicate dominates(ReachableBasicBlock bb) { bbIDominates*(this, bb) }
/**
* Holds if this basic block strictly post-dominates `bb`.
*/
pragma[inline]
predicate strictlyPostDominates(ReachableBasicBlock bb) { bbIPostDominates+(this, bb) }
/**
* Holds if this basic block post-dominates `bb`.
*
* This predicate is reflexive: each reachable basic block post-dominates itself.
*/
pragma[inline]
predicate postDominates(ReachableBasicBlock bb) { bbIPostDominates*(this, bb) }
}
/**
* A reachable basic block with more than one predecessor.
*/
class ReachableJoinBlock extends ReachableBasicBlock {
ReachableJoinBlock() { this.getFirstNode().isJoin() }
/**
* Holds if this basic block belongs to the dominance frontier of `b`, that is
* `b` dominates a predecessor of this block, but not this block itself.
*
* Algorithm from Cooper et al., "A Simple, Fast Dominance Algorithm" (Figure 5),
* who in turn attribute it to Ferrante et al., "The program dependence graph and
* its use in optimization".
*/
predicate inDominanceFrontierOf(ReachableBasicBlock b) {
b = this.getAPredecessor() and not b = this.getImmediateDominator()
or
exists(ReachableBasicBlock prev | this.inDominanceFrontierOf(prev) |
b = prev.getImmediateDominator() and
not b = this.getImmediateDominator()
)
}
}
import internal.BasicBlockInternal::Public

View File

@@ -16,7 +16,7 @@ private module CollectionDataFlow {
/**
* A step for `Set.add()` method, which adds an element to a Set.
*/
private class SetAdd extends PreCallGraphStep {
private class SetAdd extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
exists(DataFlow::MethodCallNode call |
call = obj.getAMethodCall("add") and
@@ -29,7 +29,7 @@ private module CollectionDataFlow {
/**
* A step for the `Set` constructor, which copies any elements from the first argument into the resulting set.
*/
private class SetConstructor extends PreCallGraphStep {
private class SetConstructor extends LegacyPreCallGraphStep {
override predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp
) {
@@ -49,7 +49,7 @@ private module CollectionDataFlow {
* For sets and iterators the l-value are the elements of the set/iterator.
* For maps the l-value is a tuple containing a key and a value.
*/
private class ForOfStep extends PreCallGraphStep {
private class ForOfStep extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) {
exists(ForOfStmt forOf |
obj = forOf.getIterationDomain().flow() and
@@ -73,7 +73,7 @@ private module CollectionDataFlow {
/**
* A step for a call to `forEach` on a Set or Map.
*/
private class SetMapForEach extends PreCallGraphStep {
private class SetMapForEach extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = "forEach" and
@@ -88,7 +88,7 @@ private module CollectionDataFlow {
* A call to the `get` method on a Map.
* If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved. (The known string value is encoded as part of the pseudo-property)
*/
private class MapGet extends PreCallGraphStep {
private class MapGet extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = "get" and
@@ -108,7 +108,7 @@ private module CollectionDataFlow {
* Otherwise the value will be stored into a pseudo-property corresponding to values with unknown keys.
* The value will additionally be stored into a pseudo-property corresponding to all values.
*/
class MapSet extends PreCallGraphStep {
class MapSet extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
exists(DataFlow::MethodCallNode call |
call = obj.getAMethodCall("set") and
@@ -121,7 +121,7 @@ private module CollectionDataFlow {
/**
* A step for a call to `values` on a Map or a Set.
*/
private class MapAndSetValues extends PreCallGraphStep {
private class MapAndSetValues extends LegacyPreCallGraphStep {
override predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp
) {
@@ -138,7 +138,7 @@ private module CollectionDataFlow {
/**
* A step for a call to `keys` on a Set.
*/
private class SetKeys extends PreCallGraphStep {
private class SetKeys extends LegacyPreCallGraphStep {
override predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp
) {

View File

@@ -11,7 +11,7 @@ private import semmle.javascript.dataflow.internal.PreCallGraphStep
private module GeneratorDataFlow {
private import DataFlow::PseudoProperties
private class ArrayIteration extends PreCallGraphStep {
private class ArrayIteration extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
exists(DataFlow::FunctionNode f | f.getFunction().isGenerator() |
prop = iteratorElement() and

View File

@@ -4,6 +4,7 @@ import javascript
private import NodeModuleResolutionImpl
private import semmle.javascript.DynamicPropertyAccess as DynamicPropertyAccess
private import semmle.javascript.internal.CachedStages
private import semmle.javascript.dataflow.internal.DataFlowNode
/**
* A Node.js module.
@@ -240,69 +241,78 @@ private class RequireVariable extends Variable {
*/
private predicate moduleInFile(Module m, File f) { m.getFile() = f }
private predicate isModuleModule(DataFlow::Node nd) {
exists(ImportDeclaration imp |
imp.getImportedPath().getValue() = "module" and
nd =
[
DataFlow::destructuredModuleImportNode(imp),
DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier))
]
private predicate isModuleModule(EarlyStageNode nd) {
exists(ImportDeclaration imp | imp.getImportedPath().getValue() = "module" |
nd = TDestructuredModuleImportNode(imp)
or
nd = TValueNode(imp.getASpecifier().(ImportNamespaceSpecifier))
)
or
isModuleModule(nd.getAPredecessor())
exists(EarlyStageNode other |
isModuleModule(other) and
DataFlow::localFlowStep(other, nd)
)
}
private predicate isCreateRequire(DataFlow::Node nd) {
private predicate isCreateRequire(EarlyStageNode nd) {
exists(PropAccess prop |
isModuleModule(prop.getBase().flow()) and
isModuleModule(TValueNode(prop.getBase())) and
prop.getPropertyName() = "createRequire" and
nd = prop.flow()
nd = TValueNode(prop)
)
or
exists(PropertyPattern prop |
isModuleModule(prop.getObjectPattern().flow()) and
isModuleModule(TValueNode(prop.getObjectPattern())) and
prop.getName() = "createRequire" and
nd = prop.getValuePattern().flow()
nd = TValueNode(prop.getValuePattern())
)
or
exists(ImportDeclaration decl, NamedImportSpecifier spec |
decl.getImportedPath().getValue() = "module" and
spec = decl.getASpecifier() and
spec.getImportedName() = "createRequire" and
nd = spec.flow()
nd = TValueNode(spec)
)
or
isCreateRequire(nd.getAPredecessor())
exists(EarlyStageNode other |
isCreateRequire(other) and
DataFlow::localFlowStep(other, nd)
)
}
/**
* Holds if `nd` may refer to `require`, either directly or modulo local data flow.
*/
cached
private predicate isRequire(DataFlow::Node nd) {
nd.asExpr() = any(RequireVariable req).getAnAccess() and
// `mjs` files explicitly disallow `require`
not nd.getFile().getExtension() = "mjs"
private predicate isRequire(EarlyStageNode nd) {
exists(VarAccess access |
access = any(RequireVariable v).getAnAccess() and
nd = TValueNode(access) and
// `mjs` files explicitly disallow `require`
not access.getFile().getExtension() = "mjs"
)
or
isRequire(nd.getAPredecessor())
exists(EarlyStageNode other |
isRequire(other) and
DataFlow::localFlowStep(other, nd)
)
or
// `import { createRequire } from 'module';`.
// specialized to ES2015 modules to avoid recursion in the `DataFlow::moduleImport()` predicate and to avoid
// negative recursion between `Import.getImportedModuleNode()` and `Import.getImportedModule()`, and
// to avoid depending on `SourceNode` as this would make `SourceNode::Range` recursive.
exists(CallExpr call |
isCreateRequire(call.getCallee().flow()) and
nd = call.flow()
isCreateRequire(TValueNode(call.getCallee())) and
nd = TValueNode(call)
)
or
// `$.require('underscore');`.
// NPM as supported in [XSJS files](https://www.npmjs.com/package/@sap/async-xsjs#npm-packages-support).
exists(MethodCallExpr require |
nd.getFile().getExtension() = ["xsjs", "xsjslib"] and
require.getFile().getExtension() = ["xsjs", "xsjslib"] and
require.getCalleeName() = "require" and
require.getReceiver().(GlobalVarAccess).getName() = "$" and
nd = require.getCallee().flow()
nd = TValueNode(require.getCallee())
)
}
@@ -316,7 +326,7 @@ private predicate isRequire(DataFlow::Node nd) {
* ```
*/
class Require extends CallExpr, Import {
Require() { isRequire(this.getCallee().flow()) }
Require() { isRequire(TValueNode(this.getCallee())) }
override PathExpr getImportedPath() { result = this.getArgument(0) }
@@ -410,7 +420,7 @@ private class RequirePath extends PathExprCandidate {
this = any(Require req).getArgument(0)
or
exists(MethodCallExpr reqres |
isRequire(reqres.getReceiver().flow()) and
isRequire(TValueNode(reqres.getReceiver())) and
reqres.getMethodName() = "resolve" and
this = reqres.getArgument(0)
)

View File

@@ -4,6 +4,7 @@
*/
import javascript
private import semmle.javascript.dataflow.internal.DataFlowNode
/**
* Internal representation of paths as lists of components.
@@ -381,16 +382,16 @@ private class PathExprString extends PathString {
}
pragma[nomagic]
private DataFlow::Node getAPathExprAlias(PathExpr expr) {
result.getImmediatePredecessor().asExpr() = expr
private EarlyStageNode getAPathExprAlias(PathExpr expr) {
DataFlow::Impl::earlyStageImmediateFlowStep(TValueNode(expr), result)
or
result.getImmediatePredecessor() = getAPathExprAlias(expr)
DataFlow::Impl::earlyStageImmediateFlowStep(getAPathExprAlias(expr), result)
}
private class PathExprFromAlias extends PathExpr {
private PathExpr other;
PathExprFromAlias() { this = getAPathExprAlias(other).asExpr() }
PathExprFromAlias() { TValueNode(this) = getAPathExprAlias(other) }
override string getValue() { result = other.getValue() }
@@ -435,13 +436,15 @@ abstract class PathExprCandidate extends Expr {
pragma[nomagic]
private Expr getAPart1() { result = this or result = this.getAPart().getAChildExpr() }
private EarlyStageNode getAnAliasedPart1() {
result = TValueNode(this.getAPart1())
or
DataFlow::Impl::earlyStageImmediateFlowStep(result, this.getAnAliasedPart1())
}
/**
* Gets an expression that is nested inside this expression.
*
* Equivalent to `getAChildExpr*()`, but useful to enforce a better join order (in spite of
* what the optimizer thinks, there are generally far fewer `PathExprCandidate`s than
* `ConstantString`s).
* Gets an expression that is depended on by an expression nested inside this expression.
*/
pragma[nomagic]
Expr getAPart() { result = this.getAPart1().flow().getImmediatePredecessor*().asExpr() }
Expr getAPart() { TValueNode(result) = this.getAnAliasedPart1() }
}

View File

@@ -6,7 +6,9 @@ import javascript
private import dataflow.internal.StepSummary
/**
* A definition of a `Promise` object.
* A call to the `Promise` constructor, such as `new Promise((resolve, reject) => { ... })`.
*
* This includes calls to the built-in `Promise` constructor as well as promise implementations from known libraries, such as `bluebird`.
*/
abstract class PromiseDefinition extends DataFlow::SourceNode {
/** Gets the executor function of this promise object. */
@@ -196,6 +198,8 @@ module Promises {
override string getAProperty() { result = [valueProp(), errorProp()] }
}
predicate promiseConstructorRef = getAPromiseObject/0;
}
/**
@@ -267,7 +271,7 @@ private import semmle.javascript.dataflow.internal.PreCallGraphStep
* These steps are for `await p`, `new Promise()`, `Promise.resolve()`,
* `Promise.then()`, `Promise.catch()`, and `Promise.finally()`.
*/
private class PromiseStep extends PreCallGraphStep {
private class PromiseStep extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
PromiseFlow::loadStep(obj, element, prop)
}
@@ -459,7 +463,7 @@ module PromiseFlow {
}
}
private class PromiseTaintStep extends TaintTracking::SharedTaintStep {
private class PromiseTaintStep extends TaintTracking::LegacyTaintStep {
override predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) {
// from `x` to `new Promise((res, rej) => res(x))`
pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0)
@@ -530,7 +534,7 @@ private module AsyncReturnSteps {
/**
* A data-flow step for ordinary and exceptional returns from async functions.
*/
private class AsyncReturn extends PreCallGraphStep {
private class AsyncReturn extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
exists(DataFlow::FunctionNode f | f.getFunction().isAsync() |
// ordinary return
@@ -548,7 +552,7 @@ private module AsyncReturnSteps {
/**
* A data-flow step for ordinary return from an async function in a taint configuration.
*/
private class AsyncTaintReturn extends TaintTracking::SharedTaintStep {
private class AsyncTaintReturn extends TaintTracking::LegacyTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(Function f |
f.isAsync() and
@@ -665,7 +669,7 @@ private module ClosurePromise {
/**
* Taint steps through closure promise methods.
*/
private class ClosurePromiseTaintStep extends TaintTracking::SharedTaintStep {
private class ClosurePromiseTaintStep extends TaintTracking::LegacyTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
// static methods in goog.Promise
exists(DataFlow::CallNode call, string name |
@@ -699,7 +703,7 @@ private module DynamicImportSteps {
* let Foo = await import('./foo');
* ```
*/
class DynamicImportStep extends PreCallGraphStep {
class DynamicImportStep extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
exists(DynamicImportExpr imprt |
pred = imprt.getImportedModule().getAnExportedValue("default") and

View File

@@ -69,7 +69,7 @@ private class ArrayIterationCallbackAsPartialInvoke extends DataFlow::PartialInv
* A flow step propagating the exception thrown from a callback to a method whose name coincides
* a built-in Array iteration method, such as `forEach` or `map`.
*/
private class IteratorExceptionStep extends DataFlow::SharedFlowStep {
private class IteratorExceptionStep extends DataFlow::LegacyFlowStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = ["forEach", "each", "map", "filter", "some", "every", "fold", "reduce"] and
@@ -160,6 +160,15 @@ class StringReplaceCall extends DataFlow::MethodCallNode {
new = ret.getStringValue()
)
}
/**
* Holds if this call takes a regexp containing a wildcard-like term such as `.`.
*
* Also see `RegExp::isWildcardLike`.
*/
final predicate hasRegExpContainingWildcard() {
RegExp::isWildcardLike(this.getRegExp().getRoot().getAChild*())
}
}
/**

View File

@@ -0,0 +1,397 @@
/**
* This contains three step-contribution classes, in order to support graceful deprecation of the old data flow library.
*
* - `class AdditionalFlowStep`: steps used only by the new dataflow library
* - `class LegacyFlowStep`: steps used only by the old data flow library
* - `class SharedFlowStep`: steps used by both
*
* The latter two will be deprecated in the future, but are currently not marked as `deprecated`.
* This is because a library model should be able to support both data flow libraries simultaneously, without itself getting
* deprecation warnings.
*
* To simplify correct consumption of these steps there is a correspondingly-named module for each:
*
* - `module AdditionalFlowStep`: exposes steps from `AdditionalFlowStep` and `SharedFlowStep` subclasses.
* - `module LegacyFlowStep`: exposes steps from `LegacyFlowStep` and `SharedFlowStep` subclasses.
* - `module SharedFlowStep`: exposes steps from all three classes.
*
* This design is intended to simplify consumption of steps, and to ensure existing consumers of `SharedFlowStep`
* outside this codebase will continue to work with as few surprises as possible.
*/
private import javascript
private import semmle.javascript.internal.CachedStages
/**
* A value-preserving data flow edge that should be used in all data flow configurations in
* addition to standard data flow edges.
*
* This class is a singleton, and thus subclasses do not need to specify a characteristic predicate.
*
* As an alternative to this class, consider using `DataFlow::SummarizedCallable`.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Use `isAdditionalFlowStep` for query-specific flow steps.
*/
class AdditionalFlowStep extends Unit {
/**
* Holds if `pred` &rarr; `succ` should be considered a value-preserving data flow edge.f
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a value-preserving data flow edge that
* crosses calling contexts.
*/
predicate jumpStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` should be stored in the given `content` of the object `succ`.
*/
predicate storeStep(DataFlow::Node pred, DataFlow::ContentSet contents, DataFlow::Node succ) {
none()
}
/**
* Holds if the given `content` of the object in `pred` should be read into `succ`.
*/
predicate readStep(DataFlow::Node pred, DataFlow::ContentSet contents, DataFlow::Node succ) {
none()
}
}
/**
* Contains predicates for accessing the steps contributed by `AdditionalFlowStep` and `SharedFlowStep` subclasses.
*/
cached
module AdditionalFlowStep {
cached
private module Internal {
// Forces this to be part of the `FlowSteps` stage.
// We use a public predicate in a private module to avoid warnings about this being unused.
cached
predicate forceStage() { Stages::FlowSteps::ref() }
}
bindingset[a, b]
pragma[inline_late]
private predicate sameContainer(DataFlow::Node a, DataFlow::Node b) {
a.getContainer() = b.getContainer()
}
/**
* Holds if `pred` &rarr; `succ` should be considered a data flow edge.
*/
cached
predicate step(DataFlow::Node pred, DataFlow::Node succ) {
any(AdditionalFlowStep s).step(pred, succ)
or
any(SharedFlowStep s).step(pred, succ) and
sameContainer(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a value-preserving data flow edge that
* crosses calling contexts.
*/
cached
predicate jumpStep(DataFlow::Node pred, DataFlow::Node succ) {
any(AdditionalFlowStep s).jumpStep(pred, succ)
or
any(SharedFlowStep s).step(pred, succ) and
not sameContainer(pred, succ)
}
/**
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
*/
cached
predicate storeStep(DataFlow::Node pred, DataFlow::ContentSet contents, DataFlow::Node succ) {
any(AdditionalFlowStep s).storeStep(pred, contents, succ)
or
exists(string prop |
any(SharedFlowStep s).storeStep(pred, succ, prop) and
contents = DataFlow::ContentSet::fromLegacyProperty(prop)
)
}
/**
* Holds if the property `prop` of the object `pred` should be read into `succ`.
*/
cached
predicate readStep(DataFlow::Node pred, DataFlow::ContentSet contents, DataFlow::Node succ) {
any(AdditionalFlowStep s).readStep(pred, contents, succ)
or
exists(string prop |
any(SharedFlowStep s).loadStep(pred, succ, prop) and
contents = DataFlow::ContentSet::fromLegacyProperty(prop)
)
}
}
/**
* A data flow edge that is only seen by the old, deprecated data flow library.
*
* This class is typically used when a step has been replaced by a flow summary. Since the old data flow
* library does not support flow summaries, such a step should remain as a legacy step, until the old data flow
* library can be removed.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Override `Configuration::isAdditionalFlowStep`
* for analysis-specific flow steps.
*/
class LegacyFlowStep extends Unit {
/**
* Holds if `pred` &rarr; `succ` should be considered a data flow edge.
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* DEPRECATED. The `FlowLabel` class and steps involving flow labels are no longer used by any queries.
*
* Holds if `pred` &rarr; `succ` should be considered a data flow edge
* transforming values with label `predlbl` to have label `succlbl`.
*/
deprecated predicate step(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
DataFlow::FlowLabel succlbl
) {
none()
}
/**
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
* The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored.
*/
predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() }
/**
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
*/
predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
/**
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
*/
predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
/**
* Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
*/
predicate loadStoreStep(
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
) {
none()
}
}
/**
* Contains predicates for accessing the steps contributed by `LegacyFlowStep` and `SharedFlowStep` subclasses.
*/
cached
module LegacyFlowStep {
/**
* Holds if `pred` &rarr; `succ` should be considered a data flow edge.
*/
cached
predicate step(DataFlow::Node pred, DataFlow::Node succ) {
any(LegacyFlowStep s).step(pred, succ)
or
any(SharedFlowStep s).step(pred, succ)
}
/**
* DEPRECATED. The `FlowLabel` class and steps involving flow labels are no longer used by any queries.
*
* Holds if `pred` &rarr; `succ` should be considered a data flow edge
* transforming values with label `predlbl` to have label `succlbl`.
*/
cached
deprecated predicate step(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
DataFlow::FlowLabel succlbl
) {
any(LegacyFlowStep s).step(pred, succ, predlbl, succlbl)
or
any(SharedFlowStep s).step(pred, succ, predlbl, succlbl)
}
/**
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
* The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored.
*/
cached
predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
any(LegacyFlowStep s).storeStep(pred, succ, prop)
or
any(SharedFlowStep s).storeStep(pred, succ, prop)
}
/**
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
*/
cached
predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
any(LegacyFlowStep s).loadStep(pred, succ, prop)
or
any(SharedFlowStep s).loadStep(pred, succ, prop)
}
/**
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
*/
cached
predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
any(LegacyFlowStep s).loadStoreStep(pred, succ, prop)
or
any(SharedFlowStep s).loadStoreStep(pred, succ, prop)
}
/**
* Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
*/
cached
predicate loadStoreStep(
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
) {
any(LegacyFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp)
or
any(SharedFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp)
}
}
/**
* A data flow edge that should be added to all data flow configurations in
* addition to standard data flow edges.
*
* This class is a singleton, and thus subclasses do not need to specify a characteristic predicate.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Override `Configuration::isAdditionalFlowStep`
* for analysis-specific flow steps.
*/
class SharedFlowStep extends Unit {
/**
* Holds if `pred` &rarr; `succ` should be considered a data flow edge.
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* DEPRECATED. The `FlowLabel` class and steps involving flow labels are no longer used by any queries.
*
* Holds if `pred` &rarr; `succ` should be considered a data flow edge
* transforming values with label `predlbl` to have label `succlbl`.
*/
deprecated predicate step(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
DataFlow::FlowLabel succlbl
) {
none()
}
/**
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
* The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored.
*/
predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() }
/**
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
*/
predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
/**
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
*/
predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
/**
* Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
*/
predicate loadStoreStep(
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
) {
none()
}
}
/**
* Contains predicates for accessing the steps contributed by `SharedFlowStep`, `LegacyFlowStep`, and `AdditionalFlowStep` subclasses.
*/
module SharedFlowStep {
/**
* Holds if `pred` &rarr; `succ` should be considered a data flow edge.
*/
pragma[inline]
predicate step(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedFlowStep s).step(pred, succ)
or
any(AdditionalFlowStep s).step(pred, succ)
or
any(LegacyFlowStep s).step(pred, succ)
}
/**
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
* The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored.
*/
pragma[inline]
predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
any(SharedFlowStep s).storeStep(pred, succ, prop)
or
any(AdditionalFlowStep s)
.storeStep(pred, DataFlow::ContentSet::property(prop), succ.getALocalUse())
or
any(LegacyFlowStep s).storeStep(pred, succ, prop)
}
/**
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
*/
pragma[inline]
predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
any(SharedFlowStep s).loadStep(pred, succ, prop)
or
any(AdditionalFlowStep s).readStep(pred, DataFlow::ContentSet::property(prop), succ)
or
any(LegacyFlowStep s).loadStep(pred, succ, prop)
}
// The following are aliases for old step predicates that have no corresponding predicate in AdditionalFlowStep
/**
* DEPRECATED. The `FlowLabel` class and steps involving flow labels are no longer used by any queries.
*
* Holds if `pred` &rarr; `succ` should be considered a data flow edge
* transforming values with label `predlbl` to have label `succlbl`.
*/
deprecated predicate step(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
DataFlow::FlowLabel succlbl
) {
any(SharedFlowStep s).step(pred, succ, predlbl, succlbl)
or
any(LegacyFlowStep s).step(pred, succ, predlbl, succlbl)
}
/**
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
*/
cached
predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
any(SharedFlowStep s).loadStoreStep(pred, succ, prop)
or
any(LegacyFlowStep s).loadStoreStep(pred, succ, prop)
}
/**
* Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
*/
cached
predicate loadStoreStep(
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
) {
any(SharedFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp)
or
any(LegacyFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp)
}
}

View File

@@ -0,0 +1,427 @@
/**
* Note: The contents of this file are exposed with the `TaintTracking::` prefix, via an import in `TaintTracking.qll`.
*/
private import javascript
private import semmle.javascript.internal.CachedStages
/**
* A taint-propagating data flow edge that should be added to all taint tracking
* configurations, but only those that use the new data flow library.
*
* This class is a singleton, and thus subclasses do not need to specify a characteristic predicate.
*
* As an alternative to this class, consider using `DataFlow::SummarizedCallable`.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Use `isAdditionalFlowStep` for query-specific taint steps.
*/
class AdditionalTaintStep extends Unit {
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge.
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
}
/**
* A taint-propagating data flow edge that should be added to all taint tracking
* configurations in addition to standard data flow edges.
*
* This class is a singleton, and thus subclasses do not need to specify a characteristic predicate.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Override `Configuration::isAdditionalTaintStep`
* for analysis-specific taint steps.
*
* This class has multiple kinds of `step` predicates; these all have the same
* effect on taint-tracking configurations. However, the categorization of steps
* allows some data-flow configurations to opt in to specific kinds of taint steps.
*/
class SharedTaintStep extends Unit {
// Each step relation in this class should have a cached version in the `Cached` module
// and be included in the `sharedTaintStep` predicate.
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge.
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through URI manipulation.
*
* Does not include string operations that aren't specific to URIs, such
* as concatenation and substring operations.
*/
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge contributed by the heuristics library.
*
* Such steps are provided by the `semmle.javascript.heuristics` libraries
* and will default to be being empty if those libraries are not imported.
*/
predicate heuristicStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through persistent storage.
*/
predicate persistentStorageStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through the heap.
*/
predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through arrays.
*
* These steps considers an array to be tainted if it contains tainted elements.
*/
predicate arrayStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through the `state` or `props` or a React component.
*/
predicate viewComponentStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through string concatenation.
*/
predicate stringConcatenationStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through string manipulation (other than concatenation).
*/
predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data serialization, such as `JSON.stringify`.
*/
predicate serializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data deserialization, such as `JSON.parse`.
*/
predicate deserializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through a promise.
*
* These steps consider a promise object to tainted if it can resolve to
* a tainted value.
*/
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
}
/**
* A taint-propagating data flow edge that should be used with the old data flow library.
*
* This class is a singleton, and thus subclasses do not need to specify a characteristic predicate.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Override `Configuration::isAdditionalTaintStep`
* for analysis-specific taint steps.
*
* This class has multiple kinds of `step` predicates; these all have the same
* effect on taint-tracking configurations. However, the categorization of steps
* allows some data-flow configurations to opt in to specific kinds of taint steps.
*/
class LegacyTaintStep extends Unit {
// Each step relation in this class should have a cached version in the `Cached` module
// and be included in the `sharedTaintStep` predicate.
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge.
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through URI manipulation.
*
* Does not include string operations that aren't specific to URIs, such
* as concatenation and substring operations.
*/
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge contributed by the heuristics library.
*
* Such steps are provided by the `semmle.javascript.heuristics` libraries
* and will default to be being empty if those libraries are not imported.
*/
predicate heuristicStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through persistent storage.
*/
predicate persistentStorageStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through the heap.
*/
predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through arrays.
*
* These steps considers an array to be tainted if it contains tainted elements.
*/
predicate arrayStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through the `state` or `props` or a React component.
*/
predicate viewComponentStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through string concatenation.
*/
predicate stringConcatenationStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through string manipulation (other than concatenation).
*/
predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data serialization, such as `JSON.stringify`.
*/
predicate serializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data deserialization, such as `JSON.parse`.
*/
predicate deserializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through a promise.
*
* These steps consider a promise object to tainted if it can resolve to
* a tainted value.
*/
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
}
/**
* Module existing only to ensure all taint steps are cached as a single stage,
* and without the the `Unit` type column.
*/
cached
private module Cached {
cached
predicate forceStage() {
// TODO: ensure that this stage is only evaluated if using the old data flow library
Stages::Taint::ref()
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge, which doesn't fit into a more specific category.
*/
cached
predicate genericStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).step(pred, succ)
or
any(LegacyTaintStep step).step(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge, contribued by the heuristics library.
*/
cached
predicate heuristicStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).heuristicStep(pred, succ)
or
any(LegacyTaintStep step).heuristicStep(pred, succ)
}
/**
* Public taint step relations.
*/
cached
module Public {
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through a URI library function.
*/
cached
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).uriStep(pred, succ)
or
any(LegacyTaintStep step).uriStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through persistent storage.
*/
cached
predicate persistentStorageStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).persistentStorageStep(pred, succ)
or
any(LegacyTaintStep step).persistentStorageStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through the heap.
*/
cached
predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).heapStep(pred, succ)
or
any(LegacyTaintStep step).heapStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through an array.
*/
cached
predicate arrayStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).arrayStep(pred, succ)
or
any(LegacyTaintStep step).arrayStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through the
* properties of a view compenent, such as the `state` or `props` of a React component.
*/
cached
predicate viewComponentStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).viewComponentStep(pred, succ)
or
any(LegacyTaintStep step).viewComponentStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through string
* concatenation.
*/
cached
predicate stringConcatenationStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).stringConcatenationStep(pred, succ)
or
any(LegacyTaintStep step).stringConcatenationStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through string manipulation
* (other than concatenation).
*/
cached
predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).stringManipulationStep(pred, succ)
or
any(LegacyTaintStep step).stringManipulationStep(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data serialization, such as `JSON.stringify`.
*/
cached
predicate serializeStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).serializeStep(pred, succ)
or
any(LegacyTaintStep step).serializeStep(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data deserialization, such as `JSON.parse`.
*/
cached
predicate deserializeStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).deserializeStep(pred, succ)
or
any(LegacyTaintStep step).deserializeStep(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through a promise.
*
* These steps consider a promise object to tainted if it can resolve to
* a tainted value.
*/
cached
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).promiseStep(pred, succ)
or
any(LegacyTaintStep step).promiseStep(pred, succ)
}
}
}
import Cached::Public
/**
* Holds if `pred -> succ` is an edge used by all taint-tracking configurations in
* the old data flow library.
*
* The new data flow library uses a different set of steps, exposed by `AdditionalTaintStep::step`.
*/
predicate sharedTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
Cached::genericStep(pred, succ) or
Cached::heuristicStep(pred, succ) or
uriStep(pred, succ) or
persistentStorageStep(pred, succ) or
heapStep(pred, succ) or
arrayStep(pred, succ) or
viewComponentStep(pred, succ) or
stringConcatenationStep(pred, succ) or
stringManipulationStep(pred, succ) or
serializeStep(pred, succ) or
deserializeStep(pred, succ) or
promiseStep(pred, succ)
}
/**
* Contains predicates for accessing the taint steps used by taint-tracking configurations
* in the new data flow library.
*/
module AdditionalTaintStep {
/**
* Holds if `pred` &rarr; `succ` is considered a taint-propagating data flow edge when
* using the new data flow library.
*/
cached
predicate step(DataFlow::Node pred, DataFlow::Node succ) {
any(AdditionalTaintStep step).step(pred, succ) or
any(SharedTaintStep step).step(pred, succ) or
any(SharedTaintStep step).heuristicStep(pred, succ) or
any(SharedTaintStep step).uriStep(pred, succ) or
any(SharedTaintStep step).persistentStorageStep(pred, succ) or
any(SharedTaintStep step).heapStep(pred, succ) or
any(SharedTaintStep step).arrayStep(pred, succ) or
any(SharedTaintStep step).viewComponentStep(pred, succ) or
any(SharedTaintStep step).stringConcatenationStep(pred, succ) or
any(SharedTaintStep step).stringManipulationStep(pred, succ) or
any(SharedTaintStep step).serializeStep(pred, succ) or
any(SharedTaintStep step).deserializeStep(pred, succ) or
any(SharedTaintStep step).promiseStep(pred, succ)
}
}

View File

@@ -25,6 +25,8 @@ private import internal.DataFlowNode
private import internal.AnalyzedParameters
private import internal.PreCallGraphStep
private import semmle.javascript.internal.CachedStages
private import semmle.javascript.dataflow.internal.DataFlowPrivate as Private
private import semmle.javascript.dataflow.internal.VariableOrThis
module DataFlow {
/**
@@ -182,29 +184,8 @@ module DataFlow {
*/
cached
DataFlow::Node getImmediatePredecessor() {
lvalueFlowStep(result, this) and
not lvalueDefaultFlowStep(_, this)
or
immediateFlowStep(result, this)
or
// Refinement of variable -> original definition of variable
exists(SsaRefinementNode refinement |
this = TSsaDefNode(refinement) and
result = TSsaDefNode(refinement.getAnInput())
)
or
exists(SsaPhiNode phi |
this = TSsaDefNode(phi) and
result = TSsaDefNode(phi.getRephinedVariable())
)
or
// IIFE call -> return value of IIFE
exists(Function fun |
localCall(this.asExpr(), fun) and
result = unique(Expr ret | ret = fun.getAReturnedExpr()).flow() and
not fun.getExit().isJoin() // can only reach exit by the return statement
)
or
FlowSteps::identityFunctionStep(result, this)
}
@@ -271,6 +252,11 @@ module DataFlow {
or
this.getFallbackTypeAnnotation().getAnUnderlyingType().hasQualifiedName(moduleName, typeName)
}
/**
* Gets the post-update node corresponding to this node, if any.
*/
final PostUpdateNode getPostUpdateNode() { result.getPreUpdateNode() = this }
}
/**
@@ -744,9 +730,7 @@ module DataFlow {
private class ParameterFieldAsPropWrite extends PropWrite, PropNode {
override ParameterField prop;
override Node getBase() {
thisNode(result, prop.getDeclaringClass().getConstructor().getBody())
}
override Node getBase() { result = TImplicitThisUse(prop, false) }
override Expr getPropertyNameExpr() {
none() // The parameter value is not the name of the field
@@ -754,16 +738,11 @@ module DataFlow {
override string getPropertyName() { result = prop.getName() }
override Node getRhs() {
exists(Parameter param, Node paramNode |
param = prop.getParameter() and
parameterNode(paramNode, param)
|
result = paramNode
)
}
override Node getRhs() { result = TValueNode(prop.getParameter()) }
override ControlFlowNode getWriteNode() { result = prop.getParameter() }
override StmtContainer getContainer() { parameter_fields(prop, result, _) }
}
/**
@@ -778,9 +757,7 @@ module DataFlow {
exists(prop.getInit())
}
override Node getBase() {
thisNode(result, prop.getDeclaringClass().getConstructor().getBody())
}
override Node getBase() { result = TImplicitThisUse(prop, false) }
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
@@ -971,6 +948,12 @@ module DataFlow {
override BasicBlock getBasicBlock() { result = function.getExit().getBasicBlock() }
override StmtContainer getContainer() {
// Override this to ensure a container exists even for unreachable returns,
// since an unreachable exit CFG node will not have a basic block
result = function
}
/**
* Gets the function corresponding to this exceptional return node.
*/
@@ -993,6 +976,12 @@ module DataFlow {
override BasicBlock getBasicBlock() { result = function.getExit().getBasicBlock() }
override StmtContainer getContainer() {
// Override this to ensure a container exists even for unreachable returns,
// since an unreachable exit CFG node will not have a basic block
result = function
}
/**
* Gets the function corresponding to this return node.
*/
@@ -1052,6 +1041,41 @@ module DataFlow {
override string toString() { result = "global access path" }
}
/**
* A node representing the value passed as `this` argument in a `new` call.
*/
class NewCallThisArgumentNode extends TNewCallThisArgument, DataFlow::Node {
private NewExpr expr;
NewCallThisArgumentNode() { this = TNewCallThisArgument(expr) }
override string toString() { result = "implicit 'this' argument of " + expr }
override StmtContainer getContainer() { result = expr.getContainer() }
override Location getLocation() { result = expr.getLocation() }
}
/**
* A node representing an implicit use of `this` or its post-update node.
*/
private class ImplicitThisUseNode extends TImplicitThisUse, DataFlow::Node {
private ImplicitThisUse use;
private boolean isPost;
ImplicitThisUseNode() { this = TImplicitThisUse(use, isPost) }
override string toString() {
if isPost = false
then result = "implicit 'this'"
else result = "[post-update] implicit 'this'"
}
override StmtContainer getContainer() { result = use.getUseContainer() }
override Location getLocation() { result = use.getLocation() }
}
/**
* INTERNAL. DO NOT USE.
*
@@ -1076,6 +1100,14 @@ module DataFlow {
* instead.
*/
module Impl {
/**
* INTERNAL. DO NOT USE.
*
* An alias for `Node.getImmediatePredecessor` that can be used at an earlier stage
* that does not depend on `DataFlow::Node`.
*/
predicate earlyStageImmediateFlowStep = immediateFlowStep/2;
/**
* A data flow node representing a function invocation, either explicitly or reflectively,
* and either with or without `new`.
@@ -1342,6 +1374,61 @@ module DataFlow {
override Location getLocation() { result = this.getTag().getLocation() }
override string toString() { result = this.getTag().toString() }
override StmtContainer getContainer() { result = this.getTag().getInnerTopLevel() }
}
/**
* A node representing the hidden parameter of a function by which a function can refer to itself.
*/
class FunctionSelfReferenceNode extends DataFlow::Node, TFunctionSelfReferenceNode {
private Function function;
FunctionSelfReferenceNode() { this = TFunctionSelfReferenceNode(function) }
/** Gets the function. */
Function getFunction() { result = function }
override StmtContainer getContainer() { result = function }
override BasicBlock getBasicBlock() { result = function.getEntryBB() }
override string toString() { result = "[function self-reference] " + function.toString() }
override Location getLocation() { result = function.getLocation() }
}
/**
* A post-update node whose pre-node corresponds to an expression. See `DataFlow::PostUpdateNode` for more details.
*/
class ExprPostUpdateNode extends DataFlow::Node, TExprPostUpdateNode, Private::PostUpdateNode {
private AST::ValueNode expr;
ExprPostUpdateNode() { this = TExprPostUpdateNode(expr) }
/** Gets the expression for which this is the post-update node. */
AST::ValueNode getExpr() { result = expr }
override StmtContainer getContainer() { result = expr.getContainer() }
override Location getLocation() { result = expr.getLocation() }
override string toString() { result = "[post update] " + expr.toString() }
}
/**
* A post-update node.
*
* This is a data-flow node that represents the new state of an object after its contents have been mutated.
* Most notably such nodes exist for arguments to a call and for the base of a property reference.
*/
class PostUpdateNode extends DataFlow::Node {
PostUpdateNode() { Private::postUpdatePair(_, this) }
/**
* Gets the corresponding pre-update node, which is usually the argument to a call or the base of a property reference.
*/
final DataFlow::Node getPreUpdateNode() { Private::postUpdatePair(result, this) }
}
/**
@@ -1374,12 +1461,12 @@ module DataFlow {
/**
* INTERNAL: Use `parameterNode(Parameter)` instead.
*/
predicate parameterNode(DataFlow::Node nd, Parameter p) { nd = valueNode(p) }
predicate parameterNode(EarlyStageNode nd, Parameter p) { nd = TValueNode(p) }
/**
* INTERNAL: Use `thisNode(StmtContainer container)` instead.
*/
predicate thisNode(DataFlow::Node node, StmtContainer container) { node = TThisNode(container) }
predicate thisNode(EarlyStageNode node, StmtContainer container) { node = TThisNode(container) }
/**
* Gets the node representing the receiver of the given function, or `this` in the given top-level.
@@ -1441,7 +1528,15 @@ module DataFlow {
* _before_ the l-value is assigned to, whereas `DataFlow::lvalueNode()`
* represents the value _after_ the assignment.
*/
Node lvalueNode(BindingPattern lvalue) {
Node lvalueNode(BindingPattern lvalue) { result = lvalueNodeInternal(lvalue) }
/**
* INTERNAL: Do not use outside standard library.
*
* Same as `lvalueNode()` except the return type is `EarlyStageNode`, which allows it to be used
* before all data flow nodes have been materialised.
*/
EarlyStageNode lvalueNodeInternal(BindingPattern lvalue) {
exists(SsaExplicitDefinition ssa |
ssa.defines(lvalue.(LValue).getDefNode(), lvalue.(VarRef).getVariable()) and
result = TSsaDefNode(ssa)
@@ -1489,31 +1584,31 @@ module DataFlow {
* Holds if there is a step from `pred -> succ` due to an assignment
* to an expression in l-value position.
*/
private predicate lvalueFlowStep(Node pred, Node succ) {
private predicate lvalueFlowStep(EarlyStageNode pred, EarlyStageNode succ) {
exists(VarDef def |
pred = valueNode(defSourceNode(def)) and
succ = lvalueNode(def.getTarget())
pred = TValueNode(defSourceNode(def)) and
succ = lvalueNodeInternal(def.getTarget())
)
or
exists(SimpleParameter param |
pred = valueNode(param) and // The value node represents the incoming argument
succ = lvalueNode(param) // The SSA node represents the parameters's local variable
pred = TValueNode(param) and // The value node represents the incoming argument
succ = lvalueNodeInternal(param) // The SSA node represents the parameters's local variable
)
or
exists(Expr arg, Parameter param |
localArgumentPassing(arg, param) and
pred = valueNode(arg) and
succ = valueNode(param)
pred = TValueNode(arg) and
succ = TValueNode(param)
)
or
exists(PropertyPattern pattern |
pred = TPropNode(pattern) and
succ = lvalueNode(pattern.getValuePattern())
succ = lvalueNodeInternal(pattern.getValuePattern())
)
or
exists(Expr element |
pred = TElementPatternNode(_, element) and
succ = lvalueNode(element)
succ = lvalueNodeInternal(element)
)
}
@@ -1521,37 +1616,37 @@ module DataFlow {
* Holds if there is a step from `pred -> succ` from the default
* value of a destructuring pattern or parameter.
*/
private predicate lvalueDefaultFlowStep(Node pred, Node succ) {
private predicate lvalueDefaultFlowStep(EarlyStageNode pred, EarlyStageNode succ) {
exists(PropertyPattern pattern |
pred = TValueNode(pattern.getDefault()) and
succ = lvalueNode(pattern.getValuePattern())
succ = lvalueNodeInternal(pattern.getValuePattern())
)
or
exists(ArrayPattern array, int i |
pred = TValueNode(array.getDefault(i)) and
succ = lvalueNode(array.getElement(i))
succ = lvalueNodeInternal(array.getElement(i))
)
or
exists(Parameter param |
pred = TValueNode(param.getDefault()) and
parameterNode(succ, param)
succ = TValueNode(param)
)
}
/**
* Flow steps shared between `getImmediatePredecessor` and `localFlowStep`.
* Flow steps shared between `immediateFlowStep` and `localFlowStep`.
*
* Inlining is forced because the two relations are indexed differently.
*/
pragma[inline]
private predicate immediateFlowStep(Node pred, Node succ) {
private predicate immediateFlowStepShared(EarlyStageNode pred, EarlyStageNode succ) {
exists(SsaVariable v |
pred = TSsaDefNode(v.getDefinition()) and
succ = valueNode(v.getAUse())
succ = TValueNode(v.getAUse())
)
or
exists(Expr predExpr, Expr succExpr |
pred = valueNode(predExpr) and succ = valueNode(succExpr)
pred = TValueNode(predExpr) and succ = TValueNode(succExpr)
|
predExpr = succExpr.(ParExpr).getExpression()
or
@@ -1581,25 +1676,61 @@ module DataFlow {
// flow from 'this' parameter into 'this' expressions
exists(ThisExpr thiz |
pred = TThisNode(thiz.getBindingContainer()) and
succ = valueNode(thiz)
succ = TValueNode(thiz)
)
or
// `f.call(...)` and `f.apply(...)` evaluate to the result of the reflective call they perform
pred = TReflectiveCallNode(succ.asExpr(), _)
exists(MethodCallExpr call |
pred = TReflectiveCallNode(call, _) and
succ = TValueNode(call)
)
or
// Pass 'this' into implicit uses of 'this'
exists(ImplicitThisUse use |
pred = TThisNode(use.getBindingContainer()) and
succ = TImplicitThisUse(use, false)
)
}
pragma[nomagic]
private predicate immediateFlowStep(EarlyStageNode pred, EarlyStageNode succ) {
lvalueFlowStep(pred, succ) and
not lvalueDefaultFlowStep(_, succ)
or
immediateFlowStepShared(pred, succ)
or
// Refinement of variable -> original definition of variable
exists(SsaRefinementNode refinement |
succ = TSsaDefNode(refinement) and
pred = TSsaDefNode(refinement.getAnInput())
)
or
exists(SsaPhiNode phi |
succ = TSsaDefNode(phi) and
pred = TSsaDefNode(phi.getRephinedVariable())
)
or
// IIFE call -> return value of IIFE
exists(Function fun, Expr expr |
succ = TValueNode(expr) and
localCall(expr, fun) and
pred = TValueNode(unique(Expr ret | ret = fun.getAReturnedExpr())) and
not fun.getExit().isJoin() // can only reach exit by the return statement
)
}
/**
* Holds if data can flow from `pred` to `succ` in one local step.
*/
cached
predicate localFlowStep(Node pred, Node succ) {
Stages::DataFlowStage::ref() and
predicate localFlowStep(EarlyStageNode pred, EarlyStageNode succ) {
Stages::EarlyDataFlowStage::ref() and
// flow from RHS into LHS
lvalueFlowStep(pred, succ)
or
lvalueDefaultFlowStep(pred, succ)
or
immediateFlowStep(pred, succ)
immediateFlowStepShared(pred, succ)
or
// From an assignment or implicit initialization of a captured variable to its flow-insensitive node.
exists(SsaDefinition predDef |
@@ -1623,7 +1754,7 @@ module DataFlow {
)
or
exists(Expr predExpr, Expr succExpr |
pred = valueNode(predExpr) and succ = valueNode(succExpr)
pred = TValueNode(predExpr) and succ = TValueNode(succExpr)
|
predExpr = succExpr.(LogicalOrExpr).getAnOperand()
or
@@ -1641,18 +1772,17 @@ module DataFlow {
or
// from returned expr to the FunctionReturnNode.
exists(Function f | not f.isAsyncOrGenerator() |
DataFlow::functionReturnNode(succ, f) and pred = valueNode(f.getAReturnedExpr())
succ = TFunctionReturnNode(f) and pred = TValueNode(f.getAReturnedExpr())
)
or
// from a reflective params node to a reference to the arguments object.
exists(DataFlow::ReflectiveParametersNode params, Function f | f = params.getFunction() |
succ = f.getArgumentsVariable().getAnAccess().flow() and
pred = params
exists(Function f |
pred = TReflectiveParametersNode(f) and
succ = TValueNode(f.getArgumentsVariable().getAnAccess())
)
}
/** A load step from a reflective parameter node to each parameter. */
private class ReflectiveParamsStep extends PreCallGraphStep {
private class ReflectiveParamsStep extends LegacyPreCallGraphStep {
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f, int i |
f.getFunction() = params.getFunction() and
@@ -1664,7 +1794,7 @@ module DataFlow {
}
/** A taint step from the reflective parameters node to any parameter. */
private class ReflectiveParamsTaintStep extends TaintTracking::SharedTaintStep {
private class ReflectiveParamsTaintStep extends TaintTracking::LegacyTaintStep {
override predicate step(DataFlow::Node obj, DataFlow::Node element) {
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f |
f.getFunction() = params.getFunction() and
@@ -1801,5 +1931,9 @@ module DataFlow {
import TypeInference
import Configuration
import TypeTracking
import AdditionalFlowSteps
import internal.FunctionWrapperSteps
import internal.sharedlib.DataFlow
import internal.BarrierGuards
import FlowSummary
}

View File

@@ -0,0 +1,83 @@
/** Provides classes and predicates for defining flow summaries. */
private import javascript
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as Impl
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
private import semmle.javascript.dataflow.internal.DataFlowPrivate
/**
* A model for a function that can propagate data flow.
*
* This class makes it possible to model flow through functions, using the same mechanism as
* `summaryModel` as described in the [library customization docs](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript).
*
* Extend this class to define summary models directly in CodeQL.
* Data extensions and `summaryModel` are usually preferred; but there are a few cases where direct use of this class may be needed:
*
* - The relevant call sites cannot be matched by the access path syntax, and require the full power of CodeQL.
* For example, complex overloading patterns might require more local reasoning at the call site.
* - The input/output behaviour cannot be described statically in the access path syntax, but the relevant access paths
* can be generated dynamically in CodeQL, based on the usages found in the codebase.
*
* Subclasses should bind `this` to a unique identifier for the function being modelled. There is no special
* interpreation of the `this` value, it should just not clash with the `this`-value used by other classes.
*
* For example, this models flow through calls such as `require("my-library").myFunction()`:
* ```codeql
* class MyFunction extends SummarizedCallable {
* MyFunction() { this = "MyFunction" }
*
* override predicate propagatesFlow(string input, string output, boolean preservesValues) {
* input = "Argument[0]" and
* output = "ReturnValue" and
* preservesValue = false
* }
*
* override DataFlow::InvokeNode getACall() {
* result = API::moduleImport("my-library").getMember("myFunction").getACall()
* }
* }
* ```
* This would be equivalent to the following model written as a data extension:
* ```yaml
* extensions:
* - addsTo:
* pack: codeql/javascript-all
* extensible: summaryModel
* data:
* - ["my-library", "Member[myFunction]", "Argument[0]", "ReturnValue", "taint"]
* ```
*/
abstract class SummarizedCallable extends LibraryCallable, Impl::Public::SummarizedCallable {
bindingset[this]
SummarizedCallable() { any() }
/**
* Holds if data may flow from `input` to `output` through this callable.
*
* `preservesValue` indicates whether this is a value-preserving step or a taint-step.
*
* See the [library customization docs](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript) for
* the syntax of the `input` and `output` parameters.
*/
pragma[nomagic]
predicate propagatesFlow(string input, string output, boolean preservesValue) { none() }
override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
) {
this.propagatesFlow(input, output, preservesValue) and model = this
}
/**
* Gets the synthesized parameter that results from an input specification
* that starts with `Argument[s]` for this library callable.
*/
DataFlow::ParameterNode getParameter(string s) {
exists(ParameterPosition pos |
DataFlowImplCommon::parameterNode(result, MkLibraryCallable(this), pos) and
s = encodeParameterPosition(pos)
)
}
}

View File

@@ -1611,7 +1611,12 @@ class RegExpConstructorInvokeNode extends DataFlow::InvokeNode {
* Gets the AST of the regular expression created here, provided that the
* first argument is a string literal.
*/
RegExpTerm getRoot() { result = this.getArgument(0).asExpr().(StringLiteral).asRegExp() }
RegExpTerm getRoot() {
result = this.getArgument(0).asExpr().(StringLiteral).asRegExp()
or
// In case someone writes `new RegExp(/foo/)` for some reason
result = this.getArgument(0).asExpr().(RegExpLiteral).getRoot()
}
/**
* Gets the flags provided in the second argument, or an empty string if no

View File

@@ -18,11 +18,14 @@ private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
private import semmle.javascript.Unit
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.internal.CachedStages
private import semmle.javascript.dataflow.internal.TaintTrackingPrivate as TaintTrackingPrivate
/**
* Provides classes for modeling taint propagation.
*/
module TaintTracking {
import AdditionalTaintSteps
/**
* A data flow tracking configuration that considers taint propagation through
* objects, arrays, promises and strings in addition to standard data flow.
@@ -30,7 +33,7 @@ module TaintTracking {
* If a different set of flow edges is desired, extend this class and override
* `isAdditionalTaintStep`.
*/
abstract class Configuration extends DataFlow::Configuration {
abstract deprecated class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }
@@ -171,20 +174,88 @@ module TaintTracking {
}
/**
* A `SanitizerGuardNode` that controls which taint tracking
* configurations it is used in.
* A barrier guard that applies to all taint-tracking configurations.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Override `Configuration::isSanitizerGuard`
* for analysis-specific taint sanitizer guards.
* of the standard library. To define a query-specific barrier guard, instead override
* `isBarrier` and use the `DataFlow::MakeBarrierGuard` module. For example:
* ```codeql
* module MyConfig implements DataFlow::ConfigSig {
* predicate isBarrier(DataFlow::Node node) {
* node = DataFlow::MakeBarrierGuard<MyGuard>
* }
* }
* class MyGuard extends DataFlow::Node {
* MyGuard() { ... }
* predicate blocksExpr(boolean outcome, Expr e) { ... }
* }
*/
abstract class AdditionalBarrierGuard extends DataFlow::Node {
/**
* Holds if this node blocks expression `e`, provided it evaluates to `outcome`.
*/
abstract predicate blocksExpr(boolean outcome, Expr e);
}
/**
* Internal barrier guard class that populates both the new `AdditionalBarrierGuard` class
* and the legacy `AdditionalSanitizerGuardNode` class.
*
* It exposes the member predicates of `AdditionalSanitizerGuardNode` for backwards compatibility.
*/
abstract private class LegacyAdditionalBarrierGuard extends AdditionalBarrierGuard,
AdditionalSanitizerGuardNodeDeprecated
{
deprecated override predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) }
deprecated override predicate appliesTo(Configuration cfg) { any() }
}
/**
* DEPRECATED. This class was part of the old data flow library which is now deprecated.
* Use `TaintTracking::AdditionalBarrierGuard` instead.
*/
deprecated class AdditionalSanitizerGuardNode = AdditionalSanitizerGuardNodeDeprecated;
cached
abstract class AdditionalSanitizerGuardNode extends SanitizerGuardNode {
abstract private class AdditionalSanitizerGuardNodeDeprecated extends DataFlow::Node {
// For backwards compatibility, this contains a copy of the SanitizerGuard interface,
// but is does not inherit from it as that would cause re-evaluation of cached barriers.
/**
* Holds if this node blocks expression `e`, provided it evaluates to `outcome`.
*/
cached
deprecated predicate blocks(boolean outcome, Expr e) { none() }
/**
* Holds if this node sanitizes expression `e`, provided it evaluates
* to `outcome`.
*/
cached
abstract deprecated predicate sanitizes(boolean outcome, Expr e);
/**
* Holds if this node blocks expression `e` from flow of type `label`, provided it evaluates to `outcome`.
*/
cached
deprecated predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
this.sanitizes(outcome, e) and label.isTaint()
or
this.sanitizes(outcome, e, label)
}
/**
* Holds if this node sanitizes expression `e`, provided it evaluates
* to `outcome`.
*/
cached
deprecated predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { none() }
/**
* Holds if this guard applies to the flow in `cfg`.
*/
cached
abstract predicate appliesTo(Configuration cfg);
abstract deprecated predicate appliesTo(Configuration cfg);
}
/**
@@ -199,7 +270,7 @@ module TaintTracking {
* implementations of `sanitizes` will _both_ apply to any configuration that includes either of
* them.
*/
abstract class SanitizerGuardNode extends DataFlow::BarrierGuardNode {
abstract deprecated class SanitizerGuardNode extends DataFlow::BarrierGuardNode {
override predicate blocks(boolean outcome, Expr e) { none() }
/**
@@ -224,255 +295,12 @@ module TaintTracking {
/**
* A sanitizer guard node that only blocks specific flow labels.
*/
abstract class LabeledSanitizerGuardNode extends SanitizerGuardNode, DataFlow::BarrierGuardNode {
abstract deprecated class LabeledSanitizerGuardNode extends SanitizerGuardNode,
DataFlow::BarrierGuardNode
{
override predicate sanitizes(boolean outcome, Expr e) { none() }
}
/**
* A taint-propagating data flow edge that should be added to all taint tracking
* configurations in addition to standard data flow edges.
*
* This class is a singleton, and thus subclasses do not need to specify a characteristic predicate.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Override `Configuration::isAdditionalTaintStep`
* for analysis-specific taint steps.
*
* This class has multiple kinds of `step` predicates; these all have the same
* effect on taint-tracking configurations. However, the categorization of steps
* allows some data-flow configurations to opt in to specific kinds of taint steps.
*/
class SharedTaintStep extends Unit {
// Each step relation in this class should have a cached version in the `Cached` module
// and be included in the `sharedTaintStep` predicate.
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge.
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through URI manipulation.
*
* Does not include string operations that aren't specific to URIs, such
* as concatenation and substring operations.
*/
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge contributed by the heuristics library.
*
* Such steps are provided by the `semmle.javascript.heuristics` libraries
* and will default to be being empty if those libraries are not imported.
*/
predicate heuristicStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through persistent storage.
*/
predicate persistentStorageStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through the heap.
*/
predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through arrays.
*
* These steps considers an array to be tainted if it contains tainted elements.
*/
predicate arrayStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through the `state` or `props` or a React component.
*/
predicate viewComponentStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through string concatenation.
*/
predicate stringConcatenationStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through string manipulation (other than concatenation).
*/
predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data serialization, such as `JSON.stringify`.
*/
predicate serializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data deserialization, such as `JSON.parse`.
*/
predicate deserializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through a promise.
*
* These steps consider a promise object to tainted if it can resolve to
* a tainted value.
*/
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
}
/**
* Module existing only to ensure all taint steps are cached as a single stage,
* and without the the `Unit` type column.
*/
cached
private module Cached {
cached
predicate forceStage() { Stages::Taint::ref() }
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge, which doesn't fit into a more specific category.
*/
cached
predicate genericStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).step(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge, contribued by the heuristics library.
*/
cached
predicate heuristicStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).heuristicStep(pred, succ)
}
/**
* Public taint step relations.
*/
cached
module Public {
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through a URI library function.
*/
cached
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).uriStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through persistent storage.
*/
cached
predicate persistentStorageStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).persistentStorageStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through the heap.
*/
cached
predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).heapStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through an array.
*/
cached
predicate arrayStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).arrayStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through the
* properties of a view compenent, such as the `state` or `props` of a React component.
*/
cached
predicate viewComponentStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).viewComponentStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through string
* concatenation.
*/
cached
predicate stringConcatenationStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).stringConcatenationStep(pred, succ)
}
/**
* Holds if `pred -> succ` is a taint propagating data flow edge through string manipulation
* (other than concatenation).
*/
cached
predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).stringManipulationStep(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data serialization, such as `JSON.stringify`.
*/
cached
predicate serializeStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).serializeStep(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through data deserialization, such as `JSON.parse`.
*/
cached
predicate deserializeStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).deserializeStep(pred, succ)
}
/**
* Holds if `pred` &rarr; `succ` should be considered a taint-propagating
* data flow edge through a promise.
*
* These steps consider a promise object to tainted if it can resolve to
* a tainted value.
*/
cached
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).promiseStep(pred, succ)
}
}
}
import Cached::Public
/**
* Holds if `pred -> succ` is an edge used by all taint-tracking configurations.
*/
predicate sharedTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
Cached::genericStep(pred, succ) or
Cached::heuristicStep(pred, succ) or
uriStep(pred, succ) or
persistentStorageStep(pred, succ) or
heapStep(pred, succ) or
arrayStep(pred, succ) or
viewComponentStep(pred, succ) or
stringConcatenationStep(pred, succ) or
stringManipulationStep(pred, succ) or
serializeStep(pred, succ) or
deserializeStep(pred, succ) or
promiseStep(pred, succ)
}
/** Gets a data flow node referring to the client side URL. */
private DataFlow::SourceNode clientSideUrlRef(DataFlow::TypeTracker t) {
t.start() and
@@ -497,11 +325,19 @@ module TaintTracking {
exists(StringSplitCall c |
c.getBaseString().getALocalSource() =
[DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] and
c.getSeparator() = "?" and
c.getSeparator() = ["?", "#"] and
read = c.getAPropertyRead("0")
)
}
private class HeapLegacyTaintStep extends LegacyTaintStep {
override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
// arrays with tainted elements are tainted (in old data flow)
succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and
not any(PromiseAllCreation call).getArrayNode() = succ
}
}
/**
* A taint propagating data flow edge through object or array elements and
* promises.
@@ -516,10 +352,6 @@ module TaintTracking {
// spreading a tainted value into an array literal gives a tainted array
succ.(DataFlow::ArrayCreationNode).getASpreadArgument() = pred
or
// arrays with tainted elements and objects with tainted property names are tainted
succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and
not any(PromiseAllCreation call).getArrayNode() = succ
or
// reading from a tainted object yields a tainted result
succ.(DataFlow::PropRead).getBase() = pred and
not (
@@ -594,6 +426,16 @@ module TaintTracking {
}
}
private class LegacySplitTaintStep extends LegacyTaintStep {
override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node target) {
exists(DataFlow::MethodCallNode call |
call.getMethodName() = "split" and
pred = call.getReceiver() and
target = call
)
}
}
/**
* A taint propagating data flow edge arising from string manipulation
* functions defined in the standard library.
@@ -610,9 +452,9 @@ module TaintTracking {
[
"anchor", "big", "blink", "bold", "concat", "fixed", "fontcolor", "fontsize",
"italics", "link", "padEnd", "padStart", "repeat", "replace", "replaceAll", "slice",
"small", "split", "strike", "sub", "substr", "substring", "sup",
"toLocaleLowerCase", "toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim",
"trimLeft", "trimRight", "toWellFormed"
"small", "strike", "sub", "substr", "substring", "sup", "toLocaleLowerCase",
"toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim", "trimLeft", "trimRight",
"toWellFormed"
]
or
// sorted, interesting, properties of Object.prototype
@@ -652,26 +494,29 @@ module TaintTracking {
]).getACall() and
pred = c.getArgument(0)
)
or
// In and out of .replace callbacks
exists(StringReplaceCall call |
// Into the callback if the regexp does not sanitize matches
hasWildcardReplaceRegExp(call) and
pred = call.getReceiver() and
succ = call.getReplacementCallback().getParameter(0)
or
// Out of the callback
pred = call.getReplacementCallback().getReturnNode() and
succ = call
)
)
}
}
/** Holds if the given call takes a regexp containing a wildcard. */
pragma[noinline]
private predicate hasWildcardReplaceRegExp(StringReplaceCall call) {
RegExp::isWildcardLike(call.getRegExp().getRoot().getAChild*())
/**
* A taint propagating edge for the string `replace` function.
*
* This is a legacy step as it crosses a function boundary, and would thus be converted to a jump step.
*/
private class ReplaceCallbackSteps extends LegacyTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
// In and out of .replace callbacks
exists(StringReplaceCall call |
// Into the callback if the regexp does not sanitize matches
call.hasRegExpContainingWildcard() and
pred = call.getReceiver() and
succ = call.getReplacementCallback().getParameter(0)
or
// Out of the callback
pred = call.getReplacementCallback().getReturnNode() and
succ = call
)
}
}
/**
@@ -969,7 +814,7 @@ module TaintTracking {
* A conditional checking a tainted string against a regular expression, which is
* considered to be a sanitizer for all configurations.
*/
class SanitizingRegExpTest extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
class SanitizingRegExpTest extends LegacyAdditionalBarrierGuard, DataFlow::ValueNode {
Expr expr;
boolean sanitizedOutcome;
@@ -1002,12 +847,10 @@ module TaintTracking {
private boolean getSanitizedOutcome() { result = sanitizedOutcome }
override predicate sanitizes(boolean outcome, Expr e) {
override predicate blocksExpr(boolean outcome, Expr e) {
outcome = sanitizedOutcome and
e = expr
}
override predicate appliesTo(Configuration cfg) { any() }
}
/**
@@ -1017,14 +860,14 @@ module TaintTracking {
*
* Note that the `includes` method is covered by `MembershipTestSanitizer`.
*/
class WhitelistContainmentCallSanitizer extends AdditionalSanitizerGuardNode,
class WhitelistContainmentCallSanitizer extends LegacyAdditionalBarrierGuard,
DataFlow::MethodCallNode
{
WhitelistContainmentCallSanitizer() {
this.getMethodName() = ["contains", "has", "hasOwnProperty", "hasOwn"]
}
override predicate sanitizes(boolean outcome, Expr e) {
override predicate blocksExpr(boolean outcome, Expr e) {
exists(int propertyIndex |
if this.getMethodName() = "hasOwn" then propertyIndex = 1 else propertyIndex = 0
|
@@ -1032,8 +875,6 @@ module TaintTracking {
e = this.getArgument(propertyIndex).asExpr()
)
}
override predicate appliesTo(Configuration cfg) { any() }
}
/**
@@ -1043,33 +884,40 @@ module TaintTracking {
*
* This sanitizer is not enabled by default.
*/
class AdHocWhitelistCheckSanitizer extends SanitizerGuardNode, DataFlow::CallNode {
class AdHocWhitelistCheckSanitizer extends DataFlow::CallNode {
AdHocWhitelistCheckSanitizer() {
this.getCalleeName()
.regexpMatch("(?i).*((?<!un)safe|whitelist|(?<!in)valid|allow|(?<!un)auth(?!or\\b)).*") and
this.getNumArgument() = 1
}
override predicate sanitizes(boolean outcome, Expr e) {
/** Holds if this node blocks flow through `e`, provided it evaluates to `outcome`. */
predicate blocksExpr(boolean outcome, Expr e) {
outcome = true and
e = this.getArgument(0).asExpr()
}
}
deprecated private class AdHocWhitelistCheckSanitizerAsSanitizerGuardNode extends SanitizerGuardNode instanceof AdHocWhitelistCheckSanitizer
{
override predicate sanitizes(boolean outcome, Expr e) { super.blocksExpr(outcome, e) }
}
/** Barrier nodes derived from the `AdHocWhitelistCheckSanitizer` class. */
module AdHocWhitelistCheckSanitizer = DataFlow::MakeBarrierGuard<AdHocWhitelistCheckSanitizer>;
/** A check of the form `if(x in o)`, which sanitizes `x` in its "then" branch. */
class InSanitizer extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
class InSanitizer extends LegacyAdditionalBarrierGuard, DataFlow::ValueNode {
override InExpr astNode;
override predicate sanitizes(boolean outcome, Expr e) {
override predicate blocksExpr(boolean outcome, Expr e) {
outcome = true and
e = astNode.getLeftOperand()
}
override predicate appliesTo(Configuration cfg) { any() }
}
/** A check of the form `if(o[x] != undefined)`, which sanitizes `x` in its "then" branch. */
class UndefinedCheckSanitizer extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
class UndefinedCheckSanitizer extends LegacyAdditionalBarrierGuard, DataFlow::ValueNode {
Expr x;
override EqualityTest astNode;
@@ -1085,27 +933,23 @@ module TaintTracking {
)
}
override predicate sanitizes(boolean outcome, Expr e) {
override predicate blocksExpr(boolean outcome, Expr e) {
outcome = astNode.getPolarity().booleanNot() and
e = x
}
override predicate appliesTo(Configuration cfg) { any() }
}
/** A check of the form `type x === "undefined"`, which sanitized `x` in its "then" branch. */
class TypeOfUndefinedSanitizer extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
class TypeOfUndefinedSanitizer extends LegacyAdditionalBarrierGuard, DataFlow::ValueNode {
Expr x;
override EqualityTest astNode;
TypeOfUndefinedSanitizer() { isTypeofGuard(astNode, x, "undefined") }
override predicate sanitizes(boolean outcome, Expr e) {
override predicate blocksExpr(boolean outcome, Expr e) {
outcome = astNode.getPolarity() and
e = x
}
override predicate appliesTo(Configuration cfg) { any() }
}
/**
@@ -1166,7 +1010,7 @@ module TaintTracking {
/**
* A test of form `x.length === "0"`, preventing `x` from being tainted.
*/
class IsEmptyGuard extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
class IsEmptyGuard extends LegacyAdditionalBarrierGuard, DataFlow::ValueNode {
override EqualityTest astNode;
boolean polarity;
Expr operand;
@@ -1180,24 +1024,20 @@ module TaintTracking {
)
}
override predicate sanitizes(boolean outcome, Expr e) { polarity = outcome and e = operand }
override predicate appliesTo(Configuration cfg) { any() }
override predicate blocksExpr(boolean outcome, Expr e) { polarity = outcome and e = operand }
}
/**
* A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch.
*/
class MembershipTestSanitizer extends AdditionalSanitizerGuardNode {
class MembershipTestSanitizer extends LegacyAdditionalBarrierGuard {
MembershipCandidate candidate;
MembershipTestSanitizer() { this = candidate.getTest() }
override predicate sanitizes(boolean outcome, Expr e) {
override predicate blocksExpr(boolean outcome, Expr e) {
candidate = e.flow() and candidate.getTestPolarity() = outcome
}
override predicate appliesTo(Configuration cfg) { any() }
}
/**
@@ -1205,7 +1045,7 @@ module TaintTracking {
*
* The more typical case of `x.indexOf(y) >= 0` is covered by `MembershipTestSanitizer`.
*/
class PositiveIndexOfSanitizer extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
class PositiveIndexOfSanitizer extends LegacyAdditionalBarrierGuard, DataFlow::ValueNode {
MethodCallExpr indexOf;
override RelationalComparison astNode;
@@ -1218,19 +1058,17 @@ module TaintTracking {
)
}
override predicate sanitizes(boolean outcome, Expr e) {
override predicate blocksExpr(boolean outcome, Expr e) {
outcome = true and
e = indexOf.getArgument(0)
}
override predicate appliesTo(Configuration cfg) { any() }
}
/**
* An equality test on `e.origin` or `e.source` where `e` is a `postMessage` event object,
* considered as a sanitizer for `e`.
*/
private class PostMessageEventSanitizer extends AdditionalSanitizerGuardNode {
private class PostMessageEventSanitizer extends LegacyAdditionalBarrierGuard {
VarAccess event;
boolean polarity;
@@ -1247,11 +1085,29 @@ module TaintTracking {
)
}
override predicate sanitizes(boolean outcome, Expr e) {
override predicate blocksExpr(boolean outcome, Expr e) {
outcome = polarity and
e = event
}
}
override predicate appliesTo(Configuration cfg) { any() }
import internal.sharedlib.TaintTracking
/**
* Holds if there is a taint step from `node1` to `node2`.
*
* This includes steps between synthesized nodes generated by flow summaries.
*/
pragma[inline]
predicate defaultTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
TaintTrackingPrivate::defaultAdditionalTaintStep(node1, node2)
}
/**
* Holds if `node` is seen as a barrier for taint-tracking.
*/
pragma[inline]
predicate defaultSanitizer(DataFlow::Node node) {
TaintTrackingPrivate::defaultTaintSanitizer(node)
}
}

View File

@@ -92,7 +92,7 @@ class AccessPath extends TAccessPath {
* Gets an expression in `bb` represented by this access path.
*/
cached
Expr getAnInstanceIn(BasicBlock bb) {
Expr getAnInstanceIn(ReachableBasicBlock bb) {
Stages::DataFlowStage::ref() and
exists(SsaVariable var |
this = MkSsaRoot(var) and

View File

@@ -0,0 +1,34 @@
private import javascript
private import semmle.javascript.dataflow.internal.DataFlowNode
private import semmle.javascript.dataflow.internal.DataFlowPrivate
/**
* Gets a data-flow node synthesized using `AdditionalFlowInternal#needsSynthesizedNode`.
*/
DataFlow::Node getSynthesizedNode(AstNode node, string tag) {
result = TGenericSynthesizedNode(node, tag, _)
}
/**
* An extension to `AdditionalFlowStep` with additional internal-only predicates.
*/
class AdditionalFlowInternal extends DataFlow::AdditionalFlowStep {
/**
* Holds if a data-flow node should be synthesized for the pair `(node, tag)`.
*
* The node can be obtained using `getSynthesizedNode(node, tag)`.
*
* `container` will be seen as the node's enclosing container.
*/
predicate needsSynthesizedNode(AstNode node, string tag, DataFlowCallable container) { none() }
/**
* Holds if `node` should only permit flow of values stored in `contents`.
*/
predicate expectsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
/**
* Holds if `node` should not permit flow of values stored in `contents`.
*/
predicate clearsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
}

View File

@@ -0,0 +1,474 @@
/**
* A copy of the barrier guard logic from `Configuration.qll` in the JS data flow library.
*
* This version considers all barrier guards to be relevant.
*/
private import javascript
private import semmle.javascript.dataflow.internal.AccessPaths
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
private signature class BarrierGuardSig extends DataFlow::Node {
/**
* Holds if this node acts as a barrier for data flow, blocking further flow from `e` if `this` evaluates to `outcome`.
*/
predicate blocksExpr(boolean outcome, Expr e);
}
/**
* Converts a barrier guard class to a set of nodes to include in an implementation of `isBarrier(node)`.
*/
module MakeBarrierGuard<BarrierGuardSig BaseGuard> {
final private class FinalBaseGuard = BaseGuard;
private class Adapter extends FinalBaseGuard {
predicate blocksExpr(boolean outcome, Expr e, Unit state) {
super.blocksExpr(outcome, e) and exists(state)
}
}
/**
* Gets a node that is blocked by a barrier guard.
*/
DataFlow::Node getABarrierNode() {
result = MakeStateBarrierGuard<Unit, Adapter>::getABarrierNode(_)
}
}
deprecated private module DeprecationWrapper {
signature class LabeledBarrierGuardSig extends DataFlow::Node {
/**
* Holds if this node acts as a barrier for `label`, blocking further flow from `e` if `this` evaluates to `outcome`.
*/
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label);
}
}
/**
* Converts a barrier guard class to a set of nodes to include in an implementation of `isBarrier(node, label)`.
*/
deprecated module MakeLabeledBarrierGuard<DeprecationWrapper::LabeledBarrierGuardSig BaseGuard> {
final private class FinalBaseGuard = BaseGuard;
private class Adapter extends FinalBaseGuard {
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
super.blocksExpr(outcome, e, label)
}
}
/**
* Gets a node and flow label that is blocked by a barrier guard.
*/
DataFlow::Node getABarrierNode(DataFlow::FlowLabel label) {
result = MakeStateBarrierGuard<DataFlow::FlowLabel, Adapter>::getABarrierNode(label)
}
}
/**
* Contains deprecated signatures.
*
* This module is a workaround for the fact that deprecated signatures can't refer to deprecated classes
* without getting a deprecation warning
*/
deprecated private module DeprecatedSigs {
signature predicate isBarrierGuardSig(DataFlow::BarrierGuardNode node);
}
/**
* Converts a labeled barrier guard class to a set of nodes to include in an implementation of `isBarrier(node)` and `isBarrier(node, label)`
* in a `DataFlow::StateConfigSig` implementation.
*/
deprecated module MakeLegacyBarrierGuardLabeled<DeprecatedSigs::isBarrierGuardSig/1 isBarrierGuard> {
final private class FinalNode = DataFlow::Node;
private class Adapter extends FinalNode instanceof DataFlow::BarrierGuardNode {
Adapter() { isBarrierGuard(this) }
predicate blocksExpr(boolean outcome, Expr e, string label) {
super.blocks(outcome, e, label)
or
super.blocks(outcome, e) and label = ""
}
}
private module Guards = MakeStateBarrierGuard<string, Adapter>;
/**
* Gets a node that is blocked by a barrier guard.
*/
DataFlow::Node getABarrierNode() { result = Guards::getABarrierNode("") }
/**
* Gets a node and flow label that is blocked by a barrier guard.
*/
DataFlow::Node getABarrierNode(DataFlow::FlowLabel label) {
result = Guards::getABarrierNode(label)
}
}
/**
* Converts a barrier guard class to a set of nodes to include in an implementation of `isBarrier(node)` in a `DataFlow::ConfigSig` implementation.
*/
deprecated module MakeLegacyBarrierGuard<DeprecatedSigs::isBarrierGuardSig/1 isBarrierGuard> {
final private class FinalNode = DataFlow::Node;
private class Adapter extends FinalNode instanceof DataFlow::BarrierGuardNode {
Adapter() { isBarrierGuard(this) }
predicate blocksExpr(boolean outcome, Expr e, string label) {
super.blocks(outcome, e, label)
or
super.blocks(outcome, e) and label = ""
}
}
private module Guards = MakeStateBarrierGuard<string, Adapter>;
/**
* Gets a node that is blocked by a barrier guard.
*/
DataFlow::Node getABarrierNode() { result = Guards::getABarrierNode(["", "data", "taint"]) }
}
bindingset[this]
private signature class FlowStateSig;
private module WithFlowState<FlowStateSig FlowState> {
signature class BarrierGuardSig extends DataFlow::Node {
/**
* Holds if this node acts as a barrier for `state`, blocking further flow from `e` if `this` evaluates to `outcome`.
*/
predicate blocksExpr(boolean outcome, Expr e, FlowState state);
}
}
/**
* Projects the dominator tree onto a tree that only considers dominance between `ConditionGuardNode`s.
*
* This exists to speeds up the dominance check for barrier guards acting on an access path, avoiding the following two
* bad join orders:
*
* - Enumerate all basic blocks dominated by a barrier guard, and then find uses of the access path in those blocks.
* - Enumerate all uses of an access path and then select those that are in a dominated block.
*
* Both joins have pathological cases in different benchmarks.
*
* We use a join order that is essentially the first one above, except we only enumerate condition guards, not all the blocks.
*/
cached
private module ConditionGuardDominators {
/** Gets the condition guard that most-immediately dominates `bb`. */
private ConditionGuardNode getDominatingCondition(ReachableBasicBlock bb) {
result.getBasicBlock() = bb
or
not bb = any(ConditionGuardNode guard).getBasicBlock() and
result = getDominatingCondition(bb.getImmediateDominator())
}
private predicate immediateDom(ConditionGuardNode dominator, ConditionGuardNode dominated) {
dominator = getDominatingCondition(dominated.getBasicBlock().getImmediateDominator())
or
dominator = dominated // make the fastTC below reflexive
}
/** Gets a condition guard dominated by `node` */
cached
ConditionGuardNode getADominatedConditionGuard(ConditionGuardNode node) =
fastTC(immediateDom/2)(node, result)
/** Gets a use of `ap` and binds `guard` to its immediately-dominating condition guard (if any). */
cached
Expr getAnAccessPathUseUnderCondition(AccessPath ap, ConditionGuardNode guard) {
exists(ReachableBasicBlock bb |
result = ap.getAnInstanceIn(bb) and
guard = getDominatingCondition(bb)
)
}
}
/**
* Converts a barrier guard class to a set of nodes to include in an implementation of `isBarrier(node, state)`.
*/
module MakeStateBarrierGuard<
FlowStateSig FlowState, WithFlowState<FlowState>::BarrierGuardSig BaseGuard>
{
final private class FinalNode = DataFlow::Node;
abstract private class BarrierGuard extends FinalNode {
abstract predicate blocksExpr(boolean outcome, Expr test, FlowState state);
}
private class ExplicitBarrierGuard extends BarrierGuard instanceof BaseGuard {
override predicate blocksExpr(boolean outcome, Expr test, FlowState state) {
BaseGuard.super.blocksExpr(outcome, test, state)
}
}
/**
* Gets a node and flow state that is blocked by a barrier guard.
*/
pragma[nomagic]
DataFlow::Node getABarrierNode(FlowState state) { barrierGuardBlocksNode(result, state) }
//
// ================================================================================================
// NOTE
// The rest of this file is a copy of the barrier-guard logic in Configuration.qll except:
// - FlowLabel is replaced by FlowState
// - BarrierGuardNode and AdditionalBarrierGuardNode are replaced by the BarrierGuard class defined above
// - `barrierGuardBlocksEdge` is missing as dataflow2 does not support barrier edges
// - `barrierGuardIsRelevant` does not check pruning results as we can't access that from here
// - `barrierGuardBlocksNode` has been rewritten to perform better without pruning.
// ================================================================================================
//
/**
* Holds if data flow node `guard` acts as a barrier for data flow.
*
* `state` is bound to the blocked state, or the empty FlowState if all labels should be blocked.
*/
pragma[nomagic]
private predicate barrierGuardBlocksExpr(
BarrierGuard guard, boolean outcome, Expr test, FlowState state
) {
guard.blocksExpr(outcome, test, state)
}
/**
* Holds if `guard` may block the flow of a value reachable through exploratory flow.
*/
pragma[nomagic]
private predicate barrierGuardIsRelevant(BarrierGuard guard) {
exists(Expr e |
barrierGuardBlocksExpr(guard, _, e, _)
// All guards are considered relevant (this is the difference from the main JS lib)
// isRelevantForward(e.flow(), _)
)
}
/**
* Holds if data flow node `guard` acts as a barrier for data flow due to aliasing through
* an access path.
*
* `state` is bound to the blocked state, or the empty FlowState if all labels should be blocked.
*/
pragma[nomagic]
private predicate barrierGuardBlocksAccessPath(
BarrierGuard guard, boolean outcome, AccessPath ap, FlowState state
) {
barrierGuardIsRelevant(guard) and
barrierGuardBlocksExpr(guard, outcome, ap.getAnInstance(), state)
}
/**
* Holds if there exists an input variable of `ref` that blocks the state `state`.
*
* This predicate is outlined to give the optimizer a hint about the join ordering.
*/
pragma[nomagic]
private predicate barrierGuardBlocksSsaRefinement(
BarrierGuard guard, boolean outcome, SsaRefinementNode ref, FlowState state
) {
barrierGuardIsRelevant(guard) and
guard.getEnclosingExpr() = ref.getGuard().getTest() and
forex(SsaVariable input | input = ref.getAnInput() |
barrierGuardBlocksExpr(guard, outcome, input.getAUse(), state)
)
}
/**
* Holds if the result of `guard` is used in the branching condition `cond`.
*
* `outcome` is bound to the outcome of `cond` for join-ordering purposes.
*/
pragma[nomagic]
private predicate barrierGuardUsedInCondition(
BarrierGuard guard, ConditionGuardNode cond, boolean outcome
) {
barrierGuardIsRelevant(guard) and
outcome = cond.getOutcome() and
(
cond.getTest() = guard.getEnclosingExpr()
or
cond.getTest().flow().getImmediatePredecessor+() = guard
)
}
private predicate ssa2GuardChecks(
Ssa2::SsaDataflowInput::Guard guard, Ssa2::SsaDataflowInput::Expr test, boolean branch,
FlowState state
) {
exists(BarrierGuard g |
g.asExpr() = guard and
g.blocksExpr(branch, test, state)
)
}
private module Ssa2Barrier = Ssa2::BarrierGuardWithState<FlowState, ssa2GuardChecks/4>;
private predicate ssa2BlocksNode(DataFlow::Node node, FlowState state) {
node = DataFlowPrivate::getNodeFromSsa2(Ssa2Barrier::getABarrierNode(state))
}
/** Holds if a barrier guard blocks uses of `ap` in basic blocks dominated by `cond`. */
pragma[nomagic]
private predicate barrierGuardBlocksAccessPathIn(
AccessPath ap, ConditionGuardNode cond, FlowState state
) {
exists(BarrierGuard guard, boolean outcome |
barrierGuardBlocksAccessPath(guard, outcome, ap, state) and
barrierGuardUsedInCondition(guard, cond, outcome)
)
}
/**
* Holds if `expr` is an access path reference that is blocked by a barrier guard.
*/
pragma[noopt]
private predicate barrierGuardBlocksAccessPathUse(Expr use, FlowState state) {
exists(AccessPath p, ConditionGuardNode cond, ConditionGuardNode useDominator |
barrierGuardBlocksAccessPathIn(p, cond, state) and
useDominator = ConditionGuardDominators::getADominatedConditionGuard(cond) and
use = ConditionGuardDominators::getAnAccessPathUseUnderCondition(p, useDominator)
)
}
/**
* Holds if data flow node `nd` acts as a barrier for data flow, possibly due to aliasing
* through an access path.
*
* `state` is bound to the blocked state.
*/
pragma[nomagic]
private predicate barrierGuardBlocksNode(DataFlow::Node nd, FlowState state) {
exists(BarrierGuard guard, SsaRefinementNode ref, boolean outcome |
nd = DataFlow::ssaDefinitionNode(ref) and
outcome = ref.getGuard().(ConditionGuardNode).getOutcome() and
barrierGuardBlocksSsaRefinement(guard, outcome, ref, state)
)
or
exists(Expr use |
barrierGuardBlocksAccessPathUse(use, state) and
nd = DataFlow::valueNode(use)
)
or
ssa2BlocksNode(nd, state)
}
/**
* Gets a logical `and` expression, or parenthesized expression, that contains `guard`.
*/
private Expr getALogicalAndParent(BarrierGuard guard) {
barrierGuardIsRelevant(guard) and result = guard.asExpr()
or
result.(LogAndExpr).getAnOperand() = getALogicalAndParent(guard)
or
result.getUnderlyingValue() = getALogicalAndParent(guard)
}
/**
* Gets a logical `or` expression, or parenthesized expression, that contains `guard`.
*/
private Expr getALogicalOrParent(BarrierGuard guard) {
barrierGuardIsRelevant(guard) and result = guard.asExpr()
or
result.(LogOrExpr).getAnOperand() = getALogicalOrParent(guard)
or
result.getUnderlyingValue() = getALogicalOrParent(guard)
}
final private class FinalFunction = Function;
/**
* A function that returns the result of a barrier guard.
*/
private class BarrierGuardFunction extends FinalFunction {
DataFlow::ParameterNode sanitizedParameter;
BarrierGuard guard;
boolean guardOutcome;
FlowState state;
int paramIndex;
BarrierGuardFunction() {
barrierGuardIsRelevant(guard) and
exists(Expr e |
exists(Expr returnExpr |
returnExpr = guard.asExpr()
or
// ad hoc support for conjunctions:
getALogicalAndParent(guard) = returnExpr and guardOutcome = true
or
// ad hoc support for disjunctions:
getALogicalOrParent(guard) = returnExpr and guardOutcome = false
|
exists(SsaExplicitDefinition ssa |
ssa.getDef().getSource() = returnExpr and
ssa.getVariable().getAUse() = this.getAReturnedExpr()
)
or
returnExpr = this.getAReturnedExpr()
) and
sanitizedParameter.flowsToExpr(e) and
barrierGuardBlocksExpr(guard, guardOutcome, e, state)
) and
sanitizedParameter.getParameter() = this.getParameter(paramIndex)
}
/**
* Holds if this function sanitizes argument `e` of call `call`, provided the call evaluates to `outcome`.
*/
predicate isBarrierCall(DataFlow::CallNode call, Expr e, boolean outcome, FlowState st) {
exists(DataFlow::Node arg |
DataFlow::argumentPassingStep(pragma[only_bind_into](call), pragma[only_bind_into](arg),
pragma[only_bind_into](this), pragma[only_bind_into](sanitizedParameter)) and
arg.asExpr() = e and
arg = call.getArgument(paramIndex) and
outcome = guardOutcome and
state = st
)
}
}
/**
* A call that sanitizes an argument.
*/
private class AdditionalBarrierGuardCall extends BarrierGuard instanceof DataFlow::CallNode {
BarrierGuardFunction f;
AdditionalBarrierGuardCall() { f.isBarrierCall(this, _, _, _) }
override predicate blocksExpr(boolean outcome, Expr e, FlowState state) {
f.isBarrierCall(this, e, outcome, state)
}
}
/**
* A sanitizer where an inner sanitizer is compared against a boolean.
* E.g. (assuming `sanitizes(e)` is an existing sanitizer):
* ```javascript
* if (sanitizes(e) === true) {
* // e is sanitized
* }
* ```
*/
private class CallAgainstEqualityCheck extends BarrierGuard {
BarrierGuard prev;
boolean polarity;
CallAgainstEqualityCheck() {
prev instanceof DataFlow::CallNode and
exists(EqualityTest test, BooleanLiteral bool |
this.asExpr() = test and
test.hasOperands(prev.asExpr(), bool) and
polarity = test.getPolarity().booleanXor(bool.getBoolValue())
)
}
override predicate blocksExpr(boolean outcome, Expr e, FlowState state) {
exists(boolean prevOutcome |
barrierGuardBlocksExpr(prev, prevOutcome, e, state) and
outcome = prevOutcome.booleanXor(polarity)
)
}
}
}

View File

@@ -0,0 +1,513 @@
private import javascript
private import semmle.javascript.frameworks.data.internal.ApiGraphModels as ApiGraphModels
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
private import semmle.javascript.dataflow.internal.VariableOrThis
private import codeql.dataflow.internal.AccessPathSyntax as AccessPathSyntax
module Private {
import Public
/**
* Gets the largest array index should be propagated precisely through flow summaries.
*
* Note that all known array indices have a corresponding singleton content, but some will
* be collapsed in flow summaries that operate on array elements.
*/
int getMaxPreciseArrayIndex() { result = 9 }
/** Gets the largest array index should be propagated precisely through flow summaries. */
int getAPreciseArrayIndex() { result = [0 .. getMaxPreciseArrayIndex()] }
/**
* Holds if a MaD access path token of form `name[arg]` exists.
*/
predicate isAccessPathTokenPresent(string name, string arg) {
arg = any(FlowSummaryPrivate::AccessPathToken tok).getAnArgument(name)
or
arg = any(ApiGraphModels::AccessPathToken tok).getAnArgument(name)
}
/**
* Holds if values associated with `key` should be tracked as a individual contents of a `Map` object.
*/
private predicate isKnownMapKey(string key) {
exists(MethodCallExpr call |
call.getMethodName() = "get" and
call.getNumArgument() = 1 and
call.getArgument(0).getStringValue() = key
)
or
isAccessPathTokenPresent("MapValue", key)
}
/**
* A known property name.
*/
class PropertyName extends string {
// Note: unlike the similarly-named class in StepSummary.qll, this class must not depend on DataFlow::Node
PropertyName() {
this = any(PropAccess access).getPropertyName()
or
this = any(Property p).getName()
or
this = any(PropertyPattern p).getName()
or
this = any(GlobalVariable v).getName()
or
this = getAPreciseArrayIndex().toString()
or
isAccessPathTokenPresent("Member", this)
}
/** Gets the array index corresponding to this property name. */
pragma[nomagic]
int asArrayIndex() { result = this.toInt() and result >= 0 and this = result.toString() }
}
cached
newtype TContent =
MkPropertyContent(PropertyName name) or
MkArrayElementUnknown() or // note: array elements with known index are just properties
MkMapKey() or
MkMapValueWithUnknownKey() or
MkMapValueWithKnownKey(string key) { isKnownMapKey(key) } or
MkSetElement() or
MkIteratorElement() or
MkIteratorError() or
MkPromiseValue() or
MkPromiseError() or
MkCapturedContent(LocalVariableOrThis v) { v.isCaptured() }
cached
newtype TContentSet =
MkSingletonContent(Content content) or
MkArrayElementKnown(int index) { index = any(PropertyName name).asArrayIndex() } or
MkArrayElementLowerBound(int index) { index = [0 .. getMaxPreciseArrayIndex() + 1] } or
MkMapValueKnown(string key) { isKnownMapKey(key) } or
MkMapValueAll() or
MkPromiseFilter() or
MkIteratorFilter() or
MkAnyProperty() or
MkAnyCapturedContent() or
// The following content sets are used exclusively as an intermediate value in flow summaries.
// These are encoded as a ContentSummaryComponent, although the flow graphs we generate are different
// than an ordinary content component. These special content sets should never appear in a step.
MkAwaited() or
MkAnyPropertyDeep() or
MkArrayElementDeep() or
MkOptionalStep(string name) { isAccessPathTokenPresent("OptionalStep", name) } or
MkOptionalBarrier(string name) { isAccessPathTokenPresent("OptionalBarrier", name) }
/**
* Holds if `cs` is used to encode a special operation as a content component, but should not
* be treated as an ordinary content component.
*/
predicate isSpecialContentSet(ContentSet cs) {
cs = MkAwaited() or
cs = MkAnyPropertyDeep() or
cs = MkArrayElementDeep() or
cs instanceof MkOptionalStep or
cs instanceof MkOptionalBarrier
}
}
module Public {
private import Private
/**
* A storage location on an object, such as a property name.
*/
class Content extends TContent {
/** Gets a string representation of this content. */
cached
string toString() {
// Note that these strings are visible to the end-user, in the access path of a PathNode.
result = this.asPropertyName()
or
this.isUnknownArrayElement() and
result = "ArrayElement"
or
this = MkMapKey() and
result = "MapKey"
or
this = MkMapValueWithUnknownKey() and
result = "MapValue"
or
exists(string key |
this = MkMapValueWithKnownKey(key) and
result = "MapValue[" + key + "]"
)
or
this = MkSetElement() and
result = "SetElement"
or
this = MkIteratorElement() and
result = "IteratorElement"
or
this = MkIteratorError() and
result = "IteratorError"
or
this = MkPromiseValue() and
result = "PromiseValue"
or
this = MkPromiseError() and
result = "PromiseError"
or
result = this.asCapturedVariable().getName()
}
/** Gets the property name represented by this content, if any. */
string asPropertyName() { this = MkPropertyContent(result) }
/** Gets the array index represented by this content, if any. */
pragma[nomagic]
int asArrayIndex() { result = this.asPropertyName().(PropertyName).asArrayIndex() }
/** Gets the captured variable represented by this content, if any. */
LocalVariableOrThis asCapturedVariable() { this = MkCapturedContent(result) }
/** Holds if this represents values stored at an unknown array index. */
predicate isUnknownArrayElement() { this = MkArrayElementUnknown() }
/** Holds if this represents values stored in a `Map` at an unknown key. */
predicate isMapValueWithUnknownKey() { this = MkMapValueWithUnknownKey() }
/** Holds if this represents values stored in a `Map` as the given string key. */
predicate isMapValueWithKnownKey(string key) { this = MkMapValueWithKnownKey(key) }
}
/**
* An entity that represents the set of `Content`s being accessed at a read or store operation.
*/
class ContentSet extends TContentSet {
/** Gets a content that may be stored into when storing into this set. */
pragma[inline]
Content getAStoreContent() {
result = this.asSingleton()
or
// For array element access with known lower bound, just store into the unknown array element
this = ContentSet::arrayElementLowerBound(_) and
result.isUnknownArrayElement()
or
exists(int n |
this = ContentSet::arrayElementKnown(n) and
result.asArrayIndex() = n
)
or
exists(string key |
this = ContentSet::mapValueWithKnownKey(key) and
result.isMapValueWithKnownKey(key)
)
or
this = ContentSet::mapValueAll() and
result.isMapValueWithUnknownKey()
}
/** Gets a content that may be read from when reading from this set. */
pragma[nomagic]
Content getAReadContent() {
result = this.asSingleton()
or
this = ContentSet::promiseFilter() and
(
result = MkPromiseValue()
or
result = MkPromiseError()
)
or
this = ContentSet::iteratorFilter() and
(
result = MkIteratorElement()
or
result = MkIteratorError()
)
or
exists(int bound | this = ContentSet::arrayElementLowerBound(bound) |
result.isUnknownArrayElement()
or
result.asArrayIndex() >= bound
)
or
exists(int n | this = ContentSet::arrayElementKnown(n) |
result.isUnknownArrayElement()
or
result.asArrayIndex() = n
)
or
exists(string key | this = ContentSet::mapValueWithKnownKey(key) |
result.isMapValueWithUnknownKey()
or
result.isMapValueWithKnownKey(key)
)
or
this = ContentSet::mapValueAll() and
(
result.isMapValueWithUnknownKey()
or
result.isMapValueWithKnownKey(_)
)
or
this = ContentSet::anyProperty() and
(
result instanceof MkPropertyContent
or
result instanceof MkArrayElementUnknown
)
or
this = ContentSet::anyCapturedContent() and
result instanceof Private::MkCapturedContent
}
/** Gets the singleton content to be accessed. */
Content asSingleton() { this = MkSingletonContent(result) }
/** Gets the property name to be accessed, provided that this is a singleton content set. */
PropertyName asPropertyName() { result = this.asSingleton().asPropertyName() }
/**
* Gets a string representation of this content set.
*/
string toString() {
result = this.asSingleton().toString()
or
this = ContentSet::promiseFilter() and result = "PromiseFilter"
or
this = ContentSet::iteratorFilter() and result = "IteratorFilter"
or
exists(int bound |
this = ContentSet::arrayElementLowerBound(bound) and
result = "ArrayElement[" + bound + "..]"
)
or
exists(int n | this = ContentSet::arrayElementKnown(n) and result = "ArrayElement[" + n + "]")
or
this = ContentSet::mapValueAll() and
result = "MapValue"
or
this = ContentSet::anyProperty() and
result = "AnyMember"
or
this = MkAwaited() and result = "Awaited (with coercion)"
or
this = MkAnyPropertyDeep() and result = "AnyMemberDeep"
or
this = MkArrayElementDeep() and result = "ArrayElementDeep"
or
this = MkAnyCapturedContent() and
result = "AnyCapturedContent"
or
exists(string name |
this = MkOptionalStep(name) and
result = "OptionalStep[" + name + "]"
)
or
exists(string name |
this = MkOptionalBarrier(name) and
result = "OptionalBarrier[" + name + "]"
)
}
}
/**
* Companion module to the `ContentSet` class, providing access to various content sets.
*/
module ContentSet {
/**
* A content set containing only the given content.
*/
pragma[inline]
ContentSet singleton(Content content) { result.asSingleton() = content }
/**
* A content set corresponding to the given property name.
*/
pragma[inline]
ContentSet property(PropertyName name) { result.asSingleton().asPropertyName() = name }
/**
* A content set that should only be used in `withContent` and `withoutContent` steps, which
* matches the two promise-related contents, `Awaited[value]` and `Awaited[error]`.
*/
ContentSet promiseFilter() { result = MkPromiseFilter() }
/**
* A content set that should only be used in `withContent` and `withoutContent` steps, which
* matches the two iterator-related contents, `IteratorElement` and `IteratorError`.
*/
ContentSet iteratorFilter() { result = MkIteratorFilter() }
/**
* A content set describing the result of a resolved promise.
*/
ContentSet promiseValue() { result = singleton(MkPromiseValue()) }
/**
* A content set describing the error stored in a rejected promise.
*/
ContentSet promiseError() { result = singleton(MkPromiseError()) }
/**
* A content set describing all array elements, regardless of their index in the array.
*/
ContentSet arrayElement() { result = MkArrayElementLowerBound(0) }
/**
* A content set describing array elements at index `bound` or greater.
*
* For `bound=0` this gets the same content set as `ContentSet::arrayElement()`, that is,
* the content set describing all array elements.
*
* For large values of `bound` this has no result - see `ContentSet::arrayElementLowerBoundFromInt`.
*/
ContentSet arrayElementLowerBound(int bound) { result = MkArrayElementLowerBound(bound) }
/**
* A content set describing an access to array index `n`.
*
* This content set reads from element `n` and the unknown element, and stores to index `n`.
*
* For large values of `n` this has no result - see `ContentSet::arrayElementFromInt`.
*/
ContentSet arrayElementKnown(int n) { result = MkArrayElementKnown(n) }
/**
* The singleton content set describing array elements stored at an unknown index.
*/
ContentSet arrayElementUnknown() { result = singleton(MkArrayElementUnknown()) }
/**
* Gets a content set describing array elements at index `bound` or greater.
*
* If `bound` is too large, it is truncated to the greatest lower bound we can represent.
*/
bindingset[bound]
ContentSet arrayElementLowerBoundFromInt(int bound) {
result = arrayElementLowerBound(bound.minimum(getMaxPreciseArrayIndex() + 1))
}
/**
* Gets the content set describing an access to array index `n`.
*
* If `n` is too large, it is truncated to the greatest lower bound we can represent.
*/
bindingset[n]
ContentSet arrayElementFromInt(int n) {
result = arrayElementKnown(n)
or
not exists(arrayElementKnown(n)) and
result = arrayElementLowerBoundFromInt(n)
}
/** Gets the content set describing the keys of a `Map` object. */
ContentSet mapKey() { result = singleton(MkMapKey()) }
/** Gets the content set describing the values of a `Map` object stored with an unknown key. */
ContentSet mapValueWithUnknownKey() { result = singleton(MkMapValueWithUnknownKey()) }
/**
* Gets the content set describing the value of a `Map` object stored with the given known `key`.
*
* This has no result if `key` is not one of the keys we track precisely. See also `mapValueFromKey`.
*/
ContentSet mapValueWithKnownKeyStrict(string key) { result = MkMapValueKnown(key) }
/**
* Gets the content set describing an access to a map value with the given `key`.
*
* This content set also reads from a value stored with an unknown key. Use `mapValueWithKnownKeyStrict` to strictly
* refer to known keys.
*
* This has no result if `key` is not one of the keys we track precisely. See also `mapValueFromKey`.
*/
ContentSet mapValueWithKnownKey(string key) { result = singleton(MkMapValueWithKnownKey(key)) }
/** Gets the content set describing all values in a map (with known or unknown key). */
ContentSet mapValueAll() { result = MkMapValueAll() }
/**
* Gets the content set describing the value in a `Map` object stored at the given `key`.
*
* If `key` is not one of the keys we track precisely, this is mapped to the unknown key instead.
*/
bindingset[key]
ContentSet mapValueFromKey(string key) {
result = mapValueWithKnownKey(key)
or
not exists(mapValueWithKnownKey(key)) and
result = mapValueWithUnknownKey()
}
/** Gets the content set describing the elements of a `Set` object. */
ContentSet setElement() { result = singleton(MkSetElement()) }
/** Gets the content set describing the elements of an iterator object. */
ContentSet iteratorElement() { result = singleton(MkIteratorElement()) }
/** Gets the content set describing the exception to be thrown when attempting to iterate over the given value. */
ContentSet iteratorError() { result = singleton(MkIteratorError()) }
/**
* Gets a content set that reads from all ordinary properties.
*
* This includes array elements, but not the contents of `Map`, `Set`, `Promise`, or iterator objects.
*
* This content set has no effect if used in a store step.
*/
ContentSet anyProperty() { result = MkAnyProperty() }
/**
* Gets a content set corresponding to the pseudo-property `propertyName`.
*/
pragma[nomagic]
private ContentSet fromLegacyPseudoProperty(string propertyName) {
propertyName = Promises::valueProp() and
result = promiseValue()
or
propertyName = Promises::errorProp() and
result = promiseError()
or
propertyName = DataFlow::PseudoProperties::arrayElement() and
result = arrayElement()
or
propertyName = DataFlow::PseudoProperties::iteratorElement() and
result = iteratorElement()
or
propertyName = DataFlow::PseudoProperties::setElement() and
result = setElement()
or
propertyName = DataFlow::PseudoProperties::mapValueAll() and
result = mapValueAll()
or
propertyName = DataFlow::PseudoProperties::mapValueUnknownKey() and
result = mapValueWithUnknownKey()
or
exists(string key |
propertyName = DataFlow::PseudoProperties::mapValueKey(key) and
result = mapValueWithKnownKey(key)
)
}
/**
* Gets the content set corresponding to the given property name, where legacy pseudo-properties
* are mapped to their corresponding content sets (which are no longer seen as property names).
*/
bindingset[propertyName]
ContentSet fromLegacyProperty(string propertyName) {
result = fromLegacyPseudoProperty(propertyName)
or
not exists(fromLegacyPseudoProperty(propertyName)) and
(
// In case a map-value key was contributed via a SharedFlowStep, but we don't have a ContentSet for it,
// convert it to the unknown key.
if DataFlow::PseudoProperties::isMapValueKey(propertyName)
then result = mapValueWithUnknownKey()
else result = property(propertyName)
)
}
/**
* Gets a content set that reads from all captured variables stored on a function.
*/
ContentSet anyCapturedContent() { result = Private::MkAnyCapturedContent() }
}
}

View File

@@ -0,0 +1,56 @@
private import javascript
private import codeql.dataflow.internal.DataFlowImplConsistency
private import sharedlib.DataFlowArg
private import semmle.javascript.dataflow.internal.DataFlowPrivate
private import semmle.javascript.dataflow.internal.DataFlowNode
private module ConsistencyConfig implements InputSig<Location, JSDataFlow> {
private predicate isAmbientNode(DataFlow::Node node) {
exists(AstNode n | n.isAmbient() |
node = TValueNode(n) or
node = TThisNode(n) or
node = TReflectiveParametersNode(n) or
node = TPropNode(n) or
node = TFunctionSelfReferenceNode(n) or
node = TExceptionalFunctionReturnNode(n) or
node = TExprPostUpdateNode(n) or
node = TExceptionalInvocationReturnNode(n) or
node = TDestructuredModuleImportNode(n)
)
}
predicate missingLocationExclude(DataFlow::Node n) {
n instanceof FlowSummaryNode
or
n instanceof FlowSummaryIntermediateAwaitStoreNode
or
n instanceof FlowSummaryDynamicParameterArrayNode
or
n instanceof FlowSummaryDefaultExceptionalReturn
or
n instanceof GenericSynthesizedNode
or
n = DataFlow::globalAccessPathRootPseudoNode()
}
predicate uniqueNodeLocationExclude(DataFlow::Node n) { missingLocationExclude(n) }
predicate uniqueEnclosingCallableExclude(DataFlow::Node n) { isAmbientNode(n) }
predicate uniqueCallEnclosingCallableExclude(DataFlowCall call) {
isAmbientNode(call.asOrdinaryCall()) or
isAmbientNode(call.asAccessorCall())
}
predicate argHasPostUpdateExclude(ArgumentNode node) {
// Side-effects directly on these can't propagate back to the caller, and for longer access paths it's too imprecise
node instanceof TStaticArgumentArrayNode or
node instanceof TDynamicArgumentArrayNode
}
predicate reverseReadExclude(DataFlow::Node node) {
node instanceof FlowSummaryDynamicParameterArrayNode
}
}
module Consistency = MakeConsistency<Location, JSDataFlow, JSTaintFlow, ConsistencyConfig>;

View File

@@ -5,38 +5,157 @@
*/
private import javascript
private import codeql.util.Boolean
private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
private import semmle.javascript.dataflow.internal.Contents::Private
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
private import semmle.javascript.dataflow.internal.VariableCapture as VariableCapture
private import semmle.javascript.dataflow.internal.VariableOrThis
cached
private module Cached {
private Content dynamicArgumentsContent() {
result.asArrayIndex() = [0 .. 10]
or
result.isUnknownArrayElement()
}
/**
* The raw data type underlying `DataFlow::Node`.
*/
cached
newtype TNode =
TValueNode(AST::ValueNode nd) or
/** An SSA node from the legacy SSA library */
TSsaDefNode(SsaDefinition d) or
/** Use of a variable or 'this', with flow from a post-update node (from an earlier use) */
TSsaUseNode(ControlFlowNode use) { use = any(Ssa2::SsaConfig::SourceVariable v).getAUse() } or
/** Phi-read node (new SSA library). Ordinary phi nodes are represented by TSsaDefNode. */
TSsaPhiReadNode(Ssa2::PhiReadNode phi) or
/** Input to a phi node (new SSA library) */
TSsaInputNode(Ssa2::SsaInputNode input) or
TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or
TPropNode(@property p) or
TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or
TElementPatternNode(ArrayPattern ap, Expr p) { p = ap.getElement(_) } or
TElementNode(ArrayExpr arr, Expr e) { e = arr.getAnElement() } or
TReflectiveCallNode(MethodCallExpr ce, string kind) {
ce.getMethodName() = kind and
(kind = "call" or kind = "apply")
} or
TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or
TFunctionSelfReferenceNode(Function f) or
TStaticArgumentArrayNode(InvokeExpr node) or
TDynamicArgumentArrayNode(InvokeExpr node) { node.isSpreadArgument(_) } or
TStaticParameterArrayNode(Function f) {
f.getAParameter().isRestParameter() or f.usesArgumentsObject()
} or
TDynamicParameterArrayNode(Function f) or
/** Data about to be stored in the rest parameter object. Needed for shifting array indices. */
TRestParameterStoreNode(Function f, Content storeContent) {
f.getRestParameter().getIndex() > 0 and
storeContent = dynamicArgumentsContent()
} or
/** Data about to be stored in the dynamic argument array of an invocation. Needed for shifting array indices. */
TDynamicArgumentStoreNode(InvokeExpr invoke, Content storeContent) {
invoke.isSpreadArgument(_) and
storeContent = dynamicArgumentsContent()
} or
TApplyCallTaintNode(MethodCallExpr node) {
node.getMethodName() = "apply" and exists(node.getArgument(1))
} or
TDestructuredModuleImportNode(ImportDeclaration decl) {
exists(decl.getASpecifier().getImportedName())
} or
THtmlAttributeNode(HTML::Attribute attr) or
TXmlAttributeNode(XmlAttribute attr) or
TFunctionReturnNode(Function f) or
TExceptionalFunctionReturnNode(Function f) or
TExceptionalInvocationReturnNode(InvokeExpr e) or
TGlobalAccessPathRoot() or
TTemplatePlaceholderTag(Templating::TemplatePlaceholderTag tag) or
TReflectiveParametersNode(Function f) { f.usesArgumentsObject() } or
TExprPostUpdateNode(AST::ValueNode e) {
e = any(InvokeExpr invoke).getAnArgument() or
e = any(PropAccess access).getBase() or
e = any(DestructuringPattern pattern) or
e = any(InvokeExpr invoke).getCallee() or
// We have read steps out of the await operand, so it technically needs a post-update
e = any(AwaitExpr a).getOperand() or
e = any(Function f) or // functions are passed as their own self-reference argument
// The RHS of an assignment can be an argument to a setter-call, so it needs a post-update node
e = any(Assignment asn | asn.getTarget() instanceof PropAccess).getRhs()
} or
TNewCallThisArgument(NewExpr e) or
TImplicitThisUse(ImplicitThisUse use, Boolean isPost) or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
TFlowSummaryDynamicParameterArrayNode(FlowSummaryImpl::Public::SummarizedCallable callable) or
TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) {
// NOTE: This dependency goes through the 'Steps' module whose instantiation depends on the call graph,
// but the specific predicate we're referering to does not use that information.
// So it doesn't cause negative recursion but it might look a bit surprising.
FlowSummaryPrivate::Steps::summaryStoreStep(sn, MkAwaited(), _)
} or
TFlowSummaryDefaultExceptionalReturn(FlowSummaryImpl::Public::SummarizedCallable callable) {
not DataFlowPrivate::mentionsExceptionalReturn(callable)
} or
TSynthCaptureNode(VariableCapture::VariableCaptureOutput::SynthesizedCaptureNode node) or
TGenericSynthesizedNode(AstNode node, string tag, DataFlowPrivate::DataFlowCallable container) {
any(AdditionalFlowInternal flow).needsSynthesizedNode(node, tag, container)
} or
TForbiddenRecursionGuard() {
none() and
// We want to prune irrelevant models before materialising data flow nodes, so types contributed
// directly from CodeQL must expose their pruning info without depending on data flow nodes.
(any(ModelInput::TypeModel tm).isTypeUsed("") implies any())
}
cached
private module Backref {
cached
predicate backref() {
DataFlowImplCommon::forceCachingInSameStage() or
exists(any(DataFlow::Node node).toString()) or
exists(any(DataFlow::Node node).getContainer()) or
any(DataFlow::Node node).hasLocationInfo(_, _, _, _, _) or
exists(any(Content c).toString())
}
}
}
import Cached
private class TEarlyStageNode =
TValueNode or TSsaDefNode or TCapturedVariableNode or TPropNode or TRestPatternNode or
TElementPatternNode or TElementNode or TReflectiveCallNode or TThisNode or
TFunctionSelfReferenceNode or TDestructuredModuleImportNode or THtmlAttributeNode or
TFunctionReturnNode or TExceptionalFunctionReturnNode or TExceptionalInvocationReturnNode or
TGlobalAccessPathRoot or TTemplatePlaceholderTag or TReflectiveParametersNode or
TExprPostUpdateNode or TNewCallThisArgument or TStaticArgumentArrayNode or
TDynamicArgumentArrayNode or TStaticParameterArrayNode or TDynamicParameterArrayNode or
TImplicitThisUse;
/**
* The raw data type underlying `DataFlow::Node`.
* A data-flow node that is not a flow summary node.
*
* This node exists to avoid an unwanted dependency on flow summaries in some parts of the codebase
* that should not depend on them.
*
* In particular, this dependency chain must not result in negative recursion:
* - Flow summaries can only be created after pruning irrelevant flow summaries
* - To prune irrelevant flow summaries, we must know which packages are imported
* - To know which packages are imported, module systems must be evaluated
* - The AMD and NodeJS module systems rely on data flow to find calls to `require` and similar.
* These module systems must therefore use `EarlyStageNode` instead of `DataFlow::Node`.
*/
cached
newtype TNode =
TValueNode(AST::ValueNode nd) or
TSsaDefNode(SsaDefinition d) or
TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or
TPropNode(@property p) or
TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or
TElementPatternNode(ArrayPattern ap, Expr p) { p = ap.getElement(_) } or
TElementNode(ArrayExpr arr, Expr e) { e = arr.getAnElement() } or
TReflectiveCallNode(MethodCallExpr ce, string kind) {
ce.getMethodName() = kind and
(kind = "call" or kind = "apply")
} or
TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or
TDestructuredModuleImportNode(ImportDeclaration decl) {
exists(decl.getASpecifier().getImportedName())
} or
THtmlAttributeNode(HTML::Attribute attr) or
TXmlAttributeNode(XmlAttribute attr) or
TFunctionReturnNode(Function f) or
TExceptionalFunctionReturnNode(Function f) or
TExceptionalInvocationReturnNode(InvokeExpr e) or
TGlobalAccessPathRoot() or
TTemplatePlaceholderTag(Templating::TemplatePlaceholderTag tag) or
TReflectiveParametersNode(Function f) or
TForbiddenRecursionGuard() {
none() and
// We want to prune irrelevant models before materialising data flow nodes, so types contributed
// directly from CodeQL must expose their pruning info without depending on data flow nodes.
(any(ModelInput::TypeModel tm).isTypeUsed("") implies any())
}
class EarlyStageNode extends TEarlyStageNode {
/** Gets a string representation of this data flow node. */
string toString() { result = this.(DataFlow::Node).toString() }
/** Gets the location of this data flow node. */
Location getLocation() { result = this.(DataFlow::Node).getLocation() }
}

File diff suppressed because it is too large Load Diff

View File

@@ -30,20 +30,36 @@ predicate returnExpr(Function f, DataFlow::Node source, DataFlow::Node sink) {
not f = any(SetterMethodDeclaration decl).getBody()
}
/**
* A step from a post-update node to the local sources of the corresponding pre-update node.
*
* This ensures that `getPostUpdateNode()` can be used in place of `getALocalSource()` when generating
* store steps, and the resulting step will work in both data flow analyses.
*/
pragma[nomagic]
private predicate legacyPostUpdateStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::Node node |
pred = node.getPostUpdateNode() and
succ = node.getALocalSource()
)
}
/**
* Holds if data can flow in one step from `pred` to `succ`, taking
* additional steps from the configuration into account.
*/
pragma[inline]
predicate localFlowStep(
deprecated predicate localFlowStep(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::Configuration configuration,
FlowLabel predlbl, FlowLabel succlbl
) {
pred = succ.getAPredecessor() and predlbl = succlbl
or
DataFlow::SharedFlowStep::step(pred, succ) and predlbl = succlbl
legacyPostUpdateStep(pred, succ) and predlbl = succlbl
or
DataFlow::SharedFlowStep::step(pred, succ, predlbl, succlbl)
DataFlow::LegacyFlowStep::step(pred, succ) and predlbl = succlbl
or
DataFlow::LegacyFlowStep::step(pred, succ, predlbl, succlbl)
or
exists(boolean vp | configuration.isAdditionalFlowStep(pred, succ, vp) |
vp = true and
@@ -529,9 +545,9 @@ class Boolean extends boolean {
/**
* A summary of an inter-procedural data flow path.
*/
newtype TPathSummary =
deprecated newtype TPathSummary =
/** A summary of an inter-procedural data flow path. */
MkPathSummary(Boolean hasReturn, Boolean hasCall, FlowLabel start, FlowLabel end)
deprecated MkPathSummary(Boolean hasReturn, Boolean hasCall, FlowLabel start, FlowLabel end)
/**
* A summary of an inter-procedural data flow path.
@@ -544,7 +560,7 @@ newtype TPathSummary =
* We only want to build properly matched call/return sequences, so if a path has both
* call steps and return steps, all return steps must precede all call steps.
*/
class PathSummary extends TPathSummary {
deprecated class PathSummary extends TPathSummary {
Boolean hasReturn;
Boolean hasCall;
FlowLabel start;
@@ -618,7 +634,7 @@ class PathSummary extends TPathSummary {
}
}
module PathSummary {
deprecated module PathSummary {
/**
* Gets a summary describing a path without any calls or returns.
*/

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