From b058854964254441185a4a97bb0128b59385f401 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 31 Oct 2018 23:12:05 -0400 Subject: [PATCH 01/68] JavaScript: Teach type inference about AMD imports. --- .../internal/InterModuleTypeInference.qll | 36 +++++++++++++++++++ .../Flow/AbstractValues.expected | 4 +++ .../test/library-tests/Flow/abseval.expected | 5 +++ javascript/ql/test/library-tests/Flow/amd3.js | 4 +++ .../ql/test/library-tests/Flow/types.expected | 2 ++ 5 files changed, 51 insertions(+) create mode 100644 javascript/ql/test/library-tests/Flow/amd3.js diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll index 117e6be397be..10337c02b059 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll @@ -232,6 +232,42 @@ private class AnalyzedAmdExport extends AnalyzedPropertyWrite, DataFlow::ValueNo } } +/** + * Flow analysis for AMD imports, interpreted as an implicit read of + * the `module.exports` property of the imported module. + */ +private class AnalyzedAmdImport extends AnalyzedPropertyRead, DataFlow::Node { + Module required; + + AnalyzedAmdImport() { + exists (AMDModule amd, PathExpr dep, Parameter p | + amd.getDefine().dependencyParameter(dep, p) and + this = DataFlow::parameterNode(p) and + required.getFile() = amd.resolve(dep) + ) + } + + override predicate reads(AbstractValue base, string propName) { + base = TAbstractModuleObject(required) and + propName = "exports" + } +} + +/** + * Flow analysis for parameters corresponding to AMD imports. + */ +private class AnalyzedAmdParameter extends AnalyzedVarDef, @vardecl { + AnalyzedAmdImport imp; + + AnalyzedAmdParameter() { + imp = DataFlow::parameterNode(this) + } + + override AbstractValue getAnRhsValue() { + result = imp.getALocalValue() + } +} + /** * Flow analysis for exports that export a single value. */ diff --git a/javascript/ql/test/library-tests/Flow/AbstractValues.expected b/javascript/ql/test/library-tests/Flow/AbstractValues.expected index 2f7ac0aebffd..8a779b60427f 100644 --- a/javascript/ql/test/library-tests/Flow/AbstractValues.expected +++ b/javascript/ql/test/library-tests/Flow/AbstractValues.expected @@ -15,6 +15,10 @@ | amd2.js:1:8:3:1 | anonymous function | | amd2.js:1:8:3:1 | instance of anonymous function | | amd2.js:2:10:2:22 | object literal | +| amd3.js:1:1:5:0 | exports object of module amd3 | +| amd3.js:1:1:5:0 | module object of module amd3 | +| amd3.js:1:24:4:1 | anonymous function | +| amd3.js:1:24:4:1 | instance of anonymous function | | amd.js:1:1:7:0 | exports object of module amd | | amd.js:1:1:7:0 | module object of module amd | | amd.js:1:31:6:1 | anonymous function | diff --git a/javascript/ql/test/library-tests/Flow/abseval.expected b/javascript/ql/test/library-tests/Flow/abseval.expected index 3bd376854141..84e7b27437ac 100644 --- a/javascript/ql/test/library-tests/Flow/abseval.expected +++ b/javascript/ql/test/library-tests/Flow/abseval.expected @@ -7,6 +7,11 @@ | a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | file://:0:0:0:0 | non-zero value | | a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | file://:0:0:0:0 | true | | a.js:14:12:14:24 | notAlwaysZero | a.js:14:28:14:28 | 0 | file://:0:0:0:0 | 0 | +| amd3.js:2:7:2:8 | _a | amd3.js:2:12:2:12 | a | a.js:1:1:18:0 | exports object of module a | +| amd3.js:2:7:2:8 | _a | amd3.js:2:12:2:12 | a | file://:0:0:0:0 | indefinite value (call) | +| amd3.js:3:7:3:8 | _c | amd3.js:3:12:3:12 | c | c.js:1:1:7:0 | exports object of module c | +| amd3.js:3:7:3:8 | _c | amd3.js:3:12:3:12 | c | c.js:1:18:1:19 | object literal | +| amd3.js:3:7:3:8 | _c | amd3.js:3:12:3:12 | c | file://:0:0:0:0 | indefinite value (call) | | amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | amd.js:1:1:7:0 | module object of module amd | | amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | file://:0:0:0:0 | indefinite value (call) | | amd.js:3:7:3:7 | e | amd.js:3:11:3:13 | exp | amd.js:1:1:7:0 | exports object of module amd | diff --git a/javascript/ql/test/library-tests/Flow/amd3.js b/javascript/ql/test/library-tests/Flow/amd3.js new file mode 100644 index 000000000000..56c21a127145 --- /dev/null +++ b/javascript/ql/test/library-tests/Flow/amd3.js @@ -0,0 +1,4 @@ +define(['./a', './c'], function(a, c) { + var _a = a; + var _c = c; +}); diff --git a/javascript/ql/test/library-tests/Flow/types.expected b/javascript/ql/test/library-tests/Flow/types.expected index 219af5fe2323..e6e4a49912a5 100644 --- a/javascript/ql/test/library-tests/Flow/types.expected +++ b/javascript/ql/test/library-tests/Flow/types.expected @@ -3,6 +3,8 @@ | a.js:1:19:1:19 | y | a.js:1:23:1:23 | 0 | number | | a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | boolean, class, date, function, null, number, object, regular expression,string or undefined | | a.js:14:12:14:24 | notAlwaysZero | a.js:14:28:14:28 | 0 | number | +| amd3.js:2:7:2:8 | _a | amd3.js:2:12:2:12 | a | boolean, class, date, function, null, number, object, regular expression,string or undefined | +| amd3.js:3:7:3:8 | _c | amd3.js:3:12:3:12 | c | boolean, class, date, function, null, number, object, regular expression,string or undefined | | amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | boolean, class, date, function, null, number, object, regular expression,string or undefined | | amd.js:3:7:3:7 | e | amd.js:3:11:3:13 | exp | boolean, class, date, function, null, number, object, regular expression,string or undefined | | arguments.js:2:7:2:7 | y | arguments.js:2:11:2:11 | x | number | From 8a444b60345fcb814fad8cd0819d46dee0a613ee Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Thu, 8 Nov 2018 16:16:50 +0000 Subject: [PATCH 02/68] Update qhelp with content and remove autogenerated qhelp files --- .../ClassHierarchies.qhelp | 24 -------------- .../ClassHierarchies.ql | 2 +- .../HubClasses.qhelp | 25 --------------- .../HubClasses.ql | 2 +- .../InheritanceDepthDistribution.qhelp | 32 +++++++------------ .../InheritanceDepthDistribution.ql | 2 +- .../CyclicNamespaces.qhelp | 13 ++------ .../GlobalNamespaceClasses.qhelp | 15 ++++----- .../GlobalNamespaceClasses.ql | 2 +- .../NamespaceDependencies.qhelp | 24 -------------- .../NamespaceDependencies.ql | 2 +- cpp/ql/src/Best Practices/RuleOfThree.qhelp | 16 ++++------ .../Namespaces/AbstractNamespaces.qhelp | 20 +++++------- .../Namespaces/ConcreteNamespaces.qhelp | 14 +++----- .../HighAfferentCouplingNamespaces.qhelp | 11 ++----- .../HighDistanceFromMainLineNamespaces.qhelp | 21 +++++------- .../HighEfferentCouplingNamespaces.qhelp | 22 ------------- .../Metrics/Namespaces/StableNamespaces.qhelp | 15 +++------ .../Namespaces/UnstableNamespaces.qhelp | 15 +++------ 19 files changed, 61 insertions(+), 216 deletions(-) delete mode 100644 cpp/ql/src/Architecture/General Class-Level Information/ClassHierarchies.qhelp delete mode 100644 cpp/ql/src/Architecture/General Class-Level Information/HubClasses.qhelp delete mode 100644 cpp/ql/src/Architecture/General Namespace-Level Information/NamespaceDependencies.qhelp delete mode 100644 cpp/ql/src/Metrics/Namespaces/HighEfferentCouplingNamespaces.qhelp diff --git a/cpp/ql/src/Architecture/General Class-Level Information/ClassHierarchies.qhelp b/cpp/ql/src/Architecture/General Class-Level Information/ClassHierarchies.qhelp deleted file mode 100644 index 423adb9f47ad..000000000000 --- a/cpp/ql/src/Architecture/General Class-Level Information/ClassHierarchies.qhelp +++ /dev/null @@ -1,24 +0,0 @@ - - - - - -

This query shows graph of class inheritance hierarchy

- -

- - -

-

- - - - - -

- - - -
diff --git a/cpp/ql/src/Architecture/General Class-Level Information/ClassHierarchies.ql b/cpp/ql/src/Architecture/General Class-Level Information/ClassHierarchies.ql index 3f783276c19c..047535675605 100644 --- a/cpp/ql/src/Architecture/General Class-Level Information/ClassHierarchies.ql +++ b/cpp/ql/src/Architecture/General Class-Level Information/ClassHierarchies.ql @@ -1,6 +1,6 @@ /** * @name Class hierarchies - * @description Shows classes and their base classes. + * @description Shows an inheritance hierarchy for classes and their base classes. * @kind graph * @id cpp/architecture/class-hierarchies * @graph.layout organic diff --git a/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.qhelp b/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.qhelp deleted file mode 100644 index 2199dbe9447f..000000000000 --- a/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.qhelp +++ /dev/null @@ -1,25 +0,0 @@ - - - - - -

This query shows coupling between classes.

- -

Red, large boxes are hub types that depend on many other classes -and are depended on by many other classes.

- -
-
-

- - - - - -

- - - -
diff --git a/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.ql b/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.ql index 52614712d879..727d58e2d0f5 100644 --- a/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.ql +++ b/cpp/ql/src/Architecture/General Class-Level Information/HubClasses.ql @@ -1,6 +1,6 @@ /** * @name Hub classes - * @description Shows coupling between classes; red, large boxes are hub types that depend on many other classes + * @description Shows coupling between classes. Large, red, boxes are hub types that depend on many other classes * and are depended on by many other classes. * @kind treemap * @id cpp/architecture/hub-classes diff --git a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp index ae24ffdf2e52..ce1fad2322cc 100644 --- a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp +++ b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp @@ -5,44 +5,34 @@ -

This query shows the distribution of inheritance depth across all types, i.e. classes. Library types are ignored.

+

This query shows the distribution of inheritance depth across all types, that is, classes. Library types are ignored.

The result of this query is a line graph showing, for each number n, how many types have an inheritance depth of n, where the inheritance depth of a type is the length of a longest path in the inheritance hierarchy from top class to the type.

- -

When hovering the mouse pointer over a specific depth value, the number of types having this inheritance depth is displayed.

-
-
+ +

The depth of a type is an indication of how deeply nested a type is in a given design. Very deep types can be an indication of over-engineering, whereas a system with predominantly shallow types may not be exploiting object-orientation to the full.

+
- - - - -
  • Shyam R. Chidamber and Chris F. Kemerer. A Metrics Suite for Object Oriented Design . IEEE Transactions on Software Engineering, -20(6), pages 476-493, June 1994. - - +20(6), pages 476-493, June 1994.
  • +
  • Diomides D. Spinnelis. Code Quality: The Open Source Perspective. -Addison-Wesley 2007. - - +Addison-Wesley 2007.
  • +
  • Diomides D. Spinnelis. ckjm - Chidamber and Kemerer Java Metrics. -(implementation of CK metrics), 2006. - - - -
  • +(implementation of CK metrics), 2006. + + diff --git a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.ql b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.ql index 2c445b6cf4e0..2c9f0bc88c2b 100644 --- a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.ql +++ b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.ql @@ -1,6 +1,6 @@ /** * @name Inheritance depth distribution - * @description Shows distribution of inheritance depth across all classes. + * @description Shows the distribution of inheritance depth across all classes. * @kind chart * @id cpp/architecture/inheritance-depth-distribution * @chart.type line diff --git a/cpp/ql/src/Architecture/General Namespace-Level Information/CyclicNamespaces.qhelp b/cpp/ql/src/Architecture/General Namespace-Level Information/CyclicNamespaces.qhelp index aed3cf620956..0351afe99340 100644 --- a/cpp/ql/src/Architecture/General Namespace-Level Information/CyclicNamespaces.qhelp +++ b/cpp/ql/src/Architecture/General Namespace-Level Information/CyclicNamespaces.qhelp @@ -7,19 +7,12 @@

    This query shows namespaces that cyclically depend on one another.

    - -

    - -

    -

    If there are cyclic dependencies between packages, they cannot be developed and tested independently. It is thus preferable to -eliminate such cycles from the program.

    - - - + +

    If there are cyclic dependencies between packages, they cannot be developed and tested independently. It is thus preferable to +eliminate such cycles from the program. -

  • Robert Martin's Acyclic Dependencies Principle.
  • diff --git a/cpp/ql/src/Architecture/General Namespace-Level Information/GlobalNamespaceClasses.qhelp b/cpp/ql/src/Architecture/General Namespace-Level Information/GlobalNamespaceClasses.qhelp index 739cce689e8b..426d527497dd 100644 --- a/cpp/ql/src/Architecture/General Namespace-Level Information/GlobalNamespaceClasses.qhelp +++ b/cpp/ql/src/Architecture/General Namespace-Level Information/GlobalNamespaceClasses.qhelp @@ -5,18 +5,15 @@ -

    This query finds classes that belong to no namespace

    - +

    This query finds classes that belong to no namespace.

    -
    -

    If there are too many classes that belong to no namespace, consider creating namespaces to get a better project structure.

    - - + +

    If there are many classes that belong to no namespace, consider defining namespaces to create a better project structure.

    +
    - -
    - +
  • C++ reference: Namespaces +
  • diff --git a/cpp/ql/src/Architecture/General Namespace-Level Information/GlobalNamespaceClasses.ql b/cpp/ql/src/Architecture/General Namespace-Level Information/GlobalNamespaceClasses.ql index 81f8efb1c742..09a7bb308496 100644 --- a/cpp/ql/src/Architecture/General Namespace-Level Information/GlobalNamespaceClasses.ql +++ b/cpp/ql/src/Architecture/General Namespace-Level Information/GlobalNamespaceClasses.ql @@ -1,6 +1,6 @@ /** * @name Global namespace classes - * @description Finds classes that belong to no namespace + * @description Finds classes that belong to no namespace. * @kind table * @id cpp/architecture/global-namespace-classes */ diff --git a/cpp/ql/src/Architecture/General Namespace-Level Information/NamespaceDependencies.qhelp b/cpp/ql/src/Architecture/General Namespace-Level Information/NamespaceDependencies.qhelp deleted file mode 100644 index f7b4615d029f..000000000000 --- a/cpp/ql/src/Architecture/General Namespace-Level Information/NamespaceDependencies.qhelp +++ /dev/null @@ -1,24 +0,0 @@ - - - - - -

    This query finds namespace dependencies and draws hierarchical graph.

    - -

    - - -

    -

    - - - - - -

    - - - -
    diff --git a/cpp/ql/src/Architecture/General Namespace-Level Information/NamespaceDependencies.ql b/cpp/ql/src/Architecture/General Namespace-Level Information/NamespaceDependencies.ql index e2f8e569ff11..fe79f5f66b4b 100644 --- a/cpp/ql/src/Architecture/General Namespace-Level Information/NamespaceDependencies.ql +++ b/cpp/ql/src/Architecture/General Namespace-Level Information/NamespaceDependencies.ql @@ -1,6 +1,6 @@ /** * @name Namespace dependencies - * @description Shows dependencies between namespaces. + * @description Shows dependencies between namespaces as a hierarchical graph. * @kind graph * @id cpp/architecture/namespace-dependencies * @graph.layout hierarchical diff --git a/cpp/ql/src/Best Practices/RuleOfThree.qhelp b/cpp/ql/src/Best Practices/RuleOfThree.qhelp index b18af74d9e59..f9ac2b396b9b 100644 --- a/cpp/ql/src/Best Practices/RuleOfThree.qhelp +++ b/cpp/ql/src/Best Practices/RuleOfThree.qhelp @@ -8,17 +8,13 @@

    This query finds classes that define a destructor, a copy constructor, or a copy assignment operator, but not all three of them. The compiler generates default implementations for these functions, and since they deal with similar concerns it is likely that if the default implementation of one of them is not satisfactory, then neither are those of the others.

    The query flags any such class with a warning, and also display the list of generated warnings in the result view.

    -
    -
    -

    Explicitly define the missing functions.

    - - - + +

    Explicitly define the missing functions.

    +
    -
    -
  • Wikipedia article - -
  • +
  • Wikipedia: Rule of three (C++ programming)
  • + + diff --git a/cpp/ql/src/Metrics/Namespaces/AbstractNamespaces.qhelp b/cpp/ql/src/Metrics/Namespaces/AbstractNamespaces.qhelp index 41cc622b84e0..52477f2ed762 100644 --- a/cpp/ql/src/Metrics/Namespaces/AbstractNamespaces.qhelp +++ b/cpp/ql/src/Metrics/Namespaces/AbstractNamespaces.qhelp @@ -9,21 +9,17 @@

    Abstractness measures the proportion of abstract types in a package relative to the total number of types in that package. - A highly abstract package (where the metric value is close 1) - that is furthermore instable is likely to be useless: the - class hierarchy has been over-engineered, and all those - abstract types are not heavily used.

    - + A metric value close to 1 indicates a highly abstract package + that is also unstable. The class hierarchy is probably over-engineered, and the abstract types are unlikely to be much used.

    -
    -

    Try to simplify the class hierarchy.

    - - + +

    Consider reducing the level of abstraction by simplifying the class hierarchy.

    +
    - -
    - +
  • C++ reference: Namespaces +
  • +
  • Geeks for Geeks: Abstraction in C++
  • diff --git a/cpp/ql/src/Metrics/Namespaces/ConcreteNamespaces.qhelp b/cpp/ql/src/Metrics/Namespaces/ConcreteNamespaces.qhelp index 24cf0f06eb72..9f276340efd5 100644 --- a/cpp/ql/src/Metrics/Namespaces/ConcreteNamespaces.qhelp +++ b/cpp/ql/src/Metrics/Namespaces/ConcreteNamespaces.qhelp @@ -5,18 +5,12 @@ -

    This query finds namespaces that have an abstractness equal to 0. These namesspaces do not contain any abstract classes.

    - +

    This query finds namespaces that have an abstractness equal to 0. These namespaces do not contain any abstract classes.

    -
    -

    - - - - -

    - +
  • C++ reference: Namespaces +
  • +
  • Geeks for Geeks: Abstraction in C++
  • diff --git a/cpp/ql/src/Metrics/Namespaces/HighAfferentCouplingNamespaces.qhelp b/cpp/ql/src/Metrics/Namespaces/HighAfferentCouplingNamespaces.qhelp index 15b284d875e6..cd1257f39b62 100644 --- a/cpp/ql/src/Metrics/Namespaces/HighAfferentCouplingNamespaces.qhelp +++ b/cpp/ql/src/Metrics/Namespaces/HighAfferentCouplingNamespaces.qhelp @@ -9,17 +9,10 @@

    The query counts number of namespaces depending on a namespace and displays those that have more than 20 namespaces depending on them.

    - -
    -

    - - - - -

    - +
  • C++ reference: Namespaces +
  • diff --git a/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.qhelp b/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.qhelp index fb067f485693..ad02846ce4f7 100644 --- a/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.qhelp +++ b/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.qhelp @@ -7,23 +7,18 @@

    This query finds namespaces that do not have a good balance between abstractness and stability.

    -

    This measure intends to capture the trade-off between abstractness - and instability: the ideal situation occurs when the sum of - abstractness and instability is one. That is, a package is +

    This metric tries to capture the trade-off between abstractness + and instability. For an ideal balance, the sum of + abstractness and instability should be one. That is, a package is completely abstract and stable (abstractness=1 and instability=0) or it is concrete and instable (abstractness=0 and instability=1). - We thus measure the distance from that ideal situation.

    - + This query measures the distance between the balance in the code base + and the ideal.

    -
    -

    - - - - -

    - +
  • C++ reference: Namespaces +
  • +
  • Geeks for Geeks: Abstraction in C++
  • diff --git a/cpp/ql/src/Metrics/Namespaces/HighEfferentCouplingNamespaces.qhelp b/cpp/ql/src/Metrics/Namespaces/HighEfferentCouplingNamespaces.qhelp deleted file mode 100644 index d97373f689a9..000000000000 --- a/cpp/ql/src/Metrics/Namespaces/HighEfferentCouplingNamespaces.qhelp +++ /dev/null @@ -1,22 +0,0 @@ - - - - - -

    This query finds namespaces that have an efferent coupling (that is, the number of namespaces they depend on) greater than 20.

    - -
    -
    -

    - - - - - -

    - - - -
    diff --git a/cpp/ql/src/Metrics/Namespaces/StableNamespaces.qhelp b/cpp/ql/src/Metrics/Namespaces/StableNamespaces.qhelp index 6d3c1bb70673..44bdc3276340 100644 --- a/cpp/ql/src/Metrics/Namespaces/StableNamespaces.qhelp +++ b/cpp/ql/src/Metrics/Namespaces/StableNamespaces.qhelp @@ -8,21 +8,14 @@

    This query finds namespaces that have an instability lower than 0.2.

    Instability is a measure of how likely a package is to be influenced - by changes to other packages. If this metric value is high, it is easily - influenced, if it is low, the impact is likely to be minimal. Instability + by changes to other packages. If this metric value is high, a package is easily + influenced. If the values is low, the impact of changes to other packages is likely to be minimal. Instability is estimated as the number of outgoing dependencies relative to the total number of depencies.

    - -
    -

    - - - - -

    - +
  • C++ reference: Namespaces +
  • diff --git a/cpp/ql/src/Metrics/Namespaces/UnstableNamespaces.qhelp b/cpp/ql/src/Metrics/Namespaces/UnstableNamespaces.qhelp index 45377a202e4a..bac1609760bf 100644 --- a/cpp/ql/src/Metrics/Namespaces/UnstableNamespaces.qhelp +++ b/cpp/ql/src/Metrics/Namespaces/UnstableNamespaces.qhelp @@ -8,21 +8,14 @@

    This query finds namespaces that have an instability higher than 0.8.

    Instability is a measure of how likely a package is to be influenced - by changes to other packages. If this metric value is high, it is easily - influenced, if it is low, the impact is likely to be minimal. Instability + by changes to other packages. If this metric value is high, a package is easily + influenced. If the values is low, the impact of changes to other packages is likely to be minimal. Instability is estimated as the number of outgoing dependencies relative to the total number of depencies.

    - -
    -

    - - - - -

    - +
  • C++ reference: Namespaces +
  • From 3d779ddebb3b194cadaafcbd57ee15d45173d391 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Thu, 8 Nov 2018 18:04:31 +0000 Subject: [PATCH 03/68] Bring qhelp inline with current guidelines --- cpp/ql/src/Critical/DeadCodeCondition.qhelp | 25 +++++++++-------- cpp/ql/src/Critical/DeadCodeFunction.cpp | 2 +- cpp/ql/src/Critical/DeadCodeFunction.qhelp | 25 +++++++++-------- cpp/ql/src/Critical/DeadCodeFunction.ql | 2 +- cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp | 18 ++++++------ cpp/ql/src/Critical/GlobalUseBeforeInit.ql | 4 +-- .../InconsistentNullnessTesting.qhelp | 27 ++++++++++-------- .../Critical/InconsistentNullnessTesting.ql | 2 +- cpp/ql/src/Critical/OverflowCalculated.qhelp | 28 ++++++++++++------- cpp/ql/src/Critical/OverflowDestination.qhelp | 22 +++++++++------ cpp/ql/src/Critical/OverflowDestination.ql | 2 +- 11 files changed, 90 insertions(+), 67 deletions(-) diff --git a/cpp/ql/src/Critical/DeadCodeCondition.qhelp b/cpp/ql/src/Critical/DeadCodeCondition.qhelp index 10b1e3253a1b..c0c65c9e017f 100644 --- a/cpp/ql/src/Critical/DeadCodeCondition.qhelp +++ b/cpp/ql/src/Critical/DeadCodeCondition.qhelp @@ -5,23 +5,26 @@ -

    This rule finds branching statements with conditions that always evaluate to the same value. -More likely than not these conditions indicate a defect in the branching condition or are an artifact left behind after debugging.

    +

    This query finds branching statements with conditions that always evaluate to the same value. +It is likely that these conditions indicate an error in the branching condition. +Alternatively, the conditions may have been left behind after debugging.

    -
    - -

    Check the branch condition for defects, and verify that it isn't a remnant from debugging.

    + +

    Check the branch condition for logic errors. Check whether it is still required.

    - - - - - - + +

    This example shows two branch conditions that always evaluate to the same value. +The two conditions and their associated branches should be deleted. +This will simplify the code and make it easier to maintain.

    +
    + + +
  • SEI CERT C++ Coding Standard MSC12-C. Detect and remove code that has no effect or is never executed.
  • +
    diff --git a/cpp/ql/src/Critical/DeadCodeFunction.cpp b/cpp/ql/src/Critical/DeadCodeFunction.cpp index 1cdcc652d97e..553104e2b3eb 100644 --- a/cpp/ql/src/Critical/DeadCodeFunction.cpp +++ b/cpp/ql/src/Critical/DeadCodeFunction.cpp @@ -2,7 +2,7 @@ class C { public: void g() { ... - //f() was previously used but is now commented, orphaning f() + //f() was previously used but is now commented-out, orphaning f() //f(); ... } diff --git a/cpp/ql/src/Critical/DeadCodeFunction.qhelp b/cpp/ql/src/Critical/DeadCodeFunction.qhelp index f43e6cefa91f..f5c4b432836c 100644 --- a/cpp/ql/src/Critical/DeadCodeFunction.qhelp +++ b/cpp/ql/src/Critical/DeadCodeFunction.qhelp @@ -3,28 +3,31 @@ "qhelp.dtd"> - -

    This rule finds functions that are non-public, non-virtual and are never called. Dead functions are often deprecated pieces of code, and should be removed -as they may increase object code size, decrease code comprehensibility, and create the possibility of misuse.

    +

    This query highlights functions that are non-public, non-virtual, and are never called. +Dead functions are often deprecated pieces of code, and should be removed. +If left in the code base they increase object code size, decrease code comprehensibility, and create the possibility of misuse.

    -public and protected functions are not considered by the check, as they could be part of the program's -API and could be used by external programs. +public and protected functions are ignored by this query. +This type of function may be part of the program's API and could be used by external programs.

    -
    - -

    Consider removing the function.

    + +

    Verify that the function is genuinely unused and consider removing it.

    - - + +

    The example below includes a function f that is no longer used and should be deleted.

    + +
    + +
  • SEI CERT C++ Coding Standard: MSC12-C. Detect and remove code that has no effect or is never executed.
  • +
    -
    diff --git a/cpp/ql/src/Critical/DeadCodeFunction.ql b/cpp/ql/src/Critical/DeadCodeFunction.ql index 8ddb30804ae6..f3eee7135bd1 100644 --- a/cpp/ql/src/Critical/DeadCodeFunction.ql +++ b/cpp/ql/src/Critical/DeadCodeFunction.ql @@ -1,6 +1,6 @@ /** * @name Function is never called - * @description A function is never called, and should be considered for removal. Unused functions may increase object size, decrease readability and create the possibility of misuse. + * @description Unused functions may increase object size, decrease readability, and create the possibility of misuse. * @kind problem * @id cpp/dead-code-function * @problem.severity warning diff --git a/cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp b/cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp index 26680a2598bf..1c3037a75296 100644 --- a/cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp +++ b/cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp @@ -5,26 +5,26 @@ -

    This rule finds calls to functions that use a global variable which happen before the variable was initialized. +

    This rule finds calls to functions that use a global variable before the variable has been initialized. Not all compilers generate code that zero-out memory, especially when optimizations are enabled or the compiler is not compliant with the latest language standards. Accessing uninitialized memory will lead to undefined results.

    -
    +

    Initialize the global variable. If no constant can be used for initialization, ensure that all accesses to the variable occur after the initialization code is executed.

    -
    - - - - - - + +In the example below, callCtr is wrongly used before it has been initialized. + + + +
  • SEI CERT C++ Coding Standard: EXP53-CPP. Do not read uninitialized memory.
  • +
    diff --git a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql index efab4be79960..244e39394227 100644 --- a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql +++ b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql @@ -1,6 +1,6 @@ /** - * @name Global variable used before initialization - * @description A function that uses a global variable has been called before the variable has been initialized. Not all compilers zero-out memory for variables, especially when optimizations are enabled, or if the compiler is not compliant with the latest language standards. Using an uninitialized variable leads to undefined results. + * @name Global variable may be used before initialization + * @description Using an uninitialized variable leads to undefined results. * @kind problem * @id cpp/global-use-before-init * @problem.severity warning diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp b/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp index ee1b29807270..9de3019bdb0f 100644 --- a/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp +++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp @@ -5,23 +5,28 @@ -

    This rule finds pointer dereferences that do not check the pointer for nullness, while the same pointer is checked for nullness in other -places in the code. It is most likely that the nullness check was omitted, and that a NULL pointer dereference can occur. -Dereferencing a null pointer and attempting to modify its contents can lead to anything from a segfault to corrupting -important system data (i.e. the interrupt table in some architectures). +

    This query finds pointer dereferences that do not first check the pointer for nullness, +even though the same pointer is checked for nullness in other +parts of the code. It is likely that the nullness check was accidentally omitted, and that a null pointer dereference can occur. +Dereferencing a null pointer and attempting to modify its contents can lead to anything from a segmentation fault to corrupting +important system data (including the interrupt table in some architectures).

    -
    + -

    Make the nullness check on the pointer consistent across all dereferences.

    +

    Use a nullness check consistently in all cases where a pointer is dereferenced.

    - - - - - + +This code shows two examples where a pointer is dereferenced. +The first example checks that the pointer is not null before dereferencing it. +The second example fails to perform a nullnes check, leading to a potential vulnerability in the code. + + + +
  • SEI CERT C++ Coding Standard: MEM10-C. Define and use a pointer validation function.
  • +
    diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql index 1b17990f6190..e54fe8f5497a 100644 --- a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql +++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql @@ -1,6 +1,6 @@ /** * @name Inconsistent null check of pointer - * @description A dereferenced pointer is not checked for nullness in the given location, but is checked in other locations. Dereferencing a NULL pointer leads to undefined results. + * @description A dereferenced pointer is not checked for nullness in this location, but it is checked in other locations. Dereferencing a null pointer leads to undefined results. * @kind problem * @id cpp/inconsistent-nullness-testing * @problem.severity warning diff --git a/cpp/ql/src/Critical/OverflowCalculated.qhelp b/cpp/ql/src/Critical/OverflowCalculated.qhelp index 7cc1691d89b6..ba441d4df4ae 100644 --- a/cpp/ql/src/Critical/OverflowCalculated.qhelp +++ b/cpp/ql/src/Critical/OverflowCalculated.qhelp @@ -6,14 +6,17 @@

    -This rule finds malloc that use a strlen for the size but to not take the -zero terminator into consideration, and strcat/strncat calls that are done on buffers that do -not have the sufficient size to contain the new string. +This query finds calls to:

    +
      +
    • malloc that use a strlen for the buffer size and do not take the +zero terminator into consideration.
    • +
    • strcat or strncat that use buffers that are too small to contain the new string.
    • +

    -The indicated expression will cause a buffer overflow due to a buffer that is of insufficient size to contain -the data being copied. Buffer overflows can result to anything from a segfault to a security vulnerability (particularly +The highlighted expression will cause a buffer overflow because the buffer is too small to contain +the data being copied. Buffer overflows can result to anything from a segmentation fault to a security vulnerability (particularly if the array is on stack-allocated memory).

    @@ -24,18 +27,23 @@ if the array is on stack-allocated memory).

    Increase the size of the buffer being allocated.

    -
    - - + +

    This example includes thre annotated calls that copy a string into a buffer. +The first call to malloc creates a buffer that's the +same size as the string, leaving no space for the zero terminator +and causing an overflow. The second call to malloc +correctly calculates the required buffer size. The call to +strcat appends an additional string to the same buffer +causing a second overflow.

    +
    - +
  • CWE-131: Incorrect Calculation of Buffer Size
  • I. Gerg. An Overview and Example of the Buffer-Overflow Exploit. IANewsletter vol 7 no 4. 2005.
  • M. Donaldson. Inside the Buffer Overflow Attack: Mechanism, Method & Prevention. SANS Institute InfoSec Reading Room. 2002.
  • -
    diff --git a/cpp/ql/src/Critical/OverflowDestination.qhelp b/cpp/ql/src/Critical/OverflowDestination.qhelp index e8a7e6ef322a..c110bc4f6a6a 100644 --- a/cpp/ql/src/Critical/OverflowDestination.qhelp +++ b/cpp/ql/src/Critical/OverflowDestination.qhelp @@ -3,27 +3,31 @@ "qhelp.dtd"> -

    The bounded copy functions memcpy, memmove, strncpy, strncat accept a size argument. You should call these functions with a size argument that is derived from the size of the destination buffer. Using a size argument that is derived from the source buffer may cause a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability.

    - - +

    The bounded copy functions memcpy, memmove, strncpy, strncat accept a size argument. +You should call these functions with a size argument that is derived from the size of the destination buffer. +Using a size argument that is derived from the source buffer may cause a buffer overflow. +Buffer overflows can lead to anything from a segmentation fault to a security vulnerability.

    + -

    Check the highlighted function calls carefully, and ensure that the size parameter is derived from the size of the destination buffer, +

    Check the highlighted function calls carefully. +Ensure that the size parameter is derived from the size of the destination buffer, and not the source buffer.

    -
    - + +

    +The code below shows an example where strncpy is called incorrectly, without checking the size of the destination buffer. +In the second example the call has been updated to include the size of the destination buffer.

    +
    - -
  • CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
  • +
  • I. Gerg. An Overview and Example of the Buffer-Overflow Exploit. IANewsletter vol 7 no 4. 2005.
  • M. Donaldson. Inside the Buffer Overflow Attack: Mechanism, Method & Prevention. SANS Institute InfoSec Reading Room. 2002.
  • -
    diff --git a/cpp/ql/src/Critical/OverflowDestination.ql b/cpp/ql/src/Critical/OverflowDestination.ql index 9f03146e366f..fd2863573cf9 100644 --- a/cpp/ql/src/Critical/OverflowDestination.ql +++ b/cpp/ql/src/Critical/OverflowDestination.ql @@ -1,7 +1,7 @@ /** * @name Copy function using source size * @description Calling a copy operation with a size derived from the source - * buffer instead of the destination buffer may result in a buffer overflow + * buffer instead of the destination buffer may result in a buffer overflow. * @kind problem * @id cpp/overflow-destination * @problem.severity warning From 48a7565a7f608a2d167733235867602fdc041cba Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Thu, 8 Nov 2018 18:43:32 +0000 Subject: [PATCH 04/68] Fix tag error spotted by PR check --- .../CyclicNamespaces.qhelp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/Architecture/General Namespace-Level Information/CyclicNamespaces.qhelp b/cpp/ql/src/Architecture/General Namespace-Level Information/CyclicNamespaces.qhelp index 0351afe99340..402cc6b8af05 100644 --- a/cpp/ql/src/Architecture/General Namespace-Level Information/CyclicNamespaces.qhelp +++ b/cpp/ql/src/Architecture/General Namespace-Level Information/CyclicNamespaces.qhelp @@ -10,9 +10,12 @@ on one another.

    -

    If there are cyclic dependencies between packages, they cannot be developed and tested independently. It is thus preferable to -eliminate such cycles from the program. +

    If there are cyclic dependencies between packages, they cannot be developed and tested independently. +It is better to eliminate such cycles from the program.

    +
  • Robert Martin's Acyclic Dependencies Principle. -
  • + +
    + From 0fb7ddc956b89c8015474a89dc39d76a6d60f578 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 26 Oct 2018 14:08:33 +0200 Subject: [PATCH 05/68] C#: Add assertion guard tests --- .../controlflow/guards/Assert.cs | 85 +++++++++++++++++++ .../controlflow/guards/GuardedExpr.expected | 4 + .../controlflow/guards/Implications.expected | 56 ++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 csharp/ql/test/library-tests/controlflow/guards/Assert.cs diff --git a/csharp/ql/test/library-tests/controlflow/guards/Assert.cs b/csharp/ql/test/library-tests/controlflow/guards/Assert.cs new file mode 100644 index 000000000000..08d053a1e219 --- /dev/null +++ b/csharp/ql/test/library-tests/controlflow/guards/Assert.cs @@ -0,0 +1,85 @@ +using System; +using System.Diagnostics; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +class AssertTests +{ + void M1(bool b) + { + string s = b ? null : ""; + Debug.Assert(s != null); + Console.WriteLine(s.Length); + } + + void M2(bool b) + { + string s = b ? null : ""; + Assert.IsNull(s); + Console.WriteLine(s.Length); + } + + void M3(bool b) + { + string s = b ? null : ""; + Assert.IsNotNull(s); + Console.WriteLine(s.Length); + } + + void M4(bool b) + { + string s = b ? null : ""; + Assert.IsTrue(s == null); + Console.WriteLine(s.Length); + } + + void M5(bool b) + { + string s = b ? null : ""; + Assert.IsTrue(s != null); + Console.WriteLine(s.Length); + } + + void M6(bool b) + { + string s = b ? null : ""; + Assert.IsFalse(s != null); + Console.WriteLine(s.Length); + } + + void M7(bool b) + { + string s = b ? null : ""; + Assert.IsFalse(s == null); + Console.WriteLine(s.Length); + } + + void M8(bool b) + { + string s = b ? null : ""; + Assert.IsTrue(s != null && b); + Console.WriteLine(s.Length); + } + + void M9(bool b) + { + string s = b ? null : ""; + Assert.IsFalse(s == null || b); + Console.WriteLine(s.Length); + } + + void M10(bool b) + { + string s = b ? null : ""; + Assert.IsTrue(s == null && b); + Console.WriteLine(s.Length); + } + + void M11(bool b) + { + string s = b ? null : ""; + Assert.IsFalse(s != null || b); + Console.WriteLine(s.Length); + } +} + +// semmle-extractor-options: ${testdir}/../../../resources/stubs/Microsoft.VisualStudio.TestTools.UnitTesting.cs diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index cb339ad23d3e..307fbc7f317d 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -1,3 +1,7 @@ +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 52cdc90c49fc..27b7d1ae5c59 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -1,4 +1,38 @@ impliesStep +| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | null | +| Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null | +| Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:31:23:31:23 | access to local variable s | non-null | +| Assert.cs:31:23:31:31 | ... == ... | true | Assert.cs:31:23:31:23 | access to local variable s | null | +| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | null | +| Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:38:23:38:23 | access to local variable s | non-null | +| Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:45:24:45:24 | access to local variable s | null | +| Assert.cs:45:24:45:32 | ... != ... | true | Assert.cs:45:24:45:24 | access to local variable s | non-null | +| Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:52:24:52:24 | access to local variable s | non-null | +| Assert.cs:52:24:52:32 | ... == ... | true | Assert.cs:52:24:52:24 | access to local variable s | null | +| Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:59:23:59:23 | access to local variable s | null | +| Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:59:23:59:36 | ... && ... | false | +| Assert.cs:59:23:59:31 | ... != ... | true | Assert.cs:59:23:59:23 | access to local variable s | non-null | +| Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:23:59:31 | ... != ... | true | +| Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:36:59:36 | access to parameter b | true | +| Assert.cs:59:36:59:36 | access to parameter b | false | Assert.cs:59:23:59:36 | ... && ... | false | +| Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:66:24:66:24 | access to local variable s | non-null | +| Assert.cs:66:24:66:32 | ... == ... | true | Assert.cs:66:24:66:24 | access to local variable s | null | +| Assert.cs:66:24:66:32 | ... == ... | true | Assert.cs:66:24:66:37 | ... \|\| ... | true | +| Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:24:66:32 | ... == ... | false | +| Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:37:66:37 | access to parameter b | false | +| Assert.cs:66:37:66:37 | access to parameter b | true | Assert.cs:66:24:66:37 | ... \|\| ... | true | +| Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:73:23:73:23 | access to local variable s | non-null | +| Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:73:23:73:36 | ... && ... | false | +| Assert.cs:73:23:73:31 | ... == ... | true | Assert.cs:73:23:73:23 | access to local variable s | null | +| Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:23:73:31 | ... == ... | true | +| Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:36:73:36 | access to parameter b | true | +| Assert.cs:73:36:73:36 | access to parameter b | false | Assert.cs:73:23:73:36 | ... && ... | false | +| Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:80:24:80:24 | access to local variable s | null | +| Assert.cs:80:24:80:32 | ... != ... | true | Assert.cs:80:24:80:24 | access to local variable s | non-null | +| Assert.cs:80:24:80:32 | ... != ... | true | Assert.cs:80:24:80:37 | ... \|\| ... | true | +| Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:24:80:32 | ... != ... | false | +| Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:37:80:37 | access to parameter b | false | +| Assert.cs:80:37:80:37 | access to parameter b | true | Assert.cs:80:24:80:37 | ... \|\| ... | true | | Guards.cs:10:13:10:25 | !... | false | Guards.cs:10:14:10:25 | !... | true | | Guards.cs:10:13:10:25 | !... | true | Guards.cs:10:14:10:25 | !... | false | | Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:13:10:25 | !... | true | @@ -115,6 +149,28 @@ impliesStep | Guards.cs:151:17:151:17 | access to parameter o | match case Action a: | Guards.cs:151:17:151:17 | access to parameter o | non-null | | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | Guards.cs:151:17:151:17 | access to parameter o | non-null | impliesStepIdentity +| Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:9:20:9:32 | ... ? ... : ... | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:9:20:9:32 | ... ? ... : ... | +| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:16:20:16:32 | ... ? ... : ... | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:16:20:16:32 | ... ? ... : ... | +| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:23:20:23:32 | ... ? ... : ... | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:23:20:23:32 | ... ? ... : ... | +| Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:30:20:30:32 | ... ? ... : ... | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:30:20:30:32 | ... ? ... : ... | +| Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:37:20:37:32 | ... ? ... : ... | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:37:20:37:32 | ... ? ... : ... | +| Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:44:20:44:32 | ... ? ... : ... | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:44:20:44:32 | ... ? ... : ... | +| Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:51:20:51:32 | ... ? ... : ... | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:51:20:51:32 | ... ? ... : ... | +| Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:58:20:58:32 | ... ? ... : ... | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:58:20:58:32 | ... ? ... : ... | +| Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:65:20:65:32 | ... ? ... : ... | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:65:20:65:32 | ... ? ... : ... | +| Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:72:20:72:32 | ... ? ... : ... | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:72:20:72:32 | ... ? ... : ... | +| Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:79:20:79:32 | ... ? ... : ... | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:79:20:79:32 | ... ? ... : ... | | Guards.cs:72:31:72:31 | access to parameter s | Guards.cs:71:17:71:20 | null | | Guards.cs:145:20:145:20 | access to local variable s | Guards.cs:144:13:144:13 | access to parameter o | | Guards.cs:156:24:156:24 | access to local variable a | Guards.cs:151:17:151:17 | access to parameter o | From 5921a9ea518f4145e339b1b2c33818c90eed54fb Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 26 Oct 2018 16:27:08 +0200 Subject: [PATCH 06/68] C#: Teach guards library about assertions --- .../semmle/code/csharp/controlflow/Guards.qll | 71 +++++++++++++++---- .../guards/BooleanGuardedExpr.expected | 13 ++++ .../controlflow/guards/GuardedExpr.expected | 24 +++++++ .../guards/NullGuardedExpr.expected | 6 ++ csharp/ql/test/query-tests/Nullness/Assert.cs | 6 ++ .../query-tests/Nullness/NullAlways.expected | 6 +- 6 files changed, 111 insertions(+), 15 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index dd167e5ddb86..633faefa4c9f 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -4,6 +4,7 @@ import csharp private import ControlFlow::SuccessorTypes +private import semmle.code.csharp.commons.Assertions private import semmle.code.csharp.commons.ComparisonTest private import semmle.code.csharp.commons.StructuralComparison::Internal private import semmle.code.csharp.controlflow.BasicBlocks @@ -472,30 +473,69 @@ module Internal { pragma [noinline] private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) { target = e.getTarget() and - controls(bb, _, e, _) + exists(Expr e0 | + e = e0.getAChildExpr*() | + controls(bb, e0, _) + or + controlsNode(bb.getANode(), e0, _) + ) } } - /** - * Holds if basic block `bb` only is reached when `e` has abstract value `v`. - * SSA qualified expression `sub` is a sub expression of `e`. - */ - private predicate controls(BasicBlock bb, Expr e, AccessOrCallExpr sub, AbstractValue v) { + /** Holds if basic block `bb` only is reached when `e` has abstract value `v`. */ + private predicate controls(BasicBlock bb, Expr e, AbstractValue v) { exists(ConditionBlock cb, ConditionalSuccessor s, AbstractValue v0, Expr cond | cb.controls(bb, s) | v0.branchImplies(cb.getLastNode().getElement(), s, cond) and - impliesSteps(cond, v0, e, v) and - sub = e.getAChildExpr*() + impliesSteps(cond, v0, e, v) + ) + } + + /** + * Holds if assertion `a` directly asserts that expression `e` evaluates to + * value `v`. + */ + predicate asserts(Assertion a, Expr e, AbstractValue v) { + e = a.getExpr() and + ( + a.getAssertMethod() instanceof AssertTrueMethod and + v.(BooleanValue).getValue() = true + or + a.getAssertMethod() instanceof AssertFalseMethod and + v.(BooleanValue).getValue() = false + or + a.getAssertMethod() instanceof AssertNullMethod and + v.(NullValue).isNull() + or + a.getAssertMethod() instanceof AssertNonNullMethod and + v = any(NullValue nv | not nv.isNull()) + ) + } + + /** Holds if control flow node `cfn` only is reached when `e` evaluates to `v`. */ + private predicate controlsNode(ControlFlow::Node cfn, Expr e, AbstractValue v) { + exists(Assertion a, Expr e0, AbstractValue v0 | + a.getAControlFlowNode().dominates(cfn) | + asserts(a, e0, v0) and + impliesSteps(e0, v0, e, v) ) } private cached module Cached { + pragma[noinline] + private predicate isGuardedBy0(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) { + exists(ControlFlow::Node cfn | + (controls(cfn.getBasicBlock(), e, v) or controlsNode(cfn, e, v)) and + cfn = guarded.getAControlFlowNode() and + exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) + ) + } + cached predicate isGuardedBy(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) { - exists(BasicBlock bb | - controls(bb, e, sub, v) and - bb = guarded.getAControlFlowNode().getBasicBlock() and - exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) | + isGuardedBy0(guarded, e, sub, v) and + sub = e.getAChildExpr*() and + ( not guarded.hasSsaQualifier() and not sub.hasSsaQualifier() or guarded.getSsaQualifier() = sub.getSsaQualifier() @@ -647,6 +687,13 @@ module Internal { e2 = e1 and v2 = v1 or + exists(Assertion a | + e1 = a.getExpr() | + asserts(a, e1, v1) and + e2 = e1 and + v2 = v1 + ) + or exists(Expr mid, AbstractValue vMid | impliesSteps(e1, v1, mid, vMid) | impliesStep(mid, vMid, e2, v2) diff --git a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected index ccaf0a86c315..494800fc5f69 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected @@ -1,3 +1,16 @@ +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:23 | access to local variable s | true | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | true | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index 307fbc7f317d..3e6b87ff108c 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -1,7 +1,31 @@ +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | non-null | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | null | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | non-null | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | null | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:23 | access to local variable s | true | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | non-null | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | true | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | null | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | non-null | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false | | Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | non-null | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | | Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | non-null | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | | Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | null | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | | Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected index 50d7cd7fec25..d73a56df8904 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected @@ -1,3 +1,9 @@ +| Assert.cs:11:27:11:27 | access to local variable s | +| Assert.cs:25:27:25:27 | access to local variable s | +| Assert.cs:39:27:39:27 | access to local variable s | +| Assert.cs:53:27:53:27 | access to local variable s | +| Assert.cs:60:27:60:27 | access to local variable s | +| Assert.cs:67:27:67:27 | access to local variable s | | Guards.cs:12:13:12:13 | access to parameter s | | Guards.cs:14:31:14:31 | access to parameter s | | Guards.cs:26:31:26:31 | access to parameter s | diff --git a/csharp/ql/test/query-tests/Nullness/Assert.cs b/csharp/ql/test/query-tests/Nullness/Assert.cs index d325d852d94f..a389a62b156f 100644 --- a/csharp/ql/test/query-tests/Nullness/Assert.cs +++ b/csharp/ql/test/query-tests/Nullness/Assert.cs @@ -10,21 +10,27 @@ void Fn() Debug.Assert(s != null); Console.WriteLine(s.Length); + s = null; Assert.IsNull(s); Console.WriteLine(s.Length); // always null + s = null; Assert.IsNotNull(s); Console.WriteLine(s.Length); + s = null; Assert.IsTrue(s == null); Console.WriteLine(s.Length); // always null + s = null; Assert.IsTrue(s != null); Console.WriteLine(s.Length); + s = null; Assert.IsFalse(s != null); Console.WriteLine(s.Length); // always null + s = null; Assert.IsFalse(s == null); Console.WriteLine(s.Length); } diff --git a/csharp/ql/test/query-tests/Nullness/NullAlways.expected b/csharp/ql/test/query-tests/Nullness/NullAlways.expected index 94476960cb2d..22e17f701fef 100644 --- a/csharp/ql/test/query-tests/Nullness/NullAlways.expected +++ b/csharp/ql/test/query-tests/Nullness/NullAlways.expected @@ -12,6 +12,6 @@ | A.cs:194:27:194:36 | access to local variable methodcall | Variable $@ is always null here. | A.cs:189:16:189:25 | methodcall | methodcall | | A.cs:247:31:247:44 | access to local variable eq_call_always | Variable $@ is always null here. | A.cs:241:11:241:24 | eq_call_always | eq_call_always | | A.cs:258:31:258:45 | access to local variable neq_call_always | Variable $@ is always null here. | A.cs:244:11:244:25 | neq_call_always | neq_call_always | -| Assert.cs:14:27:14:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:20:27:20:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | -| Assert.cs:26:27:26:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:15:27:15:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:23:27:23:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | +| Assert.cs:31:27:31:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s | From a5dfc10197f5059e090b061c97b47ceb63397225 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 6 Nov 2018 10:18:45 +0100 Subject: [PATCH 07/68] C#: Add tests for custom null guards --- .../guards/BooleanGuardedExpr.expected | 11 +++++ .../controlflow/guards/GuardedExpr.expected | 11 +++++ .../controlflow/guards/Guards.cs | 35 +++++++++++++++ .../controlflow/guards/Implications.expected | 44 +++++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected index 494800fc5f69..073d8485852d 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected @@ -60,3 +60,14 @@ | Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | true | | Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | false | | Guards.cs:146:16:146:16 | access to parameter o | Guards.cs:144:13:144:25 | ... is ... | Guards.cs:144:13:144:13 | access to parameter o | false | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:13:168:41 | !... | Guards.cs:168:40:168:40 | access to parameter x | true | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | Guards.cs:168:40:168:40 | access to parameter x | false | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:13:189:25 | !... | Guards.cs:189:24:189:24 | access to parameter s | true | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:14:189:25 | call to method NullTest1 | Guards.cs:189:24:189:24 | access to parameter s | false | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:13:191:25 | !... | Guards.cs:191:24:191:24 | access to parameter s | true | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:14:191:25 | call to method NullTest2 | Guards.cs:191:24:191:24 | access to parameter s | false | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:13:193:25 | !... | Guards.cs:193:24:193:24 | access to parameter s | true | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:14:193:25 | call to method NullTest3 | Guards.cs:193:24:193:24 | access to parameter s | false | +| Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:13:195:27 | call to method NotNullTest4 | Guards.cs:195:26:195:26 | access to parameter s | true | +| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:13:197:29 | !... | Guards.cs:197:28:197:28 | access to parameter s | true | +| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index 3e6b87ff108c..be39ad639e71 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -148,3 +148,14 @@ | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action: | | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action a: | | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:13:168:41 | !... | Guards.cs:168:40:168:40 | access to parameter x | true | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | Guards.cs:168:40:168:40 | access to parameter x | false | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:13:189:25 | !... | Guards.cs:189:24:189:24 | access to parameter s | true | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:14:189:25 | call to method NullTest1 | Guards.cs:189:24:189:24 | access to parameter s | false | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:13:191:25 | !... | Guards.cs:191:24:191:24 | access to parameter s | true | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:14:191:25 | call to method NullTest2 | Guards.cs:191:24:191:24 | access to parameter s | false | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:13:193:25 | !... | Guards.cs:193:24:193:24 | access to parameter s | true | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:14:193:25 | call to method NullTest3 | Guards.cs:193:24:193:24 | access to parameter s | false | +| Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:13:195:27 | call to method NotNullTest4 | Guards.cs:195:26:195:26 | access to parameter s | true | +| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:13:197:29 | !... | Guards.cs:197:28:197:28 | access to parameter s | true | +| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs index 7634b26f0cfe..2c0753a81337 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Guards.cs +++ b/csharp/ql/test/library-tests/controlflow/guards/Guards.cs @@ -162,4 +162,39 @@ string M14(object o) return o.ToString(); // null guarded } } + + void M15(string x) + { + if (!string.IsNullOrWhiteSpace(x)) + Console.WriteLine(x); // null guarded + } + + bool NullTest1(object o) => o == null; + + bool NullTest2(object o) + { + if (o is null) + return true; + return false; + } + + bool NullTest3(object o) => o == null ? true : false; + + bool NotNullTest4(object o) => !NullTest3(o); + + bool NullTestWrong(object o) => o == null ? true : true; + + void M16(string s) + { + if (!NullTest1(s)) + Console.WriteLine(s); // null guarded + if (!NullTest2(s)) + Console.WriteLine(s); // null guarded + if (!NullTest3(s)) + Console.WriteLine(s); // null guarded + if (NotNullTest4(s)) + Console.WriteLine(s); // null guarded + if (!NullTestWrong(s)) + Console.WriteLine(s); // not null guarded + } } diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 27b7d1ae5c59..16c315b37813 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -148,6 +148,50 @@ impliesStep | Guards.cs:151:17:151:17 | access to parameter o | match case Action: | Guards.cs:151:17:151:17 | access to parameter o | non-null | | Guards.cs:151:17:151:17 | access to parameter o | match case Action a: | Guards.cs:151:17:151:17 | access to parameter o | non-null | | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:168:13:168:41 | !... | false | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | true | +| Guards.cs:168:13:168:41 | !... | true | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | false | +| Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | false | Guards.cs:168:13:168:41 | !... | true | +| Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | true | Guards.cs:168:13:168:41 | !... | false | +| Guards.cs:172:33:172:41 | ... == ... | false | Guards.cs:172:33:172:33 | access to parameter o | non-null | +| Guards.cs:172:33:172:41 | ... == ... | true | Guards.cs:172:33:172:33 | access to parameter o | null | +| Guards.cs:176:13:176:21 | ... is ... | false | Guards.cs:176:13:176:13 | access to parameter o | non-null | +| Guards.cs:176:13:176:21 | ... is ... | true | Guards.cs:176:13:176:13 | access to parameter o | null | +| Guards.cs:181:33:181:41 | ... == ... | false | Guards.cs:181:33:181:33 | access to parameter o | non-null | +| Guards.cs:181:33:181:41 | ... == ... | false | Guards.cs:181:33:181:56 | ... ? ... : ... | false | +| Guards.cs:181:33:181:41 | ... == ... | true | Guards.cs:181:33:181:33 | access to parameter o | null | +| Guards.cs:181:33:181:41 | ... == ... | true | Guards.cs:181:33:181:56 | ... ? ... : ... | true | +| Guards.cs:181:33:181:56 | ... ? ... : ... | false | Guards.cs:181:33:181:41 | ... == ... | false | +| Guards.cs:181:33:181:56 | ... ? ... : ... | false | Guards.cs:181:52:181:56 | false | false | +| Guards.cs:181:33:181:56 | ... ? ... : ... | true | Guards.cs:181:33:181:41 | ... == ... | true | +| Guards.cs:181:33:181:56 | ... ? ... : ... | true | Guards.cs:181:45:181:48 | true | true | +| Guards.cs:183:36:183:48 | !... | false | Guards.cs:183:37:183:48 | call to method NullTest3 | true | +| Guards.cs:183:36:183:48 | !... | true | Guards.cs:183:37:183:48 | call to method NullTest3 | false | +| Guards.cs:183:37:183:48 | call to method NullTest3 | false | Guards.cs:183:36:183:48 | !... | true | +| Guards.cs:183:37:183:48 | call to method NullTest3 | true | Guards.cs:183:36:183:48 | !... | false | +| Guards.cs:185:37:185:45 | ... == ... | false | Guards.cs:185:37:185:37 | access to parameter o | non-null | +| Guards.cs:185:37:185:45 | ... == ... | false | Guards.cs:185:37:185:59 | ... ? ... : ... | true | +| Guards.cs:185:37:185:45 | ... == ... | true | Guards.cs:185:37:185:37 | access to parameter o | null | +| Guards.cs:185:37:185:45 | ... == ... | true | Guards.cs:185:37:185:59 | ... ? ... : ... | true | +| Guards.cs:185:37:185:59 | ... ? ... : ... | false | Guards.cs:185:37:185:45 | ... == ... | false | +| Guards.cs:185:37:185:59 | ... ? ... : ... | false | Guards.cs:185:37:185:45 | ... == ... | true | +| Guards.cs:185:37:185:59 | ... ? ... : ... | false | Guards.cs:185:49:185:52 | true | false | +| Guards.cs:185:37:185:59 | ... ? ... : ... | false | Guards.cs:185:56:185:59 | true | false | +| Guards.cs:189:13:189:25 | !... | false | Guards.cs:189:14:189:25 | call to method NullTest1 | true | +| Guards.cs:189:13:189:25 | !... | true | Guards.cs:189:14:189:25 | call to method NullTest1 | false | +| Guards.cs:189:14:189:25 | call to method NullTest1 | false | Guards.cs:189:13:189:25 | !... | true | +| Guards.cs:189:14:189:25 | call to method NullTest1 | true | Guards.cs:189:13:189:25 | !... | false | +| Guards.cs:191:13:191:25 | !... | false | Guards.cs:191:14:191:25 | call to method NullTest2 | true | +| Guards.cs:191:13:191:25 | !... | true | Guards.cs:191:14:191:25 | call to method NullTest2 | false | +| Guards.cs:191:14:191:25 | call to method NullTest2 | false | Guards.cs:191:13:191:25 | !... | true | +| Guards.cs:191:14:191:25 | call to method NullTest2 | true | Guards.cs:191:13:191:25 | !... | false | +| Guards.cs:193:13:193:25 | !... | false | Guards.cs:193:14:193:25 | call to method NullTest3 | true | +| Guards.cs:193:13:193:25 | !... | true | Guards.cs:193:14:193:25 | call to method NullTest3 | false | +| Guards.cs:193:14:193:25 | call to method NullTest3 | false | Guards.cs:193:13:193:25 | !... | true | +| Guards.cs:193:14:193:25 | call to method NullTest3 | true | Guards.cs:193:13:193:25 | !... | false | +| Guards.cs:197:13:197:29 | !... | false | Guards.cs:197:14:197:29 | call to method NullTestWrong | true | +| Guards.cs:197:13:197:29 | !... | true | Guards.cs:197:14:197:29 | call to method NullTestWrong | false | +| Guards.cs:197:14:197:29 | call to method NullTestWrong | false | Guards.cs:197:13:197:29 | !... | true | +| Guards.cs:197:14:197:29 | call to method NullTestWrong | true | Guards.cs:197:13:197:29 | !... | false | impliesStepIdentity | Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:9:20:9:32 | ... ? ... : ... | | Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:9:20:9:32 | ... ? ... : ... | From e4aa196c37d426d32b095bd97b591f1b6502d844 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 6 Nov 2018 09:52:58 +0100 Subject: [PATCH 08/68] C#: Teach guards library about custom null guards --- .../csharp/controlflow/ControlFlowGraph.qll | 64 +++++----- .../semmle/code/csharp/controlflow/Guards.qll | 119 +++++++++++++++++- .../controlflow/guards/GuardedExpr.expected | 5 + .../controlflow/guards/Implications.expected | 11 ++ .../guards/NullGuardedExpr.expected | 5 + 5 files changed, 171 insertions(+), 33 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 767ec38e555c..aa7bf06f2a25 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -2473,7 +2473,7 @@ module ControlFlow { not startsBB(succ) } - predicate bbIndex(ControlFlowElement bbStart, ControlFlowElement cfe, int i) = + private predicate bbIndex(ControlFlowElement bbStart, ControlFlowElement cfe, int i) = shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfe, i) private predicate succBB(PreBasicBlock pred, PreBasicBlock succ) { @@ -2488,13 +2488,9 @@ module ControlFlow { idominance(entryBB/1, succBB/2)(_, dom, bb) class PreBasicBlock extends ControlFlowElement { - PreBasicBlock() { - startsBB(this) - } + PreBasicBlock() { startsBB(this) } - PreBasicBlock getASuccessor() { - result = succ(this.getLastElement(), _) - } + PreBasicBlock getASuccessor() { result = succ(this.getLastElement(), _) } PreBasicBlock getAPredecessor() { result.getASuccessor() = this @@ -2548,6 +2544,22 @@ module ControlFlow { exists(succExit(this.getLastElement(), c)) ) > 1 } + + private predicate isCandidateSuccessor(PreBasicBlock succ, ConditionalCompletion c) { + succ = succ(this.getLastElement(), c) and + forall(PreBasicBlock pred | + pred = succ.getAPredecessor() and pred != this | + succ.dominates(pred) + ) + } + + predicate controls(PreBasicBlock controlled, ConditionalSuccessor s) { + exists(PreBasicBlock succ, ConditionalCompletion c | + isCandidateSuccessor(succ, c) | + succ.dominates(controlled) and + s.matchesCompletion(c) + ) + } } } @@ -2729,29 +2741,21 @@ module ControlFlow { ssaRefRank(bb2, i2, v, _) = 1 } - private cached module PreSsaCached { - cached - predicate firstReadSameVar(Definition def, LocalScopeVariableRead read) { - exists(SimpleLocalScopeVariable v, PreBasicBlock b1, int i1, PreBasicBlock b2, int i2 | - adjacentVarRefs(v, b1, i1, b2, i2) and - defAt(b1, i1, def, v) and - readAt(b2, i2, read, v) - ) - } - - cached - predicate adjacentReadPairSameVar(LocalScopeVariableRead read1, LocalScopeVariableRead read2) { - exists(SimpleLocalScopeVariable v, PreBasicBlock bb1, int i1, PreBasicBlock bb2, int i2 | - adjacentVarRefs(v, bb1, i1, bb2, i2) and - readAt(bb1, i1, read1, v) and - readAt(bb2, i2, read2, v) - ) - } + predicate firstReadSameVar(Definition def, LocalScopeVariableRead read) { + exists(SimpleLocalScopeVariable v, PreBasicBlock b1, int i1, PreBasicBlock b2, int i2 | + adjacentVarRefs(v, b1, i1, b2, i2) and + defAt(b1, i1, def, v) and + readAt(b2, i2, read, v) + ) + } - cached - predicate forceCachingInSameStage() { any() } + predicate adjacentReadPairSameVar(LocalScopeVariableRead read1, LocalScopeVariableRead read2) { + exists(SimpleLocalScopeVariable v, PreBasicBlock bb1, int i1, PreBasicBlock bb2, int i2 | + adjacentVarRefs(v, bb1, i1, bb2, i2) and + readAt(bb1, i1, read1, v) and + readAt(bb2, i2, read2, v) + ) } - import PreSsaCached } /** @@ -3837,10 +3841,12 @@ module ControlFlow { } private cached module Cached { + private import semmle.code.csharp.controlflow.Guards as Guards + cached newtype TPreSsaDef = TExplicitPreSsaDef(PreBasicBlocks::PreBasicBlock bb, int i, AssignableDefinition def, LocalScopeVariable v) { - PreSsa::forceCachingInSameStage() and + Guards::Internal::CachedWithCFG::forceCachingInSameStage() and PreSsa::assignableDefAt(bb, i, def, v) } or diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index 633faefa4c9f..bf1ae974cca1 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -162,9 +162,11 @@ class DereferenceableExpr extends Expr { if ck.isInequality() then branch = false else branch = true ) or - // Call to `string.IsNullOrEmpty()` - result = any(MethodCall mc | - mc.getTarget() = any(SystemStringClass c).getIsNullOrEmptyMethod() and + // Call to `string.IsNullOrEmpty()` or `string.IsNullOrWhiteSpace()` + exists(MethodCall mc, string name | + result = mc | + mc.getTarget() = any(SystemStringClass c).getAMethod(name) and + name.regexpMatch("IsNullOr(Empty|WhiteSpace)") and mc.getArgument(0) = this and branch = false and isNull = false @@ -179,6 +181,8 @@ class DereferenceableExpr extends Expr { // E.g. `x is string` or `x is ""` (branch = true and isNull = false) ) + or + isCustomNullCheck(result, this, v, isNull) ) } @@ -491,6 +495,15 @@ module Internal { ) } + /** Holds if pre basic block `bb` only is reached when `e` has abstract value `v`. */ + private predicate preControls(PreBasicBlocks::PreBasicBlock bb, Expr e, AbstractValue v) { + exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s, AbstractValue v0, Expr cond | + cb.controls(bb, s) | + v0.branchImplies(cb.getLastElement(), s, cond) and + impliesSteps(cond, v0, e, v) + ) + } + /** * Holds if assertion `a` directly asserts that expression `e` evaluates to * value `v`. @@ -521,6 +534,86 @@ module Internal { ) } + private Expr stripConditionalExpr(Expr e) { + e = any(ConditionalExpr ce | + result = stripConditionalExpr(ce.getThen()) + or + result = stripConditionalExpr(ce.getElse()) + ) + or + not e instanceof ConditionalExpr and + result = e + } + + private predicate canReturn(Callable c, Expr ret) { + exists(Expr e | c.canReturn(e) | ret = stripConditionalExpr(e)) + } + + private class PreSsaImplicitParameterDefinition extends PreSsa::Definition { + private Parameter p; + + PreSsaImplicitParameterDefinition() { + p = this.getDefinition().(AssignableDefinitions::ImplicitParameterDefinition).getParameter() + } + + Parameter getParameter() { result = p } + + /** + * Holds if the callable that this parameter belongs to can return `ret`, but + * only if this parameter is `null` or non-`null`, as specified by `isNull`. + */ + predicate nullGuardedReturn(Expr ret, boolean isNull) { + canReturn(p.getCallable(), ret) and + exists(PreBasicBlocks::PreBasicBlock bb, NullValue nv | + preControls(bb, this.getARead(), nv) | + ret = bb.getAnElement() and + if nv.isNull() then isNull = true else isNull = false + ) + } + } + + /** + * Holds if `ret` is an expression returned by the callable to which parameter + * `p` belongs, and `ret` having Boolean value `retVal` allows the conclusion + * that the parameter `p` either is `null` or non-`null`, as specified by `isNull`. + */ + private predicate validReturnInCustomNullCheck(Expr ret, Parameter p, BooleanValue retVal, boolean isNull) { + exists(Callable c | + canReturn(c, ret) | + p.getCallable() = c and + c.getReturnType() instanceof BoolType + ) and + exists(PreSsaImplicitParameterDefinition def | + p = def.getParameter() | + def.nullGuardedReturn(ret, isNull) + or + exists(NullValue nv | + impliesSteps(ret, retVal, def.getARead(), nv) | + if nv.isNull() then isNull = true else isNull = false + ) + ) + } + + /** + * Gets a non-overridable callable with a Boolean return value that performs a + * `null`-check on parameter `p`. A return value having Boolean value `retVal` + * allows us to conclude that the argument either is `null` or non-`null`, as + * specified by `isNull`. + */ + private Callable customNullCheck(Parameter p, BooleanValue retVal, boolean isNull) { + result.getReturnType() instanceof BoolType and + not result.(Virtualizable).isOverridableOrImplementable() and + p.getCallable() = result and + not p.isParams() and + p.getType() = any(Type t | t instanceof RefType or t instanceof NullableType) and + forex(Expr ret | + canReturn(result, ret) and + not ret.(BoolLiteral).getBoolValue() = retVal.getValue().booleanNot() + | + validReturnInCustomNullCheck(ret, p, retVal, isNull) + ) + } + private cached module Cached { pragma[noinline] private predicate isGuardedBy0(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) { @@ -541,6 +634,21 @@ module Internal { guarded.getSsaQualifier() = sub.getSsaQualifier() ) } + } + import Cached + + // The predicates in this module should be cached in the same stage as the cache stage + // in ControlFlowGraph.qll. This is to avoid recomputation of pre-basic-blocks and + // pre-SSA predicates + cached module CachedWithCFG { + cached + predicate isCustomNullCheck(Call call, Expr arg, BooleanValue v, boolean isNull) { + exists(Callable callable, Parameter p | + arg = call.getArgumentForParameter(any(Parameter p0 | p0.getSourceDeclaration() = p)) and + call.getTarget().getSourceDeclaration() = callable and + callable = customNullCheck(p, v, isNull) + ) + } /** * Holds if `e1` having abstract value `v1` implies that `e2` has abstract @@ -659,8 +767,11 @@ module Internal { v1 instanceof NullValue and v1 = v2 } + + cached + predicate forceCachingInSameStage() { any() } } - import Cached + import CachedWithCFG /** * Holds if `e1` having some abstract value, `v`, implies that `e2` has the same diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index be39ad639e71..a9da42be893a 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -150,12 +150,17 @@ | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | | Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:13:168:41 | !... | Guards.cs:168:40:168:40 | access to parameter x | true | | Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | Guards.cs:168:40:168:40 | access to parameter x | false | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:40:168:40 | access to parameter x | Guards.cs:168:40:168:40 | access to parameter x | non-null | | Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:13:189:25 | !... | Guards.cs:189:24:189:24 | access to parameter s | true | | Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:14:189:25 | call to method NullTest1 | Guards.cs:189:24:189:24 | access to parameter s | false | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:24:189:24 | access to parameter s | Guards.cs:189:24:189:24 | access to parameter s | non-null | | Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:13:191:25 | !... | Guards.cs:191:24:191:24 | access to parameter s | true | | Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:14:191:25 | call to method NullTest2 | Guards.cs:191:24:191:24 | access to parameter s | false | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:24:191:24 | access to parameter s | Guards.cs:191:24:191:24 | access to parameter s | non-null | | Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:13:193:25 | !... | Guards.cs:193:24:193:24 | access to parameter s | true | | Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:14:193:25 | call to method NullTest3 | Guards.cs:193:24:193:24 | access to parameter s | false | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:24:193:24 | access to parameter s | Guards.cs:193:24:193:24 | access to parameter s | non-null | | Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:13:195:27 | call to method NotNullTest4 | Guards.cs:195:26:195:26 | access to parameter s | true | +| Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:26:195:26 | access to parameter s | Guards.cs:195:26:195:26 | access to parameter s | non-null | | Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:13:197:29 | !... | Guards.cs:197:28:197:28 | access to parameter s | true | | Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 16c315b37813..8e067718b2d2 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -151,6 +151,7 @@ impliesStep | Guards.cs:168:13:168:41 | !... | false | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | true | | Guards.cs:168:13:168:41 | !... | true | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | false | | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | false | Guards.cs:168:13:168:41 | !... | true | +| Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | false | Guards.cs:168:40:168:40 | access to parameter x | non-null | | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | true | Guards.cs:168:13:168:41 | !... | false | | Guards.cs:172:33:172:41 | ... == ... | false | Guards.cs:172:33:172:33 | access to parameter o | non-null | | Guards.cs:172:33:172:41 | ... == ... | true | Guards.cs:172:33:172:33 | access to parameter o | null | @@ -167,7 +168,9 @@ impliesStep | Guards.cs:183:36:183:48 | !... | false | Guards.cs:183:37:183:48 | call to method NullTest3 | true | | Guards.cs:183:36:183:48 | !... | true | Guards.cs:183:37:183:48 | call to method NullTest3 | false | | Guards.cs:183:37:183:48 | call to method NullTest3 | false | Guards.cs:183:36:183:48 | !... | true | +| Guards.cs:183:37:183:48 | call to method NullTest3 | false | Guards.cs:183:47:183:47 | access to parameter o | non-null | | Guards.cs:183:37:183:48 | call to method NullTest3 | true | Guards.cs:183:36:183:48 | !... | false | +| Guards.cs:183:37:183:48 | call to method NullTest3 | true | Guards.cs:183:47:183:47 | access to parameter o | null | | Guards.cs:185:37:185:45 | ... == ... | false | Guards.cs:185:37:185:37 | access to parameter o | non-null | | Guards.cs:185:37:185:45 | ... == ... | false | Guards.cs:185:37:185:59 | ... ? ... : ... | true | | Guards.cs:185:37:185:45 | ... == ... | true | Guards.cs:185:37:185:37 | access to parameter o | null | @@ -179,15 +182,23 @@ impliesStep | Guards.cs:189:13:189:25 | !... | false | Guards.cs:189:14:189:25 | call to method NullTest1 | true | | Guards.cs:189:13:189:25 | !... | true | Guards.cs:189:14:189:25 | call to method NullTest1 | false | | Guards.cs:189:14:189:25 | call to method NullTest1 | false | Guards.cs:189:13:189:25 | !... | true | +| Guards.cs:189:14:189:25 | call to method NullTest1 | false | Guards.cs:189:24:189:24 | access to parameter s | non-null | | Guards.cs:189:14:189:25 | call to method NullTest1 | true | Guards.cs:189:13:189:25 | !... | false | +| Guards.cs:189:14:189:25 | call to method NullTest1 | true | Guards.cs:189:24:189:24 | access to parameter s | null | | Guards.cs:191:13:191:25 | !... | false | Guards.cs:191:14:191:25 | call to method NullTest2 | true | | Guards.cs:191:13:191:25 | !... | true | Guards.cs:191:14:191:25 | call to method NullTest2 | false | | Guards.cs:191:14:191:25 | call to method NullTest2 | false | Guards.cs:191:13:191:25 | !... | true | +| Guards.cs:191:14:191:25 | call to method NullTest2 | false | Guards.cs:191:24:191:24 | access to parameter s | non-null | | Guards.cs:191:14:191:25 | call to method NullTest2 | true | Guards.cs:191:13:191:25 | !... | false | +| Guards.cs:191:14:191:25 | call to method NullTest2 | true | Guards.cs:191:24:191:24 | access to parameter s | null | | Guards.cs:193:13:193:25 | !... | false | Guards.cs:193:14:193:25 | call to method NullTest3 | true | | Guards.cs:193:13:193:25 | !... | true | Guards.cs:193:14:193:25 | call to method NullTest3 | false | | Guards.cs:193:14:193:25 | call to method NullTest3 | false | Guards.cs:193:13:193:25 | !... | true | +| Guards.cs:193:14:193:25 | call to method NullTest3 | false | Guards.cs:193:24:193:24 | access to parameter s | non-null | | Guards.cs:193:14:193:25 | call to method NullTest3 | true | Guards.cs:193:13:193:25 | !... | false | +| Guards.cs:193:14:193:25 | call to method NullTest3 | true | Guards.cs:193:24:193:24 | access to parameter s | null | +| Guards.cs:195:13:195:27 | call to method NotNullTest4 | false | Guards.cs:195:26:195:26 | access to parameter s | null | +| Guards.cs:195:13:195:27 | call to method NotNullTest4 | true | Guards.cs:195:26:195:26 | access to parameter s | non-null | | Guards.cs:197:13:197:29 | !... | false | Guards.cs:197:14:197:29 | call to method NullTestWrong | true | | Guards.cs:197:13:197:29 | !... | true | Guards.cs:197:14:197:29 | call to method NullTestWrong | false | | Guards.cs:197:14:197:29 | call to method NullTestWrong | false | Guards.cs:197:13:197:29 | !... | true | diff --git a/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected index d73a56df8904..9e1088c0edc9 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/NullGuardedExpr.expected @@ -34,3 +34,8 @@ | Guards.cs:154:24:154:24 | access to parameter o | | Guards.cs:158:24:158:24 | access to parameter o | | Guards.cs:162:24:162:24 | access to parameter o | +| Guards.cs:169:31:169:31 | access to parameter x | +| Guards.cs:190:31:190:31 | access to parameter s | +| Guards.cs:192:31:192:31 | access to parameter s | +| Guards.cs:194:31:194:31 | access to parameter s | +| Guards.cs:196:31:196:31 | access to parameter s | From 29f163fd4e3929bd5100ca46cdafbd919c6f891a Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 6 Nov 2018 15:39:44 +0100 Subject: [PATCH 09/68] C#: Fix guards implications logic --- .../semmle/code/csharp/controlflow/Guards.qll | 309 ++++++++---------- .../guards/BooleanGuardedExpr.expected | 9 - .../controlflow/guards/GuardedExpr.expected | 9 - .../controlflow/guards/Implications.expected | 129 +++----- .../controlflow/guards/Implications.ql | 4 - 5 files changed, 191 insertions(+), 269 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index bf1ae974cca1..b920a60168b0 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -363,11 +363,11 @@ private AssignableRead getATrackedRead(Ssa::Definition def) { * definition). */ class GuardedExpr extends AccessOrCallExpr { - private Expr e0; + private Guard g; private AccessOrCallExpr sub0; private AbstractValue v0; - GuardedExpr() { isGuardedBy(this, e0, sub0, v0) } + GuardedExpr() { isGuardedBy(this, g, sub0, v0) } /** * Gets an expression that guards this expression. That is, this expression is @@ -381,7 +381,7 @@ class GuardedExpr extends AccessOrCallExpr { * variable). */ Expr getAGuard(Expr sub, AbstractValue v) { - result = e0 and + result = g and sub = sub0 and v = v0 } @@ -420,6 +420,11 @@ module Internal { or TEmptyCollectionValue(boolean b) { b = true or b = false } + /** Holds if expression `e` is a non-`null` value. */ + predicate nonNullValue(Expr e) { + e.stripCasts() = any(Expr s | s.hasValue() and not s instanceof NullLiteral) + } + /** * Gets the parent expression of `e` which is `null` only if `e` is `null`, * if any. For example, `result = x?.y` and `e = x`, or `result = x + 1` @@ -446,67 +451,66 @@ module Internal { ) } - /** Holds if expression `e` is a non-`null` value. */ - predicate nonNullValue(Expr e) { - e.stripCasts() = any(Expr s | s.hasValue() and not s instanceof NullLiteral) - } + /** An expression whose value may control the execution of another element. */ + class Guard extends Expr { + private AbstractValue val; - /** - * A helper class for calculating structurally equal access/call expressions. - */ - private class ConditionOnExprComparisonConfig extends InternalStructuralComparisonConfiguration { - ConditionOnExprComparisonConfig() { - this = "ConditionOnExprComparisonConfig" + Guard() { + this.getType() instanceof BoolType and + not this instanceof BoolLiteral and + val = TBooleanValue(_) + or + this instanceof DereferenceableExpr and + val = TNullValue(_) + or + val.branchImplies(_, _, this) + or + asserts(_, this, val) } - override predicate candidate(Element x, Element y) { - exists(BasicBlock bb, Declaration d | - candidateAux(x, d, bb) and - y = any(AccessOrCallExpr e | - e.getAControlFlowNode().getBasicBlock() = bb and - e.getTarget() = d - ) + /** Gets an abstract value that this guard may have. */ + AbstractValue getAValue() { result = val } + + /** Holds if basic block `bb` only is reached when this guard has abstract value `v`. */ + predicate controls(BasicBlock bb, AbstractValue v) { + exists(ConditionBlock cb, ConditionalSuccessor s, AbstractValue v0, Guard g | + cb.controls(bb, s) | + v0.branchImplies(cb.getLastNode().getElement(), s, g) and + impliesSteps(g, v0, this, v) + ) + } + + /** Holds if control flow node `cfn` only is reached when this guard evaluates to `v`. */ + predicate controlsNode(ControlFlow::Node cfn, AbstractValue v) { + exists(Assertion a, Guard g, AbstractValue v0 | + a.getAControlFlowNode().dominates(cfn) | + asserts(a, g, v0) and + impliesSteps(g, v0, this, v) ) } /** - * Holds if access/call expression `e` (targeting declaration `target`) - * is a sub expression of a condition that controls whether basic block - * `bb` is reached. + * Holds if pre-basic-block `bb` only is reached when this guard has abstract value `v`, + * not taking implications into account. */ - pragma [noinline] - private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) { - target = e.getTarget() and - exists(Expr e0 | - e = e0.getAChildExpr*() | - controls(bb, e0, _) - or - controlsNode(bb.getANode(), e0, _) + predicate preControlsDirect(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) { + exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s | + cb.controls(bb, s) | + v.branchImplies(cb.getLastElement(), s, this) ) } - } - /** Holds if basic block `bb` only is reached when `e` has abstract value `v`. */ - private predicate controls(BasicBlock bb, Expr e, AbstractValue v) { - exists(ConditionBlock cb, ConditionalSuccessor s, AbstractValue v0, Expr cond | - cb.controls(bb, s) | - v0.branchImplies(cb.getLastNode().getElement(), s, cond) and - impliesSteps(cond, v0, e, v) - ) - } - - /** Holds if pre basic block `bb` only is reached when `e` has abstract value `v`. */ - private predicate preControls(PreBasicBlocks::PreBasicBlock bb, Expr e, AbstractValue v) { - exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s, AbstractValue v0, Expr cond | - cb.controls(bb, s) | - v0.branchImplies(cb.getLastElement(), s, cond) and - impliesSteps(cond, v0, e, v) - ) + /** Holds if pre-basic-block `bb` only is reached when this guard has abstract value `v`. */ + predicate preControls(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) { + exists(AbstractValue v0, Guard g | + g.preControlsDirect(bb, v0) | + impliesSteps(g, v0, this, v) + ) + } } /** - * Holds if assertion `a` directly asserts that expression `e` evaluates to - * value `v`. + * Holds if assertion `a` directly asserts that expression `e` evaluates to value `v`. */ predicate asserts(Assertion a, Expr e, AbstractValue v) { e = a.getExpr() and @@ -525,15 +529,6 @@ module Internal { ) } - /** Holds if control flow node `cfn` only is reached when `e` evaluates to `v`. */ - private predicate controlsNode(ControlFlow::Node cfn, Expr e, AbstractValue v) { - exists(Assertion a, Expr e0, AbstractValue v0 | - a.getAControlFlowNode().dominates(cfn) | - asserts(a, e0, v0) and - impliesSteps(e0, v0, e, v) - ) - } - private Expr stripConditionalExpr(Expr e) { e = any(ConditionalExpr ce | result = stripConditionalExpr(ce.getThen()) @@ -565,7 +560,7 @@ module Internal { predicate nullGuardedReturn(Expr ret, boolean isNull) { canReturn(p.getCallable(), ret) and exists(PreBasicBlocks::PreBasicBlock bb, NullValue nv | - preControls(bb, this.getARead(), nv) | + this.getARead().(Guard).preControls(bb, nv) | ret = bb.getAnElement() and if nv.isNull() then isNull = true else isNull = false ) @@ -614,20 +609,55 @@ module Internal { ) } + /** + * A helper class for calculating structurally equal access/call expressions. + */ + private class ConditionOnExprComparisonConfig extends InternalStructuralComparisonConfiguration { + ConditionOnExprComparisonConfig() { + this = "ConditionOnExprComparisonConfig" + } + + override predicate candidate(Element x, Element y) { + exists(BasicBlock bb, Declaration d | + candidateAux(x, d, bb) and + y = any(AccessOrCallExpr e | + e.getAControlFlowNode().getBasicBlock() = bb and + e.getTarget() = d + ) + ) + } + + /** + * Holds if access/call expression `e` (targeting declaration `target`) + * is a sub expression of a condition that controls whether basic block + * `bb` is reached. + */ + pragma [noinline] + private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) { + target = e.getTarget() and + exists(Guard g | + e = g.getAChildExpr*() | + g.controls(bb, _) + or + g.controlsNode(bb.getANode(), _) + ) + } + } + private cached module Cached { pragma[noinline] - private predicate isGuardedBy0(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) { + private predicate isGuardedBy0(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { exists(ControlFlow::Node cfn | - (controls(cfn.getBasicBlock(), e, v) or controlsNode(cfn, e, v)) and + (g.controls(cfn.getBasicBlock(), v) or g.controlsNode(cfn, v)) and cfn = guarded.getAControlFlowNode() and exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) ) } cached - predicate isGuardedBy(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) { - isGuardedBy0(guarded, e, sub, v) and - sub = e.getAChildExpr*() and + predicate isGuardedBy(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + isGuardedBy0(guarded, g, sub, v) and + sub = g.getAChildExpr*() and ( not guarded.hasSsaQualifier() and not sub.hasSsaQualifier() or @@ -651,74 +681,46 @@ module Internal { } /** - * Holds if `e1` having abstract value `v1` implies that `e2` has abstract - * value `v2, using one step of reasoning. + * Holds if the assumption that `g1` has abstract value `v1` implies that + * `g2` has abstract value `v2`, using one step of reasoning. That is, the + * evaluation of `g2` to `v2` dominates the evaluation of `g1` to `v1`. */ cached - predicate impliesStep(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) { - exists(BinaryOperation bo | - bo instanceof BitwiseAndExpr or - bo instanceof LogicalAndExpr - | - bo = e1 and - e2 = bo.getAnOperand() and + predicate impliesStep(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) { + g1 = any(BinaryOperation bo | + ( + bo instanceof BitwiseAndExpr or + bo instanceof LogicalAndExpr + ) and + g2 = bo.getAnOperand() and v1 = TBooleanValue(true) and v2 = v1 - or - bo = e2 and - e1 = bo.getAnOperand() and - v1 = TBooleanValue(false) and - v2 = v1 ) or - exists(BinaryOperation bo | - bo instanceof BitwiseOrExpr or - bo instanceof LogicalOrExpr - | - bo = e1 and - e2 = bo.getAnOperand() and + g1 = any(BinaryOperation bo | + ( + bo instanceof BitwiseOrExpr or + bo instanceof LogicalOrExpr + ) and + g2 = bo.getAnOperand() and v1 = TBooleanValue(false) and v2 = v1 - or - bo = e2 and - e1 = bo.getAnOperand() and - v1 = TBooleanValue(true) and - v2 = v1 ) or - e1.(LogicalNotExpr).getOperand() = e2 and - v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanNot()) - or - e1 = e2.(LogicalNotExpr).getOperand() and + g2 = g1.(LogicalNotExpr).getOperand() and v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanNot()) or exists(ComparisonTest ct, boolean polarity, BoolLiteral boolLit, boolean b | ct.getAnArgument() = boolLit and b = boolLit.getBoolValue() and + g2 = ct.getAnArgument() and + g1 = ct.getExpr() and v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanXor(polarity).booleanXor(b)) | ct.getComparisonKind().isEquality() and - polarity = true and - ( - // e1 === e2 == b, v1 === !(v2 xor b) - e1 = ct.getExpr() and - e2 = ct.getAnArgument() - or - // e2 === e1 == b, v1 === !(v2 xor b) - e1 = ct.getAnArgument() and - e2 = ct.getExpr() - ) + polarity = true or ct.getComparisonKind().isInequality() and - polarity = false and - ( - // e1 === e2 != b, v1 === v2 xor b - e1 = ct.getExpr() and - e2 = ct.getAnArgument() - or - // e2 === e1 != true, v1 === v2 xor b - e1 = ct.getAnArgument() and - e2 = ct.getExpr() - ) + polarity = false ) or exists(ConditionalExpr cond, boolean branch, BoolLiteral boolLit, boolean b | @@ -729,43 +731,39 @@ module Internal { cond.getElse() = boolLit and branch = false ) | - e1 = cond and + g1 = cond and v1 = TBooleanValue(b.booleanNot()) and ( - // e1 === e2 ? b : x, v1 === !b, v2 === false; or - // e1 === e2 ? x : b, v1 === !b, v2 === true - e2 = cond.getCondition() and + g2 = cond.getCondition() and v2 = TBooleanValue(branch.booleanNot()) or - // e1 === x ? e2 : b, v1 === !b, v2 === v1 - e2 = cond.getThen() and + g2 = cond.getThen() and branch = false and v2 = v1 or - // e1 === x ? b : e2, v1 === !b, v2 === v1 - e2 = cond.getElse() and + g2 = cond.getElse() and branch = true and v2 = v1 ) - or - // e2 === e1 ? b : x, v1 === true, v2 === b; or - // e2 === e1 ? x : b, v1 === false, v2 === b - e1 = cond.getCondition() and - e2 = cond and - v1 = TBooleanValue(branch) and - v2 = TBooleanValue(b) ) or exists(boolean isNull | - v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) | - e1 = e2.(DereferenceableExpr).getANullCheck(v1, isNull) and - (e1 != e2 or v1 != v2) + g1 = g2.(DereferenceableExpr).getANullCheck(v1, isNull) | + v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) and + (g1 != g2 or v1 != v2) ) or - e1 instanceof DereferenceableExpr and - e1 = getNullEquivParent(e2) and + g1 instanceof DereferenceableExpr and + g1 = getNullEquivParent(g2) and v1 instanceof NullValue and - v1 = v2 + v2 = v1 + or + exists(PreSsa::Definition def | + def.getDefinition().getSource() = g2 | + g1 = def.getARead() and + v1 = g1.getAValue() and + v2 = v1 + ) } cached @@ -774,43 +772,18 @@ module Internal { import CachedWithCFG /** - * Holds if `e1` having some abstract value, `v`, implies that `e2` has the same - * abstract value `v`. + * Holds if the assumption that `g1` has abstract value `v1` implies that + * `g2` has abstract value `v2`, using zero or more steps of reasoning. That is, + * the evaluation of `g2` to `v2` dominates the evaluation of `g1` to `v1`. */ - predicate impliesStepIdentity(Expr e1, Expr e2) { - exists(PreSsa::Definition def | - def.getDefinition().getSource() = e2 | - e1 = def.getARead() - ) - } - - /** - * Holds if `e1` having abstract value `v1` implies that `e2` has abstract value - * `v2, using zero or more steps of reasoning. - */ - predicate impliesSteps(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) { - e1.getType() instanceof BoolType and - e1 = e2 and + predicate impliesSteps(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) { + g1 = g2 and v1 = v2 and - v1 = TBooleanValue(_) - or - v1.branchImplies(_, _, e1) and - e2 = e1 and - v2 = v1 - or - exists(Assertion a | - e1 = a.getExpr() | - asserts(a, e1, v1) and - e2 = e1 and - v2 = v1 - ) + v1 = g1.getAValue() or exists(Expr mid, AbstractValue vMid | - impliesSteps(e1, v1, mid, vMid) | - impliesStep(mid, vMid, e2, v2) - or - impliesStepIdentity(mid, e2) and - v2 = vMid + impliesSteps(g1, v1, mid, vMid) | + impliesStep(mid, vMid, g2, v2) ) } } diff --git a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected index 073d8485852d..8435df1f7593 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected @@ -11,11 +11,7 @@ | Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | -| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false | -| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | -| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false | -| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:12:13:12:24 | ... > ... | Guards.cs:12:13:12:13 | access to parameter s | true | | Guards.cs:26:31:26:31 | access to parameter s | Guards.cs:24:13:24:21 | ... != ... | Guards.cs:24:13:24:13 | access to parameter s | true | @@ -60,14 +56,9 @@ | Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | true | | Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | false | | Guards.cs:146:16:146:16 | access to parameter o | Guards.cs:144:13:144:25 | ... is ... | Guards.cs:144:13:144:13 | access to parameter o | false | -| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:13:168:41 | !... | Guards.cs:168:40:168:40 | access to parameter x | true | | Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | Guards.cs:168:40:168:40 | access to parameter x | false | -| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:13:189:25 | !... | Guards.cs:189:24:189:24 | access to parameter s | true | | Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:14:189:25 | call to method NullTest1 | Guards.cs:189:24:189:24 | access to parameter s | false | -| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:13:191:25 | !... | Guards.cs:191:24:191:24 | access to parameter s | true | | Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:14:191:25 | call to method NullTest2 | Guards.cs:191:24:191:24 | access to parameter s | false | -| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:13:193:25 | !... | Guards.cs:193:24:193:24 | access to parameter s | true | | Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:14:193:25 | call to method NullTest3 | Guards.cs:193:24:193:24 | access to parameter s | false | | Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:13:195:27 | call to method NotNullTest4 | Guards.cs:195:26:195:26 | access to parameter s | true | -| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:13:197:29 | !... | Guards.cs:197:28:197:28 | access to parameter s | true | | Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index a9da42be893a..6e9dea296995 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -26,12 +26,8 @@ | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | | Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | -| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false | -| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | -| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false | -| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:12:13:12:24 | ... > ... | Guards.cs:12:13:12:13 | access to parameter s | true | @@ -148,19 +144,14 @@ | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action: | | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action a: | | Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | -| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:13:168:41 | !... | Guards.cs:168:40:168:40 | access to parameter x | true | | Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | Guards.cs:168:40:168:40 | access to parameter x | false | | Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:40:168:40 | access to parameter x | Guards.cs:168:40:168:40 | access to parameter x | non-null | -| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:13:189:25 | !... | Guards.cs:189:24:189:24 | access to parameter s | true | | Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:14:189:25 | call to method NullTest1 | Guards.cs:189:24:189:24 | access to parameter s | false | | Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:24:189:24 | access to parameter s | Guards.cs:189:24:189:24 | access to parameter s | non-null | -| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:13:191:25 | !... | Guards.cs:191:24:191:24 | access to parameter s | true | | Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:14:191:25 | call to method NullTest2 | Guards.cs:191:24:191:24 | access to parameter s | false | | Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:24:191:24 | access to parameter s | Guards.cs:191:24:191:24 | access to parameter s | non-null | -| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:13:193:25 | !... | Guards.cs:193:24:193:24 | access to parameter s | true | | Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:14:193:25 | call to method NullTest3 | Guards.cs:193:24:193:24 | access to parameter s | false | | Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:24:193:24 | access to parameter s | Guards.cs:193:24:193:24 | access to parameter s | non-null | | Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:13:195:27 | call to method NotNullTest4 | Guards.cs:195:26:195:26 | access to parameter s | true | | Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:26:195:26 | access to parameter s | Guards.cs:195:26:195:26 | access to parameter s | non-null | -| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:13:197:29 | !... | Guards.cs:197:28:197:28 | access to parameter s | true | | Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 8e067718b2d2..e92ac6ea78c1 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -1,103 +1,114 @@ -impliesStep +| Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | +| Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | | Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | null | | Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null | +| Assert.cs:11:27:11:27 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | +| Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null | +| Assert.cs:17:23:17:23 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | +| Assert.cs:17:23:17:23 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null | +| Assert.cs:18:27:18:27 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | +| Assert.cs:18:27:18:27 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null | +| Assert.cs:24:26:24:26 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | +| Assert.cs:24:26:24:26 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null | +| Assert.cs:25:27:25:27 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | +| Assert.cs:25:27:25:27 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null | +| Assert.cs:31:23:31:23 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | +| Assert.cs:31:23:31:23 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null | | Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:31:23:31:23 | access to local variable s | non-null | | Assert.cs:31:23:31:31 | ... == ... | true | Assert.cs:31:23:31:23 | access to local variable s | null | +| Assert.cs:32:27:32:27 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | +| Assert.cs:32:27:32:27 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null | +| Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | +| Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null | | Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | null | | Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:38:23:38:23 | access to local variable s | non-null | +| Assert.cs:39:27:39:27 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | +| Assert.cs:39:27:39:27 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null | +| Assert.cs:45:24:45:24 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | +| Assert.cs:45:24:45:24 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null | | Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:45:24:45:24 | access to local variable s | null | | Assert.cs:45:24:45:32 | ... != ... | true | Assert.cs:45:24:45:24 | access to local variable s | non-null | +| Assert.cs:46:27:46:27 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | +| Assert.cs:46:27:46:27 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null | +| Assert.cs:52:24:52:24 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | +| Assert.cs:52:24:52:24 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null | | Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:52:24:52:24 | access to local variable s | non-null | | Assert.cs:52:24:52:32 | ... == ... | true | Assert.cs:52:24:52:24 | access to local variable s | null | +| Assert.cs:53:27:53:27 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | +| Assert.cs:53:27:53:27 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null | +| Assert.cs:59:23:59:23 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | +| Assert.cs:59:23:59:23 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null | | Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:59:23:59:23 | access to local variable s | null | -| Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:59:23:59:36 | ... && ... | false | | Assert.cs:59:23:59:31 | ... != ... | true | Assert.cs:59:23:59:23 | access to local variable s | non-null | | Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:23:59:31 | ... != ... | true | | Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:36:59:36 | access to parameter b | true | -| Assert.cs:59:36:59:36 | access to parameter b | false | Assert.cs:59:23:59:36 | ... && ... | false | +| Assert.cs:60:27:60:27 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | +| Assert.cs:60:27:60:27 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null | +| Assert.cs:66:24:66:24 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | +| Assert.cs:66:24:66:24 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null | | Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:66:24:66:24 | access to local variable s | non-null | | Assert.cs:66:24:66:32 | ... == ... | true | Assert.cs:66:24:66:24 | access to local variable s | null | -| Assert.cs:66:24:66:32 | ... == ... | true | Assert.cs:66:24:66:37 | ... \|\| ... | true | | Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:24:66:32 | ... == ... | false | | Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:37:66:37 | access to parameter b | false | -| Assert.cs:66:37:66:37 | access to parameter b | true | Assert.cs:66:24:66:37 | ... \|\| ... | true | +| Assert.cs:67:27:67:27 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | +| Assert.cs:67:27:67:27 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null | +| Assert.cs:73:23:73:23 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | +| Assert.cs:73:23:73:23 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null | | Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:73:23:73:23 | access to local variable s | non-null | -| Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:73:23:73:36 | ... && ... | false | | Assert.cs:73:23:73:31 | ... == ... | true | Assert.cs:73:23:73:23 | access to local variable s | null | | Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:23:73:31 | ... == ... | true | | Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:36:73:36 | access to parameter b | true | -| Assert.cs:73:36:73:36 | access to parameter b | false | Assert.cs:73:23:73:36 | ... && ... | false | +| Assert.cs:74:27:74:27 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | +| Assert.cs:74:27:74:27 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null | +| Assert.cs:80:24:80:24 | access to local variable s | non-null | Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | +| Assert.cs:80:24:80:24 | access to local variable s | null | Assert.cs:79:20:79:32 | ... ? ... : ... | null | | Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:80:24:80:24 | access to local variable s | null | | Assert.cs:80:24:80:32 | ... != ... | true | Assert.cs:80:24:80:24 | access to local variable s | non-null | -| Assert.cs:80:24:80:32 | ... != ... | true | Assert.cs:80:24:80:37 | ... \|\| ... | true | | Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:24:80:32 | ... != ... | false | | Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:37:80:37 | access to parameter b | false | -| Assert.cs:80:37:80:37 | access to parameter b | true | Assert.cs:80:24:80:37 | ... \|\| ... | true | +| Assert.cs:81:27:81:27 | access to local variable s | non-null | Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | +| Assert.cs:81:27:81:27 | access to local variable s | null | Assert.cs:79:20:79:32 | ... ? ... : ... | null | | Guards.cs:10:13:10:25 | !... | false | Guards.cs:10:14:10:25 | !... | true | | Guards.cs:10:13:10:25 | !... | true | Guards.cs:10:14:10:25 | !... | false | -| Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:13:10:25 | !... | true | | Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:16:10:24 | ... == ... | true | -| Guards.cs:10:14:10:25 | !... | true | Guards.cs:10:13:10:25 | !... | false | | Guards.cs:10:14:10:25 | !... | true | Guards.cs:10:16:10:24 | ... == ... | false | -| Guards.cs:10:16:10:24 | ... == ... | false | Guards.cs:10:14:10:25 | !... | true | | Guards.cs:10:16:10:24 | ... == ... | false | Guards.cs:10:16:10:16 | access to parameter s | non-null | -| Guards.cs:10:16:10:24 | ... == ... | true | Guards.cs:10:14:10:25 | !... | false | | Guards.cs:10:16:10:24 | ... == ... | true | Guards.cs:10:16:10:16 | access to parameter s | null | | Guards.cs:24:13:24:21 | ... != ... | false | Guards.cs:24:13:24:13 | access to parameter s | null | | Guards.cs:24:13:24:21 | ... != ... | true | Guards.cs:24:13:24:13 | access to parameter s | non-null | -| Guards.cs:32:13:32:36 | !... | false | Guards.cs:32:13:32:51 | ... & ... | false | | Guards.cs:32:13:32:36 | !... | false | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | true | | Guards.cs:32:13:32:36 | !... | true | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false | | Guards.cs:32:13:32:51 | ... & ... | true | Guards.cs:32:13:32:36 | !... | true | | Guards.cs:32:13:32:51 | ... & ... | true | Guards.cs:32:40:32:51 | !... | true | -| Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false | Guards.cs:32:13:32:36 | !... | true | | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false | Guards.cs:32:35:32:35 | access to parameter x | non-null | -| Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | true | Guards.cs:32:13:32:36 | !... | false | -| Guards.cs:32:40:32:51 | !... | false | Guards.cs:32:13:32:51 | ... & ... | false | | Guards.cs:32:40:32:51 | !... | false | Guards.cs:32:42:32:50 | ... == ... | true | | Guards.cs:32:40:32:51 | !... | true | Guards.cs:32:42:32:50 | ... == ... | false | -| Guards.cs:32:42:32:50 | ... == ... | false | Guards.cs:32:40:32:51 | !... | true | | Guards.cs:32:42:32:50 | ... == ... | false | Guards.cs:32:42:32:42 | access to parameter y | non-null | -| Guards.cs:32:42:32:50 | ... == ... | true | Guards.cs:32:40:32:51 | !... | false | | Guards.cs:32:42:32:50 | ... == ... | true | Guards.cs:32:42:32:42 | access to parameter y | null | | Guards.cs:35:13:35:21 | ... == ... | false | Guards.cs:35:13:35:13 | access to parameter x | non-null | | Guards.cs:35:13:35:21 | ... == ... | true | Guards.cs:35:13:35:13 | access to parameter x | null | -| Guards.cs:35:13:35:21 | ... == ... | true | Guards.cs:35:13:35:34 | ... \|\| ... | true | | Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:13:35:21 | ... == ... | false | | Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:26:35:34 | ... == ... | false | | Guards.cs:35:26:35:34 | ... == ... | false | Guards.cs:35:26:35:26 | access to parameter y | non-null | -| Guards.cs:35:26:35:34 | ... == ... | true | Guards.cs:35:13:35:34 | ... \|\| ... | true | | Guards.cs:35:26:35:34 | ... == ... | true | Guards.cs:35:26:35:26 | access to parameter y | null | | Guards.cs:38:13:38:37 | !... | false | Guards.cs:38:15:38:36 | ... \|\| ... | true | | Guards.cs:38:13:38:37 | !... | true | Guards.cs:38:15:38:36 | ... \|\| ... | false | | Guards.cs:38:15:38:23 | ... == ... | false | Guards.cs:38:15:38:15 | access to parameter x | non-null | | Guards.cs:38:15:38:23 | ... == ... | true | Guards.cs:38:15:38:15 | access to parameter x | null | -| Guards.cs:38:15:38:23 | ... == ... | true | Guards.cs:38:15:38:36 | ... \|\| ... | true | -| Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:13:38:37 | !... | true | | Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:15:38:23 | ... == ... | false | | Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:28:38:36 | ... == ... | false | -| Guards.cs:38:15:38:36 | ... \|\| ... | true | Guards.cs:38:13:38:37 | !... | false | | Guards.cs:38:28:38:36 | ... == ... | false | Guards.cs:38:28:38:28 | access to parameter y | non-null | -| Guards.cs:38:28:38:36 | ... == ... | true | Guards.cs:38:15:38:36 | ... \|\| ... | true | | Guards.cs:38:28:38:36 | ... == ... | true | Guards.cs:38:28:38:28 | access to parameter y | null | | Guards.cs:41:13:41:39 | !... | false | Guards.cs:41:14:41:39 | !... | true | | Guards.cs:41:13:41:39 | !... | true | Guards.cs:41:14:41:39 | !... | false | -| Guards.cs:41:14:41:39 | !... | false | Guards.cs:41:13:41:39 | !... | true | | Guards.cs:41:14:41:39 | !... | false | Guards.cs:41:15:41:39 | !... | true | -| Guards.cs:41:14:41:39 | !... | true | Guards.cs:41:13:41:39 | !... | false | | Guards.cs:41:14:41:39 | !... | true | Guards.cs:41:15:41:39 | !... | false | -| Guards.cs:41:15:41:39 | !... | false | Guards.cs:41:14:41:39 | !... | true | | Guards.cs:41:15:41:39 | !... | false | Guards.cs:41:17:41:38 | ... && ... | true | -| Guards.cs:41:15:41:39 | !... | true | Guards.cs:41:14:41:39 | !... | false | | Guards.cs:41:15:41:39 | !... | true | Guards.cs:41:17:41:38 | ... && ... | false | | Guards.cs:41:17:41:25 | ... != ... | false | Guards.cs:41:17:41:17 | access to parameter x | null | -| Guards.cs:41:17:41:25 | ... != ... | false | Guards.cs:41:17:41:38 | ... && ... | false | | Guards.cs:41:17:41:25 | ... != ... | true | Guards.cs:41:17:41:17 | access to parameter x | non-null | -| Guards.cs:41:17:41:38 | ... && ... | false | Guards.cs:41:15:41:39 | !... | true | -| Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:15:41:39 | !... | false | | Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:17:41:25 | ... != ... | true | | Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:30:41:38 | ... != ... | true | -| Guards.cs:41:30:41:38 | ... != ... | false | Guards.cs:41:17:41:38 | ... && ... | false | | Guards.cs:41:30:41:38 | ... != ... | false | Guards.cs:41:30:41:30 | access to parameter y | null | | Guards.cs:41:30:41:38 | ... != ... | true | Guards.cs:41:30:41:30 | access to parameter y | non-null | | Guards.cs:44:13:44:25 | ... != ... | false | Guards.cs:44:13:44:17 | access to field Field | null | @@ -110,6 +121,8 @@ impliesStep | Guards.cs:60:13:60:45 | ... == ... | true | Guards.cs:60:13:60:37 | access to field Field | null | | Guards.cs:68:16:68:24 | ... != ... | false | Guards.cs:68:16:68:16 | access to parameter s | null | | Guards.cs:68:16:68:24 | ... != ... | true | Guards.cs:68:16:68:16 | access to parameter s | non-null | +| Guards.cs:72:31:72:31 | access to parameter s | non-null | Guards.cs:71:17:71:20 | null | non-null | +| Guards.cs:72:31:72:31 | access to parameter s | null | Guards.cs:71:17:71:20 | null | null | | Guards.cs:78:13:78:26 | ... == ... | true | Guards.cs:78:15:78:21 | access to property Length | non-null | | Guards.cs:78:15:78:21 | access to property Length | non-null | Guards.cs:78:13:78:13 | access to parameter s | non-null | | Guards.cs:78:15:78:21 | access to property Length | null | Guards.cs:78:13:78:13 | access to parameter s | null | @@ -143,89 +156,47 @@ impliesStep | Guards.cs:130:13:130:21 | ... is ... | true | Guards.cs:130:13:130:13 | access to parameter s | null | | Guards.cs:137:13:137:23 | ... is ... | true | Guards.cs:137:13:137:13 | access to parameter s | non-null | | Guards.cs:144:13:144:25 | ... is ... | true | Guards.cs:144:13:144:13 | access to parameter o | non-null | +| Guards.cs:145:20:145:20 | access to local variable s | non-null | Guards.cs:144:13:144:13 | access to parameter o | non-null | +| Guards.cs:145:20:145:20 | access to local variable s | null | Guards.cs:144:13:144:13 | access to parameter o | null | | Guards.cs:151:17:151:17 | access to parameter o | match case ...: | Guards.cs:151:17:151:17 | access to parameter o | non-null | | Guards.cs:151:17:151:17 | access to parameter o | match case ...: | Guards.cs:151:17:151:17 | access to parameter o | null | | Guards.cs:151:17:151:17 | access to parameter o | match case Action: | Guards.cs:151:17:151:17 | access to parameter o | non-null | | Guards.cs:151:17:151:17 | access to parameter o | match case Action a: | Guards.cs:151:17:151:17 | access to parameter o | non-null | | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:156:24:156:24 | access to local variable a | non-null | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:156:24:156:24 | access to local variable a | null | Guards.cs:151:17:151:17 | access to parameter o | null | | Guards.cs:168:13:168:41 | !... | false | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | true | | Guards.cs:168:13:168:41 | !... | true | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | false | -| Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | false | Guards.cs:168:13:168:41 | !... | true | | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | false | Guards.cs:168:40:168:40 | access to parameter x | non-null | -| Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | true | Guards.cs:168:13:168:41 | !... | false | | Guards.cs:172:33:172:41 | ... == ... | false | Guards.cs:172:33:172:33 | access to parameter o | non-null | | Guards.cs:172:33:172:41 | ... == ... | true | Guards.cs:172:33:172:33 | access to parameter o | null | | Guards.cs:176:13:176:21 | ... is ... | false | Guards.cs:176:13:176:13 | access to parameter o | non-null | | Guards.cs:176:13:176:21 | ... is ... | true | Guards.cs:176:13:176:13 | access to parameter o | null | | Guards.cs:181:33:181:41 | ... == ... | false | Guards.cs:181:33:181:33 | access to parameter o | non-null | -| Guards.cs:181:33:181:41 | ... == ... | false | Guards.cs:181:33:181:56 | ... ? ... : ... | false | | Guards.cs:181:33:181:41 | ... == ... | true | Guards.cs:181:33:181:33 | access to parameter o | null | -| Guards.cs:181:33:181:41 | ... == ... | true | Guards.cs:181:33:181:56 | ... ? ... : ... | true | | Guards.cs:181:33:181:56 | ... ? ... : ... | false | Guards.cs:181:33:181:41 | ... == ... | false | -| Guards.cs:181:33:181:56 | ... ? ... : ... | false | Guards.cs:181:52:181:56 | false | false | | Guards.cs:181:33:181:56 | ... ? ... : ... | true | Guards.cs:181:33:181:41 | ... == ... | true | -| Guards.cs:181:33:181:56 | ... ? ... : ... | true | Guards.cs:181:45:181:48 | true | true | | Guards.cs:183:36:183:48 | !... | false | Guards.cs:183:37:183:48 | call to method NullTest3 | true | | Guards.cs:183:36:183:48 | !... | true | Guards.cs:183:37:183:48 | call to method NullTest3 | false | -| Guards.cs:183:37:183:48 | call to method NullTest3 | false | Guards.cs:183:36:183:48 | !... | true | | Guards.cs:183:37:183:48 | call to method NullTest3 | false | Guards.cs:183:47:183:47 | access to parameter o | non-null | -| Guards.cs:183:37:183:48 | call to method NullTest3 | true | Guards.cs:183:36:183:48 | !... | false | | Guards.cs:183:37:183:48 | call to method NullTest3 | true | Guards.cs:183:47:183:47 | access to parameter o | null | | Guards.cs:185:37:185:45 | ... == ... | false | Guards.cs:185:37:185:37 | access to parameter o | non-null | -| Guards.cs:185:37:185:45 | ... == ... | false | Guards.cs:185:37:185:59 | ... ? ... : ... | true | | Guards.cs:185:37:185:45 | ... == ... | true | Guards.cs:185:37:185:37 | access to parameter o | null | -| Guards.cs:185:37:185:45 | ... == ... | true | Guards.cs:185:37:185:59 | ... ? ... : ... | true | | Guards.cs:185:37:185:59 | ... ? ... : ... | false | Guards.cs:185:37:185:45 | ... == ... | false | | Guards.cs:185:37:185:59 | ... ? ... : ... | false | Guards.cs:185:37:185:45 | ... == ... | true | -| Guards.cs:185:37:185:59 | ... ? ... : ... | false | Guards.cs:185:49:185:52 | true | false | -| Guards.cs:185:37:185:59 | ... ? ... : ... | false | Guards.cs:185:56:185:59 | true | false | | Guards.cs:189:13:189:25 | !... | false | Guards.cs:189:14:189:25 | call to method NullTest1 | true | | Guards.cs:189:13:189:25 | !... | true | Guards.cs:189:14:189:25 | call to method NullTest1 | false | -| Guards.cs:189:14:189:25 | call to method NullTest1 | false | Guards.cs:189:13:189:25 | !... | true | | Guards.cs:189:14:189:25 | call to method NullTest1 | false | Guards.cs:189:24:189:24 | access to parameter s | non-null | -| Guards.cs:189:14:189:25 | call to method NullTest1 | true | Guards.cs:189:13:189:25 | !... | false | | Guards.cs:189:14:189:25 | call to method NullTest1 | true | Guards.cs:189:24:189:24 | access to parameter s | null | | Guards.cs:191:13:191:25 | !... | false | Guards.cs:191:14:191:25 | call to method NullTest2 | true | | Guards.cs:191:13:191:25 | !... | true | Guards.cs:191:14:191:25 | call to method NullTest2 | false | -| Guards.cs:191:14:191:25 | call to method NullTest2 | false | Guards.cs:191:13:191:25 | !... | true | | Guards.cs:191:14:191:25 | call to method NullTest2 | false | Guards.cs:191:24:191:24 | access to parameter s | non-null | -| Guards.cs:191:14:191:25 | call to method NullTest2 | true | Guards.cs:191:13:191:25 | !... | false | | Guards.cs:191:14:191:25 | call to method NullTest2 | true | Guards.cs:191:24:191:24 | access to parameter s | null | | Guards.cs:193:13:193:25 | !... | false | Guards.cs:193:14:193:25 | call to method NullTest3 | true | | Guards.cs:193:13:193:25 | !... | true | Guards.cs:193:14:193:25 | call to method NullTest3 | false | -| Guards.cs:193:14:193:25 | call to method NullTest3 | false | Guards.cs:193:13:193:25 | !... | true | | Guards.cs:193:14:193:25 | call to method NullTest3 | false | Guards.cs:193:24:193:24 | access to parameter s | non-null | -| Guards.cs:193:14:193:25 | call to method NullTest3 | true | Guards.cs:193:13:193:25 | !... | false | | Guards.cs:193:14:193:25 | call to method NullTest3 | true | Guards.cs:193:24:193:24 | access to parameter s | null | | Guards.cs:195:13:195:27 | call to method NotNullTest4 | false | Guards.cs:195:26:195:26 | access to parameter s | null | | Guards.cs:195:13:195:27 | call to method NotNullTest4 | true | Guards.cs:195:26:195:26 | access to parameter s | non-null | | Guards.cs:197:13:197:29 | !... | false | Guards.cs:197:14:197:29 | call to method NullTestWrong | true | | Guards.cs:197:13:197:29 | !... | true | Guards.cs:197:14:197:29 | call to method NullTestWrong | false | -| Guards.cs:197:14:197:29 | call to method NullTestWrong | false | Guards.cs:197:13:197:29 | !... | true | -| Guards.cs:197:14:197:29 | call to method NullTestWrong | true | Guards.cs:197:13:197:29 | !... | false | -impliesStepIdentity -| Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:9:20:9:32 | ... ? ... : ... | -| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:9:20:9:32 | ... ? ... : ... | -| Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:16:20:16:32 | ... ? ... : ... | -| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:16:20:16:32 | ... ? ... : ... | -| Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:23:20:23:32 | ... ? ... : ... | -| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:23:20:23:32 | ... ? ... : ... | -| Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:30:20:30:32 | ... ? ... : ... | -| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:30:20:30:32 | ... ? ... : ... | -| Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:37:20:37:32 | ... ? ... : ... | -| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:37:20:37:32 | ... ? ... : ... | -| Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:44:20:44:32 | ... ? ... : ... | -| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:44:20:44:32 | ... ? ... : ... | -| Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:51:20:51:32 | ... ? ... : ... | -| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:51:20:51:32 | ... ? ... : ... | -| Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:58:20:58:32 | ... ? ... : ... | -| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:58:20:58:32 | ... ? ... : ... | -| Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:65:20:65:32 | ... ? ... : ... | -| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:65:20:65:32 | ... ? ... : ... | -| Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:72:20:72:32 | ... ? ... : ... | -| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:72:20:72:32 | ... ? ... : ... | -| Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:79:20:79:32 | ... ? ... : ... | -| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:79:20:79:32 | ... ? ... : ... | -| Guards.cs:72:31:72:31 | access to parameter s | Guards.cs:71:17:71:20 | null | -| Guards.cs:145:20:145:20 | access to local variable s | Guards.cs:144:13:144:13 | access to parameter o | -| Guards.cs:156:24:156:24 | access to local variable a | Guards.cs:151:17:151:17 | access to parameter o | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.ql b/csharp/ql/test/library-tests/controlflow/guards/Implications.ql index 05caaa5f2464..0c185b1a2dc0 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.ql +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.ql @@ -4,7 +4,3 @@ import semmle.code.csharp.controlflow.Guards query predicate impliesStep(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) { Internal::impliesStep(e1, v1, e2, v2) } - -query predicate impliesStepIdentity(Expr e1, Expr e2) { - Internal::impliesStepIdentity(e1, e2) -} From c14ebac4552e912bf2fef0162266c955fd13d9e6 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 9 Nov 2018 08:36:30 +0000 Subject: [PATCH 10/68] JavaScript: Port regular expression parser to Java. --- .../src/com/semmle/js/ast/regexp/Error.java | 14 + .../com/semmle/js/parser/RegExpParser.java | 521 +++- .../tests/exprs/output/trap/regexp.js.trap | 2541 +++++++++-------- .../extractor/tests/regexp/input/es2018.js | 1 + .../extractor/tests/regexp/input/tst.js | 2 + .../tests/regexp/output/trap/es2018.js.trap | 174 +- .../tests/regexp/output/trap/tst.js.trap | Bin 0 -> 3092 bytes 7 files changed, 1843 insertions(+), 1410 deletions(-) create mode 100644 javascript/extractor/tests/regexp/input/tst.js create mode 100644 javascript/extractor/tests/regexp/output/trap/tst.js.trap diff --git a/javascript/extractor/src/com/semmle/js/ast/regexp/Error.java b/javascript/extractor/src/com/semmle/js/ast/regexp/Error.java index b5f56e3d4f66..66977309781b 100644 --- a/javascript/extractor/src/com/semmle/js/ast/regexp/Error.java +++ b/javascript/extractor/src/com/semmle/js/ast/regexp/Error.java @@ -7,6 +7,20 @@ * An error encountered while parsing a regular expression. */ public class Error extends SourceElement { + public static final int UNEXPECTED_EOS = 0; + public static final int UNEXPECTED_CHARACTER = 1; + public static final int EXPECTED_DIGIT = 2; + public static final int EXPECTED_HEX_DIGIT = 3; + public static final int EXPECTED_CONTROL_LETTER = 4; + public static final int EXPECTED_CLOSING_PAREN = 5; + public static final int EXPECTED_CLOSING_BRACE = 6; + public static final int EXPECTED_EOS = 7; + public static final int OCTAL_ESCAPE = 8; + public static final int INVALID_BACKREF = 9; + public static final int EXPECTED_RBRACKET = 10; + public static final int EXPECTED_IDENTIFIER = 11; + public static final int EXPECTED_CLOSING_ANGLE = 12; + private final int code; public Error(SourceLocation loc, Number code) { diff --git a/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java b/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java index 2099edcbd91b..bfa4919cde6b 100644 --- a/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java @@ -1,17 +1,9 @@ package com.semmle.js.parser; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; - -import org.mozilla.javascript.Function; -import org.mozilla.javascript.NativeArray; -import org.mozilla.javascript.NativeObject; -import org.mozilla.javascript.ScriptableObject; +import com.semmle.js.ast.Position; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.regexp.BackReference; import com.semmle.js.ast.regexp.Caret; @@ -47,54 +39,9 @@ import com.semmle.js.ast.regexp.ZeroWidthPositiveLookbehind; /** - * Wrapper for invoking esregex through Rhino. + * A parser for ECMAScript 2018 regular expressions. */ -public class RegExpParser extends ScriptLoader { - /** - * Specification for esregex AST types. - */ - private static final Map, List> spec = new LinkedHashMap, List>(); - static { - spec.put(BackReference.class, Arrays.asList("value", "raw")); - spec.put(Caret.class, Collections.emptyList()); - spec.put(CharacterClass.class, Arrays.asList("elements", "inverted")); - spec.put(CharacterClassEscape.class, Arrays.asList("class", "raw")); - spec.put(CharacterClassRange.class, Arrays.asList("left", "right")); - spec.put(Constant.class, Arrays.asList("value")); - spec.put(ControlEscape.class, Arrays.asList("value", "codepoint", "raw")); - spec.put(ControlLetter.class, Arrays.asList("value", "codepoint", "raw")); - spec.put(DecimalEscape.class, Arrays.asList("value", "codepoint", "raw")); - spec.put(Disjunction.class, Arrays.asList("disjuncts")); - spec.put(Dollar.class, Collections.emptyList()); - spec.put(Dot.class, Collections.emptyList()); - spec.put(Group.class, Arrays.asList("capture", "number", "name", "operand")); - spec.put(HexEscapeSequence.class, Arrays.asList("value", "codepoint", "raw")); - spec.put(IdentityEscape.class, Arrays.asList("value", "codepoint", "raw")); - spec.put(NamedBackReference.class, Arrays.asList("name", "raw")); - spec.put(NonWordBoundary.class, Collections.emptyList()); - spec.put(OctalEscape.class, Arrays.asList("value", "codepoint", "raw")); - spec.put(Opt.class, Arrays.asList("operand", "greedy")); - spec.put(Plus.class, Arrays.asList("operand", "greedy")); - spec.put(Range.class, Arrays.asList("operand", "greedy", "lo", "hi")); - spec.put(Sequence.class, Arrays.asList("elements")); - spec.put(Star.class, Arrays.asList("operand", "greedy")); - spec.put(UnicodeEscapeSequence.class, Arrays.asList("value", "codepoint", "raw")); - spec.put(WordBoundary.class, Collections.emptyList()); - spec.put(ZeroWidthNegativeLookahead.class, Arrays.asList("operand")); - spec.put(ZeroWidthPositiveLookahead.class, Arrays.asList("operand")); - spec.put(ZeroWidthNegativeLookbehind.class, Arrays.asList("operand")); - spec.put(ZeroWidthPositiveLookbehind.class, Arrays.asList("operand")); - spec.put(UnicodePropertyEscape.class, Arrays.asList("name", "value", "raw")); - } - - /** - * Specification for esregex parse errors. - */ - private static final Map, List> errspec = new LinkedHashMap, List>(); - static { - errspec.put(Error.class, Arrays.asList("code")); - } - +public class RegExpParser { /** * The result of a parse. */ @@ -102,12 +49,12 @@ public static class Result { /** * The root of the parsed AST. */ - private final RegExpTerm ast; + public final RegExpTerm ast; /** * A list of errors encountered during parsing. */ - private final List errors; + public final List errors; public Result(RegExpTerm ast, List errors) { this.ast = ast; @@ -123,28 +70,450 @@ public List getErrors() { } } - public RegExpParser() { - super("/regexparser.js"); - } + private String src; + private int pos; + private List errors; + private List backrefs; + private int maxbackref; /** * Parse the given string as a regular expression. */ public Result parse(String src) { - Function ctor = (Function)readGlobal("RegExpParser"); - ScriptableObject parser = construct(ctor, src); - NativeObject ast = (NativeObject)callMethod(parser, "Pattern"); - NativeArray errors = (NativeArray)readProperty(parser, "errors"); - JSObjectDecoder decoder = new JSObjectDecoder(src, this, "com.semmle.js.ast.regexp", spec); - List errs = null; - RegExpTerm term = null; - try { - term = decoder.decodeObject(ast); - errs = new JSObjectDecoder(src, this, "com.semmle.js.ast.regexp", errspec).decodeObjects(errors); - } catch (ParseError e) { - errs = new ArrayList(); - errs.add(new Error(new SourceLocation("", e.getPosition(), e.getPosition()), 1)); - } - return new Result(term, errs); + this.src = src; + this.pos = 0; + this.errors = new ArrayList<>(); + this.backrefs = new ArrayList<>(); + this.maxbackref = 0; + RegExpTerm root = parsePattern(); + for (BackReference backref : backrefs) + if (backref.getValue() > maxbackref) + errors.add(new Error(backref.getLoc(), Error.INVALID_BACKREF)); + return new Result(root, errors); + } + + private static String fromCodePoint(int codepoint) { + if (Character.isValidCodePoint(codepoint)) + return new String(Character.toChars(codepoint)); + // replacement character + return "\ufffd"; + } + + private Position pos() { + return new Position(1, pos, pos); + } + + private void error(int code, int start, int end) { + Position startPos, endPos; + startPos = new Position(1, start, start); + endPos = new Position(1, end, end); + this.errors.add(new Error(new SourceLocation(inputSubstring(start, end), startPos, endPos), code)); + } + + private void error(int code, int start) { + error(code, start, start+1); + } + + private void error(int code) { + error(code, this.pos); + } + + private boolean atEOS() { + return pos >= src.length(); + } + + private char peekChar(boolean opt) { + if (this.atEOS()) { + if (!opt) + this.error(Error.UNEXPECTED_EOS); + return '\0'; + } else { + return this.src.charAt(this.pos); + } + } + + private char nextChar() { + char c = peekChar(false); + if (this.pos < src.length()) + ++this.pos; + return c; + } + + private String readHexDigit() { + char c = this.peekChar(false); + if (c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F') { + ++this.pos; + return String.valueOf(c); + } + if (c != '\0') + this.error(Error.EXPECTED_HEX_DIGIT, this.pos); + return ""; + } + + private String readHexDigits(int n) { + StringBuilder res = new StringBuilder(); + while (n-->0) { + res.append(readHexDigit()); + } + if (res.length() == 0) + return "0"; + return res.toString(); + } + + private String readDigits(boolean opt) { + StringBuilder res = new StringBuilder(); + for (char c=peekChar(true); c >= '0' && c <= '9'; nextChar(), c=peekChar(true)) + res.append(c); + if (res.length() == 0 && !opt) + this.error(Error.EXPECTED_DIGIT); + return res.toString(); + } + + private Double toNumber(String s) { + if (s.isEmpty()) + return 0.0; + return Double.valueOf(s); + } + + private String readIdentifier() { + StringBuilder res = new StringBuilder(); + for (char c=peekChar(true); + c != '\0' && Character.isJavaIdentifierPart(c); + nextChar(), c=peekChar(true)) + res.append(c); + if (res.length() == 0) + this.error(Error.EXPECTED_IDENTIFIER); + return res.toString(); + } + + private void expectRParen() { + if (!this.match(")")) + this.error(Error.EXPECTED_CLOSING_PAREN, this.pos-1); + } + + private void expectRBrace() { + if (!this.match("}")) + this.error(Error.EXPECTED_CLOSING_BRACE, this.pos-1); + } + + private void expectRAngle() { + if (!this.match(">")) + this.error(Error.EXPECTED_CLOSING_ANGLE, this.pos-1); + } + + private boolean lookahead(String... arguments) { + for (String prefix : arguments) { + if (prefix == null) { + if (atEOS()) + return true; + } else if (inputSubstring(pos, pos+prefix.length()).equals(prefix)) { + return true; + } + } + return false; + } + + private boolean match(String... arguments) { + for (String prefix : arguments) { + if (this.lookahead(prefix)) { + if (prefix == null) + prefix = ""; + this.pos += prefix.length(); + return true; + } + } + return false; + } + + private RegExpTerm parsePattern() { + RegExpTerm res = parseDisjunction(); + if (!this.atEOS()) + this.error(Error.EXPECTED_EOS); + return res; + } + + protected String inputSubstring(int start, int end) { + if (start >= src.length()) + return ""; + if (end > src.length()) + end = src.length(); + return src.substring(start, end); + } + + private T finishTerm(T term) { + SourceLocation loc = term.getLoc(); + Position end = pos(); + loc.setSource(inputSubstring(loc.getStart().getOffset(), end.getOffset())); + loc.setEnd(end); + return term; + } + + private RegExpTerm parseDisjunction() { + SourceLocation loc = new SourceLocation(pos()); + List disjuncts = new ArrayList<>(); + disjuncts.add(this.parseAlternative()); + while (this.match("|")) + disjuncts.add(this.parseAlternative()); + if (disjuncts.size() == 1) + return disjuncts.get(0); + return this.finishTerm(new Disjunction(loc, disjuncts)); + } + + private RegExpTerm parseAlternative() { + SourceLocation loc = new SourceLocation(pos()); + List elements = new ArrayList<>(); + while (!this.lookahead(null, "|", ")")) + elements.add(this.parseTerm()); + if (elements.size() == 1) + return elements.get(0); + return this.finishTerm(new Sequence(loc, elements)); + } + + private RegExpTerm parseTerm() { + SourceLocation loc = new SourceLocation(pos()); + + if (this.match("^")) + return this.finishTerm(new Caret(loc)); + + if (this.match("$")) + return this.finishTerm(new Dollar(loc)); + + if (this.match("\\b")) + return this.finishTerm(new WordBoundary(loc)); + + if (this.match("\\B")) + return this.finishTerm(new NonWordBoundary(loc)); + + if (this.match("(?=")) { + RegExpTerm dis = this.parseDisjunction(); + this.expectRParen(); + return this.finishTerm(new ZeroWidthPositiveLookahead(loc, dis)); + } + + if (this.match("(?!")) { + RegExpTerm dis = this.parseDisjunction(); + this.expectRParen(); + return this.finishTerm(new ZeroWidthNegativeLookahead(loc, dis)); + } + + if (this.match("(?<=")) { + RegExpTerm dis = this.parseDisjunction(); + this.expectRParen(); + return this.finishTerm(new ZeroWidthPositiveLookbehind(loc, dis)); + } + + if (this.match("(?")); + } + + if (this.match("p{", "P{")) { + String name = this.readIdentifier(); + if (this.match("=")) { + value = this.readIdentifier(); + raw = "\\p{" + name + "=" + value + "}"; + } else { + value = null; + raw = "\\p{" + name + "}"; + } + this.expectRBrace(); + return this.finishTerm(new UnicodePropertyEscape(loc, name, value, raw)); + } + + int startpos = this.pos-1; + char c = this.nextChar(); + + if (c >= '0' && c <= '9') { + raw = c + this.readDigits(true); + if (c == '0' || inCharClass) { + int base = c == '0' && raw.length() > 1 ? 8 : 10; + try { + codepoint = Long.parseLong(raw, base); + value = fromCodePoint((int) codepoint); + } catch (NumberFormatException nfe) { + codepoint = 0; + value = "\0"; + } + if (base == 8) { + this.error(Error.OCTAL_ESCAPE, startpos, this.pos); + return this.finishTerm(new OctalEscape(loc, value, (double)codepoint, "\\" + raw)); + } else { + return this.finishTerm(new DecimalEscape(loc, value, (double)codepoint, "\\" + raw)); + } + } else { + try { + codepoint = Long.parseLong(raw, 10); + } catch (NumberFormatException nfe) { + codepoint = 0; + } + BackReference br = this.finishTerm(new BackReference(loc, (double)codepoint, "\\" + raw)); + this.backrefs.add(br); + return br; + } + } + + String ctrltab = "f\fn\nr\rt\tv\u000b"; + int idx; + if ((idx=ctrltab.indexOf(c)) % 2 == 0) { + codepoint = ctrltab.charAt(idx+1); + value = String.valueOf((char)codepoint); + return this.finishTerm(new ControlEscape(loc, value, codepoint, "\\" + c)); + } + + if (c == 'c') { + c = this.nextChar(); + if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) + this.error(Error.EXPECTED_CONTROL_LETTER, this.pos-1); + codepoint = c % 32; + value = String.valueOf((char)codepoint); + return this.finishTerm(new ControlLetter(loc, value, codepoint, "\\c" + c)); + } + + if ("dDsSwW".indexOf(c) >= 0) { + return this.finishTerm(new CharacterClassEscape(loc, String.valueOf(c), "\\" + c)); + } + + codepoint = c; + value = String.valueOf((char)codepoint); + return this.finishTerm(new IdentityEscape(loc, value, codepoint, "\\" + c)); + } + + private RegExpTerm parseCharacterClass() { + SourceLocation loc = new SourceLocation(pos()); + List elements = new ArrayList<>(); + + this.match("["); + boolean inverted = this.match("^"); + while (!this.match("]")) { + if (this.atEOS()) { + this.error(Error.EXPECTED_RBRACKET); + break; + } + elements.add(this.parseCharacterClassElement()); + } + return this.finishTerm(new CharacterClass(loc, elements, inverted)); + } + + private RegExpTerm parseCharacterClassElement() { + SourceLocation loc = new SourceLocation(pos()); + RegExpTerm atom = this.parseCharacterClassAtom(); + if (!this.lookahead("-]") && this.match("-")) + return this.finishTerm(new CharacterClassRange(loc, atom, this.parseCharacterClassAtom())); + return atom; + } + + private RegExpTerm parseCharacterClassAtom() { + SourceLocation loc = new SourceLocation(pos()); + char c = this.nextChar(); + if (c == '\\') { + if (this.match("b")) + return this.finishTerm(new ControlEscape(loc, "\b", 8, "\\b")); + return this.finishTerm(this.parseAtomEscape(loc, true)); + } + return this.finishTerm(new Constant(loc, String.valueOf(c))); } } diff --git a/javascript/extractor/tests/exprs/output/trap/regexp.js.trap b/javascript/extractor/tests/exprs/output/trap/regexp.js.trap index 9a3eb7e3595d..b255ddbb8a3f 100644 --- a/javascript/extractor/tests/exprs/output/trap/regexp.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/regexp.js.trap @@ -792,1409 +792,1412 @@ locations_default(#20250,#10000,26,2,26,4) hasLocation(#20249,#20250) backref(#20249,10) #20251=* -stmts(#20251,2,#20001,26,"/\t\n\r\f\v/;") -#20252=@"loc,{#10000},27,1,27,13" -locations_default(#20252,#10000,27,1,27,13) -hasLocation(#20251,#20252) -stmtContainers(#20251,#20001) -#20253=* -exprs(#20253,5,#20251,0,"/\t\n\r\f\v/") -#20254=@"loc,{#10000},27,1,27,12" -locations_default(#20254,#10000,27,1,27,12) -hasLocation(#20253,#20254) -enclosingStmt(#20253,#20251) -exprContainers(#20253,#20001) -literals("/\t\n\r\f\v/","/\t\n\r\f\v/",#20253) -#20255=* -regexpterm(#20255,1,#20253,0,"\t\n\r\f\v") -#20256=@"loc,{#10000},27,2,27,11" -locations_default(#20256,#10000,27,2,27,11) -hasLocation(#20255,#20256) -#20257=* -regexpterm(#20257,19,#20255,0,"\t") -#20258=@"loc,{#10000},27,2,27,3" -locations_default(#20258,#10000,27,2,27,3) -hasLocation(#20257,#20258) -regexpConstValue(#20257," ") -#20259=* -regexpterm(#20259,19,#20255,1,"\n") -#20260=@"loc,{#10000},27,4,27,5" -locations_default(#20260,#10000,27,4,27,5) -hasLocation(#20259,#20260) -regexpConstValue(#20259," +regexpParseErrors(#20251,#20249,"invalid back reference") +hasLocation(#20251,#20250) +#20252=* +stmts(#20252,2,#20001,26,"/\t\n\r\f\v/;") +#20253=@"loc,{#10000},27,1,27,13" +locations_default(#20253,#10000,27,1,27,13) +hasLocation(#20252,#20253) +stmtContainers(#20252,#20001) +#20254=* +exprs(#20254,5,#20252,0,"/\t\n\r\f\v/") +#20255=@"loc,{#10000},27,1,27,12" +locations_default(#20255,#10000,27,1,27,12) +hasLocation(#20254,#20255) +enclosingStmt(#20254,#20252) +exprContainers(#20254,#20001) +literals("/\t\n\r\f\v/","/\t\n\r\f\v/",#20254) +#20256=* +regexpterm(#20256,1,#20254,0,"\t\n\r\f\v") +#20257=@"loc,{#10000},27,2,27,11" +locations_default(#20257,#10000,27,2,27,11) +hasLocation(#20256,#20257) +#20258=* +regexpterm(#20258,19,#20256,0,"\t") +#20259=@"loc,{#10000},27,2,27,3" +locations_default(#20259,#10000,27,2,27,3) +hasLocation(#20258,#20259) +regexpConstValue(#20258," ") +#20260=* +regexpterm(#20260,19,#20256,1,"\n") +#20261=@"loc,{#10000},27,4,27,5" +locations_default(#20261,#10000,27,4,27,5) +hasLocation(#20260,#20261) +regexpConstValue(#20260," ") -#20261=* -regexpterm(#20261,19,#20255,2,"\r") -#20262=@"loc,{#10000},27,6,27,7" -locations_default(#20262,#10000,27,6,27,7) -hasLocation(#20261,#20262) -regexpConstValue(#20261," ") -#20263=* -regexpterm(#20263,19,#20255,3,"\f") -#20264=@"loc,{#10000},27,8,27,9" -locations_default(#20264,#10000,27,8,27,9) -hasLocation(#20263,#20264) -regexpConstValue(#20263," ") -#20265=* -regexpterm(#20265,19,#20255,4,"\v") -#20266=@"loc,{#10000},27,10,27,11" -locations_default(#20266,#10000,27,10,27,11) -hasLocation(#20265,#20266) -regexpConstValue(#20265," ") -#20267=* -stmts(#20267,2,#20001,27,"/\ca\cN/;") -#20268=@"loc,{#10000},28,1,28,9" -locations_default(#20268,#10000,28,1,28,9) -hasLocation(#20267,#20268) -stmtContainers(#20267,#20001) -#20269=* -exprs(#20269,5,#20267,0,"/\ca\cN/") -#20270=@"loc,{#10000},28,1,28,8" -locations_default(#20270,#10000,28,1,28,8) -hasLocation(#20269,#20270) -enclosingStmt(#20269,#20267) -exprContainers(#20269,#20001) -literals("/\ca\cN/","/\ca\cN/",#20269) -#20271=* -regexpterm(#20271,1,#20269,0,"\ca\cN") -#20272=@"loc,{#10000},28,2,28,7" -locations_default(#20272,#10000,28,2,28,7) -hasLocation(#20271,#20272) -#20273=* -regexpterm(#20273,19,#20271,0,"\ca") -#20274=@"loc,{#10000},28,2,28,4" -locations_default(#20274,#10000,28,2,28,4) -hasLocation(#20273,#20274) -regexpConstValue(#20273,"") -#20275=* -regexpterm(#20275,19,#20271,1,"\cN") -#20276=@"loc,{#10000},28,5,28,7" -locations_default(#20276,#10000,28,5,28,7) -hasLocation(#20275,#20276) -regexpConstValue(#20275,"") -#20277=* -stmts(#20277,2,#20001,28,"/\w\S/;") -#20278=@"loc,{#10000},29,1,29,7" -locations_default(#20278,#10000,29,1,29,7) -hasLocation(#20277,#20278) -stmtContainers(#20277,#20001) -#20279=* -exprs(#20279,5,#20277,0,"/\w\S/") -#20280=@"loc,{#10000},29,1,29,6" -locations_default(#20280,#10000,29,1,29,6) -hasLocation(#20279,#20280) -enclosingStmt(#20279,#20277) -exprContainers(#20279,#20001) -literals("/\w\S/","/\w\S/",#20279) -#20281=* -regexpterm(#20281,1,#20279,0,"\w\S") -#20282=@"loc,{#10000},29,2,29,5" -locations_default(#20282,#10000,29,2,29,5) -hasLocation(#20281,#20282) -#20283=* -regexpterm(#20283,20,#20281,0,"\w") -#20284=@"loc,{#10000},29,2,29,3" -locations_default(#20284,#10000,29,2,29,3) -hasLocation(#20283,#20284) -charClassEscape(#20283,"w") -#20285=* -regexpterm(#20285,20,#20281,1,"\S") -#20286=@"loc,{#10000},29,4,29,5" -locations_default(#20286,#10000,29,4,29,5) -hasLocation(#20285,#20286) -charClassEscape(#20285,"S") -#20287=* -stmts(#20287,2,#20001,29,"/\\/;") -#20288=@"loc,{#10000},30,1,30,5" -locations_default(#20288,#10000,30,1,30,5) -hasLocation(#20287,#20288) -stmtContainers(#20287,#20001) -#20289=* -exprs(#20289,5,#20287,0,"/\\/") -#20290=@"loc,{#10000},30,1,30,4" -locations_default(#20290,#10000,30,1,30,4) -hasLocation(#20289,#20290) -enclosingStmt(#20289,#20287) -exprContainers(#20289,#20001) -literals("/\\/","/\\/",#20289) -#20291=* -regexpterm(#20291,21,#20289,0,"\\") -#20292=@"loc,{#10000},30,2,30,3" -locations_default(#20292,#10000,30,2,30,3) -hasLocation(#20291,#20292) -regexpConstValue(#20291,"\") -#20293=* -stmts(#20293,2,#20001,30,"/[abc]/;") -#20294=@"loc,{#10000},31,1,31,8" -locations_default(#20294,#10000,31,1,31,8) -hasLocation(#20293,#20294) -stmtContainers(#20293,#20001) -#20295=* -exprs(#20295,5,#20293,0,"/[abc]/") -#20296=@"loc,{#10000},31,1,31,7" -locations_default(#20296,#10000,31,1,31,7) -hasLocation(#20295,#20296) -enclosingStmt(#20295,#20293) -exprContainers(#20295,#20001) -literals("/[abc]/","/[abc]/",#20295) -#20297=* -regexpterm(#20297,23,#20295,0,"[abc]") -#20298=@"loc,{#10000},31,2,31,6" -locations_default(#20298,#10000,31,2,31,6) -hasLocation(#20297,#20298) -#20299=* -regexpterm(#20299,14,#20297,0,"a") -#20300=@"loc,{#10000},31,3,31,3" -locations_default(#20300,#10000,31,3,31,3) -hasLocation(#20299,#20300) -regexpConstValue(#20299,"a") -#20301=* -regexpterm(#20301,14,#20297,1,"b") -#20302=@"loc,{#10000},31,4,31,4" -locations_default(#20302,#10000,31,4,31,4) -hasLocation(#20301,#20302) -regexpConstValue(#20301,"b") -#20303=* -regexpterm(#20303,14,#20297,2,"c") -#20304=@"loc,{#10000},31,5,31,5" -locations_default(#20304,#10000,31,5,31,5) -hasLocation(#20303,#20304) -regexpConstValue(#20303,"c") -#20305=* -stmts(#20305,2,#20001,31,"/[a-z]/;") -#20306=@"loc,{#10000},32,1,32,8" -locations_default(#20306,#10000,32,1,32,8) -hasLocation(#20305,#20306) -stmtContainers(#20305,#20001) -#20307=* -exprs(#20307,5,#20305,0,"/[a-z]/") -#20308=@"loc,{#10000},32,1,32,7" -locations_default(#20308,#10000,32,1,32,7) -hasLocation(#20307,#20308) -enclosingStmt(#20307,#20305) -exprContainers(#20307,#20001) -literals("/[a-z]/","/[a-z]/",#20307) -#20309=* -regexpterm(#20309,23,#20307,0,"[a-z]") -#20310=@"loc,{#10000},32,2,32,6" -locations_default(#20310,#10000,32,2,32,6) -hasLocation(#20309,#20310) -#20311=* -regexpterm(#20311,24,#20309,0,"a-z") -#20312=@"loc,{#10000},32,3,32,5" -locations_default(#20312,#10000,32,3,32,5) -hasLocation(#20311,#20312) -#20313=* -regexpterm(#20313,14,#20311,0,"a") -#20314=@"loc,{#10000},32,3,32,3" -locations_default(#20314,#10000,32,3,32,3) -hasLocation(#20313,#20314) -regexpConstValue(#20313,"a") -#20315=* -regexpterm(#20315,14,#20311,1,"z") -#20316=@"loc,{#10000},32,5,32,5" -locations_default(#20316,#10000,32,5,32,5) -hasLocation(#20315,#20316) -regexpConstValue(#20315,"z") -#20317=* -stmts(#20317,2,#20001,32,"/[a-zA-Z]/;") -#20318=@"loc,{#10000},33,1,33,11" -locations_default(#20318,#10000,33,1,33,11) -hasLocation(#20317,#20318) -stmtContainers(#20317,#20001) -#20319=* -exprs(#20319,5,#20317,0,"/[a-zA-Z]/") -#20320=@"loc,{#10000},33,1,33,10" -locations_default(#20320,#10000,33,1,33,10) -hasLocation(#20319,#20320) -enclosingStmt(#20319,#20317) -exprContainers(#20319,#20001) -literals("/[a-zA-Z]/","/[a-zA-Z]/",#20319) -#20321=* -regexpterm(#20321,23,#20319,0,"[a-zA-Z]") -#20322=@"loc,{#10000},33,2,33,9" -locations_default(#20322,#10000,33,2,33,9) -hasLocation(#20321,#20322) -#20323=* -regexpterm(#20323,24,#20321,0,"a-z") -#20324=@"loc,{#10000},33,3,33,5" -locations_default(#20324,#10000,33,3,33,5) -hasLocation(#20323,#20324) -#20325=* -regexpterm(#20325,14,#20323,0,"a") -#20326=@"loc,{#10000},33,3,33,3" -locations_default(#20326,#10000,33,3,33,3) -hasLocation(#20325,#20326) -regexpConstValue(#20325,"a") -#20327=* -regexpterm(#20327,14,#20323,1,"z") -#20328=@"loc,{#10000},33,5,33,5" -locations_default(#20328,#10000,33,5,33,5) -hasLocation(#20327,#20328) -regexpConstValue(#20327,"z") -#20329=* -regexpterm(#20329,24,#20321,1,"A-Z") -#20330=@"loc,{#10000},33,6,33,8" -locations_default(#20330,#10000,33,6,33,8) -hasLocation(#20329,#20330) -#20331=* -regexpterm(#20331,14,#20329,0,"A") -#20332=@"loc,{#10000},33,6,33,6" -locations_default(#20332,#10000,33,6,33,6) -hasLocation(#20331,#20332) -regexpConstValue(#20331,"A") -#20333=* -regexpterm(#20333,14,#20329,1,"Z") -#20334=@"loc,{#10000},33,8,33,8" -locations_default(#20334,#10000,33,8,33,8) -hasLocation(#20333,#20334) -regexpConstValue(#20333,"Z") -#20335=* -stmts(#20335,2,#20001,33,"/[-a-z]/;") -#20336=@"loc,{#10000},34,1,34,9" -locations_default(#20336,#10000,34,1,34,9) -hasLocation(#20335,#20336) -stmtContainers(#20335,#20001) -#20337=* -exprs(#20337,5,#20335,0,"/[-a-z]/") -#20338=@"loc,{#10000},34,1,34,8" -locations_default(#20338,#10000,34,1,34,8) -hasLocation(#20337,#20338) -enclosingStmt(#20337,#20335) -exprContainers(#20337,#20001) -literals("/[-a-z]/","/[-a-z]/",#20337) -#20339=* -regexpterm(#20339,23,#20337,0,"[-a-z]") -#20340=@"loc,{#10000},34,2,34,7" -locations_default(#20340,#10000,34,2,34,7) -hasLocation(#20339,#20340) -#20341=* -regexpterm(#20341,14,#20339,0,"-") -#20342=@"loc,{#10000},34,3,34,3" -locations_default(#20342,#10000,34,3,34,3) -hasLocation(#20341,#20342) -regexpConstValue(#20341,"-") -#20343=* -regexpterm(#20343,24,#20339,1,"a-z") -#20344=@"loc,{#10000},34,4,34,6" -locations_default(#20344,#10000,34,4,34,6) -hasLocation(#20343,#20344) -#20345=* -regexpterm(#20345,14,#20343,0,"a") -#20346=@"loc,{#10000},34,4,34,4" -locations_default(#20346,#10000,34,4,34,4) -hasLocation(#20345,#20346) -regexpConstValue(#20345,"a") -#20347=* -regexpterm(#20347,14,#20343,1,"z") -#20348=@"loc,{#10000},34,6,34,6" -locations_default(#20348,#10000,34,6,34,6) -hasLocation(#20347,#20348) -regexpConstValue(#20347,"z") -#20349=* -stmts(#20349,2,#20001,34,"/[^a-z]/;") -#20350=@"loc,{#10000},35,1,35,9" -locations_default(#20350,#10000,35,1,35,9) -hasLocation(#20349,#20350) -stmtContainers(#20349,#20001) -#20351=* -exprs(#20351,5,#20349,0,"/[^a-z]/") -#20352=@"loc,{#10000},35,1,35,8" -locations_default(#20352,#10000,35,1,35,8) -hasLocation(#20351,#20352) -enclosingStmt(#20351,#20349) -exprContainers(#20351,#20001) -literals("/[^a-z]/","/[^a-z]/",#20351) -#20353=* -regexpterm(#20353,23,#20351,0,"[^a-z]") -#20354=@"loc,{#10000},35,2,35,7" -locations_default(#20354,#10000,35,2,35,7) -hasLocation(#20353,#20354) -isInverted(#20353) -#20355=* -regexpterm(#20355,24,#20353,0,"a-z") -#20356=@"loc,{#10000},35,4,35,6" -locations_default(#20356,#10000,35,4,35,6) -hasLocation(#20355,#20356) -#20357=* -regexpterm(#20357,14,#20355,0,"a") -#20358=@"loc,{#10000},35,4,35,4" -locations_default(#20358,#10000,35,4,35,4) -hasLocation(#20357,#20358) -regexpConstValue(#20357,"a") -#20359=* -regexpterm(#20359,14,#20355,1,"z") -#20360=@"loc,{#10000},35,6,35,6" -locations_default(#20360,#10000,35,6,35,6) -hasLocation(#20359,#20360) -regexpConstValue(#20359,"z") -#20361=* -stmts(#20361,2,#20001,35,"/[a\b\x0c]/;") -#20362=@"loc,{#10000},36,1,36,12" -locations_default(#20362,#10000,36,1,36,12) -hasLocation(#20361,#20362) -stmtContainers(#20361,#20001) -#20363=* -exprs(#20363,5,#20361,0,"/[a\b\x0c]/") -#20364=@"loc,{#10000},36,1,36,11" -locations_default(#20364,#10000,36,1,36,11) -hasLocation(#20363,#20364) -enclosingStmt(#20363,#20361) -exprContainers(#20363,#20001) -literals("/[a\b\x0c]/","/[a\b\x0c]/",#20363) -#20365=* -regexpterm(#20365,23,#20363,0,"[a\b\x0c]") -#20366=@"loc,{#10000},36,2,36,10" -locations_default(#20366,#10000,36,2,36,10) -hasLocation(#20365,#20366) -#20367=* -regexpterm(#20367,14,#20365,0,"a") -#20368=@"loc,{#10000},36,3,36,3" -locations_default(#20368,#10000,36,3,36,3) -hasLocation(#20367,#20368) -regexpConstValue(#20367,"a") -#20369=* -regexpterm(#20369,19,#20365,1,"\b") -#20370=@"loc,{#10000},36,4,36,5" -locations_default(#20370,#10000,36,4,36,5) -hasLocation(#20369,#20370) -regexpConstValue(#20369,"") -#20371=* -regexpterm(#20371,15,#20365,2,"\x0c") -#20372=@"loc,{#10000},36,6,36,9" -locations_default(#20372,#10000,36,6,36,9) -hasLocation(#20371,#20372) -regexpConstValue(#20371," ") -#20373=* -stmts(#20373,2,#20001,36,"/a{/;") -#20374=@"loc,{#10000},37,1,37,5" -locations_default(#20374,#10000,37,1,37,5) -hasLocation(#20373,#20374) -stmtContainers(#20373,#20001) -#20375=* -exprs(#20375,5,#20373,0,"/a{/") -#20376=@"loc,{#10000},37,1,37,4" -locations_default(#20376,#10000,37,1,37,4) -hasLocation(#20375,#20376) -enclosingStmt(#20375,#20373) -exprContainers(#20375,#20001) -literals("/a{/","/a{/",#20375) -#20377=* -regexpterm(#20377,11,#20375,0,"a{") -#20378=@"loc,{#10000},37,2,37,3" -locations_default(#20378,#10000,37,2,37,3) -hasLocation(#20377,#20378) -isGreedy(#20377) -rangeQuantifierLowerBound(#20377,0) -#20379=* -regexpterm(#20379,14,#20377,0,"a") -#20380=@"loc,{#10000},37,2,37,2" -locations_default(#20380,#10000,37,2,37,2) -hasLocation(#20379,#20380) -regexpConstValue(#20379,"a") -#20381=* -regexpParseErrors(#20381,#20377,"expected digit") -#20382=@"loc,{#10000},37,4,37,4" -locations_default(#20382,#10000,37,4,37,4) -hasLocation(#20381,#20382) -#20383=* -regexpParseErrors(#20383,#20377,"expected '}'") -#20384=@"loc,{#10000},37,3,37,3" -locations_default(#20384,#10000,37,3,37,3) -hasLocation(#20383,#20384) -#20385=* -stmts(#20385,2,#20001,37,"/a{b}/;") -#20386=@"loc,{#10000},38,1,38,7" -locations_default(#20386,#10000,38,1,38,7) -hasLocation(#20385,#20386) -stmtContainers(#20385,#20001) -#20387=* -exprs(#20387,5,#20385,0,"/a{b}/") -#20388=@"loc,{#10000},38,1,38,6" -locations_default(#20388,#10000,38,1,38,6) -hasLocation(#20387,#20388) -enclosingStmt(#20387,#20385) -exprContainers(#20387,#20001) -literals("/a{b}/","/a{b}/",#20387) -#20389=* -regexpterm(#20389,1,#20387,0,"a{b}") -#20390=@"loc,{#10000},38,2,38,5" -locations_default(#20390,#10000,38,2,38,5) -hasLocation(#20389,#20390) -#20391=* -regexpterm(#20391,11,#20389,0,"a{") -#20392=@"loc,{#10000},38,2,38,3" -locations_default(#20392,#10000,38,2,38,3) -hasLocation(#20391,#20392) -isGreedy(#20391) -rangeQuantifierLowerBound(#20391,0) -#20393=* -regexpterm(#20393,14,#20391,0,"a") -#20394=@"loc,{#10000},38,2,38,2" -locations_default(#20394,#10000,38,2,38,2) -hasLocation(#20393,#20394) -regexpConstValue(#20393,"a") -#20395=* -regexpterm(#20395,14,#20389,1,"b") -#20396=@"loc,{#10000},38,4,38,4" -locations_default(#20396,#10000,38,4,38,4) -hasLocation(#20395,#20396) -regexpConstValue(#20395,"b") -#20397=* -regexpterm(#20397,14,#20389,2,"}") -#20398=@"loc,{#10000},38,5,38,5" -locations_default(#20398,#10000,38,5,38,5) -hasLocation(#20397,#20398) -regexpConstValue(#20397,"}") -#20399=* -regexpParseErrors(#20399,#20389,"expected digit") -hasLocation(#20399,#20396) +#20262=* +regexpterm(#20262,19,#20256,2,"\r") +#20263=@"loc,{#10000},27,6,27,7" +locations_default(#20263,#10000,27,6,27,7) +hasLocation(#20262,#20263) +regexpConstValue(#20262," ") +#20264=* +regexpterm(#20264,19,#20256,3,"\f") +#20265=@"loc,{#10000},27,8,27,9" +locations_default(#20265,#10000,27,8,27,9) +hasLocation(#20264,#20265) +regexpConstValue(#20264," ") +#20266=* +regexpterm(#20266,19,#20256,4,"\v") +#20267=@"loc,{#10000},27,10,27,11" +locations_default(#20267,#10000,27,10,27,11) +hasLocation(#20266,#20267) +regexpConstValue(#20266," ") +#20268=* +stmts(#20268,2,#20001,27,"/\ca\cN/;") +#20269=@"loc,{#10000},28,1,28,9" +locations_default(#20269,#10000,28,1,28,9) +hasLocation(#20268,#20269) +stmtContainers(#20268,#20001) +#20270=* +exprs(#20270,5,#20268,0,"/\ca\cN/") +#20271=@"loc,{#10000},28,1,28,8" +locations_default(#20271,#10000,28,1,28,8) +hasLocation(#20270,#20271) +enclosingStmt(#20270,#20268) +exprContainers(#20270,#20001) +literals("/\ca\cN/","/\ca\cN/",#20270) +#20272=* +regexpterm(#20272,1,#20270,0,"\ca\cN") +#20273=@"loc,{#10000},28,2,28,7" +locations_default(#20273,#10000,28,2,28,7) +hasLocation(#20272,#20273) +#20274=* +regexpterm(#20274,19,#20272,0,"\ca") +#20275=@"loc,{#10000},28,2,28,4" +locations_default(#20275,#10000,28,2,28,4) +hasLocation(#20274,#20275) +regexpConstValue(#20274,"") +#20276=* +regexpterm(#20276,19,#20272,1,"\cN") +#20277=@"loc,{#10000},28,5,28,7" +locations_default(#20277,#10000,28,5,28,7) +hasLocation(#20276,#20277) +regexpConstValue(#20276,"") +#20278=* +stmts(#20278,2,#20001,28,"/\w\S/;") +#20279=@"loc,{#10000},29,1,29,7" +locations_default(#20279,#10000,29,1,29,7) +hasLocation(#20278,#20279) +stmtContainers(#20278,#20001) +#20280=* +exprs(#20280,5,#20278,0,"/\w\S/") +#20281=@"loc,{#10000},29,1,29,6" +locations_default(#20281,#10000,29,1,29,6) +hasLocation(#20280,#20281) +enclosingStmt(#20280,#20278) +exprContainers(#20280,#20001) +literals("/\w\S/","/\w\S/",#20280) +#20282=* +regexpterm(#20282,1,#20280,0,"\w\S") +#20283=@"loc,{#10000},29,2,29,5" +locations_default(#20283,#10000,29,2,29,5) +hasLocation(#20282,#20283) +#20284=* +regexpterm(#20284,20,#20282,0,"\w") +#20285=@"loc,{#10000},29,2,29,3" +locations_default(#20285,#10000,29,2,29,3) +hasLocation(#20284,#20285) +charClassEscape(#20284,"w") +#20286=* +regexpterm(#20286,20,#20282,1,"\S") +#20287=@"loc,{#10000},29,4,29,5" +locations_default(#20287,#10000,29,4,29,5) +hasLocation(#20286,#20287) +charClassEscape(#20286,"S") +#20288=* +stmts(#20288,2,#20001,29,"/\\/;") +#20289=@"loc,{#10000},30,1,30,5" +locations_default(#20289,#10000,30,1,30,5) +hasLocation(#20288,#20289) +stmtContainers(#20288,#20001) +#20290=* +exprs(#20290,5,#20288,0,"/\\/") +#20291=@"loc,{#10000},30,1,30,4" +locations_default(#20291,#10000,30,1,30,4) +hasLocation(#20290,#20291) +enclosingStmt(#20290,#20288) +exprContainers(#20290,#20001) +literals("/\\/","/\\/",#20290) +#20292=* +regexpterm(#20292,21,#20290,0,"\\") +#20293=@"loc,{#10000},30,2,30,3" +locations_default(#20293,#10000,30,2,30,3) +hasLocation(#20292,#20293) +regexpConstValue(#20292,"\") +#20294=* +stmts(#20294,2,#20001,30,"/[abc]/;") +#20295=@"loc,{#10000},31,1,31,8" +locations_default(#20295,#10000,31,1,31,8) +hasLocation(#20294,#20295) +stmtContainers(#20294,#20001) +#20296=* +exprs(#20296,5,#20294,0,"/[abc]/") +#20297=@"loc,{#10000},31,1,31,7" +locations_default(#20297,#10000,31,1,31,7) +hasLocation(#20296,#20297) +enclosingStmt(#20296,#20294) +exprContainers(#20296,#20001) +literals("/[abc]/","/[abc]/",#20296) +#20298=* +regexpterm(#20298,23,#20296,0,"[abc]") +#20299=@"loc,{#10000},31,2,31,6" +locations_default(#20299,#10000,31,2,31,6) +hasLocation(#20298,#20299) +#20300=* +regexpterm(#20300,14,#20298,0,"a") +#20301=@"loc,{#10000},31,3,31,3" +locations_default(#20301,#10000,31,3,31,3) +hasLocation(#20300,#20301) +regexpConstValue(#20300,"a") +#20302=* +regexpterm(#20302,14,#20298,1,"b") +#20303=@"loc,{#10000},31,4,31,4" +locations_default(#20303,#10000,31,4,31,4) +hasLocation(#20302,#20303) +regexpConstValue(#20302,"b") +#20304=* +regexpterm(#20304,14,#20298,2,"c") +#20305=@"loc,{#10000},31,5,31,5" +locations_default(#20305,#10000,31,5,31,5) +hasLocation(#20304,#20305) +regexpConstValue(#20304,"c") +#20306=* +stmts(#20306,2,#20001,31,"/[a-z]/;") +#20307=@"loc,{#10000},32,1,32,8" +locations_default(#20307,#10000,32,1,32,8) +hasLocation(#20306,#20307) +stmtContainers(#20306,#20001) +#20308=* +exprs(#20308,5,#20306,0,"/[a-z]/") +#20309=@"loc,{#10000},32,1,32,7" +locations_default(#20309,#10000,32,1,32,7) +hasLocation(#20308,#20309) +enclosingStmt(#20308,#20306) +exprContainers(#20308,#20001) +literals("/[a-z]/","/[a-z]/",#20308) +#20310=* +regexpterm(#20310,23,#20308,0,"[a-z]") +#20311=@"loc,{#10000},32,2,32,6" +locations_default(#20311,#10000,32,2,32,6) +hasLocation(#20310,#20311) +#20312=* +regexpterm(#20312,24,#20310,0,"a-z") +#20313=@"loc,{#10000},32,3,32,5" +locations_default(#20313,#10000,32,3,32,5) +hasLocation(#20312,#20313) +#20314=* +regexpterm(#20314,14,#20312,0,"a") +#20315=@"loc,{#10000},32,3,32,3" +locations_default(#20315,#10000,32,3,32,3) +hasLocation(#20314,#20315) +regexpConstValue(#20314,"a") +#20316=* +regexpterm(#20316,14,#20312,1,"z") +#20317=@"loc,{#10000},32,5,32,5" +locations_default(#20317,#10000,32,5,32,5) +hasLocation(#20316,#20317) +regexpConstValue(#20316,"z") +#20318=* +stmts(#20318,2,#20001,32,"/[a-zA-Z]/;") +#20319=@"loc,{#10000},33,1,33,11" +locations_default(#20319,#10000,33,1,33,11) +hasLocation(#20318,#20319) +stmtContainers(#20318,#20001) +#20320=* +exprs(#20320,5,#20318,0,"/[a-zA-Z]/") +#20321=@"loc,{#10000},33,1,33,10" +locations_default(#20321,#10000,33,1,33,10) +hasLocation(#20320,#20321) +enclosingStmt(#20320,#20318) +exprContainers(#20320,#20001) +literals("/[a-zA-Z]/","/[a-zA-Z]/",#20320) +#20322=* +regexpterm(#20322,23,#20320,0,"[a-zA-Z]") +#20323=@"loc,{#10000},33,2,33,9" +locations_default(#20323,#10000,33,2,33,9) +hasLocation(#20322,#20323) +#20324=* +regexpterm(#20324,24,#20322,0,"a-z") +#20325=@"loc,{#10000},33,3,33,5" +locations_default(#20325,#10000,33,3,33,5) +hasLocation(#20324,#20325) +#20326=* +regexpterm(#20326,14,#20324,0,"a") +#20327=@"loc,{#10000},33,3,33,3" +locations_default(#20327,#10000,33,3,33,3) +hasLocation(#20326,#20327) +regexpConstValue(#20326,"a") +#20328=* +regexpterm(#20328,14,#20324,1,"z") +#20329=@"loc,{#10000},33,5,33,5" +locations_default(#20329,#10000,33,5,33,5) +hasLocation(#20328,#20329) +regexpConstValue(#20328,"z") +#20330=* +regexpterm(#20330,24,#20322,1,"A-Z") +#20331=@"loc,{#10000},33,6,33,8" +locations_default(#20331,#10000,33,6,33,8) +hasLocation(#20330,#20331) +#20332=* +regexpterm(#20332,14,#20330,0,"A") +#20333=@"loc,{#10000},33,6,33,6" +locations_default(#20333,#10000,33,6,33,6) +hasLocation(#20332,#20333) +regexpConstValue(#20332,"A") +#20334=* +regexpterm(#20334,14,#20330,1,"Z") +#20335=@"loc,{#10000},33,8,33,8" +locations_default(#20335,#10000,33,8,33,8) +hasLocation(#20334,#20335) +regexpConstValue(#20334,"Z") +#20336=* +stmts(#20336,2,#20001,33,"/[-a-z]/;") +#20337=@"loc,{#10000},34,1,34,9" +locations_default(#20337,#10000,34,1,34,9) +hasLocation(#20336,#20337) +stmtContainers(#20336,#20001) +#20338=* +exprs(#20338,5,#20336,0,"/[-a-z]/") +#20339=@"loc,{#10000},34,1,34,8" +locations_default(#20339,#10000,34,1,34,8) +hasLocation(#20338,#20339) +enclosingStmt(#20338,#20336) +exprContainers(#20338,#20001) +literals("/[-a-z]/","/[-a-z]/",#20338) +#20340=* +regexpterm(#20340,23,#20338,0,"[-a-z]") +#20341=@"loc,{#10000},34,2,34,7" +locations_default(#20341,#10000,34,2,34,7) +hasLocation(#20340,#20341) +#20342=* +regexpterm(#20342,14,#20340,0,"-") +#20343=@"loc,{#10000},34,3,34,3" +locations_default(#20343,#10000,34,3,34,3) +hasLocation(#20342,#20343) +regexpConstValue(#20342,"-") +#20344=* +regexpterm(#20344,24,#20340,1,"a-z") +#20345=@"loc,{#10000},34,4,34,6" +locations_default(#20345,#10000,34,4,34,6) +hasLocation(#20344,#20345) +#20346=* +regexpterm(#20346,14,#20344,0,"a") +#20347=@"loc,{#10000},34,4,34,4" +locations_default(#20347,#10000,34,4,34,4) +hasLocation(#20346,#20347) +regexpConstValue(#20346,"a") +#20348=* +regexpterm(#20348,14,#20344,1,"z") +#20349=@"loc,{#10000},34,6,34,6" +locations_default(#20349,#10000,34,6,34,6) +hasLocation(#20348,#20349) +regexpConstValue(#20348,"z") +#20350=* +stmts(#20350,2,#20001,34,"/[^a-z]/;") +#20351=@"loc,{#10000},35,1,35,9" +locations_default(#20351,#10000,35,1,35,9) +hasLocation(#20350,#20351) +stmtContainers(#20350,#20001) +#20352=* +exprs(#20352,5,#20350,0,"/[^a-z]/") +#20353=@"loc,{#10000},35,1,35,8" +locations_default(#20353,#10000,35,1,35,8) +hasLocation(#20352,#20353) +enclosingStmt(#20352,#20350) +exprContainers(#20352,#20001) +literals("/[^a-z]/","/[^a-z]/",#20352) +#20354=* +regexpterm(#20354,23,#20352,0,"[^a-z]") +#20355=@"loc,{#10000},35,2,35,7" +locations_default(#20355,#10000,35,2,35,7) +hasLocation(#20354,#20355) +isInverted(#20354) +#20356=* +regexpterm(#20356,24,#20354,0,"a-z") +#20357=@"loc,{#10000},35,4,35,6" +locations_default(#20357,#10000,35,4,35,6) +hasLocation(#20356,#20357) +#20358=* +regexpterm(#20358,14,#20356,0,"a") +#20359=@"loc,{#10000},35,4,35,4" +locations_default(#20359,#10000,35,4,35,4) +hasLocation(#20358,#20359) +regexpConstValue(#20358,"a") +#20360=* +regexpterm(#20360,14,#20356,1,"z") +#20361=@"loc,{#10000},35,6,35,6" +locations_default(#20361,#10000,35,6,35,6) +hasLocation(#20360,#20361) +regexpConstValue(#20360,"z") +#20362=* +stmts(#20362,2,#20001,35,"/[a\b\x0c]/;") +#20363=@"loc,{#10000},36,1,36,12" +locations_default(#20363,#10000,36,1,36,12) +hasLocation(#20362,#20363) +stmtContainers(#20362,#20001) +#20364=* +exprs(#20364,5,#20362,0,"/[a\b\x0c]/") +#20365=@"loc,{#10000},36,1,36,11" +locations_default(#20365,#10000,36,1,36,11) +hasLocation(#20364,#20365) +enclosingStmt(#20364,#20362) +exprContainers(#20364,#20001) +literals("/[a\b\x0c]/","/[a\b\x0c]/",#20364) +#20366=* +regexpterm(#20366,23,#20364,0,"[a\b\x0c]") +#20367=@"loc,{#10000},36,2,36,10" +locations_default(#20367,#10000,36,2,36,10) +hasLocation(#20366,#20367) +#20368=* +regexpterm(#20368,14,#20366,0,"a") +#20369=@"loc,{#10000},36,3,36,3" +locations_default(#20369,#10000,36,3,36,3) +hasLocation(#20368,#20369) +regexpConstValue(#20368,"a") +#20370=* +regexpterm(#20370,19,#20366,1,"\b") +#20371=@"loc,{#10000},36,4,36,5" +locations_default(#20371,#10000,36,4,36,5) +hasLocation(#20370,#20371) +regexpConstValue(#20370,"") +#20372=* +regexpterm(#20372,15,#20366,2,"\x0c") +#20373=@"loc,{#10000},36,6,36,9" +locations_default(#20373,#10000,36,6,36,9) +hasLocation(#20372,#20373) +regexpConstValue(#20372," ") +#20374=* +stmts(#20374,2,#20001,36,"/a{/;") +#20375=@"loc,{#10000},37,1,37,5" +locations_default(#20375,#10000,37,1,37,5) +hasLocation(#20374,#20375) +stmtContainers(#20374,#20001) +#20376=* +exprs(#20376,5,#20374,0,"/a{/") +#20377=@"loc,{#10000},37,1,37,4" +locations_default(#20377,#10000,37,1,37,4) +hasLocation(#20376,#20377) +enclosingStmt(#20376,#20374) +exprContainers(#20376,#20001) +literals("/a{/","/a{/",#20376) +#20378=* +regexpterm(#20378,11,#20376,0,"a{") +#20379=@"loc,{#10000},37,2,37,3" +locations_default(#20379,#10000,37,2,37,3) +hasLocation(#20378,#20379) +isGreedy(#20378) +rangeQuantifierLowerBound(#20378,0) +#20380=* +regexpterm(#20380,14,#20378,0,"a") +#20381=@"loc,{#10000},37,2,37,2" +locations_default(#20381,#10000,37,2,37,2) +hasLocation(#20380,#20381) +regexpConstValue(#20380,"a") +#20382=* +regexpParseErrors(#20382,#20378,"expected digit") +#20383=@"loc,{#10000},37,4,37,4" +locations_default(#20383,#10000,37,4,37,4) +hasLocation(#20382,#20383) +#20384=* +regexpParseErrors(#20384,#20378,"expected '}'") +#20385=@"loc,{#10000},37,3,37,3" +locations_default(#20385,#10000,37,3,37,3) +hasLocation(#20384,#20385) +#20386=* +stmts(#20386,2,#20001,37,"/a{b}/;") +#20387=@"loc,{#10000},38,1,38,7" +locations_default(#20387,#10000,38,1,38,7) +hasLocation(#20386,#20387) +stmtContainers(#20386,#20001) +#20388=* +exprs(#20388,5,#20386,0,"/a{b}/") +#20389=@"loc,{#10000},38,1,38,6" +locations_default(#20389,#10000,38,1,38,6) +hasLocation(#20388,#20389) +enclosingStmt(#20388,#20386) +exprContainers(#20388,#20001) +literals("/a{b}/","/a{b}/",#20388) +#20390=* +regexpterm(#20390,1,#20388,0,"a{b}") +#20391=@"loc,{#10000},38,2,38,5" +locations_default(#20391,#10000,38,2,38,5) +hasLocation(#20390,#20391) +#20392=* +regexpterm(#20392,11,#20390,0,"a{") +#20393=@"loc,{#10000},38,2,38,3" +locations_default(#20393,#10000,38,2,38,3) +hasLocation(#20392,#20393) +isGreedy(#20392) +rangeQuantifierLowerBound(#20392,0) +#20394=* +regexpterm(#20394,14,#20392,0,"a") +#20395=@"loc,{#10000},38,2,38,2" +locations_default(#20395,#10000,38,2,38,2) +hasLocation(#20394,#20395) +regexpConstValue(#20394,"a") +#20396=* +regexpterm(#20396,14,#20390,1,"b") +#20397=@"loc,{#10000},38,4,38,4" +locations_default(#20397,#10000,38,4,38,4) +hasLocation(#20396,#20397) +regexpConstValue(#20396,"b") +#20398=* +regexpterm(#20398,14,#20390,2,"}") +#20399=@"loc,{#10000},38,5,38,5" +locations_default(#20399,#10000,38,5,38,5) +hasLocation(#20398,#20399) +regexpConstValue(#20398,"}") #20400=* -regexpParseErrors(#20400,#20389,"expected '}'") -#20401=@"loc,{#10000},38,3,38,3" -locations_default(#20401,#10000,38,3,38,3) -hasLocation(#20400,#20401) -#20402=* -regexpParseErrors(#20402,#20389,"unexpected character") -hasLocation(#20402,#20398) +regexpParseErrors(#20400,#20390,"expected digit") +hasLocation(#20400,#20397) +#20401=* +regexpParseErrors(#20401,#20390,"expected '}'") +#20402=@"loc,{#10000},38,3,38,3" +locations_default(#20402,#10000,38,3,38,3) +hasLocation(#20401,#20402) #20403=* -stmts(#20403,2,#20001,38,"/a{2/;") -#20404=@"loc,{#10000},39,1,39,6" -locations_default(#20404,#10000,39,1,39,6) -hasLocation(#20403,#20404) -stmtContainers(#20403,#20001) -#20405=* -exprs(#20405,5,#20403,0,"/a{2/") -#20406=@"loc,{#10000},39,1,39,5" -locations_default(#20406,#10000,39,1,39,5) -hasLocation(#20405,#20406) -enclosingStmt(#20405,#20403) -exprContainers(#20405,#20001) -literals("/a{2/","/a{2/",#20405) -#20407=* -regexpterm(#20407,11,#20405,0,"a{2") -#20408=@"loc,{#10000},39,2,39,4" -locations_default(#20408,#10000,39,2,39,4) -hasLocation(#20407,#20408) -isGreedy(#20407) -rangeQuantifierLowerBound(#20407,2) -#20409=* -regexpterm(#20409,14,#20407,0,"a") -#20410=@"loc,{#10000},39,2,39,2" -locations_default(#20410,#10000,39,2,39,2) -hasLocation(#20409,#20410) -regexpConstValue(#20409,"a") -#20411=* -regexpParseErrors(#20411,#20407,"expected '}'") -#20412=@"loc,{#10000},39,4,39,4" -locations_default(#20412,#10000,39,4,39,4) -hasLocation(#20411,#20412) -#20413=* -stmts(#20413,2,#20001,39,"/\xa/;") -#20414=@"loc,{#10000},40,1,40,6" -locations_default(#20414,#10000,40,1,40,6) -hasLocation(#20413,#20414) -stmtContainers(#20413,#20001) -#20415=* -exprs(#20415,5,#20413,0,"/\xa/") -#20416=@"loc,{#10000},40,1,40,5" -locations_default(#20416,#10000,40,1,40,5) -hasLocation(#20415,#20416) -enclosingStmt(#20415,#20413) -exprContainers(#20415,#20001) -literals("/\xa/","/\xa/",#20415) -#20417=* -regexpterm(#20417,15,#20415,0,"\xa") -#20418=@"loc,{#10000},40,2,40,4" -locations_default(#20418,#10000,40,2,40,4) -hasLocation(#20417,#20418) -regexpConstValue(#20417," +regexpParseErrors(#20403,#20390,"unexpected character") +hasLocation(#20403,#20399) +#20404=* +stmts(#20404,2,#20001,38,"/a{2/;") +#20405=@"loc,{#10000},39,1,39,6" +locations_default(#20405,#10000,39,1,39,6) +hasLocation(#20404,#20405) +stmtContainers(#20404,#20001) +#20406=* +exprs(#20406,5,#20404,0,"/a{2/") +#20407=@"loc,{#10000},39,1,39,5" +locations_default(#20407,#10000,39,1,39,5) +hasLocation(#20406,#20407) +enclosingStmt(#20406,#20404) +exprContainers(#20406,#20001) +literals("/a{2/","/a{2/",#20406) +#20408=* +regexpterm(#20408,11,#20406,0,"a{2") +#20409=@"loc,{#10000},39,2,39,4" +locations_default(#20409,#10000,39,2,39,4) +hasLocation(#20408,#20409) +isGreedy(#20408) +rangeQuantifierLowerBound(#20408,2) +#20410=* +regexpterm(#20410,14,#20408,0,"a") +#20411=@"loc,{#10000},39,2,39,2" +locations_default(#20411,#10000,39,2,39,2) +hasLocation(#20410,#20411) +regexpConstValue(#20410,"a") +#20412=* +regexpParseErrors(#20412,#20408,"expected '}'") +#20413=@"loc,{#10000},39,4,39,4" +locations_default(#20413,#10000,39,4,39,4) +hasLocation(#20412,#20413) +#20414=* +stmts(#20414,2,#20001,39,"/\xa/;") +#20415=@"loc,{#10000},40,1,40,6" +locations_default(#20415,#10000,40,1,40,6) +hasLocation(#20414,#20415) +stmtContainers(#20414,#20001) +#20416=* +exprs(#20416,5,#20414,0,"/\xa/") +#20417=@"loc,{#10000},40,1,40,5" +locations_default(#20417,#10000,40,1,40,5) +hasLocation(#20416,#20417) +enclosingStmt(#20416,#20414) +exprContainers(#20416,#20001) +literals("/\xa/","/\xa/",#20416) +#20418=* +regexpterm(#20418,15,#20416,0,"\xa") +#20419=@"loc,{#10000},40,2,40,4" +locations_default(#20419,#10000,40,2,40,4) +hasLocation(#20418,#20419) +regexpConstValue(#20418," ") -#20419=* -regexpParseErrors(#20419,#20417,"unexpected end of regular expression") -#20420=@"loc,{#10000},40,5,40,5" -locations_default(#20420,#10000,40,5,40,5) -hasLocation(#20419,#20420) -#20421=* -stmts(#20421,2,#20001,40,"/\c0/;") -#20422=@"loc,{#10000},41,1,41,6" -locations_default(#20422,#10000,41,1,41,6) -hasLocation(#20421,#20422) -stmtContainers(#20421,#20001) -#20423=* -exprs(#20423,5,#20421,0,"/\c0/") -#20424=@"loc,{#10000},41,1,41,5" -locations_default(#20424,#10000,41,1,41,5) -hasLocation(#20423,#20424) -enclosingStmt(#20423,#20421) -exprContainers(#20423,#20001) -literals("/\c0/","/\c0/",#20423) -#20425=* -regexpterm(#20425,19,#20423,0,"\c0") -#20426=@"loc,{#10000},41,2,41,4" -locations_default(#20426,#10000,41,2,41,4) -hasLocation(#20425,#20426) -regexpConstValue(#20425,"") -#20427=* -regexpParseErrors(#20427,#20425,"expected control letter") -#20428=@"loc,{#10000},41,4,41,4" -locations_default(#20428,#10000,41,4,41,4) -hasLocation(#20427,#20428) -#20429=* -stmts(#20429,2,#20001,41,"/[]/;") -#20430=@"loc,{#10000},42,1,42,5" -locations_default(#20430,#10000,42,1,42,5) -hasLocation(#20429,#20430) -stmtContainers(#20429,#20001) -#20431=* -exprs(#20431,5,#20429,0,"/[]/") -#20432=@"loc,{#10000},42,1,42,4" -locations_default(#20432,#10000,42,1,42,4) -hasLocation(#20431,#20432) -enclosingStmt(#20431,#20429) -exprContainers(#20431,#20001) -literals("/[]/","/[]/",#20431) -#20433=* -regexpterm(#20433,23,#20431,0,"[]") -#20434=@"loc,{#10000},42,2,42,3" -locations_default(#20434,#10000,42,2,42,3) -hasLocation(#20433,#20434) -#20435=* -stmts(#20435,2,#20001,42,"/[^]/;") -#20436=@"loc,{#10000},43,1,43,6" -locations_default(#20436,#10000,43,1,43,6) -hasLocation(#20435,#20436) -stmtContainers(#20435,#20001) -#20437=* -exprs(#20437,5,#20435,0,"/[^]/") -#20438=@"loc,{#10000},43,1,43,5" -locations_default(#20438,#10000,43,1,43,5) -hasLocation(#20437,#20438) -enclosingStmt(#20437,#20435) -exprContainers(#20437,#20001) -literals("/[^]/","/[^]/",#20437) -#20439=* -regexpterm(#20439,23,#20437,0,"[^]") -#20440=@"loc,{#10000},43,2,43,4" -locations_default(#20440,#10000,43,2,43,4) -hasLocation(#20439,#20440) -isInverted(#20439) -#20441=* -stmts(#20441,2,#20001,43,"//;") -#20442=@"loc,{#10000},44,1,44,60" -locations_default(#20442,#10000,44,1,44,60) -hasLocation(#20441,#20442) -stmtContainers(#20441,#20001) -#20443=* -exprs(#20443,5,#20441,0,"//") -#20444=@"loc,{#10000},44,1,44,59" -locations_default(#20444,#10000,44,1,44,59) -hasLocation(#20443,#20444) -enclosingStmt(#20443,#20441) -exprContainers(#20443,#20001) -literals("/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/","/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/",#20443) -#20445=* -regexpterm(#20445,1,#20443,0,"]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>") -#20446=@"loc,{#10000},44,2,44,58" -locations_default(#20446,#10000,44,2,44,58) -hasLocation(#20445,#20446) -#20447=* -regexpterm(#20447,14,#20445,0,"<") -#20448=@"loc,{#10000},44,2,44,2" -locations_default(#20448,#10000,44,2,44,2) -hasLocation(#20447,#20448) -regexpConstValue(#20447,"<") -#20449=* -regexpterm(#20449,14,#20445,1,"t") -#20450=@"loc,{#10000},44,3,44,3" -locations_default(#20450,#10000,44,3,44,3) -hasLocation(#20449,#20450) -regexpConstValue(#20449,"t") -#20451=* -regexpterm(#20451,14,#20445,2,"p") -#20452=@"loc,{#10000},44,4,44,4" -locations_default(#20452,#10000,44,4,44,4) -hasLocation(#20451,#20452) -regexpConstValue(#20451,"p") -#20453=* -regexpterm(#20453,14,#20445,3,"l") -#20454=@"loc,{#10000},44,5,44,5" -locations_default(#20454,#10000,44,5,44,5) -hasLocation(#20453,#20454) -regexpConstValue(#20453,"l") -#20455=* -regexpterm(#20455,4,#20445,4,"\b") -#20456=@"loc,{#10000},44,6,44,7" -locations_default(#20456,#10000,44,6,44,7) -hasLocation(#20455,#20456) -#20457=* -regexpterm(#20457,8,#20445,5,"[^>]*") -#20458=@"loc,{#10000},44,8,44,12" -locations_default(#20458,#10000,44,8,44,12) -hasLocation(#20457,#20458) -isGreedy(#20457) -#20459=* -regexpterm(#20459,23,#20457,0,"[^>]") -#20460=@"loc,{#10000},44,8,44,11" -locations_default(#20460,#10000,44,8,44,11) -hasLocation(#20459,#20460) -isInverted(#20459) -#20461=* -regexpterm(#20461,14,#20459,0,">") -#20462=@"loc,{#10000},44,10,44,10" -locations_default(#20462,#10000,44,10,44,10) -hasLocation(#20461,#20462) -regexpConstValue(#20461,">") -#20463=* -regexpterm(#20463,14,#20445,6,">") -#20464=@"loc,{#10000},44,13,44,13" -locations_default(#20464,#10000,44,13,44,13) -hasLocation(#20463,#20464) -regexpConstValue(#20463,">") -#20465=* -regexpterm(#20465,13,#20445,7,"((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)") -#20466=@"loc,{#10000},44,14,44,51" -locations_default(#20466,#10000,44,14,44,51) -hasLocation(#20465,#20466) -isCapture(#20465,1) -#20467=* -regexpterm(#20467,8,#20465,0,"(?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?") -#20468=@"loc,{#10000},44,15,44,50" -locations_default(#20468,#10000,44,15,44,50) -hasLocation(#20467,#20468) -#20469=* -regexpterm(#20469,13,#20467,0,"(?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))") -#20470=@"loc,{#10000},44,15,44,48" -locations_default(#20470,#10000,44,15,44,48) -hasLocation(#20469,#20470) -#20471=* -regexpterm(#20471,0,#20469,0,"(?=([^<]+))\2|<(?!tpl\b[^>]*>)") -#20472=@"loc,{#10000},44,18,44,47" -locations_default(#20472,#10000,44,18,44,47) -hasLocation(#20471,#20472) -#20473=* -regexpterm(#20473,1,#20471,0,"(?=([^<]+))\2") -#20474=@"loc,{#10000},44,18,44,30" -locations_default(#20474,#10000,44,18,44,30) -hasLocation(#20473,#20474) -#20475=* -regexpterm(#20475,6,#20473,0,"(?=([^<]+))") -#20476=@"loc,{#10000},44,18,44,28" -locations_default(#20476,#10000,44,18,44,28) -hasLocation(#20475,#20476) -#20477=* -regexpterm(#20477,13,#20475,0,"([^<]+)") -#20478=@"loc,{#10000},44,21,44,27" -locations_default(#20478,#10000,44,21,44,27) -hasLocation(#20477,#20478) -isCapture(#20477,2) -#20479=* -regexpterm(#20479,9,#20477,0,"[^<]+") -#20480=@"loc,{#10000},44,22,44,26" -locations_default(#20480,#10000,44,22,44,26) -hasLocation(#20479,#20480) -isGreedy(#20479) -#20481=* -regexpterm(#20481,23,#20479,0,"[^<]") -#20482=@"loc,{#10000},44,22,44,25" -locations_default(#20482,#10000,44,22,44,25) -hasLocation(#20481,#20482) -isInverted(#20481) -#20483=* -regexpterm(#20483,14,#20481,0,"<") -#20484=@"loc,{#10000},44,24,44,24" -locations_default(#20484,#10000,44,24,44,24) -hasLocation(#20483,#20484) -regexpConstValue(#20483,"<") -#20485=* -regexpterm(#20485,22,#20473,1,"\2") -#20486=@"loc,{#10000},44,29,44,30" -locations_default(#20486,#10000,44,29,44,30) -hasLocation(#20485,#20486) -backref(#20485,2) -#20487=* -regexpterm(#20487,1,#20471,1,"<(?!tpl\b[^>]*>)") -#20488=@"loc,{#10000},44,32,44,47" -locations_default(#20488,#10000,44,32,44,47) -hasLocation(#20487,#20488) -#20489=* -regexpterm(#20489,14,#20487,0,"<") -#20490=@"loc,{#10000},44,32,44,32" -locations_default(#20490,#10000,44,32,44,32) -hasLocation(#20489,#20490) -regexpConstValue(#20489,"<") -#20491=* -regexpterm(#20491,7,#20487,1,"(?!tpl\b[^>]*>)") -#20492=@"loc,{#10000},44,33,44,47" -locations_default(#20492,#10000,44,33,44,47) -hasLocation(#20491,#20492) -#20493=* -regexpterm(#20493,1,#20491,0,"tpl\b[^>]*>") -#20494=@"loc,{#10000},44,36,44,46" -locations_default(#20494,#10000,44,36,44,46) -hasLocation(#20493,#20494) -#20495=* -regexpterm(#20495,14,#20493,0,"t") -#20496=@"loc,{#10000},44,36,44,36" -locations_default(#20496,#10000,44,36,44,36) -hasLocation(#20495,#20496) -regexpConstValue(#20495,"t") -#20497=* -regexpterm(#20497,14,#20493,1,"p") -#20498=@"loc,{#10000},44,37,44,37" -locations_default(#20498,#10000,44,37,44,37) -hasLocation(#20497,#20498) -regexpConstValue(#20497,"p") -#20499=* -regexpterm(#20499,14,#20493,2,"l") -#20500=@"loc,{#10000},44,38,44,38" -locations_default(#20500,#10000,44,38,44,38) -hasLocation(#20499,#20500) -regexpConstValue(#20499,"l") -#20501=* -regexpterm(#20501,4,#20493,3,"\b") -#20502=@"loc,{#10000},44,39,44,40" -locations_default(#20502,#10000,44,39,44,40) -hasLocation(#20501,#20502) -#20503=* -regexpterm(#20503,8,#20493,4,"[^>]*") -#20504=@"loc,{#10000},44,41,44,45" -locations_default(#20504,#10000,44,41,44,45) -hasLocation(#20503,#20504) -isGreedy(#20503) -#20505=* -regexpterm(#20505,23,#20503,0,"[^>]") -#20506=@"loc,{#10000},44,41,44,44" -locations_default(#20506,#10000,44,41,44,44) -hasLocation(#20505,#20506) -isInverted(#20505) -#20507=* -regexpterm(#20507,14,#20505,0,">") -#20508=@"loc,{#10000},44,43,44,43" -locations_default(#20508,#10000,44,43,44,43) -hasLocation(#20507,#20508) -regexpConstValue(#20507,">") -#20509=* -regexpterm(#20509,14,#20493,5,">") -#20510=@"loc,{#10000},44,46,44,46" -locations_default(#20510,#10000,44,46,44,46) -hasLocation(#20509,#20510) -regexpConstValue(#20509,">") -#20511=* -regexpterm(#20511,14,#20445,8,"<") -#20512=@"loc,{#10000},44,52,44,52" -locations_default(#20512,#10000,44,52,44,52) -hasLocation(#20511,#20512) -regexpConstValue(#20511,"<") -#20513=* -regexpterm(#20513,21,#20445,9,"\/") -#20514=@"loc,{#10000},44,53,44,54" -locations_default(#20514,#10000,44,53,44,54) -hasLocation(#20513,#20514) -regexpConstValue(#20513,"/") -#20515=* -regexpterm(#20515,14,#20445,10,"t") -#20516=@"loc,{#10000},44,55,44,55" -locations_default(#20516,#10000,44,55,44,55) -hasLocation(#20515,#20516) -regexpConstValue(#20515,"t") -#20517=* -regexpterm(#20517,14,#20445,11,"p") -#20518=@"loc,{#10000},44,56,44,56" -locations_default(#20518,#10000,44,56,44,56) -hasLocation(#20517,#20518) -regexpConstValue(#20517,"p") -#20519=* -regexpterm(#20519,14,#20445,12,"l") -#20520=@"loc,{#10000},44,57,44,57" -locations_default(#20520,#10000,44,57,44,57) -hasLocation(#20519,#20520) -regexpConstValue(#20519,"l") -#20521=* -regexpterm(#20521,14,#20445,13,">") -#20522=@"loc,{#10000},44,58,44,58" -locations_default(#20522,#10000,44,58,44,58) -hasLocation(#20521,#20522) -regexpConstValue(#20521,">") -#20523=* -lines(#20523,#20001,"/t/;"," -") -hasLocation(#20523,#20004) +#20420=* +regexpParseErrors(#20420,#20418,"unexpected end of regular expression") +#20421=@"loc,{#10000},40,5,40,5" +locations_default(#20421,#10000,40,5,40,5) +hasLocation(#20420,#20421) +#20422=* +stmts(#20422,2,#20001,40,"/\c0/;") +#20423=@"loc,{#10000},41,1,41,6" +locations_default(#20423,#10000,41,1,41,6) +hasLocation(#20422,#20423) +stmtContainers(#20422,#20001) +#20424=* +exprs(#20424,5,#20422,0,"/\c0/") +#20425=@"loc,{#10000},41,1,41,5" +locations_default(#20425,#10000,41,1,41,5) +hasLocation(#20424,#20425) +enclosingStmt(#20424,#20422) +exprContainers(#20424,#20001) +literals("/\c0/","/\c0/",#20424) +#20426=* +regexpterm(#20426,19,#20424,0,"\c0") +#20427=@"loc,{#10000},41,2,41,4" +locations_default(#20427,#10000,41,2,41,4) +hasLocation(#20426,#20427) +regexpConstValue(#20426,"") +#20428=* +regexpParseErrors(#20428,#20426,"expected control letter") +#20429=@"loc,{#10000},41,4,41,4" +locations_default(#20429,#10000,41,4,41,4) +hasLocation(#20428,#20429) +#20430=* +stmts(#20430,2,#20001,41,"/[]/;") +#20431=@"loc,{#10000},42,1,42,5" +locations_default(#20431,#10000,42,1,42,5) +hasLocation(#20430,#20431) +stmtContainers(#20430,#20001) +#20432=* +exprs(#20432,5,#20430,0,"/[]/") +#20433=@"loc,{#10000},42,1,42,4" +locations_default(#20433,#10000,42,1,42,4) +hasLocation(#20432,#20433) +enclosingStmt(#20432,#20430) +exprContainers(#20432,#20001) +literals("/[]/","/[]/",#20432) +#20434=* +regexpterm(#20434,23,#20432,0,"[]") +#20435=@"loc,{#10000},42,2,42,3" +locations_default(#20435,#10000,42,2,42,3) +hasLocation(#20434,#20435) +#20436=* +stmts(#20436,2,#20001,42,"/[^]/;") +#20437=@"loc,{#10000},43,1,43,6" +locations_default(#20437,#10000,43,1,43,6) +hasLocation(#20436,#20437) +stmtContainers(#20436,#20001) +#20438=* +exprs(#20438,5,#20436,0,"/[^]/") +#20439=@"loc,{#10000},43,1,43,5" +locations_default(#20439,#10000,43,1,43,5) +hasLocation(#20438,#20439) +enclosingStmt(#20438,#20436) +exprContainers(#20438,#20001) +literals("/[^]/","/[^]/",#20438) +#20440=* +regexpterm(#20440,23,#20438,0,"[^]") +#20441=@"loc,{#10000},43,2,43,4" +locations_default(#20441,#10000,43,2,43,4) +hasLocation(#20440,#20441) +isInverted(#20440) +#20442=* +stmts(#20442,2,#20001,43,"//;") +#20443=@"loc,{#10000},44,1,44,60" +locations_default(#20443,#10000,44,1,44,60) +hasLocation(#20442,#20443) +stmtContainers(#20442,#20001) +#20444=* +exprs(#20444,5,#20442,0,"//") +#20445=@"loc,{#10000},44,1,44,59" +locations_default(#20445,#10000,44,1,44,59) +hasLocation(#20444,#20445) +enclosingStmt(#20444,#20442) +exprContainers(#20444,#20001) +literals("/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/","/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/",#20444) +#20446=* +regexpterm(#20446,1,#20444,0,"]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>") +#20447=@"loc,{#10000},44,2,44,58" +locations_default(#20447,#10000,44,2,44,58) +hasLocation(#20446,#20447) +#20448=* +regexpterm(#20448,14,#20446,0,"<") +#20449=@"loc,{#10000},44,2,44,2" +locations_default(#20449,#10000,44,2,44,2) +hasLocation(#20448,#20449) +regexpConstValue(#20448,"<") +#20450=* +regexpterm(#20450,14,#20446,1,"t") +#20451=@"loc,{#10000},44,3,44,3" +locations_default(#20451,#10000,44,3,44,3) +hasLocation(#20450,#20451) +regexpConstValue(#20450,"t") +#20452=* +regexpterm(#20452,14,#20446,2,"p") +#20453=@"loc,{#10000},44,4,44,4" +locations_default(#20453,#10000,44,4,44,4) +hasLocation(#20452,#20453) +regexpConstValue(#20452,"p") +#20454=* +regexpterm(#20454,14,#20446,3,"l") +#20455=@"loc,{#10000},44,5,44,5" +locations_default(#20455,#10000,44,5,44,5) +hasLocation(#20454,#20455) +regexpConstValue(#20454,"l") +#20456=* +regexpterm(#20456,4,#20446,4,"\b") +#20457=@"loc,{#10000},44,6,44,7" +locations_default(#20457,#10000,44,6,44,7) +hasLocation(#20456,#20457) +#20458=* +regexpterm(#20458,8,#20446,5,"[^>]*") +#20459=@"loc,{#10000},44,8,44,12" +locations_default(#20459,#10000,44,8,44,12) +hasLocation(#20458,#20459) +isGreedy(#20458) +#20460=* +regexpterm(#20460,23,#20458,0,"[^>]") +#20461=@"loc,{#10000},44,8,44,11" +locations_default(#20461,#10000,44,8,44,11) +hasLocation(#20460,#20461) +isInverted(#20460) +#20462=* +regexpterm(#20462,14,#20460,0,">") +#20463=@"loc,{#10000},44,10,44,10" +locations_default(#20463,#10000,44,10,44,10) +hasLocation(#20462,#20463) +regexpConstValue(#20462,">") +#20464=* +regexpterm(#20464,14,#20446,6,">") +#20465=@"loc,{#10000},44,13,44,13" +locations_default(#20465,#10000,44,13,44,13) +hasLocation(#20464,#20465) +regexpConstValue(#20464,">") +#20466=* +regexpterm(#20466,13,#20446,7,"((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)") +#20467=@"loc,{#10000},44,14,44,51" +locations_default(#20467,#10000,44,14,44,51) +hasLocation(#20466,#20467) +isCapture(#20466,1) +#20468=* +regexpterm(#20468,8,#20466,0,"(?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?") +#20469=@"loc,{#10000},44,15,44,50" +locations_default(#20469,#10000,44,15,44,50) +hasLocation(#20468,#20469) +#20470=* +regexpterm(#20470,13,#20468,0,"(?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))") +#20471=@"loc,{#10000},44,15,44,48" +locations_default(#20471,#10000,44,15,44,48) +hasLocation(#20470,#20471) +#20472=* +regexpterm(#20472,0,#20470,0,"(?=([^<]+))\2|<(?!tpl\b[^>]*>)") +#20473=@"loc,{#10000},44,18,44,47" +locations_default(#20473,#10000,44,18,44,47) +hasLocation(#20472,#20473) +#20474=* +regexpterm(#20474,1,#20472,0,"(?=([^<]+))\2") +#20475=@"loc,{#10000},44,18,44,30" +locations_default(#20475,#10000,44,18,44,30) +hasLocation(#20474,#20475) +#20476=* +regexpterm(#20476,6,#20474,0,"(?=([^<]+))") +#20477=@"loc,{#10000},44,18,44,28" +locations_default(#20477,#10000,44,18,44,28) +hasLocation(#20476,#20477) +#20478=* +regexpterm(#20478,13,#20476,0,"([^<]+)") +#20479=@"loc,{#10000},44,21,44,27" +locations_default(#20479,#10000,44,21,44,27) +hasLocation(#20478,#20479) +isCapture(#20478,2) +#20480=* +regexpterm(#20480,9,#20478,0,"[^<]+") +#20481=@"loc,{#10000},44,22,44,26" +locations_default(#20481,#10000,44,22,44,26) +hasLocation(#20480,#20481) +isGreedy(#20480) +#20482=* +regexpterm(#20482,23,#20480,0,"[^<]") +#20483=@"loc,{#10000},44,22,44,25" +locations_default(#20483,#10000,44,22,44,25) +hasLocation(#20482,#20483) +isInverted(#20482) +#20484=* +regexpterm(#20484,14,#20482,0,"<") +#20485=@"loc,{#10000},44,24,44,24" +locations_default(#20485,#10000,44,24,44,24) +hasLocation(#20484,#20485) +regexpConstValue(#20484,"<") +#20486=* +regexpterm(#20486,22,#20474,1,"\2") +#20487=@"loc,{#10000},44,29,44,30" +locations_default(#20487,#10000,44,29,44,30) +hasLocation(#20486,#20487) +backref(#20486,2) +#20488=* +regexpterm(#20488,1,#20472,1,"<(?!tpl\b[^>]*>)") +#20489=@"loc,{#10000},44,32,44,47" +locations_default(#20489,#10000,44,32,44,47) +hasLocation(#20488,#20489) +#20490=* +regexpterm(#20490,14,#20488,0,"<") +#20491=@"loc,{#10000},44,32,44,32" +locations_default(#20491,#10000,44,32,44,32) +hasLocation(#20490,#20491) +regexpConstValue(#20490,"<") +#20492=* +regexpterm(#20492,7,#20488,1,"(?!tpl\b[^>]*>)") +#20493=@"loc,{#10000},44,33,44,47" +locations_default(#20493,#10000,44,33,44,47) +hasLocation(#20492,#20493) +#20494=* +regexpterm(#20494,1,#20492,0,"tpl\b[^>]*>") +#20495=@"loc,{#10000},44,36,44,46" +locations_default(#20495,#10000,44,36,44,46) +hasLocation(#20494,#20495) +#20496=* +regexpterm(#20496,14,#20494,0,"t") +#20497=@"loc,{#10000},44,36,44,36" +locations_default(#20497,#10000,44,36,44,36) +hasLocation(#20496,#20497) +regexpConstValue(#20496,"t") +#20498=* +regexpterm(#20498,14,#20494,1,"p") +#20499=@"loc,{#10000},44,37,44,37" +locations_default(#20499,#10000,44,37,44,37) +hasLocation(#20498,#20499) +regexpConstValue(#20498,"p") +#20500=* +regexpterm(#20500,14,#20494,2,"l") +#20501=@"loc,{#10000},44,38,44,38" +locations_default(#20501,#10000,44,38,44,38) +hasLocation(#20500,#20501) +regexpConstValue(#20500,"l") +#20502=* +regexpterm(#20502,4,#20494,3,"\b") +#20503=@"loc,{#10000},44,39,44,40" +locations_default(#20503,#10000,44,39,44,40) +hasLocation(#20502,#20503) +#20504=* +regexpterm(#20504,8,#20494,4,"[^>]*") +#20505=@"loc,{#10000},44,41,44,45" +locations_default(#20505,#10000,44,41,44,45) +hasLocation(#20504,#20505) +isGreedy(#20504) +#20506=* +regexpterm(#20506,23,#20504,0,"[^>]") +#20507=@"loc,{#10000},44,41,44,44" +locations_default(#20507,#10000,44,41,44,44) +hasLocation(#20506,#20507) +isInverted(#20506) +#20508=* +regexpterm(#20508,14,#20506,0,">") +#20509=@"loc,{#10000},44,43,44,43" +locations_default(#20509,#10000,44,43,44,43) +hasLocation(#20508,#20509) +regexpConstValue(#20508,">") +#20510=* +regexpterm(#20510,14,#20494,5,">") +#20511=@"loc,{#10000},44,46,44,46" +locations_default(#20511,#10000,44,46,44,46) +hasLocation(#20510,#20511) +regexpConstValue(#20510,">") +#20512=* +regexpterm(#20512,14,#20446,8,"<") +#20513=@"loc,{#10000},44,52,44,52" +locations_default(#20513,#10000,44,52,44,52) +hasLocation(#20512,#20513) +regexpConstValue(#20512,"<") +#20514=* +regexpterm(#20514,21,#20446,9,"\/") +#20515=@"loc,{#10000},44,53,44,54" +locations_default(#20515,#10000,44,53,44,54) +hasLocation(#20514,#20515) +regexpConstValue(#20514,"/") +#20516=* +regexpterm(#20516,14,#20446,10,"t") +#20517=@"loc,{#10000},44,55,44,55" +locations_default(#20517,#10000,44,55,44,55) +hasLocation(#20516,#20517) +regexpConstValue(#20516,"t") +#20518=* +regexpterm(#20518,14,#20446,11,"p") +#20519=@"loc,{#10000},44,56,44,56" +locations_default(#20519,#10000,44,56,44,56) +hasLocation(#20518,#20519) +regexpConstValue(#20518,"p") +#20520=* +regexpterm(#20520,14,#20446,12,"l") +#20521=@"loc,{#10000},44,57,44,57" +locations_default(#20521,#10000,44,57,44,57) +hasLocation(#20520,#20521) +regexpConstValue(#20520,"l") +#20522=* +regexpterm(#20522,14,#20446,13,">") +#20523=@"loc,{#10000},44,58,44,58" +locations_default(#20523,#10000,44,58,44,58) +hasLocation(#20522,#20523) +regexpConstValue(#20522,">") #20524=* -lines(#20524,#20001,"/foo|bar/;"," +lines(#20524,#20001,"/t/;"," ") -hasLocation(#20524,#20010) +hasLocation(#20524,#20004) #20525=* -lines(#20525,#20001,"/(?:)/;"," +lines(#20525,#20001,"/foo|bar/;"," ") -hasLocation(#20525,#20032) +hasLocation(#20525,#20010) #20526=* -lines(#20526,#20001,"/^abc$/;"," +lines(#20526,#20001,"/(?:)/;"," ") -hasLocation(#20526,#20040) +hasLocation(#20526,#20032) #20527=* -lines(#20527,#20001,"/\bx\b/;"," +lines(#20527,#20001,"/^abc$/;"," ") -hasLocation(#20527,#20056) +hasLocation(#20527,#20040) #20528=* -lines(#20528,#20001,"/\bx\B/;"," +lines(#20528,#20001,"/\bx\b/;"," ") -hasLocation(#20528,#20068) +hasLocation(#20528,#20056) #20529=* -lines(#20529,#20001,"/x(?=y)/;"," +lines(#20529,#20001,"/\bx\B/;"," ") -hasLocation(#20529,#20080) +hasLocation(#20529,#20068) #20530=* -lines(#20530,#20001,"/x(?!z)/;"," +lines(#20530,#20001,"/x(?=y)/;"," ") -hasLocation(#20530,#20092) +hasLocation(#20530,#20080) #20531=* -lines(#20531,#20001,"/a*/;"," +lines(#20531,#20001,"/x(?!z)/;"," ") -hasLocation(#20531,#20104) +hasLocation(#20531,#20092) #20532=* -lines(#20532,#20001,"/a*?/;"," +lines(#20532,#20001,"/a*/;"," ") -hasLocation(#20532,#20112) +hasLocation(#20532,#20104) #20533=* -lines(#20533,#20001,"/a+/;"," +lines(#20533,#20001,"/a*?/;"," ") -hasLocation(#20533,#20120) +hasLocation(#20533,#20112) #20534=* -lines(#20534,#20001,"/a+?/;"," +lines(#20534,#20001,"/a+/;"," ") -hasLocation(#20534,#20128) +hasLocation(#20534,#20120) #20535=* -lines(#20535,#20001,"/a?/;"," +lines(#20535,#20001,"/a+?/;"," ") -hasLocation(#20535,#20136) +hasLocation(#20535,#20128) #20536=* -lines(#20536,#20001,"/a??/;"," +lines(#20536,#20001,"/a?/;"," ") -hasLocation(#20536,#20144) +hasLocation(#20536,#20136) #20537=* -lines(#20537,#20001,"/a{1}/;"," +lines(#20537,#20001,"/a??/;"," ") -hasLocation(#20537,#20152) +hasLocation(#20537,#20144) #20538=* -lines(#20538,#20001,"/a{1,}/;"," +lines(#20538,#20001,"/a{1}/;"," ") -hasLocation(#20538,#20160) +hasLocation(#20538,#20152) #20539=* -lines(#20539,#20001,"/a{1,2}/;"," +lines(#20539,#20001,"/a{1,}/;"," ") -hasLocation(#20539,#20168) +hasLocation(#20539,#20160) #20540=* -lines(#20540,#20001,"/a{1}?/;"," +lines(#20540,#20001,"/a{1,2}/;"," ") -hasLocation(#20540,#20176) +hasLocation(#20540,#20168) #20541=* -lines(#20541,#20001,"/a{1,}?/;"," +lines(#20541,#20001,"/a{1}?/;"," ") -hasLocation(#20541,#20184) +hasLocation(#20541,#20176) #20542=* -lines(#20542,#20001,"/a{1,2}?/;"," +lines(#20542,#20001,"/a{1,}?/;"," ") -hasLocation(#20542,#20192) +hasLocation(#20542,#20184) #20543=* -lines(#20543,#20001,"/./;"," +lines(#20543,#20001,"/a{1,2}?/;"," ") -hasLocation(#20543,#20200) +hasLocation(#20543,#20192) #20544=* -lines(#20544,#20001,"/(abc)/;"," +lines(#20544,#20001,"/./;"," ") -hasLocation(#20544,#20206) +hasLocation(#20544,#20200) #20545=* -lines(#20545,#20001,"/(?:abc)/;"," +lines(#20545,#20001,"/(abc)/;"," ") -hasLocation(#20545,#20220) +hasLocation(#20545,#20206) #20546=* -lines(#20546,#20001,"/\x0a/;"," +lines(#20546,#20001,"/(?:abc)/;"," ") -hasLocation(#20546,#20234) +hasLocation(#20546,#20220) #20547=* -lines(#20547,#20001,"/\u000a/;"," +lines(#20547,#20001,"/\x0a/;"," ") -hasLocation(#20547,#20240) +hasLocation(#20547,#20234) #20548=* -lines(#20548,#20001,"/\10/;"," +lines(#20548,#20001,"/\u000a/;"," ") -hasLocation(#20548,#20246) +hasLocation(#20548,#20240) #20549=* -lines(#20549,#20001,"/\t\n\r\f\v/;"," +lines(#20549,#20001,"/\10/;"," ") -hasLocation(#20549,#20252) +hasLocation(#20549,#20246) #20550=* -lines(#20550,#20001,"/\ca\cN/;"," +lines(#20550,#20001,"/\t\n\r\f\v/;"," ") -hasLocation(#20550,#20268) +hasLocation(#20550,#20253) #20551=* -lines(#20551,#20001,"/\w\S/;"," +lines(#20551,#20001,"/\ca\cN/;"," ") -hasLocation(#20551,#20278) +hasLocation(#20551,#20269) #20552=* -lines(#20552,#20001,"/\\/;"," +lines(#20552,#20001,"/\w\S/;"," ") -hasLocation(#20552,#20288) +hasLocation(#20552,#20279) #20553=* -lines(#20553,#20001,"/[abc]/;"," +lines(#20553,#20001,"/\\/;"," ") -hasLocation(#20553,#20294) +hasLocation(#20553,#20289) #20554=* -lines(#20554,#20001,"/[a-z]/;"," +lines(#20554,#20001,"/[abc]/;"," ") -hasLocation(#20554,#20306) +hasLocation(#20554,#20295) #20555=* -lines(#20555,#20001,"/[a-zA-Z]/;"," +lines(#20555,#20001,"/[a-z]/;"," ") -hasLocation(#20555,#20318) +hasLocation(#20555,#20307) #20556=* -lines(#20556,#20001,"/[-a-z]/;"," +lines(#20556,#20001,"/[a-zA-Z]/;"," ") -hasLocation(#20556,#20336) +hasLocation(#20556,#20319) #20557=* -lines(#20557,#20001,"/[^a-z]/;"," +lines(#20557,#20001,"/[-a-z]/;"," ") -hasLocation(#20557,#20350) +hasLocation(#20557,#20337) #20558=* -lines(#20558,#20001,"/[a\b\x0c]/;"," +lines(#20558,#20001,"/[^a-z]/;"," ") -hasLocation(#20558,#20362) +hasLocation(#20558,#20351) #20559=* -lines(#20559,#20001,"/a{/;"," +lines(#20559,#20001,"/[a\b\x0c]/;"," ") -hasLocation(#20559,#20374) +hasLocation(#20559,#20363) #20560=* -lines(#20560,#20001,"/a{b}/;"," +lines(#20560,#20001,"/a{/;"," ") -hasLocation(#20560,#20386) +hasLocation(#20560,#20375) #20561=* -lines(#20561,#20001,"/a{2/;"," +lines(#20561,#20001,"/a{b}/;"," ") -hasLocation(#20561,#20404) +hasLocation(#20561,#20387) #20562=* -lines(#20562,#20001,"/\xa/;"," +lines(#20562,#20001,"/a{2/;"," ") -hasLocation(#20562,#20414) +hasLocation(#20562,#20405) #20563=* -lines(#20563,#20001,"/\c0/;"," +lines(#20563,#20001,"/\xa/;"," ") -hasLocation(#20563,#20422) +hasLocation(#20563,#20415) #20564=* -lines(#20564,#20001,"/[]/;"," +lines(#20564,#20001,"/\c0/;"," ") -hasLocation(#20564,#20430) +hasLocation(#20564,#20423) #20565=* -lines(#20565,#20001,"/[^]/;"," +lines(#20565,#20001,"/[]/;"," ") -hasLocation(#20565,#20436) +hasLocation(#20565,#20431) #20566=* -lines(#20566,#20001,"/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;","") -hasLocation(#20566,#20442) -numlines(#20001,44,44,0) +lines(#20566,#20001,"/[^]/;"," +") +hasLocation(#20566,#20437) #20567=* -tokeninfo(#20567,5,#20001,0,"/t/") -hasLocation(#20567,#20006) +lines(#20567,#20001,"/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;","") +hasLocation(#20567,#20443) +numlines(#20001,44,44,0) #20568=* -tokeninfo(#20568,8,#20001,1,";") -#20569=@"loc,{#10000},1,4,1,4" -locations_default(#20569,#10000,1,4,1,4) -hasLocation(#20568,#20569) -#20570=* -tokeninfo(#20570,5,#20001,2,"/foo|bar/") -hasLocation(#20570,#20012) +tokeninfo(#20568,5,#20001,0,"/t/") +hasLocation(#20568,#20006) +#20569=* +tokeninfo(#20569,8,#20001,1,";") +#20570=@"loc,{#10000},1,4,1,4" +locations_default(#20570,#10000,1,4,1,4) +hasLocation(#20569,#20570) #20571=* -tokeninfo(#20571,8,#20001,3,";") -#20572=@"loc,{#10000},2,10,2,10" -locations_default(#20572,#10000,2,10,2,10) -hasLocation(#20571,#20572) -#20573=* -tokeninfo(#20573,5,#20001,4,"/(?:)/") -hasLocation(#20573,#20034) +tokeninfo(#20571,5,#20001,2,"/foo|bar/") +hasLocation(#20571,#20012) +#20572=* +tokeninfo(#20572,8,#20001,3,";") +#20573=@"loc,{#10000},2,10,2,10" +locations_default(#20573,#10000,2,10,2,10) +hasLocation(#20572,#20573) #20574=* -tokeninfo(#20574,8,#20001,5,";") -#20575=@"loc,{#10000},3,7,3,7" -locations_default(#20575,#10000,3,7,3,7) -hasLocation(#20574,#20575) -#20576=* -tokeninfo(#20576,5,#20001,6,"/^abc$/") -hasLocation(#20576,#20042) +tokeninfo(#20574,5,#20001,4,"/(?:)/") +hasLocation(#20574,#20034) +#20575=* +tokeninfo(#20575,8,#20001,5,";") +#20576=@"loc,{#10000},3,7,3,7" +locations_default(#20576,#10000,3,7,3,7) +hasLocation(#20575,#20576) #20577=* -tokeninfo(#20577,8,#20001,7,";") -#20578=@"loc,{#10000},4,8,4,8" -locations_default(#20578,#10000,4,8,4,8) -hasLocation(#20577,#20578) -#20579=* -tokeninfo(#20579,5,#20001,8,"/\bx\b/") -hasLocation(#20579,#20058) +tokeninfo(#20577,5,#20001,6,"/^abc$/") +hasLocation(#20577,#20042) +#20578=* +tokeninfo(#20578,8,#20001,7,";") +#20579=@"loc,{#10000},4,8,4,8" +locations_default(#20579,#10000,4,8,4,8) +hasLocation(#20578,#20579) #20580=* -tokeninfo(#20580,8,#20001,9,";") -#20581=@"loc,{#10000},5,8,5,8" -locations_default(#20581,#10000,5,8,5,8) -hasLocation(#20580,#20581) -#20582=* -tokeninfo(#20582,5,#20001,10,"/\bx\B/") -hasLocation(#20582,#20070) +tokeninfo(#20580,5,#20001,8,"/\bx\b/") +hasLocation(#20580,#20058) +#20581=* +tokeninfo(#20581,8,#20001,9,";") +#20582=@"loc,{#10000},5,8,5,8" +locations_default(#20582,#10000,5,8,5,8) +hasLocation(#20581,#20582) #20583=* -tokeninfo(#20583,8,#20001,11,";") -#20584=@"loc,{#10000},6,8,6,8" -locations_default(#20584,#10000,6,8,6,8) -hasLocation(#20583,#20584) -#20585=* -tokeninfo(#20585,5,#20001,12,"/x(?=y)/") -hasLocation(#20585,#20082) +tokeninfo(#20583,5,#20001,10,"/\bx\B/") +hasLocation(#20583,#20070) +#20584=* +tokeninfo(#20584,8,#20001,11,";") +#20585=@"loc,{#10000},6,8,6,8" +locations_default(#20585,#10000,6,8,6,8) +hasLocation(#20584,#20585) #20586=* -tokeninfo(#20586,8,#20001,13,";") -#20587=@"loc,{#10000},7,9,7,9" -locations_default(#20587,#10000,7,9,7,9) -hasLocation(#20586,#20587) -#20588=* -tokeninfo(#20588,5,#20001,14,"/x(?!z)/") -hasLocation(#20588,#20094) +tokeninfo(#20586,5,#20001,12,"/x(?=y)/") +hasLocation(#20586,#20082) +#20587=* +tokeninfo(#20587,8,#20001,13,";") +#20588=@"loc,{#10000},7,9,7,9" +locations_default(#20588,#10000,7,9,7,9) +hasLocation(#20587,#20588) #20589=* -tokeninfo(#20589,8,#20001,15,";") -#20590=@"loc,{#10000},8,9,8,9" -locations_default(#20590,#10000,8,9,8,9) -hasLocation(#20589,#20590) -#20591=* -tokeninfo(#20591,5,#20001,16,"/a*/") -hasLocation(#20591,#20106) +tokeninfo(#20589,5,#20001,14,"/x(?!z)/") +hasLocation(#20589,#20094) +#20590=* +tokeninfo(#20590,8,#20001,15,";") +#20591=@"loc,{#10000},8,9,8,9" +locations_default(#20591,#10000,8,9,8,9) +hasLocation(#20590,#20591) #20592=* -tokeninfo(#20592,8,#20001,17,";") -#20593=@"loc,{#10000},9,5,9,5" -locations_default(#20593,#10000,9,5,9,5) -hasLocation(#20592,#20593) -#20594=* -tokeninfo(#20594,5,#20001,18,"/a*?/") -hasLocation(#20594,#20114) +tokeninfo(#20592,5,#20001,16,"/a*/") +hasLocation(#20592,#20106) +#20593=* +tokeninfo(#20593,8,#20001,17,";") +#20594=@"loc,{#10000},9,5,9,5" +locations_default(#20594,#10000,9,5,9,5) +hasLocation(#20593,#20594) #20595=* -tokeninfo(#20595,8,#20001,19,";") -#20596=@"loc,{#10000},10,6,10,6" -locations_default(#20596,#10000,10,6,10,6) -hasLocation(#20595,#20596) -#20597=* -tokeninfo(#20597,5,#20001,20,"/a+/") -hasLocation(#20597,#20122) +tokeninfo(#20595,5,#20001,18,"/a*?/") +hasLocation(#20595,#20114) +#20596=* +tokeninfo(#20596,8,#20001,19,";") +#20597=@"loc,{#10000},10,6,10,6" +locations_default(#20597,#10000,10,6,10,6) +hasLocation(#20596,#20597) #20598=* -tokeninfo(#20598,8,#20001,21,";") -#20599=@"loc,{#10000},11,5,11,5" -locations_default(#20599,#10000,11,5,11,5) -hasLocation(#20598,#20599) -#20600=* -tokeninfo(#20600,5,#20001,22,"/a+?/") -hasLocation(#20600,#20130) +tokeninfo(#20598,5,#20001,20,"/a+/") +hasLocation(#20598,#20122) +#20599=* +tokeninfo(#20599,8,#20001,21,";") +#20600=@"loc,{#10000},11,5,11,5" +locations_default(#20600,#10000,11,5,11,5) +hasLocation(#20599,#20600) #20601=* -tokeninfo(#20601,8,#20001,23,";") -#20602=@"loc,{#10000},12,6,12,6" -locations_default(#20602,#10000,12,6,12,6) -hasLocation(#20601,#20602) -#20603=* -tokeninfo(#20603,5,#20001,24,"/a?/") -hasLocation(#20603,#20138) +tokeninfo(#20601,5,#20001,22,"/a+?/") +hasLocation(#20601,#20130) +#20602=* +tokeninfo(#20602,8,#20001,23,";") +#20603=@"loc,{#10000},12,6,12,6" +locations_default(#20603,#10000,12,6,12,6) +hasLocation(#20602,#20603) #20604=* -tokeninfo(#20604,8,#20001,25,";") -#20605=@"loc,{#10000},13,5,13,5" -locations_default(#20605,#10000,13,5,13,5) -hasLocation(#20604,#20605) -#20606=* -tokeninfo(#20606,5,#20001,26,"/a??/") -hasLocation(#20606,#20146) +tokeninfo(#20604,5,#20001,24,"/a?/") +hasLocation(#20604,#20138) +#20605=* +tokeninfo(#20605,8,#20001,25,";") +#20606=@"loc,{#10000},13,5,13,5" +locations_default(#20606,#10000,13,5,13,5) +hasLocation(#20605,#20606) #20607=* -tokeninfo(#20607,8,#20001,27,";") -#20608=@"loc,{#10000},14,6,14,6" -locations_default(#20608,#10000,14,6,14,6) -hasLocation(#20607,#20608) -#20609=* -tokeninfo(#20609,5,#20001,28,"/a{1}/") -hasLocation(#20609,#20154) +tokeninfo(#20607,5,#20001,26,"/a??/") +hasLocation(#20607,#20146) +#20608=* +tokeninfo(#20608,8,#20001,27,";") +#20609=@"loc,{#10000},14,6,14,6" +locations_default(#20609,#10000,14,6,14,6) +hasLocation(#20608,#20609) #20610=* -tokeninfo(#20610,8,#20001,29,";") -#20611=@"loc,{#10000},15,7,15,7" -locations_default(#20611,#10000,15,7,15,7) -hasLocation(#20610,#20611) -#20612=* -tokeninfo(#20612,5,#20001,30,"/a{1,}/") -hasLocation(#20612,#20162) +tokeninfo(#20610,5,#20001,28,"/a{1}/") +hasLocation(#20610,#20154) +#20611=* +tokeninfo(#20611,8,#20001,29,";") +#20612=@"loc,{#10000},15,7,15,7" +locations_default(#20612,#10000,15,7,15,7) +hasLocation(#20611,#20612) #20613=* -tokeninfo(#20613,8,#20001,31,";") -#20614=@"loc,{#10000},16,8,16,8" -locations_default(#20614,#10000,16,8,16,8) -hasLocation(#20613,#20614) -#20615=* -tokeninfo(#20615,5,#20001,32,"/a{1,2}/") -hasLocation(#20615,#20170) +tokeninfo(#20613,5,#20001,30,"/a{1,}/") +hasLocation(#20613,#20162) +#20614=* +tokeninfo(#20614,8,#20001,31,";") +#20615=@"loc,{#10000},16,8,16,8" +locations_default(#20615,#10000,16,8,16,8) +hasLocation(#20614,#20615) #20616=* -tokeninfo(#20616,8,#20001,33,";") -#20617=@"loc,{#10000},17,9,17,9" -locations_default(#20617,#10000,17,9,17,9) -hasLocation(#20616,#20617) -#20618=* -tokeninfo(#20618,5,#20001,34,"/a{1}?/") -hasLocation(#20618,#20178) +tokeninfo(#20616,5,#20001,32,"/a{1,2}/") +hasLocation(#20616,#20170) +#20617=* +tokeninfo(#20617,8,#20001,33,";") +#20618=@"loc,{#10000},17,9,17,9" +locations_default(#20618,#10000,17,9,17,9) +hasLocation(#20617,#20618) #20619=* -tokeninfo(#20619,8,#20001,35,";") -#20620=@"loc,{#10000},18,8,18,8" -locations_default(#20620,#10000,18,8,18,8) -hasLocation(#20619,#20620) -#20621=* -tokeninfo(#20621,5,#20001,36,"/a{1,}?/") -hasLocation(#20621,#20186) +tokeninfo(#20619,5,#20001,34,"/a{1}?/") +hasLocation(#20619,#20178) +#20620=* +tokeninfo(#20620,8,#20001,35,";") +#20621=@"loc,{#10000},18,8,18,8" +locations_default(#20621,#10000,18,8,18,8) +hasLocation(#20620,#20621) #20622=* -tokeninfo(#20622,8,#20001,37,";") -#20623=@"loc,{#10000},19,9,19,9" -locations_default(#20623,#10000,19,9,19,9) -hasLocation(#20622,#20623) -#20624=* -tokeninfo(#20624,5,#20001,38,"/a{1,2}?/") -hasLocation(#20624,#20194) +tokeninfo(#20622,5,#20001,36,"/a{1,}?/") +hasLocation(#20622,#20186) +#20623=* +tokeninfo(#20623,8,#20001,37,";") +#20624=@"loc,{#10000},19,9,19,9" +locations_default(#20624,#10000,19,9,19,9) +hasLocation(#20623,#20624) #20625=* -tokeninfo(#20625,8,#20001,39,";") -#20626=@"loc,{#10000},20,10,20,10" -locations_default(#20626,#10000,20,10,20,10) -hasLocation(#20625,#20626) -#20627=* -tokeninfo(#20627,5,#20001,40,"/./") -hasLocation(#20627,#20202) +tokeninfo(#20625,5,#20001,38,"/a{1,2}?/") +hasLocation(#20625,#20194) +#20626=* +tokeninfo(#20626,8,#20001,39,";") +#20627=@"loc,{#10000},20,10,20,10" +locations_default(#20627,#10000,20,10,20,10) +hasLocation(#20626,#20627) #20628=* -tokeninfo(#20628,8,#20001,41,";") -#20629=@"loc,{#10000},21,4,21,4" -locations_default(#20629,#10000,21,4,21,4) -hasLocation(#20628,#20629) -#20630=* -tokeninfo(#20630,5,#20001,42,"/(abc)/") -hasLocation(#20630,#20208) +tokeninfo(#20628,5,#20001,40,"/./") +hasLocation(#20628,#20202) +#20629=* +tokeninfo(#20629,8,#20001,41,";") +#20630=@"loc,{#10000},21,4,21,4" +locations_default(#20630,#10000,21,4,21,4) +hasLocation(#20629,#20630) #20631=* -tokeninfo(#20631,8,#20001,43,";") -#20632=@"loc,{#10000},22,8,22,8" -locations_default(#20632,#10000,22,8,22,8) -hasLocation(#20631,#20632) -#20633=* -tokeninfo(#20633,5,#20001,44,"/(?:abc)/") -hasLocation(#20633,#20222) +tokeninfo(#20631,5,#20001,42,"/(abc)/") +hasLocation(#20631,#20208) +#20632=* +tokeninfo(#20632,8,#20001,43,";") +#20633=@"loc,{#10000},22,8,22,8" +locations_default(#20633,#10000,22,8,22,8) +hasLocation(#20632,#20633) #20634=* -tokeninfo(#20634,8,#20001,45,";") -#20635=@"loc,{#10000},23,10,23,10" -locations_default(#20635,#10000,23,10,23,10) -hasLocation(#20634,#20635) -#20636=* -tokeninfo(#20636,5,#20001,46,"/\x0a/") -hasLocation(#20636,#20236) +tokeninfo(#20634,5,#20001,44,"/(?:abc)/") +hasLocation(#20634,#20222) +#20635=* +tokeninfo(#20635,8,#20001,45,";") +#20636=@"loc,{#10000},23,10,23,10" +locations_default(#20636,#10000,23,10,23,10) +hasLocation(#20635,#20636) #20637=* -tokeninfo(#20637,8,#20001,47,";") -#20638=@"loc,{#10000},24,7,24,7" -locations_default(#20638,#10000,24,7,24,7) -hasLocation(#20637,#20638) -#20639=* -tokeninfo(#20639,5,#20001,48,"/\u000a/") -hasLocation(#20639,#20242) +tokeninfo(#20637,5,#20001,46,"/\x0a/") +hasLocation(#20637,#20236) +#20638=* +tokeninfo(#20638,8,#20001,47,";") +#20639=@"loc,{#10000},24,7,24,7" +locations_default(#20639,#10000,24,7,24,7) +hasLocation(#20638,#20639) #20640=* -tokeninfo(#20640,8,#20001,49,";") -#20641=@"loc,{#10000},25,9,25,9" -locations_default(#20641,#10000,25,9,25,9) -hasLocation(#20640,#20641) -#20642=* -tokeninfo(#20642,5,#20001,50,"/\10/") -hasLocation(#20642,#20248) +tokeninfo(#20640,5,#20001,48,"/\u000a/") +hasLocation(#20640,#20242) +#20641=* +tokeninfo(#20641,8,#20001,49,";") +#20642=@"loc,{#10000},25,9,25,9" +locations_default(#20642,#10000,25,9,25,9) +hasLocation(#20641,#20642) #20643=* -tokeninfo(#20643,8,#20001,51,";") -#20644=@"loc,{#10000},26,6,26,6" -locations_default(#20644,#10000,26,6,26,6) -hasLocation(#20643,#20644) -#20645=* -tokeninfo(#20645,5,#20001,52,"/\t\n\r\f\v/") -hasLocation(#20645,#20254) +tokeninfo(#20643,5,#20001,50,"/\10/") +hasLocation(#20643,#20248) +#20644=* +tokeninfo(#20644,8,#20001,51,";") +#20645=@"loc,{#10000},26,6,26,6" +locations_default(#20645,#10000,26,6,26,6) +hasLocation(#20644,#20645) #20646=* -tokeninfo(#20646,8,#20001,53,";") -#20647=@"loc,{#10000},27,13,27,13" -locations_default(#20647,#10000,27,13,27,13) -hasLocation(#20646,#20647) -#20648=* -tokeninfo(#20648,5,#20001,54,"/\ca\cN/") -hasLocation(#20648,#20270) +tokeninfo(#20646,5,#20001,52,"/\t\n\r\f\v/") +hasLocation(#20646,#20255) +#20647=* +tokeninfo(#20647,8,#20001,53,";") +#20648=@"loc,{#10000},27,13,27,13" +locations_default(#20648,#10000,27,13,27,13) +hasLocation(#20647,#20648) #20649=* -tokeninfo(#20649,8,#20001,55,";") -#20650=@"loc,{#10000},28,9,28,9" -locations_default(#20650,#10000,28,9,28,9) -hasLocation(#20649,#20650) -#20651=* -tokeninfo(#20651,5,#20001,56,"/\w\S/") -hasLocation(#20651,#20280) +tokeninfo(#20649,5,#20001,54,"/\ca\cN/") +hasLocation(#20649,#20271) +#20650=* +tokeninfo(#20650,8,#20001,55,";") +#20651=@"loc,{#10000},28,9,28,9" +locations_default(#20651,#10000,28,9,28,9) +hasLocation(#20650,#20651) #20652=* -tokeninfo(#20652,8,#20001,57,";") -#20653=@"loc,{#10000},29,7,29,7" -locations_default(#20653,#10000,29,7,29,7) -hasLocation(#20652,#20653) -#20654=* -tokeninfo(#20654,5,#20001,58,"/\\/") -hasLocation(#20654,#20290) +tokeninfo(#20652,5,#20001,56,"/\w\S/") +hasLocation(#20652,#20281) +#20653=* +tokeninfo(#20653,8,#20001,57,";") +#20654=@"loc,{#10000},29,7,29,7" +locations_default(#20654,#10000,29,7,29,7) +hasLocation(#20653,#20654) #20655=* -tokeninfo(#20655,8,#20001,59,";") -#20656=@"loc,{#10000},30,5,30,5" -locations_default(#20656,#10000,30,5,30,5) -hasLocation(#20655,#20656) -#20657=* -tokeninfo(#20657,5,#20001,60,"/[abc]/") -hasLocation(#20657,#20296) +tokeninfo(#20655,5,#20001,58,"/\\/") +hasLocation(#20655,#20291) +#20656=* +tokeninfo(#20656,8,#20001,59,";") +#20657=@"loc,{#10000},30,5,30,5" +locations_default(#20657,#10000,30,5,30,5) +hasLocation(#20656,#20657) #20658=* -tokeninfo(#20658,8,#20001,61,";") -#20659=@"loc,{#10000},31,8,31,8" -locations_default(#20659,#10000,31,8,31,8) -hasLocation(#20658,#20659) -#20660=* -tokeninfo(#20660,5,#20001,62,"/[a-z]/") -hasLocation(#20660,#20308) +tokeninfo(#20658,5,#20001,60,"/[abc]/") +hasLocation(#20658,#20297) +#20659=* +tokeninfo(#20659,8,#20001,61,";") +#20660=@"loc,{#10000},31,8,31,8" +locations_default(#20660,#10000,31,8,31,8) +hasLocation(#20659,#20660) #20661=* -tokeninfo(#20661,8,#20001,63,";") -#20662=@"loc,{#10000},32,8,32,8" -locations_default(#20662,#10000,32,8,32,8) -hasLocation(#20661,#20662) -#20663=* -tokeninfo(#20663,5,#20001,64,"/[a-zA-Z]/") -hasLocation(#20663,#20320) +tokeninfo(#20661,5,#20001,62,"/[a-z]/") +hasLocation(#20661,#20309) +#20662=* +tokeninfo(#20662,8,#20001,63,";") +#20663=@"loc,{#10000},32,8,32,8" +locations_default(#20663,#10000,32,8,32,8) +hasLocation(#20662,#20663) #20664=* -tokeninfo(#20664,8,#20001,65,";") -#20665=@"loc,{#10000},33,11,33,11" -locations_default(#20665,#10000,33,11,33,11) -hasLocation(#20664,#20665) -#20666=* -tokeninfo(#20666,5,#20001,66,"/[-a-z]/") -hasLocation(#20666,#20338) +tokeninfo(#20664,5,#20001,64,"/[a-zA-Z]/") +hasLocation(#20664,#20321) +#20665=* +tokeninfo(#20665,8,#20001,65,";") +#20666=@"loc,{#10000},33,11,33,11" +locations_default(#20666,#10000,33,11,33,11) +hasLocation(#20665,#20666) #20667=* -tokeninfo(#20667,8,#20001,67,";") -#20668=@"loc,{#10000},34,9,34,9" -locations_default(#20668,#10000,34,9,34,9) -hasLocation(#20667,#20668) -#20669=* -tokeninfo(#20669,5,#20001,68,"/[^a-z]/") -hasLocation(#20669,#20352) +tokeninfo(#20667,5,#20001,66,"/[-a-z]/") +hasLocation(#20667,#20339) +#20668=* +tokeninfo(#20668,8,#20001,67,";") +#20669=@"loc,{#10000},34,9,34,9" +locations_default(#20669,#10000,34,9,34,9) +hasLocation(#20668,#20669) #20670=* -tokeninfo(#20670,8,#20001,69,";") -#20671=@"loc,{#10000},35,9,35,9" -locations_default(#20671,#10000,35,9,35,9) -hasLocation(#20670,#20671) -#20672=* -tokeninfo(#20672,5,#20001,70,"/[a\b\x0c]/") -hasLocation(#20672,#20364) +tokeninfo(#20670,5,#20001,68,"/[^a-z]/") +hasLocation(#20670,#20353) +#20671=* +tokeninfo(#20671,8,#20001,69,";") +#20672=@"loc,{#10000},35,9,35,9" +locations_default(#20672,#10000,35,9,35,9) +hasLocation(#20671,#20672) #20673=* -tokeninfo(#20673,8,#20001,71,";") -#20674=@"loc,{#10000},36,12,36,12" -locations_default(#20674,#10000,36,12,36,12) -hasLocation(#20673,#20674) -#20675=* -tokeninfo(#20675,5,#20001,72,"/a{/") -hasLocation(#20675,#20376) +tokeninfo(#20673,5,#20001,70,"/[a\b\x0c]/") +hasLocation(#20673,#20365) +#20674=* +tokeninfo(#20674,8,#20001,71,";") +#20675=@"loc,{#10000},36,12,36,12" +locations_default(#20675,#10000,36,12,36,12) +hasLocation(#20674,#20675) #20676=* -tokeninfo(#20676,8,#20001,73,";") -#20677=@"loc,{#10000},37,5,37,5" -locations_default(#20677,#10000,37,5,37,5) -hasLocation(#20676,#20677) -#20678=* -tokeninfo(#20678,5,#20001,74,"/a{b}/") -hasLocation(#20678,#20388) +tokeninfo(#20676,5,#20001,72,"/a{/") +hasLocation(#20676,#20377) +#20677=* +tokeninfo(#20677,8,#20001,73,";") +#20678=@"loc,{#10000},37,5,37,5" +locations_default(#20678,#10000,37,5,37,5) +hasLocation(#20677,#20678) #20679=* -tokeninfo(#20679,8,#20001,75,";") -#20680=@"loc,{#10000},38,7,38,7" -locations_default(#20680,#10000,38,7,38,7) -hasLocation(#20679,#20680) -#20681=* -tokeninfo(#20681,5,#20001,76,"/a{2/") -hasLocation(#20681,#20406) +tokeninfo(#20679,5,#20001,74,"/a{b}/") +hasLocation(#20679,#20389) +#20680=* +tokeninfo(#20680,8,#20001,75,";") +#20681=@"loc,{#10000},38,7,38,7" +locations_default(#20681,#10000,38,7,38,7) +hasLocation(#20680,#20681) #20682=* -tokeninfo(#20682,8,#20001,77,";") -#20683=@"loc,{#10000},39,6,39,6" -locations_default(#20683,#10000,39,6,39,6) -hasLocation(#20682,#20683) -#20684=* -tokeninfo(#20684,5,#20001,78,"/\xa/") -hasLocation(#20684,#20416) +tokeninfo(#20682,5,#20001,76,"/a{2/") +hasLocation(#20682,#20407) +#20683=* +tokeninfo(#20683,8,#20001,77,";") +#20684=@"loc,{#10000},39,6,39,6" +locations_default(#20684,#10000,39,6,39,6) +hasLocation(#20683,#20684) #20685=* -tokeninfo(#20685,8,#20001,79,";") -#20686=@"loc,{#10000},40,6,40,6" -locations_default(#20686,#10000,40,6,40,6) -hasLocation(#20685,#20686) -#20687=* -tokeninfo(#20687,5,#20001,80,"/\c0/") -hasLocation(#20687,#20424) +tokeninfo(#20685,5,#20001,78,"/\xa/") +hasLocation(#20685,#20417) +#20686=* +tokeninfo(#20686,8,#20001,79,";") +#20687=@"loc,{#10000},40,6,40,6" +locations_default(#20687,#10000,40,6,40,6) +hasLocation(#20686,#20687) #20688=* -tokeninfo(#20688,8,#20001,81,";") -#20689=@"loc,{#10000},41,6,41,6" -locations_default(#20689,#10000,41,6,41,6) -hasLocation(#20688,#20689) -#20690=* -tokeninfo(#20690,5,#20001,82,"/[]/") -hasLocation(#20690,#20432) +tokeninfo(#20688,5,#20001,80,"/\c0/") +hasLocation(#20688,#20425) +#20689=* +tokeninfo(#20689,8,#20001,81,";") +#20690=@"loc,{#10000},41,6,41,6" +locations_default(#20690,#10000,41,6,41,6) +hasLocation(#20689,#20690) #20691=* -tokeninfo(#20691,8,#20001,83,";") -#20692=@"loc,{#10000},42,5,42,5" -locations_default(#20692,#10000,42,5,42,5) -hasLocation(#20691,#20692) -#20693=* -tokeninfo(#20693,5,#20001,84,"/[^]/") -hasLocation(#20693,#20438) +tokeninfo(#20691,5,#20001,82,"/[]/") +hasLocation(#20691,#20433) +#20692=* +tokeninfo(#20692,8,#20001,83,";") +#20693=@"loc,{#10000},42,5,42,5" +locations_default(#20693,#10000,42,5,42,5) +hasLocation(#20692,#20693) #20694=* -tokeninfo(#20694,8,#20001,85,";") -#20695=@"loc,{#10000},43,6,43,6" -locations_default(#20695,#10000,43,6,43,6) -hasLocation(#20694,#20695) -#20696=* -tokeninfo(#20696,5,#20001,86,"/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/") -hasLocation(#20696,#20444) +tokeninfo(#20694,5,#20001,84,"/[^]/") +hasLocation(#20694,#20439) +#20695=* +tokeninfo(#20695,8,#20001,85,";") +#20696=@"loc,{#10000},43,6,43,6" +locations_default(#20696,#10000,43,6,43,6) +hasLocation(#20695,#20696) #20697=* -tokeninfo(#20697,8,#20001,87,";") -#20698=@"loc,{#10000},44,60,44,60" -locations_default(#20698,#10000,44,60,44,60) -hasLocation(#20697,#20698) -#20699=* -tokeninfo(#20699,0,#20001,88,"") -#20700=@"loc,{#10000},44,61,44,60" -locations_default(#20700,#10000,44,61,44,60) -hasLocation(#20699,#20700) -#20701=* -entry_cfg_node(#20701,#20001) -#20702=@"loc,{#10000},1,1,1,0" -locations_default(#20702,#10000,1,1,1,0) -hasLocation(#20701,#20702) -#20703=* -exit_cfg_node(#20703,#20001) -hasLocation(#20703,#20700) -successor(#20441,#20443) -successor(#20443,#20703) -successor(#20435,#20437) -successor(#20437,#20441) -successor(#20429,#20431) -successor(#20431,#20435) -successor(#20421,#20423) -successor(#20423,#20429) -successor(#20413,#20415) -successor(#20415,#20421) -successor(#20403,#20405) -successor(#20405,#20413) -successor(#20385,#20387) -successor(#20387,#20403) -successor(#20373,#20375) -successor(#20375,#20385) -successor(#20361,#20363) -successor(#20363,#20373) -successor(#20349,#20351) -successor(#20351,#20361) -successor(#20335,#20337) -successor(#20337,#20349) -successor(#20317,#20319) -successor(#20319,#20335) -successor(#20305,#20307) -successor(#20307,#20317) -successor(#20293,#20295) -successor(#20295,#20305) -successor(#20287,#20289) -successor(#20289,#20293) -successor(#20277,#20279) -successor(#20279,#20287) -successor(#20267,#20269) -successor(#20269,#20277) -successor(#20251,#20253) -successor(#20253,#20267) +tokeninfo(#20697,5,#20001,86,"/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/") +hasLocation(#20697,#20445) +#20698=* +tokeninfo(#20698,8,#20001,87,";") +#20699=@"loc,{#10000},44,60,44,60" +locations_default(#20699,#10000,44,60,44,60) +hasLocation(#20698,#20699) +#20700=* +tokeninfo(#20700,0,#20001,88,"") +#20701=@"loc,{#10000},44,61,44,60" +locations_default(#20701,#10000,44,61,44,60) +hasLocation(#20700,#20701) +#20702=* +entry_cfg_node(#20702,#20001) +#20703=@"loc,{#10000},1,1,1,0" +locations_default(#20703,#10000,1,1,1,0) +hasLocation(#20702,#20703) +#20704=* +exit_cfg_node(#20704,#20001) +hasLocation(#20704,#20701) +successor(#20442,#20444) +successor(#20444,#20704) +successor(#20436,#20438) +successor(#20438,#20442) +successor(#20430,#20432) +successor(#20432,#20436) +successor(#20422,#20424) +successor(#20424,#20430) +successor(#20414,#20416) +successor(#20416,#20422) +successor(#20404,#20406) +successor(#20406,#20414) +successor(#20386,#20388) +successor(#20388,#20404) +successor(#20374,#20376) +successor(#20376,#20386) +successor(#20362,#20364) +successor(#20364,#20374) +successor(#20350,#20352) +successor(#20352,#20362) +successor(#20336,#20338) +successor(#20338,#20350) +successor(#20318,#20320) +successor(#20320,#20336) +successor(#20306,#20308) +successor(#20308,#20318) +successor(#20294,#20296) +successor(#20296,#20306) +successor(#20288,#20290) +successor(#20290,#20294) +successor(#20278,#20280) +successor(#20280,#20288) +successor(#20268,#20270) +successor(#20270,#20278) +successor(#20252,#20254) +successor(#20254,#20268) successor(#20245,#20247) -successor(#20247,#20251) +successor(#20247,#20252) successor(#20239,#20241) successor(#20241,#20245) successor(#20233,#20235) @@ -2245,6 +2248,6 @@ successor(#20009,#20011) successor(#20011,#20031) successor(#20003,#20005) successor(#20005,#20009) -successor(#20701,#20003) +successor(#20702,#20003) numlines(#10000,44,44,0) filetype(#10000,"javascript") diff --git a/javascript/extractor/tests/regexp/input/es2018.js b/javascript/extractor/tests/regexp/input/es2018.js index f7d0d826b2c8..fef868bf99b4 100644 --- a/javascript/extractor/tests/regexp/input/es2018.js +++ b/javascript/extractor/tests/regexp/input/es2018.js @@ -3,3 +3,4 @@ /(?$/;") @@ -169,81 +169,125 @@ hasLocation(#20051,#20052) unicodePropertyEscapeName(#20051,"Script") unicodePropertyEscapeValue(#20051,"Greek") #20053=* -lines(#20053,#20001,"/^(?\s+)\w+\k$/;"," -") -hasLocation(#20053,#20004) -#20054=* -lines(#20054,#20001,"/(?<=.)/;"," -") -hasLocation(#20054,#20026) +stmts(#20053,2,#20001,5,"/\k\s+)\w+\k$/") -hasLocation(#20058,#20006) +regexpterm(#20057,22,#20055,0,"\k<") +#20058=@"loc,{#10000},6,2,6,4" +locations_default(#20058,#10000,6,2,6,4) +hasLocation(#20057,#20058) +namedBackref(#20057,"") #20059=* -tokeninfo(#20059,8,#20001,1,";") -#20060=@"loc,{#10000},1,24,1,24" -locations_default(#20060,#10000,1,24,1,24) +regexpParseErrors(#20059,#20057,"expected identifier") +#20060=@"loc,{#10000},6,5,6,5" +locations_default(#20060,#10000,6,5,6,5) hasLocation(#20059,#20060) #20061=* -tokeninfo(#20061,5,#20001,2,"/(?<=.)/") -hasLocation(#20061,#20028) -#20062=* -tokeninfo(#20062,8,#20001,3,";") -#20063=@"loc,{#10000},2,9,2,9" -locations_default(#20063,#10000,2,9,2,9) -hasLocation(#20062,#20063) +regexpParseErrors(#20061,#20057,"expected '>'") +#20062=@"loc,{#10000},6,4,6,4" +locations_default(#20062,#10000,6,4,6,4) +hasLocation(#20061,#20062) +#20063=* +lines(#20063,#20001,"/^(?\s+)\w+\k$/;"," +") +hasLocation(#20063,#20004) #20064=* -tokeninfo(#20064,5,#20001,4,"/(?\s+)\w+\k$/") +hasLocation(#20069,#20006) #20070=* -tokeninfo(#20070,5,#20001,8,"/\P{Script=Greek}/u") -hasLocation(#20070,#20050) -#20071=* -tokeninfo(#20071,8,#20001,9,";") -#20072=@"loc,{#10000},5,20,5,20" -locations_default(#20072,#10000,5,20,5,20) -hasLocation(#20071,#20072) +tokeninfo(#20070,8,#20001,1,";") +#20071=@"loc,{#10000},1,24,1,24" +locations_default(#20071,#10000,1,24,1,24) +hasLocation(#20070,#20071) +#20072=* +tokeninfo(#20072,5,#20001,2,"/(?<=.)/") +hasLocation(#20072,#20028) #20073=* -tokeninfo(#20073,0,#20001,10,"") -#20074=@"loc,{#10000},6,1,6,0" -locations_default(#20074,#10000,6,1,6,0) +tokeninfo(#20073,8,#20001,3,";") +#20074=@"loc,{#10000},2,9,2,9" +locations_default(#20074,#10000,2,9,2,9) hasLocation(#20073,#20074) #20075=* -entry_cfg_node(#20075,#20001) -#20076=@"loc,{#10000},1,1,1,0" -locations_default(#20076,#10000,1,1,1,0) -hasLocation(#20075,#20076) -#20077=* -exit_cfg_node(#20077,#20001) -hasLocation(#20077,#20074) +tokeninfo(#20075,5,#20001,4,"/(?`k(SLZS4o7Y7dXst{bSHr>>*7u#D}O5r?0AGMFr zZ!{zA+Ln_*Hi<@~-~9PTdZ{yfy?L8n4gK)?vA^rvQ&-vjp|)v4Kl^`PIuqqBQkB9K zKOg&4W$VN(Yw~cnZ|j}yu+M$UPK}+gPS;7*HbZ%6Y+YIbjEA}sr3>?*MrGD~% zf2oYW(**x5heO-+_dB~UPqpkfvfmr7lP_ieL2Ny{b7pXak!T<4_H$X^_f>mDobCg- zZq>y^zfnwm)g6w*U7*oQr^(PBYx~XCvO|X*GkBP*TxC&sIwHV};RN1MD2L_Y^Ea=O zes~(>>|DVGn`OxJr_)cJ6JIsK3&k{{bQHeLB2?is>MbKwIiFgr9n3pl*g(Zh zg0KOz{eJ9Zb)z=C8<`m~d*tf{WTZaQ1Qh-C1X)Lr<w`_e59( z=rkT#h1dEp*set7FLRCVzQ}ya!EGe?8wB6k2e`$~CqC^)X%G|mhEfo!<`Zx`Pk^DC zEjQBbIRR`LNx%&sdAk-KMA;7?%lc$JRr=@m@Bcl-cHC*(bElD_KUJZ{G>wmuW(mQl z%~H8^=4r(+0=spv8uNv^eOeG+%}@}^qSm7Z)7m%KmK&_Pl9=>NpbStfk_Lf_;hYqw zIR*%H-dD1iZKHkVS0{Z1Tuv}|lJ-%O^e3I9bEPFym_q2J%11hry+K8c$`>OIsu#mZ zq%3+3(KE)RfdG@f@aL1}+3Mf2>+SolYeoN>)kM~(2C}f#V0SCq>{ji5g)OJL>{g^g z+xHmv-r;O07*!yk<q^T4H9(N*U zB+lmabVk8GY94wMkZ)4u(0;Yeq1m@?#F(H=*R7XBbB+pQ2P4%nX70`?WRHP??5{kN zPv;R`chBB=2CdDnoM0LO;;Yu=5??U~D*WW3Ot>K#seysi0IlUpHzbuwo;K&e&~hQL zhz2$|XmQY*3k^8KNKmW+x02twXxP7-#vLpG literal 0 HcmV?d00001 From f06cef5d40ce1bb6c383c328fe528409e993ff1d Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 9 Nov 2018 08:38:52 +0000 Subject: [PATCH 11/68] JavaScript: Port JSDoc parser to Java. --- .../src/com/semmle/js/ast/SourceLocation.java | 4 + .../src/com/semmle/js/parser/JSDocParser.java | 1776 ++++++++++++++++- .../extractor/tests/comments/input/jsdoc.js | 25 + .../tests/comments/output/trap/jsdoc.js.trap | 650 ++++-- 4 files changed, 2217 insertions(+), 238 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/ast/SourceLocation.java b/javascript/extractor/src/com/semmle/js/ast/SourceLocation.java index 2ef727051f56..3a8475c3a5e0 100644 --- a/javascript/extractor/src/com/semmle/js/ast/SourceLocation.java +++ b/javascript/extractor/src/com/semmle/js/ast/SourceLocation.java @@ -21,6 +21,10 @@ public SourceLocation(String source, Position start) { this(source, start, null); } + public SourceLocation(SourceLocation that) { + this(that.source, that.start, that.end); + } + /** * The source code contained in this location. */ diff --git a/javascript/extractor/src/com/semmle/js/parser/JSDocParser.java b/javascript/extractor/src/com/semmle/js/parser/JSDocParser.java index a4fcd7867587..da5c351d23c8 100644 --- a/javascript/extractor/src/com/semmle/js/parser/JSDocParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/JSDocParser.java @@ -3,12 +3,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; - -import org.mozilla.javascript.NativeArray; -import org.mozilla.javascript.NativeObject; -import org.mozilla.javascript.Undefined; +import java.util.Set; import com.semmle.js.ast.Comment; import com.semmle.js.ast.Position; @@ -33,71 +31,38 @@ import com.semmle.js.ast.jsdoc.UndefinedLiteral; import com.semmle.js.ast.jsdoc.UnionType; import com.semmle.js.ast.jsdoc.VoidLiteral; +import com.semmle.util.data.Pair; import com.semmle.util.exception.Exceptions; /** - * A wrapper for invoking doctrine through Rhino. + * A Java port of doctrine. */ -public class JSDocParser extends ScriptLoader { - public JSDocParser() { - super("/doctrine.js"); - } +public class JSDocParser { + private String source; /** * Parse the given string as a JSDoc comment. */ public JSDocComment parse(Comment comment) { - NativeObject doctrine = (NativeObject)readGlobal("doctrine"); - NativeObject opts = mkObject("unwrap", true, "recoverable", true, - "sloppy", true, "lineNumbers", true); - NativeObject res = (NativeObject)callMethod(doctrine, "parse", comment.getText().substring(1), opts); - return decodeJSDocComment(res, comment); - } - - private JSDocComment decodeJSDocComment(NativeObject obj, Comment comment) { - String description = (String)readProperty(obj, "description"); - NativeArray tags = (NativeArray)readProperty(obj, "tags"); - return new JSDocComment(comment, description, decodeJSDocTags(tags, comment)); - } - - private List decodeJSDocTags(NativeArray tags, Comment comment) { - String src = comment.getText().substring(1); - List result = new ArrayList(tags.size()); - for (Object tag : tags) { - String title = readStringProperty(tag, "title"); - String description = readStringProperty(tag, "description"); - String name = readStringProperty(tag, "name"); - int startLine = readIntProperty(tag, "startLine"); - int startColumn = readIntProperty(tag, "startColumn"); - - Object type = readProperty(tag, "type"); - JSDocTypeExpression jsdocType; - if (type == null || type == Undefined.instance) { - jsdocType = null; - } else { - JSObjectDecoder typeDecoder = new JSObjectDecoder(src, this, "com.semmle.js.ast.jsdoc", spec); - try { - jsdocType = typeDecoder.decodeObject((NativeObject)type); - } catch (ParseError e) { - Exceptions.ignore(e, "Exceptions in JSDoc should always be ignored."); - jsdocType = null; - } - } + source = comment.getText().substring(1); + JSDocTagParser p = new JSDocTagParser(); + Pair> r = p.new TagParser(null).parse(source); + List tags = new ArrayList<>(); + for (JSDocTagParser.Tag tag : r.snd()) { + String title = tag.title; + String description = tag.description; + String name = tag.name; + int startLine = tag.startLine; + int startColumn = tag.startColumn; - NativeArray err = (NativeArray)readProperty(tag, "errors"); - List errors = new ArrayList(); - if (err != null) { - for (Object msg : err) { - errors.add(String.valueOf(msg)); - } - } + JSDocTypeExpression jsdocType = tag.type; int realStartLine = comment.getLoc().getStart().getLine() + startLine; int realStartColumn = (startLine == 0 ? comment.getLoc().getStart().getColumn() + 3 : 0) + startColumn; - SourceLocation loc = new SourceLocation(src, new Position(realStartLine, realStartColumn, -1), new Position(realStartLine, realStartColumn + 1 + title.length(), -1)); - result.add(new JSDocTag(loc, title, description, name, jsdocType, errors)); + SourceLocation loc = new SourceLocation(source, new Position(realStartLine, realStartColumn, -1), new Position(realStartLine, realStartColumn + 1 + title.length(), -1)); + tags.add(new JSDocTag(loc, title, description, name, jsdocType, tag.errors)); } - return result; + return new JSDocComment(comment, r.fst(), tags); } /** @@ -123,4 +88,1705 @@ private List decodeJSDocTags(NativeArray tags, Comment comment) { spec.put(UnionType.class, Arrays.asList("elements")); spec.put(VoidLiteral.class, Arrays.asList()); } + + private static String sliceSource(String source, int index, int last) { + if (index >= source.length()) + return ""; + if (last > source.length()) + last = source.length(); + return source.substring(index, last); + } + + private static boolean isLineTerminator(int ch) { + return ch == '\n' || ch == '\r' || ch == '\u2028' || ch == '\u2029'; + } + + private static boolean isWhiteSpace(char ch) { + return Character.isWhitespace(ch) && !isLineTerminator(ch) || + ch == '\u00a0'; + } + + private static boolean isDecimalDigit(char ch) { + return "0123456789".indexOf(ch) >= 0; + } + + private static boolean isHexDigit(char ch) { + return "0123456789abcdefABCDEF".indexOf(ch) >= 0; + } + + private static boolean isOctalDigit(char ch) { + return "01234567".indexOf(ch) >= 0; + } + + private static boolean isASCIIAlphanumeric(char ch) { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'); + } + + private static boolean isIdentifierStart(char ch) { + return (ch == '\\') || Character.isJavaIdentifierStart(ch); + } + + private static boolean isIdentifierPart(char ch) { + return (ch == '\\') || Character.isJavaIdentifierPart(ch); + } + + private static boolean isTypeName(char ch) { + return "><(){}[],:*|?!=".indexOf(ch) == -1 && !isWhiteSpace(ch) && !isLineTerminator(ch); + } + + private static boolean isParamTitle(String title) { + return title.equals("param") || title.equals("argument") || title.equals("arg"); + } + + private static boolean isProperty(String title) { + return title.equals("property") || title.equals("prop"); + } + + private static boolean isNameParameterRequired(String title) { + return isParamTitle(title) || isProperty(title) || + title.equals("alias") || title.equals("this") || title.equals("mixes") || title.equals("requires"); + } + + private static boolean isAllowedName(String title) { + return isNameParameterRequired(title) || title.equals("const") || title.equals("constant"); + } + + private static boolean isAllowedNested(String title) { + return isProperty(title) || isParamTitle(title); + } + + private static boolean isTypeParameterRequired(String title) { + return isParamTitle(title) || title.equals("define") || title.equals("enum") || + title.equals("implements") || title.equals("return") || + title.equals("this") || title.equals("type") || title.equals("typedef") || + title.equals("returns") || isProperty(title); + } + + // Consider deprecation instead using 'isTypeParameterRequired' and 'Rules' declaration to pick when a type is optional/required + // This would require changes to 'parseType' + private static boolean isAllowedType(String title) { + return isTypeParameterRequired(title) || title.equals("throws") || title.equals("const") || title.equals("constant") || + title.equals("namespace") || title.equals("member") || title.equals("var") || title.equals("module") || + title.equals("constructor") || title.equals("class") || title.equals("extends") || title.equals("augments") || + title.equals("public") || title.equals("private") || title.equals("protected"); + } + + private static T throwError(String message) throws ParseError { + throw new ParseError(message, null); + } + + private static class TypeExpressionParser { + private enum Token { + ILLEGAL, // ILLEGAL + DOT, // . + DOT_LT, // .< + REST, // ... + LT, // < + GT, // > + LPAREN, // ( + RPAREN, // ) + LBRACE, // { + RBRACE, // } + LBRACK, // [ + RBRACK, // ] + COMMA, // , + COLON, // : + STAR, // * + PIPE, // | + QUESTION, // ? + BANG, // ! + EQUAL, // = + NAME, // name token + STRING, // string + NUMBER, // number + EOF + }; + + String source; + int length; + int previous, index; + Token token; + Object value; + + private class Context { + int _previous, _index; + Token _token; + Object _value; + + Context(int previous, int index, Token token, Object value) { + this._previous = previous; + this._index = index; + this._token = token; + this._value = value; + } + + void restore() { + previous = this._previous; + index = this._index; + token = this._token; + value = this._value; + } + } + + Context save() { + return new Context(previous, index, token, value); + } + + private SourceLocation loc() { + return new SourceLocation(pos()); + } + + private Position pos() { + return new Position(1, index+1, index); + } + + private T finishNode(T node) { + SourceLocation loc = node.getLoc(); + Position end = pos(); + loc.setSource(inputSubstring(loc.getStart().getOffset(), end.getOffset())); + loc.setEnd(end); + return node; + } + + private String inputSubstring(int start, int end) { + if (start >= source.length()) + return ""; + if (end > source.length()) + end = source.length(); + return source.substring(start, end); + } + + private int advance() { + if (index >= source.length()) + return -1; + return source.charAt(index++); + } + + private String scanHexEscape(char prefix) { + int i, len, ch, code = 0; + + len = (prefix == 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source.charAt(index))) { + ch = advance(); + code = code * 16 + "0123456789abcdef".indexOf(Character.toLowerCase(ch)); + } else { + return ""; + } + } + return new String(Character.toChars(code)); + } + + private Token scanString() throws ParseError { + StringBuilder str = new StringBuilder(); + int quote, ch, code, restore; //TODO review removal octal = false + String unescaped; + quote = source.charAt(index); + ++index; + + while (index < length) { + ch = advance(); + + if (ch == quote) { + quote = -1; + break; + } else if (ch == '\\') { + ch = advance(); + if (!isLineTerminator(ch)) { + switch (ch) { + case 'n': + str.append('\n'); + break; + case 'r': + str.append('\r'); + break; + case 't': + str.append('\t'); + break; + case 'u': + case 'x': + restore = index; + unescaped = scanHexEscape((char) ch); + if (!unescaped.isEmpty()) { + str.append(unescaped); + } else { + index = restore; + str.append((char) ch); + } + break; + case 'b': + str.append('\b'); + break; + case 'f': + str.append('\f'); + break; + case 'v': + str.append('\u000b'); + break; + + default: + if (isOctalDigit((char) ch)) { + code = "01234567".indexOf(ch); + + // \0 is not octal escape sequence + // Deprecating unused code. TODO review removal + //if (code != 0) { + // octal = true; + //} + + if (index < length && isOctalDigit(source.charAt(index))) { + //TODO Review Removal octal = true; + code = code * 8 + "01234567".indexOf(advance()); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ("0123".indexOf(ch) >= 0 && + index < length && + isOctalDigit(source.charAt(index))) { + code = code * 8 + "01234567".indexOf(advance()); + } + } + str.append(Character.toChars(code)); + } else { + str.append((char) ch); + } + break; + } + } else { + if (ch == '\r' && index < length && source.charAt(index) == '\n') { + ++index; + } + } + } else if (isLineTerminator(ch)) { + break; + } else { + str.append((char) ch); + } + } + + if (quote != -1) { + throwError("unexpected quote"); + } + + value = str.toString(); + return Token.STRING; + } + + private Token scanNumber() throws ParseError { + StringBuilder number = new StringBuilder(); + boolean isFloat = false; + char ch = '\0'; + + if (ch != '.') { + int next = advance(); + number.append((char)next); + ch = index < length ? source.charAt(index) : '\0'; + + if (next == '0') { + if (ch == 'x' || ch == 'X') { + number.append((char)advance()); + while (index < length) { + ch = source.charAt(index); + if (!isHexDigit(ch)) { + break; + } + number.append((char)advance()); + } + + if (number.length() <= 2) { + // only 0x + throwError("unexpected token"); + } + + if (index < length) { + ch = source.charAt(index); + if (isIdentifierStart(ch)) { + throwError("unexpected token"); + } + } + try { + value = Integer.parseInt(number.toString(), 16); + } catch (NumberFormatException nfe) { + Exceptions.ignore(nfe, "Precise exception content is unimportant"); + throwError("Invalid hexadecimal constant " + number); + } + return Token.NUMBER; + } + + if (isOctalDigit(ch)) { + number.append((char)advance()); + while (index < length) { + ch = source.charAt(index); + if (!isOctalDigit(ch)) { + break; + } + number.append((char)advance()); + } + + if (index < length) { + ch = source.charAt(index); + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwError("unexpected token"); + } + } + try { + value = Integer.parseInt(number.toString(), 8); + } catch (NumberFormatException nfe) { + Exceptions.ignore(nfe, "Precise exception content is unimportant"); + throwError("Invalid octal constant " + number); + } + return Token.NUMBER; + } + + if (isDecimalDigit(ch)) { + throwError("unexpected token"); + } + } + + while (index < length) { + ch = source.charAt(index); + if (!isDecimalDigit(ch)) { + break; + } + number.append((char)advance()); + } + } + + if (ch == '.') { + isFloat = true; + number.append((char)advance()); + while (index < length) { + ch = source.charAt(index); + if (!isDecimalDigit(ch)) { + break; + } + number.append((char)advance()); + } + } + + if (ch == 'e' || ch == 'E') { + isFloat = true; + number.append((char)advance()); + + ch = index < length ? source.charAt(index) : '\0'; + if (ch == '+' || ch == '-') { + number.append((char)advance()); + } + + ch = index < length ? source.charAt(index) : '\0'; + if (isDecimalDigit(ch)) { + number.append((char)advance()); + while (index < length) { + ch = source.charAt(index); + if (!isDecimalDigit(ch)) { + break; + } + number.append((char)advance()); + } + } else { + throwError("unexpected token"); + } + } + + if (index < length) { + ch = source.charAt(index); + if (isIdentifierStart(ch)) { + throwError("unexpected token"); + } + } + + String num = number.toString(); + try { + if (isFloat) + value = Double.parseDouble(num); + else + value = Integer.parseInt(num); + } catch (NumberFormatException nfe) { + Exceptions.ignore(nfe, "Precise exception content is unimportant"); + throwError("Invalid numeric literal " + num); + } + return Token.NUMBER; + } + + private Token scanTypeName() { + char ch, ch2; + + value = new String(Character.toChars(advance())); + while (index < length && isTypeName(source.charAt(index))) { + ch = source.charAt(index); + if (ch == '.') { + if ((index + 1) < length) { + ch2 = source.charAt(index + 1); + if (ch2 == '<') { + break; + } + } + } + value += new String(Character.toChars(advance())); + } + return Token.NAME; + } + + private Token next() throws ParseError { + char ch; + + previous = index; + + while (index < length && isWhiteSpace(source.charAt(index))) { + advance(); + } + if (index >= length) { + token = Token.EOF; + return token; + } + + ch = source.charAt(index); + switch (ch) { + case '"': + token = scanString(); + return token; + + case ':': + advance(); + token = Token.COLON; + return token; + + case ',': + advance(); + token = Token.COMMA; + return token; + + case '(': + advance(); + token = Token.LPAREN; + return token; + + case ')': + advance(); + token = Token.RPAREN; + return token; + + case '[': + advance(); + token = Token.LBRACK; + return token; + + case ']': + advance(); + token = Token.RBRACK; + return token; + + case '{': + advance(); + token = Token.LBRACE; + return token; + + case '}': + advance(); + token = Token.RBRACE; + return token; + + case '.': + advance(); + if (index < length) { + ch = source.charAt(index); + if (ch == '<') { + advance(); + token = Token.DOT_LT; + return token; + } + + if (ch == '.' && index + 1 < length && source.charAt(index + 1) == '.') { + advance(); + advance(); + token = Token.REST; + return token; + } + + if (isDecimalDigit(ch)) { + token = scanNumber(); + return token; + } + } + token = Token.DOT; + return token; + + case '<': + advance(); + token = Token.LT; + return token; + + case '>': + advance(); + token = Token.GT; + return token; + + case '*': + advance(); + token = Token.STAR; + return token; + + case '|': + advance(); + token = Token.PIPE; + return token; + + case '?': + advance(); + token = Token.QUESTION; + return token; + + case '!': + advance(); + token = Token.BANG; + return token; + + case '=': + advance(); + token = Token.EQUAL; + return token; + + default: + if (isDecimalDigit(ch)) { + token = scanNumber(); + return token; + } + + // type string permits following case, + // + // namespace.module.MyClass + // + // this reduced 1 token TK_NAME + if (isTypeName(ch)) { + token = scanTypeName(); + return token; + } + + token = Token.ILLEGAL; + return token; + } + } + + private void consume(Token target, String text) throws ParseError { + if (token != target) + throwError(text == null ? "consumed token not matched" : text); + next(); + } + + private void consume(Token target) throws ParseError { + consume(target, null); + } + + private void expect(Token target) throws ParseError { + if (token != target) { + throwError("unexpected token"); + } + next(); + } + + // UnionType := '(' TypeUnionList ')' + // + // TypeUnionList := + // <> + // | NonemptyTypeUnionList + // + // NonemptyTypeUnionList := + // TypeExpression + // | TypeExpression '|' NonemptyTypeUnionList + private JSDocTypeExpression parseUnionType() throws ParseError { + SourceLocation loc = loc(); + List elements = new ArrayList<>(); + consume(Token.LPAREN, "UnionType should start with ("); + if (token != Token.RPAREN) { + while (true) { + elements.add(parseTypeExpression()); + if (token == Token.RPAREN) { + break; + } + expect(Token.PIPE); + } + } + consume(Token.RPAREN, "UnionType should end with )"); + return finishNode(new UnionType(loc, elements)); + } + + // ArrayType := '[' ElementTypeList ']' + // + // ElementTypeList := + // <> + // | TypeExpression + // | '...' TypeExpression + // | TypeExpression ',' ElementTypeList + private JSDocTypeExpression parseArrayType() throws ParseError { + SourceLocation loc = loc(); + List elements = new ArrayList<>(); + consume(Token.LBRACK, "ArrayType should start with ["); + while (token != Token.RBRACK) { + loc = loc(); + if (token == Token.REST) { + consume(Token.REST); + elements.add(finishNode(new RestType(loc, parseTypeExpression()))); + break; + } else { + elements.add(parseTypeExpression()); + } + if (token != Token.RBRACK) { + expect(Token.COMMA); + } + } + expect(Token.RBRACK); + return finishNode(new ArrayType(loc, elements)); + } + + private String parseFieldName() throws ParseError { + Object v = value; + if (token == Token.NAME || token == Token.STRING) { + next(); + return v.toString(); + } + + if (token == Token.NUMBER) { + consume(Token.NUMBER); + return v.toString(); + } + + return throwError("unexpected token"); + } + + // FieldType := + // FieldName + // | FieldName ':' TypeExpression + // + // FieldName := + // NameExpression + // | StringLiteral + // | NumberLiteral + // | ReservedIdentifier + private FieldType parseFieldType() throws ParseError { + String key; + SourceLocation loc = loc(); + key = parseFieldName(); + if (token == Token.COLON) { + consume(Token.COLON); + return finishNode(new FieldType(loc, key, parseTypeExpression())); + } + return finishNode(new FieldType(loc, key, null)); + } + + // RecordType := '{' FieldTypeList '}' + // + // FieldTypeList := + // <> + // | FieldType + // | FieldType ',' FieldTypeList + private JSDocTypeExpression parseRecordType() throws ParseError { + List fields = new ArrayList<>(); + SourceLocation loc = loc(); + consume(Token.LBRACE, "RecordType should start with {"); + if (token == Token.COMMA) { + consume(Token.COMMA); + } else { + while (token != Token.RBRACE) { + fields.add(parseFieldType()); + if (token != Token.RBRACE) { + expect(Token.COMMA); + } + } + } + expect(Token.RBRACE); + return finishNode(new RecordType(loc, fields)); + } + + private JSDocTypeExpression parseNameExpression() throws ParseError { + Object name = value; + SourceLocation loc = loc(); + expect(Token.NAME); + return finishNode(new NameExpression(loc, name.toString())); + } + + // TypeExpressionList := + // TopLevelTypeExpression + // | TopLevelTypeExpression ',' TypeExpressionList + private List parseTypeExpressionList() throws ParseError { + List elements = new ArrayList<>(); + + elements.add(parseTop()); + while (token == Token.COMMA) { + consume(Token.COMMA); + elements.add(parseTop()); + } + return elements; + } + + // TypeName := + // NameExpression + // | NameExpression TypeApplication + // + // TypeApplication := + // '.<' TypeExpressionList '>' + // | '<' TypeExpressionList '>' // this is extension of doctrine + private JSDocTypeExpression parseTypeName() throws ParseError { + JSDocTypeExpression expr; + List applications; + SourceLocation loc = loc(); + expr = parseNameExpression(); + if (token == Token.DOT_LT || token == Token.LT) { + next(); + applications = parseTypeExpressionList(); + expect(Token.GT); + return finishNode(new TypeApplication(loc, expr, applications)); + } + return expr; + } + + // ResultType := + // <> + // | ':' void + // | ':' TypeExpression + // + // BNF is above + // but, we remove <> pattern, so token is always TypeToken::COLON + private JSDocTypeExpression parseResultType() throws ParseError { + consume(Token.COLON, "ResultType should start with :"); + SourceLocation loc = loc(); + if (token == Token.NAME && value.equals("void")) { + consume(Token.NAME); + return finishNode(new VoidLiteral(loc)); + } + return parseTypeExpression(); + } + + // ParametersType := + // RestParameterType + // | NonRestParametersType + // | NonRestParametersType ',' RestParameterType + // + // RestParameterType := + // '...' + // '...' Identifier + // + // NonRestParametersType := + // ParameterType ',' NonRestParametersType + // | ParameterType + // | OptionalParametersType + // + // OptionalParametersType := + // OptionalParameterType + // | OptionalParameterType, OptionalParametersType + // + // OptionalParameterType := ParameterType= + // + // ParameterType := TypeExpression | Identifier ':' TypeExpression + // + // Identifier is "new" or "this" + private List parseParametersType() throws ParseError { + List params = new ArrayList<>(); + boolean normal = true; + JSDocTypeExpression expr; + boolean rest = false; + + while (token != Token.RPAREN) { + if (token == Token.REST) { + // RestParameterType + consume(Token.REST); + rest = true; + } + + SourceLocation loc = loc(); + expr = parseTypeExpression(); + if (expr instanceof NameExpression && token == Token.COLON) { + // Identifier ':' TypeExpression + consume(Token.COLON); + expr = finishNode(new ParameterType(loc, ((NameExpression) expr).getName(), parseTypeExpression())); + } + if (token == Token.EQUAL) { + consume(Token.EQUAL); + expr = finishNode(new OptionalType(loc, expr)); + normal = false; + } else { + if (!normal) { + throwError("unexpected token"); + } + } + if (rest) { + expr = finishNode(new RestType(new SourceLocation(loc), expr)); + } + params.add(expr); + if (token != Token.RPAREN) { + expect(Token.COMMA); + } + } + return params; + } + + // FunctionType := 'function' FunctionSignatureType + // + // FunctionSignatureType := + // | TypeParameters '(' ')' ResultType + // | TypeParameters '(' ParametersType ')' ResultType + // | TypeParameters '(' 'this' ':' TypeName ')' ResultType + // | TypeParameters '(' 'this' ':' TypeName ',' ParametersType ')' ResultType + private JSDocTypeExpression parseFunctionType() throws ParseError { + SourceLocation loc = loc(); + boolean isNew; + JSDocTypeExpression thisBinding; + List params; + JSDocTypeExpression result; + consume(Token.NAME); + + // Google Closure Compiler is not implementing TypeParameters. + // So we do not. if we don't get '(', we see it as error. + expect(Token.LPAREN); + + isNew = false; + params = new ArrayList(); + thisBinding = null; + if (token != Token.RPAREN) { + // ParametersType or 'this' + if (token == Token.NAME && + (value.equals("this") || value.equals("new"))) { + // 'this' or 'new' + // 'new' is Closure Compiler extension + isNew = value.equals("new"); + consume(Token.NAME); + expect(Token.COLON); + thisBinding = parseTypeName(); + if (token == Token.COMMA) { + consume(Token.COMMA); + params = parseParametersType(); + } + } else { + params = parseParametersType(); + } + } + + expect(Token.RPAREN); + + result = null; + if (token == Token.COLON) { + result = parseResultType(); + } + + return finishNode(new FunctionType(loc, thisBinding, isNew, params, result)); + } + + // BasicTypeExpression := + // '*' + // | 'null' + // | 'undefined' + // | TypeName + // | FunctionType + // | UnionType + // | RecordType + // | ArrayType + private JSDocTypeExpression parseBasicTypeExpression() throws ParseError { + Context context; + SourceLocation loc; + switch (token) { + case STAR: + loc = loc(); + consume(Token.STAR); + return new AllLiteral(loc); + + case LPAREN: + return parseUnionType(); + + case LBRACK: + return parseArrayType(); + + case LBRACE: + return parseRecordType(); + + case NAME: + if (value.equals("null")) { + loc = loc(); + consume(Token.NAME); + return new NullLiteral(loc); + } + + if (value.equals("undefined")) { + loc = loc(); + consume(Token.NAME); + return new UndefinedLiteral(loc); + } + + context = save(); + if (value.equals("function")) { + try { + return parseFunctionType(); + } catch (ParseError e) { + context.restore(); + } + } + + return parseTypeName(); + + default: + return throwError("unexpected token"); + } + } + + // TypeExpression := + // BasicTypeExpression + // | '?' BasicTypeExpression + // | '!' BasicTypeExpression + // | BasicTypeExpression '?' + // | BasicTypeExpression '!' + // | '?' + // | BasicTypeExpression '[]' + private JSDocTypeExpression parseTypeExpression() throws ParseError { + JSDocTypeExpression expr; + SourceLocation loc = loc(); + + if (token == Token.QUESTION) { + consume(Token.QUESTION); + if (token == Token.COMMA || token == Token.EQUAL || token == Token.RBRACE || + token == Token.RPAREN || token == Token.PIPE || token == Token.EOF || + token == Token.RBRACK) { + return finishNode(new NullableLiteral(loc)); + } + return finishNode(new NullableType(loc, parseBasicTypeExpression(), true)); + } + + if (token == Token.BANG) { + consume(Token.BANG); + return finishNode(new NonNullableType(loc, parseBasicTypeExpression(), true)); + } + + expr = parseBasicTypeExpression(); + if (token == Token.BANG) { + consume(Token.BANG); + return finishNode(new NonNullableType(loc, expr, false)); + } + + if (token == Token.QUESTION) { + consume(Token.QUESTION); + return finishNode(new NullableType(loc, expr, false)); + } + + if (token == Token.LBRACK) { + consume(Token.LBRACK); + consume(Token.RBRACK, "expected an array-style type declaration (' + value + '[])"); + List expressions = new ArrayList<>(); + expressions.add(expr); + return finishNode(new TypeApplication(loc, new NameExpression(loc, "Array"), expressions)); + } + + return expr; + } + + // TopLevelTypeExpression := + // TypeExpression + // | TypeUnionList + // + // This rule is Google Closure Compiler extension, not ES4 + // like, + // { number | string } + // If strict to ES4, we should write it as + // { (number|string) } + private JSDocTypeExpression parseTop() throws ParseError { + JSDocTypeExpression expr; + List elements = new ArrayList(); + SourceLocation loc = loc(); + + expr = parseTypeExpression(); + if (token != Token.PIPE) { + return expr; + } + + elements.add(expr); + consume(Token.PIPE); + while (true) { + elements.add(parseTypeExpression()); + if (token != Token.PIPE) { + break; + } + consume(Token.PIPE); + } + + return finishNode(new UnionType(loc, elements)); + } + + private JSDocTypeExpression parseTopParamType() throws ParseError { + JSDocTypeExpression expr; + SourceLocation loc = loc(); + + if (token == Token.REST) { + consume(Token.REST); + return finishNode(new RestType(loc, parseTop())); + } + + expr = parseTop(); + if (token == Token.EQUAL) { + consume(Token.EQUAL); + return finishNode(new OptionalType(loc, expr)); + } + + return expr; + } + + private JSDocTypeExpression parseType(String src) throws ParseError { + JSDocTypeExpression expr; + + source = src; + length = source.length(); + index = 0; + previous = 0; + + next(); + expr = parseTop(); + + if (token != Token.EOF) { + throwError("not reach to EOF"); + } + + return expr; + } + + private JSDocTypeExpression parseParamType(String src) throws ParseError { + JSDocTypeExpression expr; + + source = src; + length = source.length(); + index = 0; + previous = 0; + + next(); + expr = parseTopParamType(); + + if (token != Token.EOF) { + throwError("not reach to EOF"); + } + + return expr; + } + } + private static TypeExpressionParser typed = new TypeExpressionParser(); + + private static class JSDocTagParser { + int index, lineNumber, lineStart, length; + String source; + boolean recoverable = true, sloppy = false; + + private int skipStars(int index) { + while (index < length && isWhiteSpace(source.charAt(index)) && !isLineTerminator(source.charAt(index))) { + index += 1; + } + while (index < length && source.charAt(index) == '*') { + index += 1; + } + while (index < length && isWhiteSpace(source.charAt(index)) && !isLineTerminator(source.charAt(index))) { + index += 1; + } + return index; + } + + private char advance() { + char ch = source.charAt(index); + index += 1; + if (isLineTerminator(ch) && + !(ch == '\r' && index < length && source.charAt(index) == '\n')) { + lineNumber += 1; + lineStart = index; + index = skipStars(index); + } + return ch; + } + + private String scanTitle() { + StringBuilder title = new StringBuilder(); + // waste '@' + advance(); + + while (index < length && isASCIIAlphanumeric(source.charAt(index))) { + title.append(advance()); + } + + return title.toString(); + } + + private int seekContent() { + char ch; + boolean waiting = false; + int last = index; + + while (last < length) { + ch = source.charAt(last); + if (isLineTerminator(ch) && + !(ch == '\r' && last + 1 < length && source.charAt(last + 1) == '\n')) { + lineNumber += 1; + lineStart = last + 1; + last = skipStars(last + 1) - 1; + waiting = true; + } else if (waiting) { + if (ch == '@') { + break; + } + if (!isWhiteSpace(ch)) { + waiting = false; + } + } + last += 1; + } + return last; + } + + // type expression may have nest brace, such as, + // { { ok: string } } + // + // therefore, scanning type expression with balancing braces. + private JSDocTypeExpression parseType(String title, int last) throws ParseError { + char ch; + int brace; + StringBuilder type; + boolean direct = false; + + // search '{' + while (index < last) { + ch = source.charAt(index); + if (isWhiteSpace(ch)) { + advance(); + } else if (ch == '{') { + advance(); + break; + } else { + // this is direct pattern + direct = true; + break; + } + } + + if (!direct) { + // type expression { is found + brace = 1; + type = new StringBuilder(); + while (index < last) { + ch = source.charAt(index); + if (isLineTerminator(ch)) { + advance(); + } else { + if (ch == '}') { + brace -= 1; + if (brace == 0) { + advance(); + break; + } + } else if (ch == '{') { + brace += 1; + } + type.append(advance()); + } + } + + if (brace != 0) { + // braces is not balanced + return throwError("Braces are not balanced"); + } + + try { + if (isParamTitle(title)) { + return typed.parseParamType(type.toString()); + } + return typed.parseType(type.toString()); + } catch (ParseError e) { + // parse failed + return null; + } + } else { + return null; + } + } + + private String scanIdentifier(int last) { + StringBuilder identifier = new StringBuilder(); + if (!(index < length && isIdentifierStart(source.charAt(index)))) { + return null; + } + identifier.append(advance()); + while (index < last && isIdentifierPart(source.charAt(index))) { + identifier.append(advance()); + } + return identifier.toString(); + } + + private void skipWhiteSpace(int last) { + while (index < last && (isWhiteSpace(source.charAt(index)) || isLineTerminator(source.charAt(index)))) { + advance(); + } + } + + private String parseName(int last, boolean allowBrackets, boolean allowNestedParams) { + StringBuilder name = new StringBuilder(); + boolean useBrackets = false; + + skipWhiteSpace(last); + + if (index >= last) { + return null; + } + + if (allowBrackets && source.charAt(index) == '[') { + useBrackets = true; + name.append(advance()); + } + + if (!isIdentifierStart(source.charAt(index))) { + return null; + } + + name.append(scanIdentifier(last)); + + if (allowNestedParams) { + while (index < last && + (source.charAt(index) == '.' || source.charAt(index) == '#' || source.charAt(index) == '~')) { + name.append(source.charAt(index)); + index += 1; + name.append(scanIdentifier(last)); + } + } + + if (useBrackets) { + // do we have a default value for this? + if (index < last && source.charAt(index) == '=') { + + // consume the '='' symbol + name.append(advance()); + // scan in the default value + while (index < last && source.charAt(index) != ']') { + name .append(advance()); + } + } + + if (index >= last || source.charAt(index) != ']') { + // we never found a closing ']' + return null; + } + + // collect the last ']' + name .append(advance()); + } + + return name.toString(); + } + + boolean skipToTag() { + while (index < length && source.charAt(index) != '@') { + advance(); + } + if (index >= length) { + return false; + } + return true; + } + + private class Tag { + public String description; + public String title; + List errors = new ArrayList<>(); + JSDocTypeExpression type; + String name; + public int startLine; + public int startColumn; + } + + private class TagParser { + String _title; + Tag _tag; + int _last; + String _extra_name; + + TagParser(String title) { + this._title = title; + this._tag = new Tag(); + this._tag.description = null; + this._tag.title = title; + this._last = 0; + // space to save special information for title parsers. + this._extra_name = null; + } + + // addError(err, ...) + public boolean addError(String errorText, Object... args) { + this._tag.errors.add(String.format(errorText, args)); + return recoverable; + } + + public boolean parseType() { + // type required titles + if (isTypeParameterRequired(this._title)) { + try { + this._tag.type = JSDocTagParser.this.parseType(this._title, this._last); + if (this._tag.type == null) { + if (!isParamTitle(this._title)) { + if (!this.addError("Missing or invalid tag type")) { + return false; + } + } + } + } catch (ParseError error) { + this._tag.type = null; + if (!this.addError(error.getMessage())) { + return false; + } + } + } else if (isAllowedType(this._title)) { + // optional types + try { + this._tag.type = JSDocTagParser.this.parseType(this._title, this._last); + } catch (ParseError e) { + //For optional types, lets drop the thrown error when we hit the end of the file + } + } + return true; + } + + private boolean _parseNamePath(boolean optional) { + String name = JSDocTagParser.this.parseName(this._last, sloppy && isParamTitle(this._title), true); + if (name == null) { + if (!optional) { + if (!this.addError("Missing or invalid tag name")) { + return false; + } + } + } + this._tag.name = name; + return true; + } + + public boolean parseNamePath() { + return _parseNamePath(false); + } + + public boolean parseNamePathOptional() { + return this._parseNamePath(true); + } + + public boolean parseName() { + String[] assign; + String name; + + // param, property requires name + if (isAllowedName(this._title)) { + this._tag.name = JSDocTagParser.this.parseName(this._last, sloppy && isParamTitle(this._title), isAllowedNested(this._title)); + if (this._tag.name == null) { + if (!isNameParameterRequired(this._title)) { + return true; + } + + // it's possible the name has already been parsed but interpreted as a type + // it's also possible this is a sloppy declaration, in which case it will be + // fixed at the end + if (isParamTitle(this._title) && this._tag.type != null && this._tag.type instanceof NameExpression) { + this._extra_name = ((NameExpression) this._tag.type).getName(); + this._tag.name = ((NameExpression) this._tag.type).getName(); + this._tag.type = null; + } else { + if (!this.addError("Missing or invalid tag name")) { + return false; + } + } + } else { + name = this._tag.name; + if (name.charAt(0) == '[' && name.charAt(name.length() - 1) == ']') { + // extract the default value if there is one + // example: @param {string} [somebody=John Doe] description + assign = name.substring(1, name.length() - 1).split("="); + this._tag.name = assign[0]; + + // convert to an optional type + if (this._tag.type != null && !(this._tag.type instanceof OptionalType)) { + Position start = new Position(_tag.startLine, _tag.startColumn, _tag.startColumn); + Position end = new Position(_tag.startLine, _tag.startColumn, _tag.startColumn); + SourceLocation loc = new SourceLocation(_extra_name, start, end); + this._tag.type = new OptionalType(loc, this._tag.type); + } + } + } + } + + return true; + } + + private boolean parseDescription() { + String description = sliceSource(source, index, this._last).trim(); + if (!description.isEmpty()) { + if (description.matches("(?s)^-\\s+.*")) { + description = description.substring(2); + } + description = description.replaceAll("(?m)^\\s*\\*+\\s*", ""); + this._tag.description = description; + } + return true; + } + + private final Set kinds = new LinkedHashSet<>(); + { + kinds.add("class"); + kinds.add("constant"); + kinds.add("event"); + kinds.add("external"); + kinds.add("file"); + kinds.add("function"); + kinds.add("member"); + kinds.add("mixin"); + kinds.add("module"); + kinds.add("namespace"); + kinds.add("typedef"); + } + + private boolean parseKind() { + String kind = sliceSource(source, index, this._last).trim(); + if (!kinds.contains(kind)) { + if (!this.addError("Invalid kind name \'%s\'", kind)) { + return false; + } + } + return true; + } + + private boolean parseAccess() { + String access = sliceSource(source, index, this._last).trim(); + if (!access.equals("private") && !access.equals("protected") && !access.equals("public")) { + if (!this.addError("Invalid access name \'%s\'", access)) { + return false; + } + } + return true; + } + + private boolean parseVariation() { + double variation; + String text = sliceSource(source, index, this._last).trim(); + try { + variation = Double.parseDouble(text); + } catch (NumberFormatException nfe) { + variation = Double.NaN; + } + if (Double.isNaN(variation)) { + if (!this.addError("Invalid variation \'%s\'", text)) { + return false; + } + } + return true; + } + + private boolean ensureEnd() { + String shouldBeEmpty = sliceSource(source, index, this._last).trim(); + if (!shouldBeEmpty.matches("^[\\s*]*$")) { + if (!this.addError("Unknown content \'%s\'", shouldBeEmpty)) { + return false; + } + } + return true; + } + + private boolean epilogue() { + String description; + + description = this._tag.description; + // un-fix potentially sloppy declaration + if (isParamTitle(this._title) && this._tag.type == null && description != null + && description.startsWith("[")) { + if (_extra_name != null) { + Position start = new Position(_tag.startLine, _tag.startColumn, _tag.startColumn); + Position end = new Position(_tag.startLine, _tag.startColumn, _tag.startColumn); + SourceLocation loc = new SourceLocation(_extra_name, start, end); + this._tag.type = new NameExpression(loc, _extra_name); + } + this._tag.name = null; + + if (!sloppy) { + if (!this.addError("Missing or invalid tag name")) { + return false; + } + } + } + + return true; + } + + private Tag parse() { + int oldLineNumber, oldLineStart, newLineNumber, newLineStart; + + // empty title + if (this._title == null || this._title.isEmpty()) { + if (!this.addError("Missing or invalid title")) { + return null; + } + } + + // Seek to content last index. + oldLineNumber = lineNumber; + oldLineStart = lineStart; + this._last = seekContent(); + newLineNumber = lineNumber; + newLineStart = lineStart; + lineNumber = oldLineNumber; + lineStart = oldLineStart; + + switch (this._title) { + // http://usejsdoc.org/tags-access.html + case "access": if (!parseAccess()) return null; break; + // http://usejsdoc.org/tags-alias.html + case "alias": if (!parseNamePath() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-augments.html + case "augments": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-constructor.html + case "constructor": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break; + // Synonym: http://usejsdoc.org/tags-constructor.html + case "class": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break; + // Synonym: http://usejsdoc.org/tags-extends.html + case "extends": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-deprecated.html + case "deprecated": if (!parseDescription()) return null; break; + // http://usejsdoc.org/tags-global.html + case "global": if (!ensureEnd()) return null; break; + // http://usejsdoc.org/tags-inner.html + case "inner": if (!ensureEnd()) return null; break; + // http://usejsdoc.org/tags-instance.html + case "instance": if (!ensureEnd()) return null; break; + // http://usejsdoc.org/tags-kind.html + case "kind": if (!parseKind()) return null; break; + // http://usejsdoc.org/tags-mixes.html + case "mixes": if (!parseNamePath() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-mixin.html + case "mixin": if (!parseNamePathOptional() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-member.html + case "member": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-method.html + case "method": if (!parseNamePathOptional() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-module.html + case "module": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break; + // Synonym: http://usejsdoc.org/tags-method.html + case "func": if (!parseNamePathOptional() || !ensureEnd()) return null; break; + // Synonym: http://usejsdoc.org/tags-method.html + case "function": if (!parseNamePathOptional() || !ensureEnd()) return null; break; + // Synonym: http://usejsdoc.org/tags-member.html + case "var": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-name.html + case "name": if (!parseNamePath() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-namespace.html + case "namespace": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-private.html + case "private": if (!parseType() || !parseDescription()) return null; break; + // http://usejsdoc.org/tags-protected.html + case "protected": if (!parseType() || !parseDescription()) return null; break; + // http://usejsdoc.org/tags-public.html + case "public": if (!parseType() || !parseDescription()) return null; break; + // http://usejsdoc.org/tags-readonly.html + case "readonly": if (!ensureEnd()) return null; break; + // http://usejsdoc.org/tags-requires.html + case "requires": if (!parseNamePath() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-since.html + case "since": if (!parseDescription()) return null; break; + // http://usejsdoc.org/tags-static.html + case "static": if (!ensureEnd()) return null; break; + // http://usejsdoc.org/tags-summary.html + case "summary": if (!parseDescription()) return null; break; + // http://usejsdoc.org/tags-this.html + case "this": if (!parseNamePath() || !ensureEnd()) return null; break; + // http://usejsdoc.org/tags-todo.html + case "todo": if (!parseDescription()) return null; break; + // http://usejsdoc.org/tags-variation.html + case "variation": if (!parseVariation()) return null; break; + // http://usejsdoc.org/tags-version.html + case "version": if (!parseDescription()) return null; break; + // default sequences + default: if (!parseType() || !parseName() || !parseDescription() || !epilogue()) return null; break; + } + + // Seek global index to end of this tag. + index = this._last; + lineNumber = newLineNumber; + lineStart = newLineStart; + return this._tag; + } + + private Tag parseTag() { + String title; + Tag res; + TagParser parser; + int startColumn; + int startLine; + + // skip to tag + if (!skipToTag()) { + return null; + } + + startLine = lineNumber; + startColumn = index - lineStart; + + // scan title + title = scanTitle(); + + // construct tag parser + parser = new TagParser(title); + res = parser.parse(); + + if (res != null) { + res.startLine = startLine; + res.startColumn = startColumn; + } + + return res; + } + + // + // Parse JSDoc + // + + String scanJSDocDescription() { + StringBuilder description = new StringBuilder(); + char ch; + boolean atAllowed; + + atAllowed = true; + while (index < length) { + ch = source.charAt(index); + + if (atAllowed && ch == '@') { + break; + } + + if (isLineTerminator(ch)) { + atAllowed = true; + } else if (atAllowed && !isWhiteSpace(ch)) { + atAllowed = false; + } + + description.append(advance()); + } + return description.toString().trim(); + } + + + public Pair> parse(String comment) { + List tags = new ArrayList<>(); + Tag tag; + String description; + + source = comment.replaceAll("^/?\\*+", "").replaceAll("\\*+/?\\z", ""); + + length = source.length(); + index = 0; + lineNumber = 0; + lineStart = 0; + recoverable = true; + sloppy = true; + + description = scanJSDocDescription(); + + while (true) { + tag = parseTag(); + if (tag == null) { + break; + } + tags.add(tag); + } + + return Pair.make(description, tags); + } + } + } } diff --git a/javascript/extractor/tests/comments/input/jsdoc.js b/javascript/extractor/tests/comments/input/jsdoc.js index e8b4b59c3bf7..5f22f8bd78d4 100644 --- a/javascript/extractor/tests/comments/input/jsdoc.js +++ b/javascript/extractor/tests/comments/input/jsdoc.js @@ -15,3 +15,28 @@ * @param {Function(DOMNode)} * @param {Function(DOMNode)} x */ + +/** + * @{link a} + */ + +/** + * @typedef + * {a} + */ + +/** + * [resize description] + * @param {[type]} w [description] + * @param { } h [description] + * @return {[type]} [description] + */ + +/** +* @exports R +* +*/ + +/** + * @typedef {{0: number}} + */ diff --git a/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap b/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap index 5c0c6c543b04..7d0e6318feeb 100644 --- a/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap +++ b/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap @@ -10,8 +10,8 @@ hasLocation(#10000,#10002) scopes(#20000,0) #20001=@"script;{#10000},1,1" toplevels(#20001,0) -#20002=@"loc,{#10000},1,1,18,0" -locations_default(#20002,#10000,1,1,18,0) +#20002=@"loc,{#10000},1,1,43,0" +locations_default(#20002,#10000,1,1,43,0) hasLocation(#20001,#20002) #20003=* comments(#20003,2,#20001," @@ -51,253 +51,537 @@ comments(#20011,2,#20001," locations_default(#20012,#10000,14,1,17,3) hasLocation(#20011,#20012) #20013=* -lines(#20013,#20001,"/**"," -") -#20014=@"loc,{#10000},1,1,1,3" -locations_default(#20014,#10000,1,1,1,3) +comments(#20013,2,#20001," + * @{link a} + ","/**\n * @{link a}\n */") +#20014=@"loc,{#10000},19,1,21,3" +locations_default(#20014,#10000,19,1,21,3) hasLocation(#20013,#20014) #20015=* -lines(#20015,#20001," * This is a constant."," -") -#20016=@"loc,{#10000},2,1,2,22" -locations_default(#20016,#10000,2,1,2,22) +comments(#20015,2,#20001," + * @typedef + * {a} + ","/**\n * ... {a}\n */") +#20016=@"loc,{#10000},23,1,26,3" +locations_default(#20016,#10000,23,1,26,3) hasLocation(#20015,#20016) -indentation(#10000,2," ",1) #20017=* -lines(#20017,#20001," * "," -") -#20018=@"loc,{#10000},3,1,3,3" -locations_default(#20018,#10000,3,1,3,3) +comments(#20017,2,#20001," + * [resize description] + * @param {[type]} w [description] + * @param { } h [description] + * @return {[type]} [description] + ","/**\n * ... on]\n */") +#20018=@"loc,{#10000},28,1,33,3" +locations_default(#20018,#10000,28,1,33,3) hasLocation(#20017,#20018) -indentation(#10000,3," ",1) #20019=* -lines(#20019,#20001," * @const x"," -") -#20020=@"loc,{#10000},4,1,4,11" -locations_default(#20020,#10000,4,1,4,11) +comments(#20019,2,#20001," +* @exports R +* +","/**\n* @ ... R\n*\n*/") +#20020=@"loc,{#10000},35,1,38,2" +locations_default(#20020,#10000,35,1,38,2) hasLocation(#20019,#20020) -indentation(#10000,4," ",1) #20021=* -lines(#20021,#20001," */"," -") -#20022=@"loc,{#10000},5,1,5,3" -locations_default(#20022,#10000,5,1,5,3) +comments(#20021,2,#20001," + * @typedef {{0: number}} + ","/**\n * ... r}}\n */") +#20022=@"loc,{#10000},40,1,42,3" +locations_default(#20022,#10000,40,1,42,3) hasLocation(#20021,#20022) -indentation(#10000,5," ",1) #20023=* -lines(#20023,#20001,"/** @class {Object} klass */"," -") -hasLocation(#20023,#20006) -#20024=* -lines(#20024,#20001,"/** @deprecated */"," +lines(#20023,#20001,"/**"," ") -hasLocation(#20024,#20008) +#20024=@"loc,{#10000},1,1,1,3" +locations_default(#20024,#10000,1,1,1,3) +hasLocation(#20023,#20024) #20025=* -lines(#20025,#20001,"/** @param {(int|bool)} x"," +lines(#20025,#20001," * This is a constant."," ") -#20026=@"loc,{#10000},8,1,8,25" -locations_default(#20026,#10000,8,1,8,25) +#20026=@"loc,{#10000},2,1,2,22" +locations_default(#20026,#10000,2,1,2,22) hasLocation(#20025,#20026) +indentation(#10000,2," ",1) #20027=* -lines(#20027,#20001," * @param {Array.} ys"," +lines(#20027,#20001," * "," ") -#20028=@"loc,{#10000},9,1,9,38" -locations_default(#20028,#10000,9,1,9,38) +#20028=@"loc,{#10000},3,1,3,3" +locations_default(#20028,#10000,3,1,3,3) hasLocation(#20027,#20028) -indentation(#10000,9," ",1) +indentation(#10000,3," ",1) #20029=* -lines(#20029,#20001," * @param {String[]} zs"," +lines(#20029,#20001," * @const x"," ") -#20030=@"loc,{#10000},10,1,10,24" -locations_default(#20030,#10000,10,1,10,24) +#20030=@"loc,{#10000},4,1,4,11" +locations_default(#20030,#10000,4,1,4,11) hasLocation(#20029,#20030) -indentation(#10000,10," ",1) +indentation(#10000,4," ",1) #20031=* -lines(#20031,#20001," * @param {function(new:goog.ui.Menu, ?string=, number=): void} f"," +lines(#20031,#20001," */"," ") -#20032=@"loc,{#10000},11,1,11,66" -locations_default(#20032,#10000,11,1,11,66) +#20032=@"loc,{#10000},5,1,5,3" +locations_default(#20032,#10000,5,1,5,3) hasLocation(#20031,#20032) -indentation(#10000,11," ",1) +indentation(#10000,5," ",1) #20033=* -lines(#20033,#20001," * @param {...number} var_args"," +lines(#20033,#20001,"/** @class {Object} klass */"," ") -#20034=@"loc,{#10000},12,1,12,31" -locations_default(#20034,#10000,12,1,12,31) -hasLocation(#20033,#20034) -indentation(#10000,12," ",1) +hasLocation(#20033,#20006) +#20034=* +lines(#20034,#20001,"/** @deprecated */"," +") +hasLocation(#20034,#20008) #20035=* -lines(#20035,#20001," */"," +lines(#20035,#20001,"/** @param {(int|bool)} x"," ") -#20036=@"loc,{#10000},13,1,13,3" -locations_default(#20036,#10000,13,1,13,3) +#20036=@"loc,{#10000},8,1,8,25" +locations_default(#20036,#10000,8,1,8,25) hasLocation(#20035,#20036) -indentation(#10000,13," ",1) #20037=* -lines(#20037,#20001,"/**"," +lines(#20037,#20001," * @param {Array.} ys"," ") -#20038=@"loc,{#10000},14,1,14,3" -locations_default(#20038,#10000,14,1,14,3) +#20038=@"loc,{#10000},9,1,9,38" +locations_default(#20038,#10000,9,1,9,38) hasLocation(#20037,#20038) +indentation(#10000,9," ",1) #20039=* -lines(#20039,#20001," * @param {Function(DOMNode)}"," +lines(#20039,#20001," * @param {String[]} zs"," ") -#20040=@"loc,{#10000},15,1,15,29" -locations_default(#20040,#10000,15,1,15,29) +#20040=@"loc,{#10000},10,1,10,24" +locations_default(#20040,#10000,10,1,10,24) hasLocation(#20039,#20040) -indentation(#10000,15," ",1) +indentation(#10000,10," ",1) #20041=* -lines(#20041,#20001," * @param {Function(DOMNode)} x"," +lines(#20041,#20001," * @param {function(new:goog.ui.Menu, ?string=, number=): void} f"," ") -#20042=@"loc,{#10000},16,1,16,31" -locations_default(#20042,#10000,16,1,16,31) +#20042=@"loc,{#10000},11,1,11,66" +locations_default(#20042,#10000,11,1,11,66) hasLocation(#20041,#20042) -indentation(#10000,16," ",1) +indentation(#10000,11," ",1) #20043=* -lines(#20043,#20001," */"," +lines(#20043,#20001," * @param {...number} var_args"," ") -#20044=@"loc,{#10000},17,1,17,3" -locations_default(#20044,#10000,17,1,17,3) +#20044=@"loc,{#10000},12,1,12,31" +locations_default(#20044,#10000,12,1,12,31) hasLocation(#20043,#20044) -indentation(#10000,17," ",1) -numlines(#20001,17,0,17) +indentation(#10000,12," ",1) #20045=* -tokeninfo(#20045,0,#20001,0,"") -#20046=@"loc,{#10000},18,1,18,0" -locations_default(#20046,#10000,18,1,18,0) +lines(#20045,#20001," */"," +") +#20046=@"loc,{#10000},13,1,13,3" +locations_default(#20046,#10000,13,1,13,3) hasLocation(#20045,#20046) -next_token(#20003,#20045) -next_token(#20005,#20045) -next_token(#20007,#20045) -next_token(#20009,#20045) -next_token(#20011,#20045) +indentation(#10000,13," ",1) #20047=* -entry_cfg_node(#20047,#20001) -#20048=@"loc,{#10000},1,1,1,0" -locations_default(#20048,#10000,1,1,1,0) +lines(#20047,#20001,"/**"," +") +#20048=@"loc,{#10000},14,1,14,3" +locations_default(#20048,#10000,14,1,14,3) hasLocation(#20047,#20048) #20049=* -exit_cfg_node(#20049,#20001) -hasLocation(#20049,#20046) -successor(#20047,#20049) -#20050=* -jsdoc(#20050,"This is a constant.",#20003) -hasLocation(#20050,#20004) +lines(#20049,#20001," * @param {Function(DOMNode)}"," +") +#20050=@"loc,{#10000},15,1,15,29" +locations_default(#20050,#10000,15,1,15,29) +hasLocation(#20049,#20050) +indentation(#10000,15," ",1) #20051=* -jsdoc_tags(#20051,"const",#20050,0,"@const") -#20052=@"loc,{#10000},4,4,4,9" -locations_default(#20052,#10000,4,4,4,9) +lines(#20051,#20001," * @param {Function(DOMNode)} x"," +") +#20052=@"loc,{#10000},16,1,16,31" +locations_default(#20052,#10000,16,1,16,31) hasLocation(#20051,#20052) -jsdoc_tag_names(#20051,"x") +indentation(#10000,16," ",1) #20053=* -jsdoc(#20053,"",#20005) -hasLocation(#20053,#20006) -#20054=* -jsdoc_tags(#20054,"class",#20053,0,"@class") -#20055=@"loc,{#10000},6,5,6,10" -locations_default(#20055,#10000,6,5,6,10) -hasLocation(#20054,#20055) -jsdoc_tag_names(#20054,"klass") -#20056=* -jsdoc_type_exprs(#20056,5,#20054,0,"Object") +lines(#20053,#20001," */"," +") +#20054=@"loc,{#10000},17,1,17,3" +locations_default(#20054,#10000,17,1,17,3) +hasLocation(#20053,#20054) +indentation(#10000,17," ",1) +#20055=* +lines(#20055,#20001,""," +") +#20056=@"loc,{#10000},18,1,18,0" +locations_default(#20056,#10000,18,1,18,0) +hasLocation(#20055,#20056) #20057=* -jsdoc(#20057,"",#20007) -hasLocation(#20057,#20008) -#20058=* -jsdoc_tags(#20058,"deprecated",#20057,0,"@deprecated") -#20059=@"loc,{#10000},7,5,7,15" -locations_default(#20059,#10000,7,5,7,15) -hasLocation(#20058,#20059) -#20060=* -jsdoc(#20060,"",#20009) -hasLocation(#20060,#20010) +lines(#20057,#20001,"/**"," +") +#20058=@"loc,{#10000},19,1,19,3" +locations_default(#20058,#10000,19,1,19,3) +hasLocation(#20057,#20058) +#20059=* +lines(#20059,#20001," * @{link a}"," +") +#20060=@"loc,{#10000},20,1,20,12" +locations_default(#20060,#10000,20,1,20,12) +hasLocation(#20059,#20060) +indentation(#10000,20," ",1) #20061=* -jsdoc_tags(#20061,"param",#20060,0,"@param") -#20062=@"loc,{#10000},8,5,8,10" -locations_default(#20062,#10000,8,5,8,10) +lines(#20061,#20001," */"," +") +#20062=@"loc,{#10000},21,1,21,3" +locations_default(#20062,#10000,21,1,21,3) hasLocation(#20061,#20062) -jsdoc_tag_names(#20061,"x") +indentation(#10000,21," ",1) #20063=* -jsdoc_type_exprs(#20063,11,#20061,0,"(int|bool)") -#20064=* -jsdoc_type_exprs(#20064,5,#20063,0,"int") +lines(#20063,#20001,""," +") +#20064=@"loc,{#10000},22,1,22,0" +locations_default(#20064,#10000,22,1,22,0) +hasLocation(#20063,#20064) #20065=* -jsdoc_type_exprs(#20065,5,#20063,1,"bool") -#20066=* -jsdoc_tags(#20066,"param",#20060,1,"@param") -#20067=@"loc,{#10000},9,5,9,10" -locations_default(#20067,#10000,9,5,9,10) -hasLocation(#20066,#20067) -jsdoc_tag_names(#20066,"ys") -#20068=* -jsdoc_type_exprs(#20068,6,#20066,0,"Array.") +lines(#20065,#20001,"/**"," +") +#20066=@"loc,{#10000},23,1,23,3" +locations_default(#20066,#10000,23,1,23,3) +hasLocation(#20065,#20066) +#20067=* +lines(#20067,#20001," * @typedef"," +") +#20068=@"loc,{#10000},24,1,24,11" +locations_default(#20068,#10000,24,1,24,11) +hasLocation(#20067,#20068) +indentation(#10000,24," ",1) #20069=* -jsdoc_type_exprs(#20069,5,#20068,-1,"Array") -#20070=* -jsdoc_type_exprs(#20070,5,#20068,0,"String") +lines(#20069,#20001," * {a}"," +") +#20070=@"loc,{#10000},25,1,25,6" +locations_default(#20070,#10000,25,1,25,6) +hasLocation(#20069,#20070) +indentation(#10000,25," ",1) #20071=* -jsdoc_type_exprs(#20071,5,#20068,1,"Number") -#20072=* -jsdoc_tags(#20072,"param",#20060,2,"@param") -#20073=@"loc,{#10000},10,5,10,10" -locations_default(#20073,#10000,10,5,10,10) -hasLocation(#20072,#20073) -jsdoc_tag_names(#20072,"zs") -#20074=* -jsdoc_type_exprs(#20074,6,#20072,0,"Array.") +lines(#20071,#20001," */"," +") +#20072=@"loc,{#10000},26,1,26,3" +locations_default(#20072,#10000,26,1,26,3) +hasLocation(#20071,#20072) +indentation(#10000,26," ",1) +#20073=* +lines(#20073,#20001,""," +") +#20074=@"loc,{#10000},27,1,27,0" +locations_default(#20074,#10000,27,1,27,0) +hasLocation(#20073,#20074) #20075=* -jsdoc_type_exprs(#20075,5,#20074,-1,"Array") -#20076=* -jsdoc_type_exprs(#20076,5,#20074,0,"String") +lines(#20075,#20001,"/**"," +") +#20076=@"loc,{#10000},28,1,28,3" +locations_default(#20076,#10000,28,1,28,3) +hasLocation(#20075,#20076) #20077=* -jsdoc_tags(#20077,"param",#20060,3,"@param") -#20078=@"loc,{#10000},11,5,11,10" -locations_default(#20078,#10000,11,5,11,10) +lines(#20077,#20001," * [resize description]"," +") +#20078=@"loc,{#10000},29,1,29,23" +locations_default(#20078,#10000,29,1,29,23) hasLocation(#20077,#20078) -jsdoc_tag_names(#20077,"f") +indentation(#10000,29," ",1) #20079=* -jsdoc_type_exprs(#20079,12,#20077,0,"function (new: goog.ui.Menu, ?string=, number=): void") -#20080=* -jsdoc_type_exprs(#20080,13,#20079,0,"?string=") +lines(#20079,#20001," * @param {[type]} w [description]"," +") +#20080=@"loc,{#10000},30,1,30,35" +locations_default(#20080,#10000,30,1,30,35) +hasLocation(#20079,#20080) +indentation(#10000,30," ",1) #20081=* -jsdoc_type_exprs(#20081,7,#20080,0,"?string") -#20082=* -jsdoc_type_exprs(#20082,5,#20081,0,"string") -jsdoc_prefix_qualifier(#20081) +lines(#20081,#20001," * @param { } h [description]"," +") +#20082=@"loc,{#10000},31,1,31,31" +locations_default(#20082,#10000,31,1,31,31) +hasLocation(#20081,#20082) +indentation(#10000,31," ",1) #20083=* -jsdoc_type_exprs(#20083,13,#20079,1,"number=") -#20084=* -jsdoc_type_exprs(#20084,5,#20083,0,"number") +lines(#20083,#20001," * @return {[type]} [description]"," +") +#20084=@"loc,{#10000},32,1,32,35" +locations_default(#20084,#10000,32,1,32,35) +hasLocation(#20083,#20084) +indentation(#10000,32," ",1) #20085=* -jsdoc_type_exprs(#20085,4,#20079,-1,"void") -#20086=* -jsdoc_type_exprs(#20086,5,#20079,-2,"goog.ui.Menu") -jsdoc_has_new_parameter(#20079) +lines(#20085,#20001," */"," +") +#20086=@"loc,{#10000},33,1,33,3" +locations_default(#20086,#10000,33,1,33,3) +hasLocation(#20085,#20086) +indentation(#10000,33," ",1) #20087=* -jsdoc_tags(#20087,"param",#20060,4,"@param") -#20088=@"loc,{#10000},12,5,12,10" -locations_default(#20088,#10000,12,5,12,10) +lines(#20087,#20001,""," +") +#20088=@"loc,{#10000},34,1,34,0" +locations_default(#20088,#10000,34,1,34,0) hasLocation(#20087,#20088) -jsdoc_tag_names(#20087,"var_args") #20089=* -jsdoc_type_exprs(#20089,14,#20087,0,"...number") -#20090=* -jsdoc_type_exprs(#20090,5,#20089,0,"number") +lines(#20089,#20001,"/**"," +") +#20090=@"loc,{#10000},35,1,35,3" +locations_default(#20090,#10000,35,1,35,3) +hasLocation(#20089,#20090) #20091=* -jsdoc(#20091,"",#20011) -hasLocation(#20091,#20012) -#20092=* -jsdoc_tags(#20092,"param",#20091,0,"@param") -#20093=@"loc,{#10000},15,4,15,9" -locations_default(#20093,#10000,15,4,15,9) -hasLocation(#20092,#20093) -#20094=* -jsdoc_errors(#20094,#20092,"Missing or invalid tag name","Missing ... ag name") +lines(#20091,#20001,"* @exports R"," +") +#20092=@"loc,{#10000},36,1,36,12" +locations_default(#20092,#10000,36,1,36,12) +hasLocation(#20091,#20092) +#20093=* +lines(#20093,#20001,"*"," +") +#20094=@"loc,{#10000},37,1,37,1" +locations_default(#20094,#10000,37,1,37,1) +hasLocation(#20093,#20094) #20095=* -jsdoc_tags(#20095,"param",#20091,1,"@param") -#20096=@"loc,{#10000},16,4,16,9" -locations_default(#20096,#10000,16,4,16,9) +lines(#20095,#20001,"*/"," +") +#20096=@"loc,{#10000},38,1,38,2" +locations_default(#20096,#10000,38,1,38,2) hasLocation(#20095,#20096) -jsdoc_tag_names(#20095,"x") -numlines(#10000,17,0,17) +#20097=* +lines(#20097,#20001,""," +") +#20098=@"loc,{#10000},39,1,39,0" +locations_default(#20098,#10000,39,1,39,0) +hasLocation(#20097,#20098) +#20099=* +lines(#20099,#20001,"/**"," +") +#20100=@"loc,{#10000},40,1,40,3" +locations_default(#20100,#10000,40,1,40,3) +hasLocation(#20099,#20100) +#20101=* +lines(#20101,#20001," * @typedef {{0: number}}"," +") +#20102=@"loc,{#10000},41,1,41,25" +locations_default(#20102,#10000,41,1,41,25) +hasLocation(#20101,#20102) +indentation(#10000,41," ",1) +#20103=* +lines(#20103,#20001," */"," +") +#20104=@"loc,{#10000},42,1,42,3" +locations_default(#20104,#10000,42,1,42,3) +hasLocation(#20103,#20104) +indentation(#10000,42," ",1) +numlines(#20001,42,0,37) +#20105=* +tokeninfo(#20105,0,#20001,0,"") +#20106=@"loc,{#10000},43,1,43,0" +locations_default(#20106,#10000,43,1,43,0) +hasLocation(#20105,#20106) +next_token(#20003,#20105) +next_token(#20005,#20105) +next_token(#20007,#20105) +next_token(#20009,#20105) +next_token(#20011,#20105) +next_token(#20013,#20105) +next_token(#20015,#20105) +next_token(#20017,#20105) +next_token(#20019,#20105) +next_token(#20021,#20105) +#20107=* +entry_cfg_node(#20107,#20001) +#20108=@"loc,{#10000},1,1,1,0" +locations_default(#20108,#10000,1,1,1,0) +hasLocation(#20107,#20108) +#20109=* +exit_cfg_node(#20109,#20001) +hasLocation(#20109,#20106) +successor(#20107,#20109) +#20110=* +jsdoc(#20110,"This is a constant.",#20003) +hasLocation(#20110,#20004) +#20111=* +jsdoc_tags(#20111,"const",#20110,0,"@const") +#20112=@"loc,{#10000},4,4,4,9" +locations_default(#20112,#10000,4,4,4,9) +hasLocation(#20111,#20112) +jsdoc_tag_names(#20111,"x") +#20113=* +jsdoc(#20113,"",#20005) +hasLocation(#20113,#20006) +#20114=* +jsdoc_tags(#20114,"class",#20113,0,"@class") +#20115=@"loc,{#10000},6,5,6,10" +locations_default(#20115,#10000,6,5,6,10) +hasLocation(#20114,#20115) +jsdoc_tag_names(#20114,"klass") +#20116=* +jsdoc_type_exprs(#20116,5,#20114,0,"Object") +#20117=* +jsdoc(#20117,"",#20007) +hasLocation(#20117,#20008) +#20118=* +jsdoc_tags(#20118,"deprecated",#20117,0,"@deprecated") +#20119=@"loc,{#10000},7,5,7,15" +locations_default(#20119,#10000,7,5,7,15) +hasLocation(#20118,#20119) +#20120=* +jsdoc(#20120,"",#20009) +hasLocation(#20120,#20010) +#20121=* +jsdoc_tags(#20121,"param",#20120,0,"@param") +#20122=@"loc,{#10000},8,5,8,10" +locations_default(#20122,#10000,8,5,8,10) +hasLocation(#20121,#20122) +jsdoc_tag_names(#20121,"x") +#20123=* +jsdoc_type_exprs(#20123,11,#20121,0,"(int|bool)") +#20124=* +jsdoc_type_exprs(#20124,5,#20123,0,"int") +#20125=* +jsdoc_type_exprs(#20125,5,#20123,1,"bool") +#20126=* +jsdoc_tags(#20126,"param",#20120,1,"@param") +#20127=@"loc,{#10000},9,5,9,10" +locations_default(#20127,#10000,9,5,9,10) +hasLocation(#20126,#20127) +jsdoc_tag_names(#20126,"ys") +#20128=* +jsdoc_type_exprs(#20128,6,#20126,0,"Array.") +#20129=* +jsdoc_type_exprs(#20129,5,#20128,-1,"Array") +#20130=* +jsdoc_type_exprs(#20130,5,#20128,0,"String") +#20131=* +jsdoc_type_exprs(#20131,5,#20128,1,"Number") +#20132=* +jsdoc_tags(#20132,"param",#20120,2,"@param") +#20133=@"loc,{#10000},10,5,10,10" +locations_default(#20133,#10000,10,5,10,10) +hasLocation(#20132,#20133) +jsdoc_tag_names(#20132,"zs") +#20134=* +jsdoc_type_exprs(#20134,6,#20132,0,"Array.") +#20135=* +jsdoc_type_exprs(#20135,5,#20134,-1,"Array") +#20136=* +jsdoc_type_exprs(#20136,5,#20134,0,"String") +#20137=* +jsdoc_tags(#20137,"param",#20120,3,"@param") +#20138=@"loc,{#10000},11,5,11,10" +locations_default(#20138,#10000,11,5,11,10) +hasLocation(#20137,#20138) +jsdoc_tag_names(#20137,"f") +#20139=* +jsdoc_type_exprs(#20139,12,#20137,0,"function (new: goog.ui.Menu, ?string=, number=): void") +#20140=* +jsdoc_type_exprs(#20140,13,#20139,0,"?string=") +#20141=* +jsdoc_type_exprs(#20141,7,#20140,0,"?string") +#20142=* +jsdoc_type_exprs(#20142,5,#20141,0,"string") +jsdoc_prefix_qualifier(#20141) +#20143=* +jsdoc_type_exprs(#20143,13,#20139,1,"number=") +#20144=* +jsdoc_type_exprs(#20144,5,#20143,0,"number") +#20145=* +jsdoc_type_exprs(#20145,4,#20139,-1,"void") +#20146=* +jsdoc_type_exprs(#20146,5,#20139,-2,"goog.ui.Menu") +jsdoc_has_new_parameter(#20139) +#20147=* +jsdoc_tags(#20147,"param",#20120,4,"@param") +#20148=@"loc,{#10000},12,5,12,10" +locations_default(#20148,#10000,12,5,12,10) +hasLocation(#20147,#20148) +jsdoc_tag_names(#20147,"var_args") +#20149=* +jsdoc_type_exprs(#20149,14,#20147,0,"...number") +#20150=* +jsdoc_type_exprs(#20150,5,#20149,0,"number") +#20151=* +jsdoc(#20151,"",#20011) +hasLocation(#20151,#20012) +#20152=* +jsdoc_tags(#20152,"param",#20151,0,"@param") +#20153=@"loc,{#10000},15,4,15,9" +locations_default(#20153,#10000,15,4,15,9) +hasLocation(#20152,#20153) +#20154=* +jsdoc_errors(#20154,#20152,"Missing or invalid tag name","Missing ... ag name") +#20155=* +jsdoc_tags(#20155,"param",#20151,1,"@param") +#20156=@"loc,{#10000},16,4,16,9" +locations_default(#20156,#10000,16,4,16,9) +hasLocation(#20155,#20156) +jsdoc_tag_names(#20155,"x") +#20157=* +jsdoc(#20157,"",#20013) +hasLocation(#20157,#20014) +#20158=* +jsdoc_tags(#20158,"",#20157,0,"@") +#20159=@"loc,{#10000},20,4,20,4" +locations_default(#20159,#10000,20,4,20,4) +hasLocation(#20158,#20159) +jsdoc_tag_descriptions(#20158,"{link a}") +#20160=* +jsdoc_errors(#20160,#20158,"Missing or invalid title","Missing ... d title") +#20161=* +jsdoc(#20161,"",#20015) +hasLocation(#20161,#20016) +#20162=* +jsdoc_tags(#20162,"typedef",#20161,0,"@typedef") +#20163=@"loc,{#10000},24,4,24,11" +locations_default(#20163,#10000,24,4,24,11) +hasLocation(#20162,#20163) +jsdoc_tag_descriptions(#20162,"{a}") +#20164=* +jsdoc_errors(#20164,#20162,"Missing or invalid tag type","Missing ... ag type") +#20165=* +jsdoc(#20165,"[resize description]",#20017) +hasLocation(#20165,#20018) +#20166=* +jsdoc_tags(#20166,"param",#20165,0,"@param") +#20167=@"loc,{#10000},30,4,30,9" +locations_default(#20167,#10000,30,4,30,9) +hasLocation(#20166,#20167) +jsdoc_tag_descriptions(#20166,"[description] +") +jsdoc_tag_names(#20166,"w") +#20168=* +jsdoc_type_exprs(#20168,10,#20166,0,"[type]") +#20169=* +jsdoc_type_exprs(#20169,5,#20168,0,"type") +#20170=* +jsdoc_tags(#20170,"param",#20165,1,"@param") +#20171=@"loc,{#10000},31,4,31,9" +locations_default(#20171,#10000,31,4,31,9) +hasLocation(#20170,#20171) +jsdoc_tag_descriptions(#20170,"[description] +") +#20172=* +jsdoc_tags(#20172,"return",#20165,2,"@return") +#20173=@"loc,{#10000},32,4,32,10" +locations_default(#20173,#10000,32,4,32,10) +hasLocation(#20172,#20173) +jsdoc_tag_descriptions(#20172,"[description]") +#20174=* +jsdoc_type_exprs(#20174,10,#20172,0,"[type]") +#20175=* +jsdoc_type_exprs(#20175,5,#20174,0,"type") +#20176=* +jsdoc(#20176,"",#20019) +hasLocation(#20176,#20020) +#20177=* +jsdoc_tags(#20177,"exports",#20176,0,"@exports") +#20178=@"loc,{#10000},36,3,36,10" +locations_default(#20178,#10000,36,3,36,10) +hasLocation(#20177,#20178) +jsdoc_tag_descriptions(#20177,"R +") +#20179=* +jsdoc(#20179,"",#20021) +hasLocation(#20179,#20022) +#20180=* +jsdoc_tags(#20180,"typedef",#20179,0,"@typedef") +#20181=@"loc,{#10000},41,4,41,11" +locations_default(#20181,#10000,41,4,41,11) +hasLocation(#20180,#20181) +#20182=* +jsdoc_type_exprs(#20182,9,#20180,0,"{0: number}") +jsdoc_record_field_name(#20182,0,"0") +#20183=* +jsdoc_type_exprs(#20183,5,#20182,0,"number") +numlines(#10000,42,0,37) filetype(#10000,"javascript") From f26d47aacb48263e1e1e98679920dd2129a79ef9 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 9 Nov 2018 08:50:55 +0000 Subject: [PATCH 12/68] JavaScript: Bump extractor version. This is not so much because extractor output has changed (it hasn't, except for corner cases) but to disable trap caching so as to help us to flush out bugs. --- javascript/extractor/src/com/semmle/js/extractor/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 9116a71dc0ac..bca6014f66cb 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -39,7 +39,7 @@ public class Main { * such a way that it may produce different tuples for the same file under the same * {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2018-10-16"; + public static final String EXTRACTOR_VERSION = "2018-11-12"; public static final Pattern NEWLINE = Pattern.compile("\n"); From 032ed1224235aa97ea2b518d6a41408d69e552b0 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 9 Nov 2018 16:02:22 +0000 Subject: [PATCH 13/68] JavaScript: Use in-dist trap cache when extracting externs. --- .../src/com/semmle/js/extractor/AutoBuild.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 1b4b57812a57..b38e28989002 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -374,6 +374,16 @@ public void run() throws IOException { */ private void extractExterns() throws IOException { ExtractorConfig config = new ExtractorConfig(false).withExterns(true); + + // use explicitly specified trap cache, or otherwise $SEMMLE_DIST/.cache/trap-cache/javascript, + // which we pre-populate when building the distribution + ITrapCache trapCache = this.trapCache; + if (trapCache instanceof DummyTrapCache) { + Path trapCachePath = SEMMLE_DIST.resolve(".cache").resolve("trap-cache").resolve("javascript"); + if (Files.isDirectory(trapCachePath)) + trapCache = new DefaultTrapCache(trapCachePath.toString(), null, Main.EXTRACTOR_VERSION); + } + FileExtractor extractor = new FileExtractor(config, outputConfig, trapCache, extractorState); FileVisitor visitor = new SimpleFileVisitor() { @Override From 01b43dff725a475b276bdbcf5ab2e768c51dea0d Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Mon, 12 Nov 2018 08:33:07 +0000 Subject: [PATCH 14/68] JavaScript: Make in-dist trap cache read-only. --- .../src/com/semmle/js/extractor/AutoBuild.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index b38e28989002..efb77fe25d15 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -380,8 +380,16 @@ private void extractExterns() throws IOException { ITrapCache trapCache = this.trapCache; if (trapCache instanceof DummyTrapCache) { Path trapCachePath = SEMMLE_DIST.resolve(".cache").resolve("trap-cache").resolve("javascript"); - if (Files.isDirectory(trapCachePath)) - trapCache = new DefaultTrapCache(trapCachePath.toString(), null, Main.EXTRACTOR_VERSION); + if (Files.isDirectory(trapCachePath)) { + trapCache = new DefaultTrapCache(trapCachePath.toString(), null, Main.EXTRACTOR_VERSION) { + @Override + public File lookup(String source, ExtractorConfig config, FileType type) { + File f = super.lookup(source, config, type); + // only return `f` if it exists; this has the effect of making the cache read-only + return f.exists() ? f : null; + } + }; + } } FileExtractor extractor = new FileExtractor(config, outputConfig, trapCache, extractorState); From 72ac2e54987a733ffcf46e10aa0e4f2af3ff2dd5 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Mon, 12 Nov 2018 09:52:00 +0000 Subject: [PATCH 15/68] Fix typos --- cpp/ql/src/Critical/GlobalUseBeforeInit.ql | 2 +- cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp | 2 +- cpp/ql/src/Critical/OverflowCalculated.qhelp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql index 244e39394227..dfbe887ad2c0 100644 --- a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql +++ b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql @@ -1,6 +1,6 @@ /** * @name Global variable may be used before initialization - * @description Using an uninitialized variable leads to undefined results. + * @description Using an uninitialized variable may lead to undefined results. * @kind problem * @id cpp/global-use-before-init * @problem.severity warning diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp b/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp index 9de3019bdb0f..dd91ef95531a 100644 --- a/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp +++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp @@ -22,7 +22,7 @@ important system data (including the interrupt table in some architectures). This code shows two examples where a pointer is dereferenced. The first example checks that the pointer is not null before dereferencing it. -The second example fails to perform a nullnes check, leading to a potential vulnerability in the code. +The second example fails to perform a nullness check, leading to a potential vulnerability in the code. diff --git a/cpp/ql/src/Critical/OverflowCalculated.qhelp b/cpp/ql/src/Critical/OverflowCalculated.qhelp index ba441d4df4ae..94655f1b7e71 100644 --- a/cpp/ql/src/Critical/OverflowCalculated.qhelp +++ b/cpp/ql/src/Critical/OverflowCalculated.qhelp @@ -30,7 +30,7 @@ Increase the size of the buffer being allocated. -

    This example includes thre annotated calls that copy a string into a buffer. +

    This example includes three annotated calls that copy a string into a buffer. The first call to malloc creates a buffer that's the same size as the string, leaving no space for the zero terminator and causing an overflow. The second call to malloc From 978fc4928f0954ea442f98d7e40bd283454e7bac Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Mon, 12 Nov 2018 10:55:13 +0000 Subject: [PATCH 16/68] Fix syntax errors in qhelp files --- cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp | 2 ++ cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp | 2 ++ cpp/ql/src/Critical/OverflowCalculated.qhelp | 1 + 3 files changed, 5 insertions(+) diff --git a/cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp b/cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp index 1c3037a75296..9566a31f8704 100644 --- a/cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp +++ b/cpp/ql/src/Critical/GlobalUseBeforeInit.qhelp @@ -20,7 +20,9 @@ the initialization code is executed.

    +

    In the example below, callCtr is wrongly used before it has been initialized. +

    diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp b/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp index dd91ef95531a..bd530b74829c 100644 --- a/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp +++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.qhelp @@ -20,9 +20,11 @@ important system data (including the interrupt table in some architectures). +

    This code shows two examples where a pointer is dereferenced. The first example checks that the pointer is not null before dereferencing it. The second example fails to perform a nullness check, leading to a potential vulnerability in the code. +

    diff --git a/cpp/ql/src/Critical/OverflowCalculated.qhelp b/cpp/ql/src/Critical/OverflowCalculated.qhelp index 94655f1b7e71..a26d28b5dce9 100644 --- a/cpp/ql/src/Critical/OverflowCalculated.qhelp +++ b/cpp/ql/src/Critical/OverflowCalculated.qhelp @@ -13,6 +13,7 @@ zero terminator into consideration.
  • strcat or strncat that use buffers that are too small to contain the new string.
  • +

    The highlighted expression will cause a buffer overflow because the buffer is too small to contain From 2e8f51a545cad8c8bedd4cb8526e0ff387253944 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Mon, 12 Nov 2018 15:30:19 +0000 Subject: [PATCH 17/68] Update to bring into line with current guidelines --- .../Critical/DescriptorMayNotBeClosed.qhelp | 22 ++++++++------- .../src/Critical/DescriptorMayNotBeClosed.ql | 2 +- .../src/Critical/DescriptorNeverClosed.qhelp | 16 +++++++---- cpp/ql/src/Critical/DescriptorNeverClosed.ql | 2 +- .../src/Critical/InitialisationNotRun.qhelp | 19 ++++++++----- cpp/ql/src/Critical/InitialisationNotRun.ql | 2 +- cpp/ql/src/Critical/LateNegativeTest.qhelp | 27 ++++++++++++------- cpp/ql/src/Critical/LateNegativeTest.ql | 5 ++-- .../src/Critical/MissingNegativityTest.qhelp | 27 ++++++++++--------- cpp/ql/src/Critical/MissingNegativityTest.ql | 3 ++- cpp/ql/src/Critical/MissingNullTest.qhelp | 22 ++++++++------- cpp/ql/src/Critical/MissingNullTest.ql | 2 +- cpp/ql/src/Critical/NotInitialised.qhelp | 15 ++++++----- cpp/ql/src/Critical/NotInitialised.ql | 2 +- .../Critical/ReturnStackAllocatedObject.qhelp | 22 ++++++++------- .../Critical/ReturnStackAllocatedObject.ql | 6 +---- cpp/ql/src/Critical/Unused.qhelp | 19 ++++++------- cpp/ql/src/Critical/Unused.ql | 2 +- .../Likely Bugs/OO/SelfAssignmentCheck.cpp | 4 +-- .../Likely Bugs/OO/SelfAssignmentCheck.qhelp | 18 +++++++------ .../AV Rule 154.cpp | 2 +- .../AV Rule 154.qhelp | 21 +++++++-------- .../4.20 Unions and Bit Fields/AV Rule 154.ql | 7 ++--- 23 files changed, 145 insertions(+), 122 deletions(-) diff --git a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.qhelp b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.qhelp index c929da28e5d9..1e0dcc2173e5 100644 --- a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.qhelp +++ b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.qhelp @@ -6,23 +6,25 @@

    -This rule looks at functions that return file or socket descriptors, but may return an error value before actually closing the resource. -This can occur when an operation performed on the open descriptor fails, and the function returns with an error before closing the open resource. An improperly handled error could cause the function to leak resource descriptors. +This query looks at functions that return file or socket descriptors, but may return an error value before actually closing the resource. +This can occur when an operation performed on the open descriptor fails, and the function returns with an error before it closes the open resource. An improperly handled error could cause the function to leak resource descriptors. Failing to close resources in the function that opened them also makes it more difficult to detect leaks.

    - - -

    Ensure that the function frees all the resources it acquired when an error occurs.

    + +

    When an error occurs, ensure that the function frees all the resources it holds open.

    + +

    In the example below, the sockfd socket may remain open if an error is triggered. +The code should be updated to ensure that the socket is always closed when when the function ends. +

    - - - - -
    + + +
  • SEI CERT C++ Coding Standard: ERR57-CPP. Do not leak resources when handling exceptions.
  • +
    diff --git a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql index 21e85bf4c21b..1f4326842baf 100644 --- a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql +++ b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql @@ -1,6 +1,6 @@ /** * @name Open descriptor may not be closed - * @description A function may return before closing a socket or file that was opened in the function. Closing resources in the same function that opened them ties the lifetime of the resource to that of the function call, making it easier to avoid and detect resource leaks. + * @description Failing to close resources in the function that opened them, makes it difficult to avoid and detect resource leaks. * @kind problem * @id cpp/descriptor-may-not-be-closed * @problem.severity warning diff --git a/cpp/ql/src/Critical/DescriptorNeverClosed.qhelp b/cpp/ql/src/Critical/DescriptorNeverClosed.qhelp index 47d82555a73c..1a14f7981dd2 100644 --- a/cpp/ql/src/Critical/DescriptorNeverClosed.qhelp +++ b/cpp/ql/src/Critical/DescriptorNeverClosed.qhelp @@ -6,20 +6,26 @@

    -This rule finds calls to open or socket with no corresponding close call in the entire program. +This rule finds calls to open or socket where there is no corresponding close call in the program analyzed. Leaving descriptors open will cause a resource leak that will persist even after the program terminates.

    -
    +

    Ensure that all file or socket descriptors allocated by the program are freed before it terminates.

    -
    - - + +

    In the example below, the sockfd socket remains open when the main program finishes. +The code should be updated to ensure that the socket is always closed when the program terminates. +

    +
    + + +
  • SEI CERT C++ Coding Standard: ERR57-CPP. Do not leak resources when handling exceptions.
  • +
    diff --git a/cpp/ql/src/Critical/DescriptorNeverClosed.ql b/cpp/ql/src/Critical/DescriptorNeverClosed.ql index 8264766ea037..c5c40cae17ac 100644 --- a/cpp/ql/src/Critical/DescriptorNeverClosed.ql +++ b/cpp/ql/src/Critical/DescriptorNeverClosed.ql @@ -1,6 +1,6 @@ /** * @name Open descriptor never closed - * @description A function always returns before closing a socket or file that was opened in the function. Closing resources in the same function that opened them ties the lifetime of the resource to that of the function call, making it easier to avoid and detect resource leaks. + * @description Functions that always return before closing the socket or file they opened leak resources. * @kind problem * @id cpp/descriptor-never-closed * @problem.severity warning diff --git a/cpp/ql/src/Critical/InitialisationNotRun.qhelp b/cpp/ql/src/Critical/InitialisationNotRun.qhelp index 384a37cf71d9..03125e9137a3 100644 --- a/cpp/ql/src/Critical/InitialisationNotRun.qhelp +++ b/cpp/ql/src/Critical/InitialisationNotRun.qhelp @@ -5,23 +5,28 @@ -

    The rule finds code that initializes a global variable (i.e. uses it as an L-value) but is never called from main. +

    The query finds code that initializes a global variable (that is, uses it as an L-value) but is never called from main. Unless there is another entry point that triggers the initialization, the code should be modified so that the variable is initialized. Uninitialized variables may contain any value, as not all compilers generate code that zero-out memory, especially when optimizations are enabled or the compiler is not compliant with the latest language standards.

    -
    + -

    Examine the code and ensure that the initialization is always run.

    +

    Examine the code and ensure that the variable is always initialized before it is used.

    - - - - + +

    In the example below, the code that triggers the initialization of g_storage is not run from main. +Unless the variable is initialized by another method, the call on line 10 may not use the intended value. +

    +
    + + +
  • C++ reference: uninitialized variables.
  • +
    diff --git a/cpp/ql/src/Critical/InitialisationNotRun.ql b/cpp/ql/src/Critical/InitialisationNotRun.ql index f33a5305eb6d..2ec66a0ea351 100644 --- a/cpp/ql/src/Critical/InitialisationNotRun.ql +++ b/cpp/ql/src/Critical/InitialisationNotRun.ql @@ -1,6 +1,6 @@ /** * @name Initialization code not run - * @description A global variable has initialization code, but that code is never run (i.e. is called directly or indirectly from main()). Accessing uninitialized variables leads to undefined results. + * @description Using an uninitialized variable may lead to undefined results. * @kind problem * @id cpp/initialization-not-run * @problem.severity warning diff --git a/cpp/ql/src/Critical/LateNegativeTest.qhelp b/cpp/ql/src/Critical/LateNegativeTest.qhelp index de8f347bca0d..95ce4c52bfb9 100644 --- a/cpp/ql/src/Critical/LateNegativeTest.qhelp +++ b/cpp/ql/src/Critical/LateNegativeTest.qhelp @@ -6,29 +6,36 @@

    -This rule finds integer values that are first used to index an array and +This query finds integer values that are first used to index an array and subsequently tested for being negative. If it is relevant to perform this test -at all then it should probably happen before the indexing, not +at all then it should happen before the indexing, not after. Otherwise, if the value is negative then the program will have failed before performing the test.

    - +
    +

    -See if the value needs checking before being used as array index. Double-check +See if the value needs to be checked before being used as array index. Double-check if the value is derived from user input. If the value clearly cannot be negative then the negativity test is redundant and can be removed.

    -
    - - - - - + +

    The example below includes two functions that use the value recordIdx to +index an array and a test to verify that the value is positive. The test is made after +printRecord is indexed and before processRecord is indexed. +Unless the value of recordIdx cannot be negative, the test should be +updated to run before both arrays are indexed. +

    +
    + + +
  • cplusplus.com: Pointers.
  • +
    diff --git a/cpp/ql/src/Critical/LateNegativeTest.ql b/cpp/ql/src/Critical/LateNegativeTest.ql index 05c761beee3e..c17355476c9e 100644 --- a/cpp/ql/src/Critical/LateNegativeTest.ql +++ b/cpp/ql/src/Critical/LateNegativeTest.ql @@ -1,8 +1,7 @@ /** * @name Pointer offset used before it is checked - * @description A value is used as a pointer offset before it is tested for - * being positive/negative. This may mean that an unsuitable - * pointer offset will be used before the test occurs. + * @description Setting a pointer offset before checking if the value is positive + * may result in unexpected behavior. * @kind problem * @id cpp/late-negative-test * @problem.severity warning diff --git a/cpp/ql/src/Critical/MissingNegativityTest.qhelp b/cpp/ql/src/Critical/MissingNegativityTest.qhelp index acc5fa2156f9..8aeb8587fec2 100644 --- a/cpp/ql/src/Critical/MissingNegativityTest.qhelp +++ b/cpp/ql/src/Critical/MissingNegativityTest.qhelp @@ -6,33 +6,34 @@

    -This rule finds pointer arithmetic expressions that use a value returned from a function before the value is checked to be positive. -Most pointer arithmetic and almost all array element accesses use a positive value for offsets. A negative value is more likely than not +This query finds pointer arithmetic expressions that use a value returned from a function without checking that the value is positive. +Most pointer arithmetic and almost all array element accesses use a positive value for offsets. A negative value is likely to be a defect in the returning function. Checking pointer offsets (particularly if they derive from user input) is necessary to avoid buffer overruns.

    -The rules only looks at return values of functions that may return a negative value (not all functions). +The query looks only at the return values of functions that may return a negative value (not all functions).

    - -
    +

    -Check the function and see whether it needs to check the value to be positive. +Review the function. Determine whether it needs to check that the value is positive before performing pointer arithmetic.

    -
    - - - - - - + +

    The example below shows an example of this problem. There is no check to ensure that the value of recordIdx +is positive and safe to use as an array offset. +

    +
    + + +
  • cplusplus.com: Pointers.
  • +
    diff --git a/cpp/ql/src/Critical/MissingNegativityTest.ql b/cpp/ql/src/Critical/MissingNegativityTest.ql index 46333edfdbf2..d0c75a2dcb29 100644 --- a/cpp/ql/src/Critical/MissingNegativityTest.ql +++ b/cpp/ql/src/Critical/MissingNegativityTest.ql @@ -1,6 +1,7 @@ /** * @name Unchecked return value used as offset - * @description A return value from a function is used as a pointer offset before it is checked for being positive/negative. Integer values used as pointer offsets should be checked, especially if they are derived from user input. + * @description Using a value as a pointer offset without checking that the value is positive + * may lead to buffer overruns. * @kind problem * @id cpp/missing-negativity-test * @problem.severity warning diff --git a/cpp/ql/src/Critical/MissingNullTest.qhelp b/cpp/ql/src/Critical/MissingNullTest.qhelp index c586806fb899..abbad3e6b90e 100644 --- a/cpp/ql/src/Critical/MissingNullTest.qhelp +++ b/cpp/ql/src/Critical/MissingNullTest.qhelp @@ -6,23 +6,27 @@

    -This rule finds pointer dereferences that use a pointer returned from a function which may return NULL. Always +This query finds pointer dereferences that use a pointer returned from a function which may return NULL. Always check your pointers for NULL-ness before dereferencing them. Dereferencing a null pointer and attempting to -modify its contents can lead to anything from a segfault to corrupting important system data -(i.e. the interrupt table in some architectures). +modify its contents can lead to anything from a segmentation fault to corruption of important system data +(for example, the interrupt table in some architectures).

    -
    +

    Add a null check before dereferencing the pointer, or modify the function so that it always returns a non-null value.

    -
    - - - - + +

    In this example, the function is not protected from dereferencing a null pointer. It should be updated to ensure that +this cannot happen. +

    +
    + + +
  • SEI CERT C Coding Standard: EXP34-C. Do not dereference null pointers.
  • +
    diff --git a/cpp/ql/src/Critical/MissingNullTest.ql b/cpp/ql/src/Critical/MissingNullTest.ql index 0870460acf67..14ce8c9509c8 100644 --- a/cpp/ql/src/Critical/MissingNullTest.ql +++ b/cpp/ql/src/Critical/MissingNullTest.ql @@ -1,6 +1,6 @@ /** * @name Returned pointer not checked - * @description A value returned from a function that may return null is not tested to determine whether or not it is null. Dereferencing NULL pointers lead to undefined behavior. + * @description Dereferencing an untested value from a function that can return null may lead to undefined behavior. * @kind problem * @id cpp/missing-null-test * @problem.severity recommendation diff --git a/cpp/ql/src/Critical/NotInitialised.qhelp b/cpp/ql/src/Critical/NotInitialised.qhelp index b9be541b606a..2da410083a71 100644 --- a/cpp/ql/src/Critical/NotInitialised.qhelp +++ b/cpp/ql/src/Critical/NotInitialised.qhelp @@ -6,22 +6,23 @@

    -This rule finds variables that are used before they are initialized. Values of uninitialized variables are +This query finds variables that are used before they are initialized. Values of uninitialized variables are undefined, as not all compilers zero out memory, especially when optimizations are enabled or the compiler is not compliant with the latest language standards.

    -
    +

    Initialize the variable before accessing it.

    -
    - - - - + + + + +
  • C++ reference: uninitialized variables.
  • +
    diff --git a/cpp/ql/src/Critical/NotInitialised.ql b/cpp/ql/src/Critical/NotInitialised.ql index 3de13c786b87..719cec8c301e 100644 --- a/cpp/ql/src/Critical/NotInitialised.ql +++ b/cpp/ql/src/Critical/NotInitialised.ql @@ -1,6 +1,6 @@ /** * @name Variable not initialized before use - * @description A variable is used before initialized. The value of a variable is undefined before initialization, and its use should be avoided. + * @description Using an uninitialized variable may lead to undefined results. * @kind problem * @id cpp/not-initialised * @problem.severity error diff --git a/cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp b/cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp index ee41612d5bde..28fd0b737db9 100644 --- a/cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp +++ b/cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp @@ -6,27 +6,31 @@

    -This rule finds return statements that return pointers to an object allocated on the stack. +This query finds return statements that return pointers to an object allocated on the stack. The lifetime of a stack allocated memory location only lasts until the function returns, and the contents of that memory become undefined after that. Clearly, using a pointer to stack memory after the function has already returned will have undefined results.

    -
    +

    Do not return pointers to stack memory locations. Instead, create an output parameter, or create a heap-allocated -buffer, copy the contents of the stack allocated memory to that buffer and return that instead. +buffer. You can then copy the contents of the stack-allocated memory to the heap-allocated buffer and return that location instead.

    -
    - - - - - + +

    The example below the reference to myRecord is useful only while the containing function is running. +If you need to access the object outside this function, either create an output parameter with its value, or copy the object into +heap-allocated memory. +

    +
    + + +
  • cplusplus.com: Pointers.
  • +
    diff --git a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql index 7b4ed2d19659..dadc53da824f 100644 --- a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql +++ b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql @@ -1,10 +1,6 @@ /** * @name Pointer to stack object used as return value - * @description A function has returned a pointer to an object allocated on - * the stack. The lifetime of stack allocated memory ends when the - * stack frame of the function that allocated it is popped off the - * stack. Any pointer to memory in a function call's stack frame - * will be a dangling pointer after the function returns. + * @description Using a pointer to stack memory after the function has returned gives undefined results. * @kind problem * @id cpp/return-stack-allocated-object * @problem.severity warning diff --git a/cpp/ql/src/Critical/Unused.qhelp b/cpp/ql/src/Critical/Unused.qhelp index c3c55f9d9c78..50ac54960694 100644 --- a/cpp/ql/src/Critical/Unused.qhelp +++ b/cpp/ql/src/Critical/Unused.qhelp @@ -6,23 +6,24 @@

    -This rule finds variables that are assigned a value but are never read. This is usually an indication of a variable that has been orphaned +This query finds variables that are assigned a value but are never read. This is usually an indication of a variable that has been orphaned due to changes in code, or a defect in the code due to the omission of the unused variable. The unused variables should be removed to avoid misuse.

    - -
    +

    -Examine the code to see if the variable should really be unused, and remove it if it is. +Examine the code to see if the variable is no longer needed. If it is unnecessary, remove the variable. +Otherwise, update the relevant code to use the variable.

    -
    - - - - + + + + +
  • SEI CERT C Coding Standard: MSC13-C. Detect and remove unused values.
  • +
    diff --git a/cpp/ql/src/Critical/Unused.ql b/cpp/ql/src/Critical/Unused.ql index 4774e83ee51c..aa8527518cbf 100644 --- a/cpp/ql/src/Critical/Unused.ql +++ b/cpp/ql/src/Critical/Unused.ql @@ -1,6 +1,6 @@ /** * @name Variable is assigned a value that is never read - * @description A variable is assigned a value but is never read. These variables are usually orphaned due to changes in code and can be removed, or may indicate a bug in the code that is caused by an omission of the unused variable. + * @description Assigning a value to a variable that is not used may indicate an error in the code. * @kind problem * @id cpp/unused-variable * @problem.severity warning diff --git a/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.cpp b/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.cpp index a9b7df2a2b2f..2657a3908490 100644 --- a/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.cpp +++ b/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.cpp @@ -8,7 +8,7 @@ class MyClass MyClass &operator=(const MyClass &other) { delete data; - data = other.data->clone(); // BAD: if other == *this, other.data has already been deleted! + data = other.data->clone(); // wrong: if other == *this, other.data has already been deleted! return *this; } @@ -28,7 +28,7 @@ class MyClass MyClass &operator=(const MyClass &other) { - if (this == &other) { return *this; } // FIXED + if (this == &other) { return *this; } // correct delete data; data = other.data->clone(); return *this; diff --git a/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.qhelp b/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.qhelp index aa1e12ab9a98..ae230867fa71 100644 --- a/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.qhelp +++ b/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.qhelp @@ -12,17 +12,19 @@ This could lead to accessing an already freed memory location.

    before getting a new value from the object on the right hand side.

    +

    Copy assignment operator should check for self-assignment.

    -
    - - - + +

    This example shows a copy assignment operator that fails to check for self assignment. +The corrected version of the same operator is also included. +

    +
    - - -
  • [1] M. Cline, Part of C++ FAQ: Assignment operators
  • -
    + +
  • Standard C++ Foundation: Assignment Operators
  • +
    + diff --git a/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.cpp b/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.cpp index a95e99d10d66..086823ea500e 100644 --- a/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.cpp +++ b/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.cpp @@ -1,4 +1,4 @@ struct { - short s : 4; //wrong: behavior of signed bit-field members vary across compilers + short s : 4; //wrong: behavior of signed bit-field members varies across compilers unsigned int : 24; //correct: unsigned } bits; diff --git a/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.qhelp b/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.qhelp index 604a44b5e70d..317ac901570b 100644 --- a/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.qhelp +++ b/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.qhelp @@ -6,34 +6,31 @@

    -This rule finds bit fields with members that are not explicitly declared to be unsigned. +This query finds bit fields with members that are not explicitly declared to be unsigned. The sign of plain char, short, int, or long bit field is implementation-specific, and declaring them all to be unsigned removes the ambiguity and ensures portability.

    - -
    +

    Declare all members of the bit field to be unsigned.

    -
    - - - + +

    The code below shows two examples of bit fields. The second field is declared to be unsigned which ensures portability. +The first field should also be declared to be unsigned. +

    +
    - - +
  • AV Rule 154, Joint Strike Fighter Air Vehicle C++ Coding Standards. Lockheed Martin Corporation, 2005.
  • - C++ Bit Fields + C++ reference: Bit Fields
  • - -
    diff --git a/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.ql b/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.ql index c5cf42641961..247a38130b50 100644 --- a/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.ql +++ b/cpp/ql/src/jsf/4.20 Unions and Bit Fields/AV Rule 154.ql @@ -1,10 +1,7 @@ /** * @name Possible signed bit-field member - * @description Bit fields should have explicitly unsigned integral or - * enumeration types only. For example, use `unsigned int` rather - * than `int`. It is implementation specific whether an - * `int`-typed bit field is signed, so there could be unexpected - * sign extension or overflow. + * @description Failing to explicitly assign bit fields to unsigned integer or enumeration types + * may result in unexpected sign extension or overflow. * @kind problem * @problem.severity warning * @precision low From 05930812a1f85f8e9b72e7131ec951008d047b6a Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Mon, 12 Nov 2018 09:47:25 +0000 Subject: [PATCH 18/68] Update for feedback --- .../InheritanceDepthDistribution.qhelp | 18 +++++++----------- .../HighDistanceFromMainLineNamespaces.qhelp | 12 ++++++++++-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp index ce1fad2322cc..84c7c6ba3509 100644 --- a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp +++ b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp @@ -19,20 +19,16 @@ may not be exploiting object-orientation to the full.

  • -Shyam R. Chidamber and Chris F. Kemerer. -A Metrics Suite for Object Oriented Design -. +Shyam R. Chidamber and Chris F. Kemerer, +A Metrics Suite for Object Oriented Design +. IEEE Transactions on Software Engineering, 20(6), pages 476-493, June 1994.
  • -Diomides D. Spinnelis. -Code Quality: The Open Source Perspective. -Addison-Wesley 2007.
  • - -
  • -Diomides D. Spinnelis. -ckjm - Chidamber and Kemerer Java Metrics. -(implementation of CK metrics), 2006.
  • +Lutz Prechelt, Barbara Unger, Michael Philippsen, and Walter Tich, A Controlled Experiment on Inheritance Depth as a Cost Factor for Code Maintenance +. +Journal of Systems and Software, 65 (2):115-126, 2003. +
    diff --git a/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.qhelp b/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.qhelp index ad02846ce4f7..5eb43361ebc7 100644 --- a/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.qhelp +++ b/cpp/ql/src/Metrics/Namespaces/HighDistanceFromMainLineNamespaces.qhelp @@ -5,9 +5,17 @@ -

    This query finds namespaces that do not have a good balance between abstractness and stability.

    +

    This query finds namespaces that do not have a good balance between abstractness and stability where:

    +
      +
    • +Abstractness measures the proportion of abstract types in a namespace relative to the total number of types in that namespace. +
    • +
    • +Instability measures the level of expectation that changes to other namespaces will affect this namespace. +
    • +
    -

    This metric tries to capture the trade-off between abstractness +

    The metric tries to capture the trade-off between abstractness and instability. For an ideal balance, the sum of abstractness and instability should be one. That is, a package is completely abstract and stable (abstractness=1 and instability=0) From 2847d5eaac290045f127ff9fd5da4b231b8049ce Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Mon, 12 Nov 2018 16:34:19 +0000 Subject: [PATCH 19/68] Replace '&' symbols in URL --- .../InheritanceDepthDistribution.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp index 84c7c6ba3509..503c0402eec3 100644 --- a/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp +++ b/cpp/ql/src/Architecture/General Class-Level Information/InheritanceDepthDistribution.qhelp @@ -26,7 +26,7 @@ IEEE Transactions on Software Engineering, 20(6), pages 476-493, June 1994.

  • -Lutz Prechelt, Barbara Unger, Michael Philippsen, and Walter Tich, A Controlled Experiment on Inheritance Depth as a Cost Factor for Code Maintenance +Lutz Prechelt, Barbara Unger, Michael Philippsen, and Walter Tich, A Controlled Experiment on Inheritance Depth as a Cost Factor for Code Maintenance . Journal of Systems and Software, 65 (2):115-126, 2003.
  • From d9d405118420121aaa7a518663832480c7148ea0 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 13 Nov 2018 08:41:38 +0000 Subject: [PATCH 20/68] JavaScript: Extract auxiliary method. --- .../src/com/semmle/js/extractor/AutoBuild.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index efb77fe25d15..4e1a24119765 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -285,9 +285,8 @@ private void setupIncludesAndExcludes() { excludes.add(toRealPath(folderPath)); } catch (InvalidPathException | URISyntaxException | ResourceError e) { Exceptions.ignore(e, "Ignore path and print warning message instead"); - System.err.println("Ignoring '" + fields[0] + "' classification for " + + warn("Ignoring '" + fields[0] + "' classification for " + folder + ", which is not a valid path."); - System.err.flush(); } } } @@ -354,8 +353,7 @@ private boolean addPathPattern(Set patterns, Path base, String pattern) { patterns.add(realPath); } catch (ResourceError e) { Exceptions.ignore(e, "Ignore exception and print warning instead."); - System.err.println("Skipping path " + path + ", which does not exist."); - System.err.flush(); + warn("Skipping path " + path + ", which does not exist."); } return true; } @@ -557,8 +555,7 @@ private SourceType getSourceType() { protected void extract(FileExtractor extractor, Path file) throws IOException { File f = file.toFile(); if (!f.exists()) { - System.err.println("Skipping " + file + ", which does not exist."); - System.err.flush(); + warn("Skipping " + file + ", which does not exist."); return; } @@ -567,6 +564,11 @@ protected void extract(FileExtractor extractor, Path file) throws IOException { logEndProcess(); } + private void warn(String msg) { + System.err.println(msg); + System.err.flush(); + } + private void logBeginProcess(String message) { System.out.print(message + "..."); System.out.flush(); From 851e71c7d0deceb546bf71c2bcecc16e7f1666a0 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 13 Nov 2018 08:41:53 +0000 Subject: [PATCH 21/68] JavaScript: Warn about externs trap cache absence/miss. --- .../src/com/semmle/js/extractor/AutoBuild.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 4e1a24119765..6d72d7fab0a5 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -380,13 +380,24 @@ private void extractExterns() throws IOException { Path trapCachePath = SEMMLE_DIST.resolve(".cache").resolve("trap-cache").resolve("javascript"); if (Files.isDirectory(trapCachePath)) { trapCache = new DefaultTrapCache(trapCachePath.toString(), null, Main.EXTRACTOR_VERSION) { + boolean warnedAboutCacheMiss = false; + @Override public File lookup(String source, ExtractorConfig config, FileType type) { File f = super.lookup(source, config, type); // only return `f` if it exists; this has the effect of making the cache read-only - return f.exists() ? f : null; + if (f.exists()) + return f; + // warn on first failed lookup + if (!warnedAboutCacheMiss) { + warn("Trap cache lookup for externs failed."); + warnedAboutCacheMiss = true; + } + return null; } }; + } else { + warn("No externs trap cache found"); } } From a5d50fc1db2be8981dfe87a26873bff38dfeba25 Mon Sep 17 00:00:00 2001 From: calum Date: Thu, 8 Nov 2018 12:31:42 +0000 Subject: [PATCH 22/68] C#: Handle `in` arguments, and add `AssignableAccess::isInArgument()` predicate. --- .../Semmle.Extraction.CSharp/Entities/Expression.cs | 3 +++ csharp/ql/src/semmle/code/csharp/exprs/Access.qll | 8 ++++++++ .../ql/test/library-tests/csharp7.2/InArguments.expected | 1 + csharp/ql/test/library-tests/csharp7.2/InArguments.ql | 5 +++++ .../test/library-tests/csharp7.2/NumericLiterals.expected | 4 ++-- .../library-tests/csharp7.2/PrivateProtected.expected | 4 ++-- .../test/library-tests/csharp7.2/ReadonlyStructs.expected | 4 ++-- .../library-tests/csharp7.2/RefReadonlyDelegate.expected | 2 +- .../library-tests/csharp7.2/RefReadonlyReturns.expected | 2 +- .../ql/test/library-tests/csharp7.2/RefStructs.expected | 4 ++-- csharp/ql/test/library-tests/csharp7.2/csharp72.cs | 6 ++++++ 11 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 csharp/ql/test/library-tests/csharp7.2/InArguments.expected create mode 100644 csharp/ql/test/library-tests/csharp7.2/InArguments.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 78c4096bf18a..c050d4d83e95 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -223,6 +223,9 @@ private void PopulateArgument(ArgumentSyntax arg, int child) case SyntaxKind.None: mode = 0; break; + case SyntaxKind.InKeyword: + mode = 3; + break; default: throw new InternalError(arg, "Unknown argument type"); } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll index e68af94ab345..b03a5b64c7a9 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll @@ -174,6 +174,14 @@ class AssignableAccess extends Access, @assignable_access_expr { isOutArgument() or isRefArgument() } + + /** + * Holds if this access passes the assignable being accessed as an `in` + * argument in a method call. + */ + predicate isInArgument() { + expr_argument(this, 3) + } } /** diff --git a/csharp/ql/test/library-tests/csharp7.2/InArguments.expected b/csharp/ql/test/library-tests/csharp7.2/InArguments.expected new file mode 100644 index 000000000000..62e4085b707e --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7.2/InArguments.expected @@ -0,0 +1 @@ +| csharp72.cs:18:12:18:12 | access to local variable s | diff --git a/csharp/ql/test/library-tests/csharp7.2/InArguments.ql b/csharp/ql/test/library-tests/csharp7.2/InArguments.ql new file mode 100644 index 000000000000..432893aa863f --- /dev/null +++ b/csharp/ql/test/library-tests/csharp7.2/InArguments.ql @@ -0,0 +1,5 @@ +import csharp + +from AssignableAccess e +where e.isInArgument() +select e diff --git a/csharp/ql/test/library-tests/csharp7.2/NumericLiterals.expected b/csharp/ql/test/library-tests/csharp7.2/NumericLiterals.expected index 12ea4a1f46a9..dcc6936de3f2 100644 --- a/csharp/ql/test/library-tests/csharp7.2/NumericLiterals.expected +++ b/csharp/ql/test/library-tests/csharp7.2/NumericLiterals.expected @@ -1,2 +1,2 @@ -| csharp72.cs:42:23:42:34 | 85 | -| csharp72.cs:47:31:47:31 | 1 | +| csharp72.cs:48:23:48:34 | 85 | +| csharp72.cs:53:31:53:31 | 1 | diff --git a/csharp/ql/test/library-tests/csharp7.2/PrivateProtected.expected b/csharp/ql/test/library-tests/csharp7.2/PrivateProtected.expected index bf125f15a494..4754b369a38e 100644 --- a/csharp/ql/test/library-tests/csharp7.2/PrivateProtected.expected +++ b/csharp/ql/test/library-tests/csharp7.2/PrivateProtected.expected @@ -1,2 +1,2 @@ -| csharp72.cs:47:27:47:27 | X | -| csharp72.cs:49:28:49:28 | F | +| csharp72.cs:53:27:53:27 | X | +| csharp72.cs:55:28:55:28 | F | diff --git a/csharp/ql/test/library-tests/csharp7.2/ReadonlyStructs.expected b/csharp/ql/test/library-tests/csharp7.2/ReadonlyStructs.expected index e1a0e8de30d1..35b88cd6c013 100644 --- a/csharp/ql/test/library-tests/csharp7.2/ReadonlyStructs.expected +++ b/csharp/ql/test/library-tests/csharp7.2/ReadonlyStructs.expected @@ -1,2 +1,2 @@ -| csharp72.cs:28:17:28:30 | ReadonlyStruct | -| csharp72.cs:36:21:36:37 | ReadonlyRefStruct | +| csharp72.cs:34:17:34:30 | ReadonlyStruct | +| csharp72.cs:42:21:42:37 | ReadonlyRefStruct | diff --git a/csharp/ql/test/library-tests/csharp7.2/RefReadonlyDelegate.expected b/csharp/ql/test/library-tests/csharp7.2/RefReadonlyDelegate.expected index af776d5c0a0c..ceb92009b446 100644 --- a/csharp/ql/test/library-tests/csharp7.2/RefReadonlyDelegate.expected +++ b/csharp/ql/test/library-tests/csharp7.2/RefReadonlyDelegate.expected @@ -1 +1 @@ -| csharp72.cs:25:31:25:33 | Del | +| csharp72.cs:31:31:31:33 | Del | diff --git a/csharp/ql/test/library-tests/csharp7.2/RefReadonlyReturns.expected b/csharp/ql/test/library-tests/csharp7.2/RefReadonlyReturns.expected index a65a390c4e68..86bbf1c956cf 100644 --- a/csharp/ql/test/library-tests/csharp7.2/RefReadonlyReturns.expected +++ b/csharp/ql/test/library-tests/csharp7.2/RefReadonlyReturns.expected @@ -1 +1 @@ -| csharp72.cs:20:22:20:22 | F | +| csharp72.cs:26:22:26:22 | F | diff --git a/csharp/ql/test/library-tests/csharp7.2/RefStructs.expected b/csharp/ql/test/library-tests/csharp7.2/RefStructs.expected index b2e1ae5bb4b2..92dd1d5020de 100644 --- a/csharp/ql/test/library-tests/csharp7.2/RefStructs.expected +++ b/csharp/ql/test/library-tests/csharp7.2/RefStructs.expected @@ -1,2 +1,2 @@ -| csharp72.cs:32:12:32:20 | RefStruct | -| csharp72.cs:36:21:36:37 | ReadonlyRefStruct | +| csharp72.cs:38:12:38:20 | RefStruct | +| csharp72.cs:42:21:42:37 | ReadonlyRefStruct | diff --git a/csharp/ql/test/library-tests/csharp7.2/csharp72.cs b/csharp/ql/test/library-tests/csharp7.2/csharp72.cs index b285b2e12421..6844e005decb 100644 --- a/csharp/ql/test/library-tests/csharp7.2/csharp72.cs +++ b/csharp/ql/test/library-tests/csharp7.2/csharp72.cs @@ -11,6 +11,12 @@ struct S void F(in S s) { } + + void CallF() + { + var s = new S(); + F(in s); + } } class RefReadonlyReturns From 9f04ace4aebf55c7129ba53938a945a37d1020ea Mon Sep 17 00:00:00 2001 From: calum Date: Thu, 8 Nov 2018 12:37:22 +0000 Subject: [PATCH 23/68] C#: Update change notes. --- change-notes/1.19/analysis-csharp.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/change-notes/1.19/analysis-csharp.md b/change-notes/1.19/analysis-csharp.md index 148a42d65fd2..86dc2d786fab 100644 --- a/change-notes/1.19/analysis-csharp.md +++ b/change-notes/1.19/analysis-csharp.md @@ -3,7 +3,7 @@ ## General improvements * Control flow graph improvements: - * The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead. +* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead. * Code that is only reachable from a constant failing assertion, such as `Debug.Assert(false)`, is considered to be unreachable. ## New queries @@ -20,7 +20,11 @@ | Cross-site scripting (`cs/web/xss`) | More results | This query now finds cross-site scripting vulnerabilities in ASP.NET Core applications. | | *@name of query (Query ID)*| *Impact on results* | *How/why the query has changed* | +## Changes to code extraction + +* Arguments passed using `in` are now extracted. ## Changes to QL libraries * `getArgument()` on `AccessorCall` has been improved so it now takes tuple assignments into account. For example, the argument for the implicit `value` parameter in the setter of property `P` is `0` in `(P, x) = (0, 1)`. Additionally, the argument for the `value` parameter in compound assignments is now only the expanded value, for example, in `P += 7` the argument is `P + 7` and not `7`. +* The predicate `isInArgument()` has been added to the `AssignableAccess` class. This holds for expressions that are passed as arguments using `in`. From 411891c30315ae7b60b2a1e2f4acc13f850c05a8 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 9 Nov 2018 12:58:37 +0100 Subject: [PATCH 24/68] Java: Don't inherit methods from co-/contra-variant supertypes. --- java/ql/src/semmle/code/java/Type.qll | 20 ++----------------- .../Naming/ConfusingOverloading.expected | 2 +- .../test/query-tests/Naming/NamingTest.java | 13 +++++++++++- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/java/ql/src/semmle/code/java/Type.qll b/java/ql/src/semmle/code/java/Type.qll index 10bec76e9a7a..da6288e0b0de 100755 --- a/java/ql/src/semmle/code/java/Type.qll +++ b/java/ql/src/semmle/code/java/Type.qll @@ -435,22 +435,6 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { hasInterfaceMethod(m, declaringType) and hidden = false } - private predicate noMethodExtraction() { - not methods(_, _, _, _, this, _) and - exists(Method m | methods(m, _, _, _, getSourceDeclaration(), _) and m.isInheritable()) - } - - private predicate canInheritFromSupertype(RefType sup) { - sup = getASupertype() and - (noMethodExtraction() implies supertypeSrcDecl(sup, getSourceDeclaration())) - } - - pragma[nomagic] - private predicate supertypeSrcDecl(RefType sup, RefType srcDecl) { - sup = getASupertype() and - srcDecl = sup.getSourceDeclaration() - } - private predicate hasNonInterfaceMethod(Method m, RefType declaringType, boolean hidden) { m = getAMethod() and this = declaringType and @@ -464,7 +448,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { else h1 = false ) and (not sup instanceof Interface or this instanceof Interface) and - canInheritFromSupertype(sup) and + this.extendsOrImplements(sup) and sup.hasNonInterfaceMethod(m, declaringType, h2) and hidden = h1.booleanOr(h2) and exists(string signature | @@ -491,7 +475,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { exists(RefType sup | sup.interfaceMethodCandidateWithSignature(m, signature, declaringType) and not cannotInheritInterfaceMethod(signature) and - canInheritFromSupertype(sup) and + this.extendsOrImplements(sup) and m.isInheritable() ) } diff --git a/java/ql/test/query-tests/Naming/ConfusingOverloading.expected b/java/ql/test/query-tests/Naming/ConfusingOverloading.expected index fcd90b496880..978ac1c7e8ed 100644 --- a/java/ql/test/query-tests/Naming/ConfusingOverloading.expected +++ b/java/ql/test/query-tests/Naming/ConfusingOverloading.expected @@ -1 +1 @@ -| NamingTest.java:4:17:4:22 | equals | Method NamingTest.equals(..) could be confused with overloaded method $@, since dispatch depends on static types. | NamingTest.java:3:17:3:22 | equals | equals | +| NamingTest.java:7:17:7:22 | equals | Method NamingTest.equals(..) could be confused with overloaded method $@, since dispatch depends on static types. | NamingTest.java:6:17:6:22 | equals | equals | diff --git a/java/ql/test/query-tests/Naming/NamingTest.java b/java/ql/test/query-tests/Naming/NamingTest.java index d426a7cd446a..e6365ead8ef1 100644 --- a/java/ql/test/query-tests/Naming/NamingTest.java +++ b/java/ql/test/query-tests/Naming/NamingTest.java @@ -1,8 +1,19 @@ +import java.util.*; +import java.util.function.*; +import java.util.stream.*; public class NamingTest { public boolean equals(Object other) { return false; } public boolean equals(NamingTest other) { return true; } - + public void visit(Object node) {} public void visit(NamingTest t) {} + + public class Elem {} + + public Object get(List> lll) { + Predicate p = null; + p.test(null); + return lll.stream().map(l -> l).filter(Objects::nonNull).collect(Collectors.toList()); + } } From fe8dfeec0dc3aa509e693e97873cc8c95619c465 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 13 Nov 2018 14:58:25 +0100 Subject: [PATCH 25/68] Java: Add some this-qualifiers. --- java/ql/src/semmle/code/java/Type.qll | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/java/ql/src/semmle/code/java/Type.qll b/java/ql/src/semmle/code/java/Type.qll index da6288e0b0de..4ae2f952de21 100755 --- a/java/ql/src/semmle/code/java/Type.qll +++ b/java/ql/src/semmle/code/java/Type.qll @@ -420,7 +420,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { * Holds if this type declares or inherits method `m`, which is declared * in `declaringType`. */ - predicate hasMethod(Method m, RefType declaringType) { hasMethod(m, declaringType, false) } + predicate hasMethod(Method m, RefType declaringType) { this.hasMethod(m, declaringType, false) } /** * Holds if this type declares or inherits method `m`, which is declared @@ -430,13 +430,13 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { */ cached predicate hasMethod(Method m, RefType declaringType, boolean hidden) { - hasNonInterfaceMethod(m, declaringType, hidden) + this.hasNonInterfaceMethod(m, declaringType, hidden) or - hasInterfaceMethod(m, declaringType) and hidden = false + this.hasInterfaceMethod(m, declaringType) and hidden = false } private predicate hasNonInterfaceMethod(Method m, RefType declaringType, boolean hidden) { - m = getAMethod() and + m = this.getAMethod() and this = declaringType and not declaringType instanceof Interface and hidden = false @@ -461,20 +461,20 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { private predicate cannotInheritInterfaceMethod(string signature) { methods(_, _, signature, _, this, _) or - exists(Method m | hasNonInterfaceMethod(m, _, false) and methods(m, _, signature, _, _, _)) + exists(Method m | this.hasNonInterfaceMethod(m, _, false) and methods(m, _, signature, _, _, _)) } private predicate interfaceMethodCandidateWithSignature( Method m, string signature, RefType declaringType ) { - m = getAMethod() and + m = this.getAMethod() and this = declaringType and declaringType instanceof Interface and methods(m, _, signature, _, _, _) or exists(RefType sup | sup.interfaceMethodCandidateWithSignature(m, signature, declaringType) and - not cannotInheritInterfaceMethod(signature) and + not this.cannotInheritInterfaceMethod(signature) and this.extendsOrImplements(sup) and m.isInheritable() ) @@ -483,8 +483,8 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { pragma[nomagic] private predicate overrideEquivalentInterfaceMethodCandidates(Method m1, Method m2) { exists(string signature | - interfaceMethodCandidateWithSignature(m1, signature, _) and - interfaceMethodCandidateWithSignature(m2, signature, _) and + this.interfaceMethodCandidateWithSignature(m1, signature, _) and + this.interfaceMethodCandidateWithSignature(m2, signature, _) and m1 != m2 and m2.overrides(_) and any(Method m).overrides(m1) @@ -494,27 +494,27 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { pragma[noinline] private predicate overriddenInterfaceMethodCandidate(Method m) { exists(Method m2 | - overrideEquivalentInterfaceMethodCandidates(m, m2) and + this.overrideEquivalentInterfaceMethodCandidates(m, m2) and m2.overrides(m) ) } private predicate hasInterfaceMethod(Method m, RefType declaringType) { - interfaceMethodCandidateWithSignature(m, _, declaringType) and - not overriddenInterfaceMethodCandidate(m) + this.interfaceMethodCandidateWithSignature(m, _, declaringType) and + not this.overriddenInterfaceMethodCandidate(m) } /** Holds if this type declares or inherits the specified member. */ predicate inherits(Member m) { exists(Field f | f = m | - f = getAField() + f = this.getAField() or - not f.isPrivate() and not declaresField(f.getName()) and getASupertype().inherits(f) + not f.isPrivate() and not this.declaresField(f.getName()) and this.getASupertype().inherits(f) or - getSourceDeclaration().inherits(f) + this.getSourceDeclaration().inherits(f) ) or - hasMethod(m.(Method), _) + this.hasMethod(m.(Method), _) } /** Holds if this is a top-level type, which is not nested inside any other types. */ From c6af79979c29d210d20d43d6ea2f92d26afca3ff Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Tue, 13 Nov 2018 16:50:00 +0000 Subject: [PATCH 26/68] Update for feedback --- cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql | 2 +- cpp/ql/src/Critical/InitialisationNotRun.qhelp | 2 +- cpp/ql/src/Critical/InitialisationNotRun.ql | 2 +- cpp/ql/src/Critical/LateNegativeTest.qhelp | 9 ++++++--- cpp/ql/src/Critical/LateNegativeTest.ql | 3 ++- cpp/ql/src/Critical/MissingNegativityTest.qhelp | 1 + cpp/ql/src/Critical/MissingNegativityTest.ql | 2 +- cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp | 1 + 8 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql index 1f4326842baf..fe7dfe148b31 100644 --- a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql +++ b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql @@ -1,6 +1,6 @@ /** * @name Open descriptor may not be closed - * @description Failing to close resources in the function that opened them, makes it difficult to avoid and detect resource leaks. + * @description Failing to close resources in the function that opened them makes it difficult to avoid and detect resource leaks. * @kind problem * @id cpp/descriptor-may-not-be-closed * @problem.severity warning diff --git a/cpp/ql/src/Critical/InitialisationNotRun.qhelp b/cpp/ql/src/Critical/InitialisationNotRun.qhelp index 03125e9137a3..5152620c502d 100644 --- a/cpp/ql/src/Critical/InitialisationNotRun.qhelp +++ b/cpp/ql/src/Critical/InitialisationNotRun.qhelp @@ -20,7 +20,7 @@ optimizations are enabled or the compiler is not compliant with the latest langu

    In the example below, the code that triggers the initialization of g_storage is not run from main. -Unless the variable is initialized by another method, the call on line 10 may not use the intended value. +Unless the variable is initialized by another method, the call on line 10 may dereference a null pointer.

    diff --git a/cpp/ql/src/Critical/InitialisationNotRun.ql b/cpp/ql/src/Critical/InitialisationNotRun.ql index 2ec66a0ea351..79b1747bcaeb 100644 --- a/cpp/ql/src/Critical/InitialisationNotRun.ql +++ b/cpp/ql/src/Critical/InitialisationNotRun.ql @@ -1,6 +1,6 @@ /** * @name Initialization code not run - * @description Using an uninitialized variable may lead to undefined results. + * @description Not running initialization code may lead to unexpected behavior. * @kind problem * @id cpp/initialization-not-run * @problem.severity warning diff --git a/cpp/ql/src/Critical/LateNegativeTest.qhelp b/cpp/ql/src/Critical/LateNegativeTest.qhelp index 95ce4c52bfb9..fd4603c5f72b 100644 --- a/cpp/ql/src/Critical/LateNegativeTest.qhelp +++ b/cpp/ql/src/Critical/LateNegativeTest.qhelp @@ -26,10 +26,12 @@ negative then the negativity test is redundant and can be removed.

    The example below includes two functions that use the value recordIdx to -index an array and a test to verify that the value is positive. The test is made after -printRecord is indexed and before processRecord is indexed. +index an array and a test to verify that the value is positive. +The test is made after records is indexed for printRecord and +before records is indexed for processRecord. Unless the value of recordIdx cannot be negative, the test should be -updated to run before both arrays are indexed. +updated to run before both times the array is indexed. +If the value cannot be negative, the test should be removed.

    @@ -37,5 +39,6 @@ updated to run before both arrays are indexed.
  • cplusplus.com: Pointers.
  • +
  • SEI CERT C Coding Standard: ARR30-C. Do not form or use out-of-bounds pointers or array subscripts.
  • diff --git a/cpp/ql/src/Critical/LateNegativeTest.ql b/cpp/ql/src/Critical/LateNegativeTest.ql index c17355476c9e..1c9eec3e986b 100644 --- a/cpp/ql/src/Critical/LateNegativeTest.ql +++ b/cpp/ql/src/Critical/LateNegativeTest.ql @@ -1,6 +1,7 @@ /** * @name Pointer offset used before it is checked - * @description Setting a pointer offset before checking if the value is positive + * @description Accessing a pointer or array using an offset before + * checking if the value is positive * may result in unexpected behavior. * @kind problem * @id cpp/late-negative-test diff --git a/cpp/ql/src/Critical/MissingNegativityTest.qhelp b/cpp/ql/src/Critical/MissingNegativityTest.qhelp index 8aeb8587fec2..c8e83acfd14d 100644 --- a/cpp/ql/src/Critical/MissingNegativityTest.qhelp +++ b/cpp/ql/src/Critical/MissingNegativityTest.qhelp @@ -35,5 +35,6 @@ is positive and safe to use as an array offset.
  • cplusplus.com: Pointers.
  • +
  • SEI CERT C Coding Standard: ARR30-C. Do not form or use out-of-bounds pointers or array subscripts.
  • diff --git a/cpp/ql/src/Critical/MissingNegativityTest.ql b/cpp/ql/src/Critical/MissingNegativityTest.ql index d0c75a2dcb29..e2f443662c1f 100644 --- a/cpp/ql/src/Critical/MissingNegativityTest.ql +++ b/cpp/ql/src/Critical/MissingNegativityTest.ql @@ -1,6 +1,6 @@ /** * @name Unchecked return value used as offset - * @description Using a value as a pointer offset without checking that the value is positive + * @description Using a return value as a pointer offset without checking that the value is positive * may lead to buffer overruns. * @kind problem * @id cpp/missing-negativity-test diff --git a/cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp b/cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp index 28fd0b737db9..0cb1371f3130 100644 --- a/cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp +++ b/cpp/ql/src/Critical/ReturnStackAllocatedObject.qhelp @@ -32,5 +32,6 @@ heap-allocated memory.
  • cplusplus.com: Pointers.
  • +
  • The craft of coding: Memory in C - the stack, the heap, and static.
  • From c51cd501337845b3c1b7770b0a35366fc2c49a8b Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 12:17:13 +0000 Subject: [PATCH 27/68] JavaScript: Remove a few unnecessary imports. --- javascript/ql/src/Security/CWE-022/TaintedPath.ql | 1 - javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-022/TaintedPath.ql b/javascript/ql/src/Security/CWE-022/TaintedPath.ql index 17d0938de3b4..82ce5358760f 100644 --- a/javascript/ql/src/Security/CWE-022/TaintedPath.ql +++ b/javascript/ql/src/Security/CWE-022/TaintedPath.ql @@ -15,7 +15,6 @@ */ import javascript -import semmle.javascript.security.dataflow.RemoteFlowSources import semmle.javascript.security.dataflow.TaintedPath::TaintedPath from Configuration cfg, DataFlow::Node source, DataFlow::Node sink diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql index 153cc3499079..eb27d36b8272 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql @@ -8,8 +8,8 @@ * @tags security * external/cwe/cwe-916 */ + import javascript -import semmle.javascript.security.dataflow.RemoteFlowSources import semmle.javascript.security.dataflow.InsufficientPasswordHash::InsufficientPasswordHash from Configuration cfg, Source source, DataFlow::Node sink From 9b4ae9e4d3407262da2a0320e0db4b1a638a3aab Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 12:41:01 +0000 Subject: [PATCH 28/68] JavaScript: Refactor `HostHeaderPoisoningInEmailGeneration` query. --- .../HostHeaderPoisoningInEmailGeneration.ql | 25 +++++------------- .../HostHeaderPoisoningInEmailGeneration.qll | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+), 18 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/HostHeaderPoisoningInEmailGeneration.qll diff --git a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql index 9d653efb2f7f..0ac715055ad2 100644 --- a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql +++ b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql @@ -1,6 +1,7 @@ /** * @name Host header poisoning in email generation - * @description Using the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens. + * @description Using the HTTP Host header to construct a link in an email can facilitate phishing + * attacks and leak password reset tokens. * @kind problem * @problem.severity error * @precision high @@ -8,22 +9,10 @@ * @tags security * external/cwe/cwe-640 */ -import javascript - -class TaintedHostHeader extends TaintTracking::Configuration { - TaintedHostHeader() { this = "TaintedHostHeader" } - override predicate isSource(DataFlow::Node node) { - exists (HTTP::RequestHeaderAccess input | node = input | - input.getKind() = "header" and - input.getAHeaderName() = "host") - } - - override predicate isSink(DataFlow::Node node) { - exists (EmailSender email | node = email.getABody()) - } -} +import javascript +import semmle.javascript.security.dataflow.HostHeaderPoisoningInEmailGeneration::HostHeaderPoisoningInEmailGeneration -from TaintedHostHeader taint, DataFlow::Node src, DataFlow::Node sink -where taint.hasFlow(src, sink) -select sink, "Links in this email can be hijacked by poisoning the HTTP host header $@.", src, "here" +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) +select sink, "Links in this email can be hijacked by poisoning the HTTP host header $@.", source, "here" diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/HostHeaderPoisoningInEmailGeneration.qll b/javascript/ql/src/semmle/javascript/security/dataflow/HostHeaderPoisoningInEmailGeneration.qll new file mode 100644 index 000000000000..00dda20e4e4f --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/HostHeaderPoisoningInEmailGeneration.qll @@ -0,0 +1,26 @@ +/** + * Provides a taint tracking configuration for reasoning about host header + * poisoning in email generation. + */ + +import javascript + +module HostHeaderPoisoningInEmailGeneration { + /** + * A taint tracking configuration for host header poisoning in email generation. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "TaintedHostHeader" } + + override predicate isSource(DataFlow::Node node) { + exists (HTTP::RequestHeaderAccess input | node = input | + input.getKind() = "header" and + input.getAHeaderName() = "host" + ) + } + + override predicate isSink(DataFlow::Node node) { + exists (EmailSender email | node = email.getABody()) + } + } +} From 65bcf0f526b2c7d9b230e7d7dc55b0e38e018cd7 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 12:41:44 +0000 Subject: [PATCH 29/68] JavaScript: Refactor security queries for uniformity. --- .../ql/src/Security/CWE-079/ReflectedXss.ql | 4 ++-- javascript/ql/src/Security/CWE-079/StoredXss.ql | 4 ++-- javascript/ql/src/Security/CWE-079/Xss.ql | 6 +++--- .../ql/src/Security/CWE-089/SqlInjection.ql | 15 ++++----------- .../ql/src/Security/CWE-094/CodeInjection.ql | 4 ++-- .../src/Security/CWE-134/TaintedFormatString.ql | 4 ++-- .../ql/src/Security/CWE-200/FileAccessToHttp.ql | 8 ++++---- .../ql/src/Security/CWE-312/CleartextLogging.ql | 4 ++-- .../ql/src/Security/CWE-312/CleartextStorage.ql | 6 +++--- .../src/Security/CWE-327/BrokenCryptoAlgorithm.ql | 8 ++++---- .../CWE-346/CorsMisconfigurationForCredentials.ql | 4 ++-- .../Security/CWE-400/RemotePropertyInjection.ql | 6 +++--- .../src/Security/CWE-601/ClientSideUrlRedirect.ql | 4 ++-- .../src/Security/CWE-601/ServerSideUrlRedirect.ql | 4 ++-- javascript/ql/src/Security/CWE-611/Xxe.ql | 4 ++-- .../ql/src/Security/CWE-643/XpathInjection.ql | 4 ++-- .../ql/src/Security/CWE-730/RegExpInjection.ql | 4 ++-- javascript/ql/src/Security/CWE-776/XmlBomb.ql | 4 ++-- .../src/Security/CWE-798/HardcodedCredentials.ql | 4 ++-- .../ql/src/Security/CWE-807/ConditionalBypass.ql | 1 + .../ql/src/Security/CWE-912/HttpToFileAccess.ql | 8 ++++---- .../Security/CWE-916/InsufficientPasswordHash.ql | 4 ++-- .../ql/src/Security/CWE-918/RequestForgery.ql | 4 ++-- 23 files changed, 56 insertions(+), 62 deletions(-) diff --git a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql index 3a4109512adc..f5598e0dccca 100644 --- a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql @@ -14,7 +14,7 @@ import javascript import semmle.javascript.security.dataflow.ReflectedXss::ReflectedXss -from Configuration xss, DataFlow::Node source, DataFlow::Node sink -where xss.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "Cross-site scripting vulnerability due to $@.", source, "user-provided value" \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-079/StoredXss.ql b/javascript/ql/src/Security/CWE-079/StoredXss.ql index 429bccdf6601..beb499a607b0 100644 --- a/javascript/ql/src/Security/CWE-079/StoredXss.ql +++ b/javascript/ql/src/Security/CWE-079/StoredXss.ql @@ -14,7 +14,7 @@ import javascript import semmle.javascript.security.dataflow.StoredXss::StoredXss -from Configuration xss, DataFlow::Node source, DataFlow::Node sink -where xss.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "Stored cross-site scripting vulnerability due to $@.", source, "stored value" \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-079/Xss.ql b/javascript/ql/src/Security/CWE-079/Xss.ql index 1971ac663553..25a6b83a4493 100644 --- a/javascript/ql/src/Security/CWE-079/Xss.ql +++ b/javascript/ql/src/Security/CWE-079/Xss.ql @@ -14,7 +14,7 @@ import javascript import semmle.javascript.security.dataflow.DomBasedXss::DomBasedXss -from Configuration xss, DataFlow::Node source, Sink sink -where xss.hasFlow(source, sink) -select sink, sink.getVulnerabilityKind() + " vulnerability due to $@.", +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) +select sink, sink.(Sink).getVulnerabilityKind() + " vulnerability due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/Security/CWE-089/SqlInjection.ql index 38b0c304631d..25a0ff693b5c 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.ql @@ -14,15 +14,8 @@ import javascript import semmle.javascript.security.dataflow.SqlInjection import semmle.javascript.security.dataflow.NosqlInjection -predicate sqlInjection(DataFlow::Node source, DataFlow::Node sink) { - any(SqlInjection::Configuration cfg).hasFlow(source, sink) -} - -predicate nosqlInjection(DataFlow::Node source, DataFlow::Node sink) { - any(NosqlInjection::Configuration cfg).hasFlow(source, sink) -} - -from DataFlow::Node source, DataFlow::Node sink -where sqlInjection(source, sink) or - nosqlInjection(source, sink) +from DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where (cfg instanceof SqlInjection::Configuration or + cfg instanceof NosqlInjection::Configuration) and + cfg.hasFlow(source, sink) select sink, "This query depends on $@.", source, "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-094/CodeInjection.ql b/javascript/ql/src/Security/CWE-094/CodeInjection.ql index 478b8b9efcc2..c52d854ea67e 100644 --- a/javascript/ql/src/Security/CWE-094/CodeInjection.ql +++ b/javascript/ql/src/Security/CWE-094/CodeInjection.ql @@ -15,6 +15,6 @@ import javascript import semmle.javascript.security.dataflow.CodeInjection::CodeInjection -from Configuration codeInjection, DataFlow::Node source, DataFlow::Node sink -where codeInjection.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "$@ flows to here and is interpreted as code.", source, "User-provided value" \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql index 6845cd5aff87..c1dd3a4c40e3 100644 --- a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql +++ b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql @@ -12,6 +12,6 @@ import javascript import semmle.javascript.security.dataflow.TaintedFormatString::TaintedFormatString -from Configuration c, DataFlow::Node source, DataFlow::Node sink -where c.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "$@ flows here and is used in a format string.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql index 10b40d686a86..e43ffe380492 100644 --- a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql +++ b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql @@ -9,8 +9,8 @@ */ import javascript -import semmle.javascript.security.dataflow.FileAccessToHttp +import semmle.javascript.security.dataflow.FileAccessToHttp::FileAccessToHttp -from FileAccessToHttp::Configuration config, DataFlow::Node src, DataFlow::Node sink -where config.hasFlow (src, sink) -select sink, "$@ flows directly to outbound network request", src, "File data" +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow (source, sink) +select sink, "$@ flows directly to outbound network request", source, "File data" diff --git a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql index 1ff15ff07b61..9a645eadeb60 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql @@ -31,8 +31,8 @@ predicate inBrowserEnvironment(TopLevel tl) { ) } -from Configuration cfg, Source source, DataFlow::Node sink +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) and // ignore logging to the browser console (even though it is not a good practice) not inBrowserEnvironment(sink.asExpr().getTopLevel()) -select sink, "Sensitive data returned by $@ is logged here.", source, source.describe() +select sink, "Sensitive data returned by $@ is logged here.", source, source.(Source).describe() diff --git a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql index b11abf5abfae..03f876f9abc2 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql @@ -15,6 +15,6 @@ import javascript import semmle.javascript.security.dataflow.CleartextStorage::CleartextStorage -from Configuration cleartextStorage, Source source, DataFlow::Node sink -where cleartextStorage.hasFlow(source, sink) -select sink, "Sensitive data returned by $@ is stored here.", source, source.describe() +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) +select sink, "Sensitive data returned by $@ is stored here.", source, source.(Source).describe() diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index a597b6fc60f0..242d79ecaa7a 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -8,12 +8,12 @@ * @tags security * external/cwe/cwe-327 */ + import javascript -import semmle.javascript.security.dataflow.RemoteFlowSources import semmle.javascript.security.dataflow.BrokenCryptoAlgorithm::BrokenCryptoAlgorithm import semmle.javascript.security.SensitiveActions -from Configuration brokenCrypto, Source source, DataFlow::Node sink -where brokenCrypto.hasFlow(source, sink) and +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) and not source.asExpr() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash -select sink, "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source , source.describe() +select sink, "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source , source.(Source).describe() diff --git a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql index b43f6f700d28..a0476e02000b 100644 --- a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql +++ b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql @@ -14,8 +14,8 @@ import javascript import semmle.javascript.security.dataflow.CorsMisconfigurationForCredentials::CorsMisconfigurationForCredentials -from Configuration cfg, DataFlow::Node source, Sink sink +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) select sink, "$@ leak vulnerability due to $@.", - sink.getCredentialsHeader(), "Credential", + sink.(Sink).getCredentialsHeader(), "Credential", source, "a misconfigured CORS header value" diff --git a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql index ae70f83ed87b..32118edee271 100644 --- a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql +++ b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql @@ -15,8 +15,8 @@ import javascript import semmle.javascript.security.dataflow.RemotePropertyInjection::RemotePropertyInjection -from Configuration c, DataFlow::Node source, Sink sink -where c.hasFlow(source, sink) -select sink, "A $@ is used as" + sink.getMessage(), +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) +select sink, "A $@ is used as" + sink.(Sink).getMessage(), source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql index 98ee34f1ef88..d0d8b0b6ddb3 100644 --- a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql @@ -15,6 +15,6 @@ import javascript import semmle.javascript.security.dataflow.ClientSideUrlRedirect::ClientSideUrlRedirect -from Configuration urlRedirect, DataFlow::Node source, DataFlow::Node sink -where urlRedirect.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "Untrusted URL redirection due to $@.", source, "user-provided value" \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql index 3c689345fd78..be6a4ef8ecb1 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql @@ -13,6 +13,6 @@ import javascript import semmle.javascript.security.dataflow.ServerSideUrlRedirect::ServerSideUrlRedirect -from Configuration urlRedirect, DataFlow::Node source, DataFlow::Node sink -where urlRedirect.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "Untrusted URL redirection due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-611/Xxe.ql b/javascript/ql/src/Security/CWE-611/Xxe.ql index 037e6af3dda1..0863ea142c67 100644 --- a/javascript/ql/src/Security/CWE-611/Xxe.ql +++ b/javascript/ql/src/Security/CWE-611/Xxe.ql @@ -14,7 +14,7 @@ import javascript import semmle.javascript.security.dataflow.Xxe::Xxe -from Configuration c, DataFlow::Node source, DataFlow::Node sink -where c.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "A $@ is parsed as XML without guarding against external entity expansion.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-643/XpathInjection.ql b/javascript/ql/src/Security/CWE-643/XpathInjection.ql index 32f373db0012..dd4e4954ca53 100644 --- a/javascript/ql/src/Security/CWE-643/XpathInjection.ql +++ b/javascript/ql/src/Security/CWE-643/XpathInjection.ql @@ -13,6 +13,6 @@ import javascript import semmle.javascript.security.dataflow.XpathInjection::XpathInjection -from Configuration c, DataFlow::Node source, DataFlow::Node sink -where c.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "$@ flows here and is used in an XPath expression.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql index 532900895bca..4de4e0ec229b 100644 --- a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql +++ b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql @@ -15,6 +15,6 @@ import javascript import semmle.javascript.security.dataflow.RegExpInjection::RegExpInjection -from Configuration c, DataFlow::Node source, DataFlow::Node sink -where c.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "This regular expression is constructed from a $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-776/XmlBomb.ql b/javascript/ql/src/Security/CWE-776/XmlBomb.ql index 3433ab5eb251..27c207751d4a 100644 --- a/javascript/ql/src/Security/CWE-776/XmlBomb.ql +++ b/javascript/ql/src/Security/CWE-776/XmlBomb.ql @@ -14,7 +14,7 @@ import javascript import semmle.javascript.security.dataflow.XmlBomb::XmlBomb -from Configuration c, DataFlow::Node source, DataFlow::Node sink -where c.hasFlow(source, sink) +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) select sink, "A $@ is parsed as XML without guarding against uncontrolled entity expansion.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql index 54b3a023da2c..e7da4f592f5a 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -15,11 +15,11 @@ import javascript private import semmle.javascript.security.dataflow.HardcodedCredentials::HardcodedCredentials -from Configuration cfg, DataFlow::Node source, Sink sink, string value +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink, string value where cfg.hasFlow(source, sink) and // use source value in message if it's available if source.asExpr() instanceof ConstantString then value = "The hard-coded value \"" + source.asExpr().(ConstantString).getStringValue() + "\"" else value = "This hard-coded value" -select source, value + " is used as $@.", sink, sink.getKind() +select source, value + " is used as $@.", sink, sink.(Sink).getKind() diff --git a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql index e939bb61f8a1..b66609cc9fa8 100644 --- a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql +++ b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql @@ -9,6 +9,7 @@ * external/cwe/cwe-807 * external/cwe/cwe-290 */ + import javascript import semmle.javascript.security.dataflow.ConditionalBypass::ConditionalBypass diff --git a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql index fa2aaf95e805..cf6144c440b4 100644 --- a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql +++ b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql @@ -9,8 +9,8 @@ */ import javascript -import semmle.javascript.security.dataflow.HttpToFileAccess +import semmle.javascript.security.dataflow.HttpToFileAccess::HttpToFileAccess -from HttpToFileAccess::Configuration configuration, DataFlow::Node src, DataFlow::Node sink -where configuration.hasFlow(src, sink) -select sink, "$@ flows to file system", src, "Untrusted data" +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) +select sink, "$@ flows to file system", source, "Untrusted data" diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql index eb27d36b8272..3b5c03e5fab4 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql @@ -12,6 +12,6 @@ import javascript import semmle.javascript.security.dataflow.InsufficientPasswordHash::InsufficientPasswordHash -from Configuration cfg, Source source, DataFlow::Node sink +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) -select sink, "Password from $@ is hashed insecurely.", source , source.describe() +select sink, "Password from $@ is hashed insecurely.", source , source.(Source).describe() diff --git a/javascript/ql/src/Security/CWE-918/RequestForgery.ql b/javascript/ql/src/Security/CWE-918/RequestForgery.ql index 3c968bf9fa6c..95f8f3484221 100644 --- a/javascript/ql/src/Security/CWE-918/RequestForgery.ql +++ b/javascript/ql/src/Security/CWE-918/RequestForgery.ql @@ -12,7 +12,7 @@ import javascript import semmle.javascript.security.dataflow.RequestForgery::RequestForgery -from Configuration cfg, DataFlow::Node source, Sink sink, DataFlow::Node request +from Configuration cfg, DataFlow::Node source, DataFlow::Node sink, DataFlow::Node request where cfg.hasFlow(source, sink) and request = sink.getARequest() -select request, "The $@ of this request depends on $@.", sink, sink.getKind(), source, "a user-provided value" +select request, "The $@ of this request depends on $@.", sink, sink.(Sink).getKind(), source, "a user-provided value" From 60a1357092c4d2aed678afce59f012f92fadf9fb Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 12:44:43 +0000 Subject: [PATCH 30/68] JavaScript: Make all taint-based security queries have `@kind path-problem`. --- javascript/ql/src/Security/CWE-022/TaintedPath.ql | 2 +- javascript/ql/src/Security/CWE-078/CommandInjection.ql | 2 +- javascript/ql/src/Security/CWE-079/ReflectedXss.ql | 2 +- javascript/ql/src/Security/CWE-079/StoredXss.ql | 2 +- javascript/ql/src/Security/CWE-079/Xss.ql | 2 +- javascript/ql/src/Security/CWE-089/SqlInjection.ql | 2 +- javascript/ql/src/Security/CWE-094/CodeInjection.ql | 2 +- javascript/ql/src/Security/CWE-134/TaintedFormatString.ql | 2 +- javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql | 2 +- javascript/ql/src/Security/CWE-209/StackTraceExposure.ql | 2 +- javascript/ql/src/Security/CWE-312/CleartextLogging.ql | 2 +- javascript/ql/src/Security/CWE-312/CleartextStorage.ql | 2 +- javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql | 2 +- javascript/ql/src/Security/CWE-338/InsecureRandomness.ql | 2 +- .../src/Security/CWE-346/CorsMisconfigurationForCredentials.ql | 2 +- javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql | 2 +- javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql | 2 +- javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql | 2 +- javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql | 2 +- javascript/ql/src/Security/CWE-611/Xxe.ql | 2 +- .../Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql | 2 +- javascript/ql/src/Security/CWE-643/XpathInjection.ql | 2 +- javascript/ql/src/Security/CWE-730/RegExpInjection.ql | 2 +- javascript/ql/src/Security/CWE-776/XmlBomb.ql | 2 +- javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql | 2 +- javascript/ql/src/Security/CWE-807/ConditionalBypass.ql | 2 +- .../Security/CWE-843/TypeConfusionThroughParameterTampering.ql | 2 +- javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql | 2 +- javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql | 2 +- javascript/ql/src/Security/CWE-918/RequestForgery.ql | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/javascript/ql/src/Security/CWE-022/TaintedPath.ql b/javascript/ql/src/Security/CWE-022/TaintedPath.ql index 82ce5358760f..fcc90abb618f 100644 --- a/javascript/ql/src/Security/CWE-022/TaintedPath.ql +++ b/javascript/ql/src/Security/CWE-022/TaintedPath.ql @@ -2,7 +2,7 @@ * @name Uncontrolled data used in path expression * @description Accessing paths influenced by users can allow an attacker to access * unexpected resources. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/path-injection diff --git a/javascript/ql/src/Security/CWE-078/CommandInjection.ql b/javascript/ql/src/Security/CWE-078/CommandInjection.ql index 36158c3d0b9b..0f000d327414 100644 --- a/javascript/ql/src/Security/CWE-078/CommandInjection.ql +++ b/javascript/ql/src/Security/CWE-078/CommandInjection.ql @@ -2,7 +2,7 @@ * @name Uncontrolled command line * @description Using externally controlled strings in a command line may allow a malicious * user to change the meaning of the command. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/command-line-injection diff --git a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql index f5598e0dccca..16a6819773da 100644 --- a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql @@ -2,7 +2,7 @@ * @name Reflected cross-site scripting * @description Writing user input directly to an HTTP response allows for * a cross-site scripting vulnerability. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/reflected-xss diff --git a/javascript/ql/src/Security/CWE-079/StoredXss.ql b/javascript/ql/src/Security/CWE-079/StoredXss.ql index beb499a607b0..affb40e27710 100644 --- a/javascript/ql/src/Security/CWE-079/StoredXss.ql +++ b/javascript/ql/src/Security/CWE-079/StoredXss.ql @@ -2,7 +2,7 @@ * @name Stored cross-site scripting * @description Using uncontrolled stored values in HTML allows for * a stored cross-site scripting vulnerability. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/stored-xss diff --git a/javascript/ql/src/Security/CWE-079/Xss.ql b/javascript/ql/src/Security/CWE-079/Xss.ql index 25a6b83a4493..368ff84b340b 100644 --- a/javascript/ql/src/Security/CWE-079/Xss.ql +++ b/javascript/ql/src/Security/CWE-079/Xss.ql @@ -2,7 +2,7 @@ * @name Client side cross-site scripting * @description Writing user input directly to the DOM allows for * a cross-site scripting vulnerability. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/xss diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/Security/CWE-089/SqlInjection.ql index 25a0ff693b5c..2e1847efd0c7 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.ql @@ -2,7 +2,7 @@ * @name Database query built from user-controlled sources * @description Building a database query from user-controlled sources is vulnerable to insertion of * malicious code by the user. -* @kind problem +* @kind path-problem * @problem.severity error * @precision high * @id js/sql-injection diff --git a/javascript/ql/src/Security/CWE-094/CodeInjection.ql b/javascript/ql/src/Security/CWE-094/CodeInjection.ql index c52d854ea67e..1ee6d4fff6ad 100644 --- a/javascript/ql/src/Security/CWE-094/CodeInjection.ql +++ b/javascript/ql/src/Security/CWE-094/CodeInjection.ql @@ -2,7 +2,7 @@ * @name Code injection * @description Interpreting unsanitized user input as code allows a malicious user arbitrary * code execution. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/code-injection diff --git a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql index c1dd3a4c40e3..98e0f10dd028 100644 --- a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql +++ b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql @@ -1,7 +1,7 @@ /** * @name Use of externally-controlled format string * @description Using external input in format strings can lead to garbled output. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id js/tainted-format-string diff --git a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql index e43ffe380492..2ff9d648c71c 100644 --- a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql +++ b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql @@ -1,7 +1,7 @@ /** * @name File data in outbound network request * @description Directly sending file data in an outbound network request can indicate unauthorized information disclosure. - * @kind problem + * @kind path-problem * @problem.severity warning * @id js/file-access-to-http * @tags security diff --git a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql index e86c090ef0cd..ffbfcb2e3810 100644 --- a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql +++ b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql @@ -3,7 +3,7 @@ * @description Propagating stack trace information to an external user can * unintentionally reveal implementation details that are useful * to an attacker for developing a subsequent exploit. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision very-high * @id js/stack-trace-exposure diff --git a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql index 9a645eadeb60..e31e6c30567e 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql @@ -2,7 +2,7 @@ * @name Clear-text logging of sensitive information * @description Logging sensitive information without encryption or hashing can * expose it to an attacker. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/clear-text-logging diff --git a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql index 03f876f9abc2..32d64d79da3d 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql @@ -2,7 +2,7 @@ * @name Clear text storage of sensitive information * @description Sensitive information stored without encryption or hashing can expose it to an * attacker. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/clear-text-storage-of-sensitive-data diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index 242d79ecaa7a..192857c520e7 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -1,7 +1,7 @@ /** * @name Use of a broken or weak cryptographic algorithm * @description Using broken or weak cryptographic algorithms can compromise security. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id js/weak-cryptographic-algorithm diff --git a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql index d2007a37636d..58ef6368052a 100644 --- a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql +++ b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql @@ -3,7 +3,7 @@ * @description Using a cryptographically weak pseudo-random number generator to generate a * security-sensitive value may allow an attacker to predict what value will * be generated. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id js/insecure-randomness diff --git a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql index a0476e02000b..a8020f6741fc 100644 --- a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql +++ b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql @@ -1,7 +1,7 @@ /** * @name CORS misconfiguration for credentials transfer * @description Misconfiguration of CORS HTTP headers allows for leaks of secret credentials. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/cors-misconfiguration-for-credentials diff --git a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql index 32118edee271..be405ebadafa 100644 --- a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql +++ b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql @@ -3,7 +3,7 @@ * @description Allowing writes to arbitrary properties or calls to arbitrary * methods of an object may lead to denial-of-service attacks. * - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id js/remote-property-injection diff --git a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql index 20a1e7fb2c20..5f40f53aeb04 100644 --- a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql +++ b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql @@ -2,7 +2,7 @@ * @name Deserialization of user-controlled data * @description Deserializing user-controlled data may allow attackers to * execute arbitrary code. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id js/unsafe-deserialization diff --git a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql index d0d8b0b6ddb3..7ac823dd2d2f 100644 --- a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql @@ -2,7 +2,7 @@ * @name Client-side URL redirect * @description Client-side URL redirection based on unvalidated user input * may cause redirection to malicious web sites. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/client-side-unvalidated-url-redirection diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql index be6a4ef8ecb1..7bf1e8e37fd1 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql @@ -2,7 +2,7 @@ * @name Server-side URL redirect * @description Server-side URL redirection based on unvalidated user input * may cause redirection to malicious web sites. - * @kind problem + * @kind path-problem * @problem.severity warning * @id js/server-side-unvalidated-url-redirection * @tags security diff --git a/javascript/ql/src/Security/CWE-611/Xxe.ql b/javascript/ql/src/Security/CWE-611/Xxe.ql index 0863ea142c67..c95fce7b0eef 100644 --- a/javascript/ql/src/Security/CWE-611/Xxe.ql +++ b/javascript/ql/src/Security/CWE-611/Xxe.ql @@ -2,7 +2,7 @@ * @name XML external entity expansion * @description Parsing user input as an XML document with external * entity expansion is vulnerable to XXE attacks. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/xxe diff --git a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql index 0ac715055ad2..656ed2e9dbe3 100644 --- a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql +++ b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql @@ -2,7 +2,7 @@ * @name Host header poisoning in email generation * @description Using the HTTP Host header to construct a link in an email can facilitate phishing * attacks and leak password reset tokens. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/host-header-forgery-in-email-generation diff --git a/javascript/ql/src/Security/CWE-643/XpathInjection.ql b/javascript/ql/src/Security/CWE-643/XpathInjection.ql index dd4e4954ca53..a083c9d6ca87 100644 --- a/javascript/ql/src/Security/CWE-643/XpathInjection.ql +++ b/javascript/ql/src/Security/CWE-643/XpathInjection.ql @@ -2,7 +2,7 @@ * @name XPath injection * @description Building an XPath expression from user-controlled sources is vulnerable to insertion of * malicious code by the user. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/xpath-injection diff --git a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql index 4de4e0ec229b..c6ba972aa8a6 100644 --- a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql +++ b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql @@ -3,7 +3,7 @@ * @description User input should not be used in regular expressions without first being escaped, * otherwise a malicious user may be able to inject an expression that could require * exponential time on certain inputs. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/regex-injection diff --git a/javascript/ql/src/Security/CWE-776/XmlBomb.ql b/javascript/ql/src/Security/CWE-776/XmlBomb.ql index 27c207751d4a..7c254249a1c2 100644 --- a/javascript/ql/src/Security/CWE-776/XmlBomb.ql +++ b/javascript/ql/src/Security/CWE-776/XmlBomb.ql @@ -2,7 +2,7 @@ * @name XML internal entity expansion * @description Parsing user input as an XML document with arbitrary internal * entity expansion is vulnerable to denial-of-service attacks. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id js/xml-bomb diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql index e7da4f592f5a..e61f42b96868 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -2,7 +2,7 @@ * @name Hard-coded credentials * @description Hard-coding credentials in source code may enable an attacker * to gain unauthorized access. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id js/hardcoded-credentials diff --git a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql index b66609cc9fa8..454621a7e039 100644 --- a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql +++ b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql @@ -1,7 +1,7 @@ /** * @name User-controlled bypass of security check * @description Conditions that the user controls are not suited for making security-related decisions. - * @kind problem + * @kind path-problem * @problem.severity error * @precision medium * @id js/user-controlled-bypass diff --git a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql index fccb209a6985..420c31418999 100644 --- a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql +++ b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql @@ -1,7 +1,7 @@ /** * @name Type confusion through parameter tampering * @description Sanitizing an HTTP request parameter may be ineffective if the user controls its type. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id js/type-confusion-through-parameter-tampering diff --git a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql index cf6144c440b4..6cb125826018 100644 --- a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql +++ b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql @@ -1,7 +1,7 @@ /** * @name User-controlled data written to file * @description Writing user-controlled data directly to the file system allows arbitrary file upload and might indicate a backdoor. - * @kind problem + * @kind path-problem * @problem.severity warning * @id js/http-to-file-access * @tags security diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql index 3b5c03e5fab4..ad7e3c77dd23 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql @@ -1,7 +1,7 @@ /** * @name Use of password hash with insufficient computational effort * @description Creating a hash of a password with low computational effort makes the hash vulnerable to password cracking attacks. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id js/insufficient-password-hash diff --git a/javascript/ql/src/Security/CWE-918/RequestForgery.ql b/javascript/ql/src/Security/CWE-918/RequestForgery.ql index 95f8f3484221..29c07985e831 100644 --- a/javascript/ql/src/Security/CWE-918/RequestForgery.ql +++ b/javascript/ql/src/Security/CWE-918/RequestForgery.ql @@ -1,7 +1,7 @@ /** * @name Uncontrolled data used in network request * @description Sending network requests with user-controlled data allows for request forgery attacks. - * @kind problem + * @kind path-problem * @problem.severity error * @precision medium * @id js/request-forgery From 4860364d91e51cc818f95b1be7f95ebf104c85b2 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Mon, 12 Nov 2018 14:43:31 +0000 Subject: [PATCH 31/68] JavaScript: Add explicit `nodes` query predicate in `PathGraph`. This is needed to correctly handle the case where `edges` is empty. --- .../ql/src/semmle/javascript/dataflow/Configuration.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 44baae1a39b8..b74e317bd10f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -827,9 +827,14 @@ class SinkPathNode extends PathNode { } /** - * Provides the query predicate needed to include a graph in a path-problem query. + * Provides the query predicates needed to include a graph in a path-problem query. */ module PathGraph { + /** Holds if `nd` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode nd) { + any() + } + /** Holds if `pred` → `succ` is an edge in the graph of data flow path explanations. */ query predicate edges(PathNode pred, PathNode succ) { pred.getASuccessor() = succ From 8d87f556e1cee4d29be9a29ddb1fb5bbc520653f Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 12:56:51 +0000 Subject: [PATCH 32/68] JavaScript: Add `import DataFlow::PathGraph`. --- javascript/ql/src/Security/CWE-022/TaintedPath.ql | 1 + javascript/ql/src/Security/CWE-078/CommandInjection.ql | 1 + javascript/ql/src/Security/CWE-079/ReflectedXss.ql | 3 ++- javascript/ql/src/Security/CWE-079/StoredXss.ql | 3 ++- javascript/ql/src/Security/CWE-079/Xss.ql | 1 + javascript/ql/src/Security/CWE-089/SqlInjection.ql | 1 + javascript/ql/src/Security/CWE-094/CodeInjection.ql | 3 ++- javascript/ql/src/Security/CWE-134/TaintedFormatString.ql | 1 + javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql | 1 + javascript/ql/src/Security/CWE-209/StackTraceExposure.ql | 3 ++- javascript/ql/src/Security/CWE-312/CleartextLogging.ql | 1 + javascript/ql/src/Security/CWE-312/CleartextStorage.ql | 1 + javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql | 1 + javascript/ql/src/Security/CWE-338/InsecureRandomness.ql | 3 ++- .../src/Security/CWE-346/CorsMisconfigurationForCredentials.ql | 1 + javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql | 2 +- javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql | 1 + javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql | 3 ++- javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql | 1 + javascript/ql/src/Security/CWE-611/Xxe.ql | 1 + .../Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql | 1 + javascript/ql/src/Security/CWE-643/XpathInjection.ql | 1 + javascript/ql/src/Security/CWE-730/RegExpInjection.ql | 1 + javascript/ql/src/Security/CWE-776/XmlBomb.ql | 1 + javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql | 1 + javascript/ql/src/Security/CWE-807/ConditionalBypass.ql | 1 + .../Security/CWE-843/TypeConfusionThroughParameterTampering.ql | 3 ++- javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql | 1 + javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql | 1 + javascript/ql/src/Security/CWE-918/RequestForgery.ql | 1 + 30 files changed, 37 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/Security/CWE-022/TaintedPath.ql b/javascript/ql/src/Security/CWE-022/TaintedPath.ql index fcc90abb618f..3bc77a53548f 100644 --- a/javascript/ql/src/Security/CWE-022/TaintedPath.ql +++ b/javascript/ql/src/Security/CWE-022/TaintedPath.ql @@ -16,6 +16,7 @@ import javascript import semmle.javascript.security.dataflow.TaintedPath::TaintedPath +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-078/CommandInjection.ql b/javascript/ql/src/Security/CWE-078/CommandInjection.ql index 0f000d327414..2cb33c1ebdb7 100644 --- a/javascript/ql/src/Security/CWE-078/CommandInjection.ql +++ b/javascript/ql/src/Security/CWE-078/CommandInjection.ql @@ -14,6 +14,7 @@ import javascript import semmle.javascript.security.dataflow.CommandInjection::CommandInjection +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink, DataFlow::Node highlight where cfg.hasFlow(source, sink) and diff --git a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql index 16a6819773da..e5879a6301fb 100644 --- a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql @@ -13,8 +13,9 @@ import javascript import semmle.javascript.security.dataflow.ReflectedXss::ReflectedXss +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) select sink, "Cross-site scripting vulnerability due to $@.", - source, "user-provided value" \ No newline at end of file + source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-079/StoredXss.ql b/javascript/ql/src/Security/CWE-079/StoredXss.ql index affb40e27710..cde3fb7ba722 100644 --- a/javascript/ql/src/Security/CWE-079/StoredXss.ql +++ b/javascript/ql/src/Security/CWE-079/StoredXss.ql @@ -13,8 +13,9 @@ import javascript import semmle.javascript.security.dataflow.StoredXss::StoredXss +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) select sink, "Stored cross-site scripting vulnerability due to $@.", - source, "stored value" \ No newline at end of file + source, "stored value" diff --git a/javascript/ql/src/Security/CWE-079/Xss.ql b/javascript/ql/src/Security/CWE-079/Xss.ql index 368ff84b340b..26c21f580aa0 100644 --- a/javascript/ql/src/Security/CWE-079/Xss.ql +++ b/javascript/ql/src/Security/CWE-079/Xss.ql @@ -13,6 +13,7 @@ import javascript import semmle.javascript.security.dataflow.DomBasedXss::DomBasedXss +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/Security/CWE-089/SqlInjection.ql index 2e1847efd0c7..73f836adaa2e 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.ql @@ -13,6 +13,7 @@ import javascript import semmle.javascript.security.dataflow.SqlInjection import semmle.javascript.security.dataflow.NosqlInjection +import DataFlow::PathGraph from DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink where (cfg instanceof SqlInjection::Configuration or diff --git a/javascript/ql/src/Security/CWE-094/CodeInjection.ql b/javascript/ql/src/Security/CWE-094/CodeInjection.ql index 1ee6d4fff6ad..1b02623d0c7e 100644 --- a/javascript/ql/src/Security/CWE-094/CodeInjection.ql +++ b/javascript/ql/src/Security/CWE-094/CodeInjection.ql @@ -14,7 +14,8 @@ import javascript import semmle.javascript.security.dataflow.CodeInjection::CodeInjection +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) -select sink, "$@ flows to here and is interpreted as code.", source, "User-provided value" \ No newline at end of file +select sink, "$@ flows to here and is interpreted as code.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql index 98e0f10dd028..c1bc1dd0dbfe 100644 --- a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql +++ b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql @@ -11,6 +11,7 @@ import javascript import semmle.javascript.security.dataflow.TaintedFormatString::TaintedFormatString +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql index 2ff9d648c71c..649b09a447b7 100644 --- a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql +++ b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql @@ -10,6 +10,7 @@ import javascript import semmle.javascript.security.dataflow.FileAccessToHttp::FileAccessToHttp +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow (source, sink) diff --git a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql index ffbfcb2e3810..29acb9f36fef 100644 --- a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql +++ b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql @@ -13,8 +13,9 @@ import javascript import semmle.javascript.security.dataflow.StackTraceExposure::StackTraceExposure +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) select sink, "Stack trace information from $@ may be exposed to an external user here.", - source, "here" \ No newline at end of file + source, "here" diff --git a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql index e31e6c30567e..f1bcf19faf9e 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql @@ -14,6 +14,7 @@ import javascript import semmle.javascript.security.dataflow.CleartextLogging::CleartextLogging +import DataFlow::PathGraph /** * Holds if `tl` is used in a browser environment. diff --git a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql index 32d64d79da3d..76545de3b204 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql @@ -14,6 +14,7 @@ import javascript import semmle.javascript.security.dataflow.CleartextStorage::CleartextStorage +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index 192857c520e7..18f712f15285 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -12,6 +12,7 @@ import javascript import semmle.javascript.security.dataflow.BrokenCryptoAlgorithm::BrokenCryptoAlgorithm import semmle.javascript.security.SensitiveActions +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) and diff --git a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql index 58ef6368052a..b415acb3a92d 100644 --- a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql +++ b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql @@ -12,7 +12,8 @@ */ import javascript import semmle.javascript.security.dataflow.InsecureRandomness::InsecureRandomness +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) -select sink, "Cryptographically insecure $@ in a security context.", source, "random value" \ No newline at end of file +select sink, "Cryptographically insecure $@ in a security context.", source, "random value" diff --git a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql index a8020f6741fc..9b18c2bf2390 100644 --- a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql +++ b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql @@ -13,6 +13,7 @@ import javascript import semmle.javascript.security.dataflow.CorsMisconfigurationForCredentials::CorsMisconfigurationForCredentials +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql index be405ebadafa..78d3cb7d938d 100644 --- a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql +++ b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql @@ -14,9 +14,9 @@ import javascript import semmle.javascript.security.dataflow.RemotePropertyInjection::RemotePropertyInjection +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) select sink, "A $@ is used as" + sink.(Sink).getMessage(), source, "user-provided value" - diff --git a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql index 5f40f53aeb04..2d5e30c74f49 100644 --- a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql +++ b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql @@ -12,6 +12,7 @@ import javascript import semmle.javascript.security.dataflow.UnsafeDeserialization::UnsafeDeserialization +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql index 7ac823dd2d2f..8272abab0f04 100644 --- a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql @@ -14,7 +14,8 @@ import javascript import semmle.javascript.security.dataflow.ClientSideUrlRedirect::ClientSideUrlRedirect +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) -select sink, "Untrusted URL redirection due to $@.", source, "user-provided value" \ No newline at end of file +select sink, "Untrusted URL redirection due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql index 7bf1e8e37fd1..42cdddc46de2 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql @@ -12,6 +12,7 @@ import javascript import semmle.javascript.security.dataflow.ServerSideUrlRedirect::ServerSideUrlRedirect +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-611/Xxe.ql b/javascript/ql/src/Security/CWE-611/Xxe.ql index c95fce7b0eef..5ebbf33a1a9b 100644 --- a/javascript/ql/src/Security/CWE-611/Xxe.ql +++ b/javascript/ql/src/Security/CWE-611/Xxe.ql @@ -13,6 +13,7 @@ import javascript import semmle.javascript.security.dataflow.Xxe::Xxe +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql index 656ed2e9dbe3..4af6c22cd702 100644 --- a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql +++ b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql @@ -12,6 +12,7 @@ import javascript import semmle.javascript.security.dataflow.HostHeaderPoisoningInEmailGeneration::HostHeaderPoisoningInEmailGeneration +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-643/XpathInjection.ql b/javascript/ql/src/Security/CWE-643/XpathInjection.ql index a083c9d6ca87..904c8149ab34 100644 --- a/javascript/ql/src/Security/CWE-643/XpathInjection.ql +++ b/javascript/ql/src/Security/CWE-643/XpathInjection.ql @@ -12,6 +12,7 @@ import javascript import semmle.javascript.security.dataflow.XpathInjection::XpathInjection +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql index c6ba972aa8a6..57127778cd6c 100644 --- a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql +++ b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql @@ -14,6 +14,7 @@ import javascript import semmle.javascript.security.dataflow.RegExpInjection::RegExpInjection +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-776/XmlBomb.ql b/javascript/ql/src/Security/CWE-776/XmlBomb.ql index 7c254249a1c2..a0c9020a5f40 100644 --- a/javascript/ql/src/Security/CWE-776/XmlBomb.ql +++ b/javascript/ql/src/Security/CWE-776/XmlBomb.ql @@ -13,6 +13,7 @@ import javascript import semmle.javascript.security.dataflow.XmlBomb::XmlBomb +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql index e61f42b96868..3d21115fd07d 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -14,6 +14,7 @@ import javascript private import semmle.javascript.security.dataflow.HardcodedCredentials::HardcodedCredentials +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink, string value where cfg.hasFlow(source, sink) and diff --git a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql index 454621a7e039..105cb2d0d358 100644 --- a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql +++ b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql @@ -12,6 +12,7 @@ import javascript import semmle.javascript.security.dataflow.ConditionalBypass::ConditionalBypass +import DataFlow::PathGraph /** * Holds if the value of `nd` flows into `guard`. diff --git a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql index 420c31418999..f9403c652380 100644 --- a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql +++ b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql @@ -11,7 +11,8 @@ import javascript import semmle.javascript.security.dataflow.TypeConfusionThroughParameterTampering::TypeConfusionThroughParameterTampering +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) -select sink, "Potential type confusion for $@.", source, "HTTP request parameter" \ No newline at end of file +select sink, "Potential type confusion for $@.", source, "HTTP request parameter" diff --git a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql index 6cb125826018..1eb21eb7c76a 100644 --- a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql +++ b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql @@ -10,6 +10,7 @@ import javascript import semmle.javascript.security.dataflow.HttpToFileAccess::HttpToFileAccess +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql index ad7e3c77dd23..b209a6c58310 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql @@ -11,6 +11,7 @@ import javascript import semmle.javascript.security.dataflow.InsufficientPasswordHash::InsufficientPasswordHash +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) diff --git a/javascript/ql/src/Security/CWE-918/RequestForgery.ql b/javascript/ql/src/Security/CWE-918/RequestForgery.ql index 29c07985e831..81d6e83a32e1 100644 --- a/javascript/ql/src/Security/CWE-918/RequestForgery.ql +++ b/javascript/ql/src/Security/CWE-918/RequestForgery.ql @@ -11,6 +11,7 @@ import javascript import semmle.javascript.security.dataflow.RequestForgery::RequestForgery +import DataFlow::PathGraph from Configuration cfg, DataFlow::Node source, DataFlow::Node sink, DataFlow::Node request where cfg.hasFlow(source, sink) and From 11d6259dbfdb4ddf896d09149e83779930525463 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 13:09:54 +0000 Subject: [PATCH 33/68] JavaScript: Move from `Node` to `PathNode`. --- javascript/ql/src/Security/CWE-022/TaintedPath.ql | 6 +++--- javascript/ql/src/Security/CWE-078/CommandInjection.ql | 10 +++++----- javascript/ql/src/Security/CWE-079/ReflectedXss.ql | 6 +++--- javascript/ql/src/Security/CWE-079/StoredXss.ql | 6 +++--- javascript/ql/src/Security/CWE-079/Xss.ql | 6 +++--- javascript/ql/src/Security/CWE-089/SqlInjection.ql | 6 +++--- javascript/ql/src/Security/CWE-094/CodeInjection.ql | 6 +++--- .../ql/src/Security/CWE-134/TaintedFormatString.ql | 6 +++--- javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql | 6 +++--- .../ql/src/Security/CWE-209/StackTraceExposure.ql | 6 +++--- javascript/ql/src/Security/CWE-312/CleartextLogging.ql | 8 ++++---- javascript/ql/src/Security/CWE-312/CleartextStorage.ql | 6 +++--- .../ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql | 6 +++--- .../ql/src/Security/CWE-338/InsecureRandomness.ql | 6 +++--- .../CWE-346/CorsMisconfigurationForCredentials.ql | 6 +++--- .../ql/src/Security/CWE-400/RemotePropertyInjection.ql | 6 +++--- .../ql/src/Security/CWE-502/UnsafeDeserialization.ql | 6 +++--- .../ql/src/Security/CWE-601/ClientSideUrlRedirect.ql | 6 +++--- .../ql/src/Security/CWE-601/ServerSideUrlRedirect.ql | 6 +++--- javascript/ql/src/Security/CWE-611/Xxe.ql | 6 +++--- .../CWE-640/HostHeaderPoisoningInEmailGeneration.ql | 6 +++--- javascript/ql/src/Security/CWE-643/XpathInjection.ql | 6 +++--- javascript/ql/src/Security/CWE-730/RegExpInjection.ql | 6 +++--- javascript/ql/src/Security/CWE-776/XmlBomb.ql | 6 +++--- .../ql/src/Security/CWE-798/HardcodedCredentials.ql | 10 +++++----- .../CWE-843/TypeConfusionThroughParameterTampering.ql | 6 +++--- javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql | 6 +++--- .../src/Security/CWE-916/InsufficientPasswordHash.ql | 6 +++--- javascript/ql/src/Security/CWE-918/RequestForgery.ql | 8 ++++---- 29 files changed, 93 insertions(+), 93 deletions(-) diff --git a/javascript/ql/src/Security/CWE-022/TaintedPath.ql b/javascript/ql/src/Security/CWE-022/TaintedPath.ql index 3bc77a53548f..ddaf8ff3e966 100644 --- a/javascript/ql/src/Security/CWE-022/TaintedPath.ql +++ b/javascript/ql/src/Security/CWE-022/TaintedPath.ql @@ -18,6 +18,6 @@ import javascript import semmle.javascript.security.dataflow.TaintedPath::TaintedPath import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "This path depends on $@.", source, "a user-provided value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "This path depends on $@.", source, "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-078/CommandInjection.ql b/javascript/ql/src/Security/CWE-078/CommandInjection.ql index 2cb33c1ebdb7..055d0b1cc1e6 100644 --- a/javascript/ql/src/Security/CWE-078/CommandInjection.ql +++ b/javascript/ql/src/Security/CWE-078/CommandInjection.ql @@ -16,10 +16,10 @@ import javascript import semmle.javascript.security.dataflow.CommandInjection::CommandInjection import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink, DataFlow::Node highlight -where cfg.hasFlow(source, sink) and - if cfg.isSinkWithHighlight(sink, _) then - cfg.isSinkWithHighlight(sink, highlight) +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node highlight +where cfg.hasPathFlow(source, sink) and + if cfg.isSinkWithHighlight(sink.getNode(), _) then + cfg.isSinkWithHighlight(sink.getNode(), highlight) else - highlight = sink + highlight = sink.getNode() select highlight, "This command depends on $@.", source, "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql index e5879a6301fb..3ea49de54dc7 100644 --- a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql @@ -15,7 +15,7 @@ import javascript import semmle.javascript.security.dataflow.ReflectedXss::ReflectedXss import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Cross-site scripting vulnerability due to $@.", +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Cross-site scripting vulnerability due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-079/StoredXss.ql b/javascript/ql/src/Security/CWE-079/StoredXss.ql index cde3fb7ba722..5ac97e1ede33 100644 --- a/javascript/ql/src/Security/CWE-079/StoredXss.ql +++ b/javascript/ql/src/Security/CWE-079/StoredXss.ql @@ -15,7 +15,7 @@ import javascript import semmle.javascript.security.dataflow.StoredXss::StoredXss import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Stored cross-site scripting vulnerability due to $@.", +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Stored cross-site scripting vulnerability due to $@.", source, "stored value" diff --git a/javascript/ql/src/Security/CWE-079/Xss.ql b/javascript/ql/src/Security/CWE-079/Xss.ql index 26c21f580aa0..238e0a87635d 100644 --- a/javascript/ql/src/Security/CWE-079/Xss.ql +++ b/javascript/ql/src/Security/CWE-079/Xss.ql @@ -15,7 +15,7 @@ import javascript import semmle.javascript.security.dataflow.DomBasedXss::DomBasedXss import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, sink.(Sink).getVulnerabilityKind() + " vulnerability due to $@.", +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), sink.getNode().(Sink).getVulnerabilityKind() + " vulnerability due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/Security/CWE-089/SqlInjection.ql index 73f836adaa2e..1ebd0176346b 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.ql @@ -15,8 +15,8 @@ import semmle.javascript.security.dataflow.SqlInjection import semmle.javascript.security.dataflow.NosqlInjection import DataFlow::PathGraph -from DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink +from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where (cfg instanceof SqlInjection::Configuration or cfg instanceof NosqlInjection::Configuration) and - cfg.hasFlow(source, sink) -select sink, "This query depends on $@.", source, "a user-provided value" + cfg.hasPathFlow(source, sink) +select sink.getNode(), "This query depends on $@.", source, "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-094/CodeInjection.ql b/javascript/ql/src/Security/CWE-094/CodeInjection.ql index 1b02623d0c7e..1983395d2d02 100644 --- a/javascript/ql/src/Security/CWE-094/CodeInjection.ql +++ b/javascript/ql/src/Security/CWE-094/CodeInjection.ql @@ -16,6 +16,6 @@ import javascript import semmle.javascript.security.dataflow.CodeInjection::CodeInjection import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "$@ flows to here and is interpreted as code.", source, "User-provided value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "$@ flows to here and is interpreted as code.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql index c1bc1dd0dbfe..e5b1a63d1c8b 100644 --- a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql +++ b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql @@ -13,6 +13,6 @@ import javascript import semmle.javascript.security.dataflow.TaintedFormatString::TaintedFormatString import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "$@ flows here and is used in a format string.", source, "User-provided value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "$@ flows here and is used in a format string.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql index 649b09a447b7..625db04eb8e9 100644 --- a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql +++ b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql @@ -12,6 +12,6 @@ import javascript import semmle.javascript.security.dataflow.FileAccessToHttp::FileAccessToHttp import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow (source, sink) -select sink, "$@ flows directly to outbound network request", source, "File data" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "$@ flows directly to outbound network request", source, "File data" diff --git a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql index 29acb9f36fef..9e82e67b1435 100644 --- a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql +++ b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql @@ -15,7 +15,7 @@ import javascript import semmle.javascript.security.dataflow.StackTraceExposure::StackTraceExposure import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Stack trace information from $@ may be exposed to an external user here.", +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Stack trace information from $@ may be exposed to an external user here.", source, "here" diff --git a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql index f1bcf19faf9e..823f01f4b020 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql @@ -32,8 +32,8 @@ predicate inBrowserEnvironment(TopLevel tl) { ) } -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) and +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) and // ignore logging to the browser console (even though it is not a good practice) - not inBrowserEnvironment(sink.asExpr().getTopLevel()) -select sink, "Sensitive data returned by $@ is logged here.", source, source.(Source).describe() + not inBrowserEnvironment(sink.getNode().asExpr().getTopLevel()) +select sink.getNode(), "Sensitive data returned by $@ is logged here.", source, source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql index 76545de3b204..56b4b2674372 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql @@ -16,6 +16,6 @@ import javascript import semmle.javascript.security.dataflow.CleartextStorage::CleartextStorage import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Sensitive data returned by $@ is stored here.", source, source.(Source).describe() +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Sensitive data returned by $@ is stored here.", source, source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index 18f712f15285..9fdf0e96df6a 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -14,7 +14,7 @@ import semmle.javascript.security.dataflow.BrokenCryptoAlgorithm::BrokenCryptoAl import semmle.javascript.security.SensitiveActions import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) and +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) and not source.asExpr() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash -select sink, "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source , source.(Source).describe() +select sink.getNode(), "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source , source.(Source).describe() diff --git a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql index b415acb3a92d..6d6720c65196 100644 --- a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql +++ b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql @@ -14,6 +14,6 @@ import javascript import semmle.javascript.security.dataflow.InsecureRandomness::InsecureRandomness import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Cryptographically insecure $@ in a security context.", source, "random value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Cryptographically insecure $@ in a security context.", source, "random value" diff --git a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql index 9b18c2bf2390..78c0e13a3c77 100644 --- a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql +++ b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql @@ -15,8 +15,8 @@ import javascript import semmle.javascript.security.dataflow.CorsMisconfigurationForCredentials::CorsMisconfigurationForCredentials import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "$@ leak vulnerability due to $@.", +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "$@ leak vulnerability due to $@.", sink.(Sink).getCredentialsHeader(), "Credential", source, "a misconfigured CORS header value" diff --git a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql index 78d3cb7d938d..c4f27c2bfc10 100644 --- a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql +++ b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql @@ -16,7 +16,7 @@ import javascript import semmle.javascript.security.dataflow.RemotePropertyInjection::RemotePropertyInjection import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "A $@ is used as" + sink.(Sink).getMessage(), +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "A $@ is used as" + sink.(Sink).getMessage(), source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql index 2d5e30c74f49..f72d04233c53 100644 --- a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql +++ b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql @@ -14,6 +14,6 @@ import javascript import semmle.javascript.security.dataflow.UnsafeDeserialization::UnsafeDeserialization import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Unsafe deserialization of $@.", source, "user input" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Unsafe deserialization of $@.", source, "user input" diff --git a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql index 8272abab0f04..02ebbbd3372d 100644 --- a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql @@ -16,6 +16,6 @@ import javascript import semmle.javascript.security.dataflow.ClientSideUrlRedirect::ClientSideUrlRedirect import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Untrusted URL redirection due to $@.", source, "user-provided value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Untrusted URL redirection due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql index 42cdddc46de2..7eb22e12eb93 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql @@ -14,6 +14,6 @@ import javascript import semmle.javascript.security.dataflow.ServerSideUrlRedirect::ServerSideUrlRedirect import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Untrusted URL redirection due to $@.", source, "user-provided value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Untrusted URL redirection due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-611/Xxe.ql b/javascript/ql/src/Security/CWE-611/Xxe.ql index 5ebbf33a1a9b..ef88aeaeaaab 100644 --- a/javascript/ql/src/Security/CWE-611/Xxe.ql +++ b/javascript/ql/src/Security/CWE-611/Xxe.ql @@ -15,7 +15,7 @@ import javascript import semmle.javascript.security.dataflow.Xxe::Xxe import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "A $@ is parsed as XML without guarding against external entity expansion.", +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "A $@ is parsed as XML without guarding against external entity expansion.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql index 4af6c22cd702..aae8e42badea 100644 --- a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql +++ b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql @@ -14,6 +14,6 @@ import javascript import semmle.javascript.security.dataflow.HostHeaderPoisoningInEmailGeneration::HostHeaderPoisoningInEmailGeneration import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Links in this email can be hijacked by poisoning the HTTP host header $@.", source, "here" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Links in this email can be hijacked by poisoning the HTTP host header $@.", source, "here" diff --git a/javascript/ql/src/Security/CWE-643/XpathInjection.ql b/javascript/ql/src/Security/CWE-643/XpathInjection.ql index 904c8149ab34..2d56505efff0 100644 --- a/javascript/ql/src/Security/CWE-643/XpathInjection.ql +++ b/javascript/ql/src/Security/CWE-643/XpathInjection.ql @@ -14,6 +14,6 @@ import javascript import semmle.javascript.security.dataflow.XpathInjection::XpathInjection import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "$@ flows here and is used in an XPath expression.", source, "User-provided value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "$@ flows here and is used in an XPath expression.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql index 57127778cd6c..27e482596b12 100644 --- a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql +++ b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql @@ -16,6 +16,6 @@ import javascript import semmle.javascript.security.dataflow.RegExpInjection::RegExpInjection import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "This regular expression is constructed from a $@.", source, "user-provided value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "This regular expression is constructed from a $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-776/XmlBomb.ql b/javascript/ql/src/Security/CWE-776/XmlBomb.ql index a0c9020a5f40..fcff0c764c49 100644 --- a/javascript/ql/src/Security/CWE-776/XmlBomb.ql +++ b/javascript/ql/src/Security/CWE-776/XmlBomb.ql @@ -15,7 +15,7 @@ import javascript import semmle.javascript.security.dataflow.XmlBomb::XmlBomb import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "A $@ is parsed as XML without guarding against uncontrolled entity expansion.", +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "A $@ is parsed as XML without guarding against uncontrolled entity expansion.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql index 3d21115fd07d..c29fd9d1b601 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -16,11 +16,11 @@ import javascript private import semmle.javascript.security.dataflow.HardcodedCredentials::HardcodedCredentials import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink, string value -where cfg.hasFlow(source, sink) and +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, string value +where cfg.hasPathFlow(source, sink) and // use source value in message if it's available - if source.asExpr() instanceof ConstantString then - value = "The hard-coded value \"" + source.asExpr().(ConstantString).getStringValue() + "\"" + if source.getNode().asExpr() instanceof ConstantString then + value = "The hard-coded value \"" + source.getNode().asExpr().(ConstantString).getStringValue() + "\"" else value = "This hard-coded value" -select source, value + " is used as $@.", sink, sink.(Sink).getKind() +select source.getNode(), value + " is used as $@.", sink, sink.getNode().(Sink).getKind() diff --git a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql index f9403c652380..3e9f6e018bd6 100644 --- a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql +++ b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql @@ -13,6 +13,6 @@ import javascript import semmle.javascript.security.dataflow.TypeConfusionThroughParameterTampering::TypeConfusionThroughParameterTampering import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Potential type confusion for $@.", source, "HTTP request parameter" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Potential type confusion for $@.", source, "HTTP request parameter" diff --git a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql index 1eb21eb7c76a..e4aff3fc8d60 100644 --- a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql +++ b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql @@ -12,6 +12,6 @@ import javascript import semmle.javascript.security.dataflow.HttpToFileAccess::HttpToFileAccess import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "$@ flows to file system", source, "Untrusted data" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "$@ flows to file system", source, "Untrusted data" diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql index b209a6c58310..ba729c28a73c 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql @@ -13,6 +13,6 @@ import javascript import semmle.javascript.security.dataflow.InsufficientPasswordHash::InsufficientPasswordHash import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select sink, "Password from $@ is hashed insecurely.", source , source.(Source).describe() +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasPathFlow(source, sink) +select sink.getNode(), "Password from $@ is hashed insecurely.", source , source.(Source).describe() diff --git a/javascript/ql/src/Security/CWE-918/RequestForgery.ql b/javascript/ql/src/Security/CWE-918/RequestForgery.ql index 81d6e83a32e1..831fb6522926 100644 --- a/javascript/ql/src/Security/CWE-918/RequestForgery.ql +++ b/javascript/ql/src/Security/CWE-918/RequestForgery.ql @@ -13,7 +13,7 @@ import javascript import semmle.javascript.security.dataflow.RequestForgery::RequestForgery import DataFlow::PathGraph -from Configuration cfg, DataFlow::Node source, DataFlow::Node sink, DataFlow::Node request -where cfg.hasFlow(source, sink) and - request = sink.getARequest() -select request, "The $@ of this request depends on $@.", sink, sink.(Sink).getKind(), source, "a user-provided value" +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node request +where cfg.hasPathFlow(source, sink) and + request = sink.getNode().(Sink).getARequest() +select request, "The $@ of this request depends on $@.", sink, sink.getNode().(Sink).getKind(), source, "a user-provided value" From d5af008e31bab3f04b3b75122c09cac1a9fa6e5f Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 13:15:25 +0000 Subject: [PATCH 34/68] JavaScript: Adjust `ConditionalBypass` query. --- .../src/Security/CWE-807/ConditionalBypass.ql | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql index 105cb2d0d358..13ae16d52cb1 100644 --- a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql +++ b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql @@ -67,18 +67,19 @@ class SensitiveActionGuardComparisonOperand extends Sink { * If flow from `source` taints `sink`, then an attacker can * control if `action` should be executed or not. */ -predicate isTaintedGuardForSensitiveAction(Sink sink, DataFlow::Node source, SensitiveAction action) { - action = sink.getAction() and +predicate isTaintedGuardForSensitiveAction(DataFlow::PathNode sink, DataFlow::PathNode source, SensitiveAction action) { + action = sink.getNode().(Sink).getAction() and // exclude the intermediary sink - not sink instanceof SensitiveActionGuardComparisonOperand and + not sink.getNode() instanceof SensitiveActionGuardComparisonOperand and exists (Configuration cfg | // ordinary taint tracking to a guard - cfg.hasFlow(source, sink) or + cfg.hasPathFlow(source, sink) or // taint tracking to both operands of a guard comparison - exists (SensitiveActionGuardComparison cmp, DataFlow::Node lSource, DataFlow::Node rSource | - sink = cmp.getGuard() and - cfg.hasFlow(lSource, DataFlow::valueNode(cmp.getLeftOperand())) and - cfg.hasFlow(rSource, DataFlow::valueNode(cmp.getRightOperand())) | + exists (SensitiveActionGuardComparison cmp, DataFlow::PathNode lSource, DataFlow::PathNode rSource, + DataFlow::PathNode lSink, DataFlow::PathNode rSink | + sink.getNode() = cmp.getGuard() and + cfg.hasPathFlow(lSource, lSink) and lSink.getNode() = DataFlow::valueNode(cmp.getLeftOperand()) and + cfg.hasPathFlow(rSource, rSink) and rSink.getNode() = DataFlow::valueNode(cmp.getRightOperand()) | source = lSource or source = rSource ) @@ -90,10 +91,10 @@ predicate isTaintedGuardForSensitiveAction(Sink sink, DataFlow::Node source, Sen * * Example: `if (e) return; action(x)`. */ -predicate isEarlyAbortGuard(Sink e, SensitiveAction action) { +predicate isEarlyAbortGuard(DataFlow::PathNode e, SensitiveAction action) { exists (IfStmt guard | // `e` is in the condition of an if-statement ... - e.asExpr().getParentExpr*() = guard.getCondition() and + e.getNode().(Sink).asExpr().getParentExpr*() = guard.getCondition() and // ... where the then-branch always throws or returns exists (Stmt abort | abort instanceof ThrowStmt or @@ -108,9 +109,9 @@ predicate isEarlyAbortGuard(Sink e, SensitiveAction action) { ) } -from DataFlow::Node source, DataFlow::Node sink, SensitiveAction action +from DataFlow::PathNode source, DataFlow::PathNode sink, SensitiveAction action where isTaintedGuardForSensitiveAction(sink, source, action) and not isEarlyAbortGuard(sink, action) -select sink, "This condition guards a sensitive $@, but $@ controls it.", +select sink.getNode(), "This condition guards a sensitive $@, but $@ controls it.", action, "action", source, "a user-provided value" From e365b722eea374b138c7d9a3ecadf8dba0f72783 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 13:18:00 +0000 Subject: [PATCH 35/68] JavaScript: Select `source` and `sink` in all path queries. --- javascript/ql/src/Security/CWE-022/TaintedPath.ql | 2 +- javascript/ql/src/Security/CWE-078/CommandInjection.ql | 2 +- javascript/ql/src/Security/CWE-079/ReflectedXss.ql | 2 +- javascript/ql/src/Security/CWE-079/StoredXss.ql | 2 +- javascript/ql/src/Security/CWE-079/Xss.ql | 2 +- javascript/ql/src/Security/CWE-089/SqlInjection.ql | 2 +- javascript/ql/src/Security/CWE-094/CodeInjection.ql | 2 +- javascript/ql/src/Security/CWE-134/TaintedFormatString.ql | 2 +- javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql | 2 +- javascript/ql/src/Security/CWE-209/StackTraceExposure.ql | 2 +- javascript/ql/src/Security/CWE-312/CleartextLogging.ql | 2 +- javascript/ql/src/Security/CWE-312/CleartextStorage.ql | 2 +- javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql | 2 +- javascript/ql/src/Security/CWE-338/InsecureRandomness.ql | 2 +- .../src/Security/CWE-346/CorsMisconfigurationForCredentials.ql | 2 +- javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql | 2 +- javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql | 2 +- javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql | 2 +- javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql | 2 +- javascript/ql/src/Security/CWE-611/Xxe.ql | 2 +- .../Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql | 2 +- javascript/ql/src/Security/CWE-643/XpathInjection.ql | 2 +- javascript/ql/src/Security/CWE-730/RegExpInjection.ql | 2 +- javascript/ql/src/Security/CWE-776/XmlBomb.ql | 2 +- javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql | 2 +- javascript/ql/src/Security/CWE-807/ConditionalBypass.ql | 2 +- .../Security/CWE-843/TypeConfusionThroughParameterTampering.ql | 2 +- javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql | 2 +- javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql | 2 +- javascript/ql/src/Security/CWE-918/RequestForgery.ql | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/javascript/ql/src/Security/CWE-022/TaintedPath.ql b/javascript/ql/src/Security/CWE-022/TaintedPath.ql index ddaf8ff3e966..e1c44d535593 100644 --- a/javascript/ql/src/Security/CWE-022/TaintedPath.ql +++ b/javascript/ql/src/Security/CWE-022/TaintedPath.ql @@ -20,4 +20,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "This path depends on $@.", source, "a user-provided value" +select sink.getNode(), source, sink, "This path depends on $@.", source, "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-078/CommandInjection.ql b/javascript/ql/src/Security/CWE-078/CommandInjection.ql index 055d0b1cc1e6..bef7c596dff1 100644 --- a/javascript/ql/src/Security/CWE-078/CommandInjection.ql +++ b/javascript/ql/src/Security/CWE-078/CommandInjection.ql @@ -22,4 +22,4 @@ where cfg.hasPathFlow(source, sink) and cfg.isSinkWithHighlight(sink.getNode(), highlight) else highlight = sink.getNode() -select highlight, "This command depends on $@.", source, "a user-provided value" +select highlight, source, sink, "This command depends on $@.", source, "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql index 3ea49de54dc7..a6f3a97e6169 100644 --- a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql @@ -17,5 +17,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Cross-site scripting vulnerability due to $@.", +select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-079/StoredXss.ql b/javascript/ql/src/Security/CWE-079/StoredXss.ql index 5ac97e1ede33..84e2c433fc11 100644 --- a/javascript/ql/src/Security/CWE-079/StoredXss.ql +++ b/javascript/ql/src/Security/CWE-079/StoredXss.ql @@ -17,5 +17,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Stored cross-site scripting vulnerability due to $@.", +select sink.getNode(), source, sink, "Stored cross-site scripting vulnerability due to $@.", source, "stored value" diff --git a/javascript/ql/src/Security/CWE-079/Xss.ql b/javascript/ql/src/Security/CWE-079/Xss.ql index 238e0a87635d..bed5436b0b53 100644 --- a/javascript/ql/src/Security/CWE-079/Xss.ql +++ b/javascript/ql/src/Security/CWE-079/Xss.ql @@ -17,5 +17,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), sink.getNode().(Sink).getVulnerabilityKind() + " vulnerability due to $@.", +select sink.getNode(), source, sink, sink.getNode().(Sink).getVulnerabilityKind() + " vulnerability due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/Security/CWE-089/SqlInjection.ql index 1ebd0176346b..7da69c8174ed 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.ql @@ -19,4 +19,4 @@ from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode where (cfg instanceof SqlInjection::Configuration or cfg instanceof NosqlInjection::Configuration) and cfg.hasPathFlow(source, sink) -select sink.getNode(), "This query depends on $@.", source, "a user-provided value" +select sink.getNode(), source, sink, "This query depends on $@.", source, "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-094/CodeInjection.ql b/javascript/ql/src/Security/CWE-094/CodeInjection.ql index 1983395d2d02..62e1ee05c77f 100644 --- a/javascript/ql/src/Security/CWE-094/CodeInjection.ql +++ b/javascript/ql/src/Security/CWE-094/CodeInjection.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "$@ flows to here and is interpreted as code.", source, "User-provided value" +select sink.getNode(), source, sink, "$@ flows to here and is interpreted as code.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql index e5b1a63d1c8b..0a277ccbb62e 100644 --- a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql +++ b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql @@ -15,4 +15,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "$@ flows here and is used in a format string.", source, "User-provided value" +select sink.getNode(), source, sink, "$@ flows here and is used in a format string.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql index 625db04eb8e9..836674f6e33a 100644 --- a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql +++ b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql @@ -14,4 +14,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "$@ flows directly to outbound network request", source, "File data" +select sink.getNode(), source, sink, "$@ flows directly to outbound network request", source, "File data" diff --git a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql index 9e82e67b1435..fac7de89b3d1 100644 --- a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql +++ b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql @@ -17,5 +17,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Stack trace information from $@ may be exposed to an external user here.", +select sink.getNode(), source, sink, "Stack trace information from $@ may be exposed to an external user here.", source, "here" diff --git a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql index 823f01f4b020..556159065842 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql @@ -36,4 +36,4 @@ from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) and // ignore logging to the browser console (even though it is not a good practice) not inBrowserEnvironment(sink.getNode().asExpr().getTopLevel()) -select sink.getNode(), "Sensitive data returned by $@ is logged here.", source, source.getNode().(Source).describe() +select sink.getNode(), source, sink, "Sensitive data returned by $@ is logged here.", source, source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql index 56b4b2674372..060cf8abe951 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Sensitive data returned by $@ is stored here.", source, source.getNode().(Source).describe() +select sink.getNode(), source, sink, "Sensitive data returned by $@ is stored here.", source, source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index 9fdf0e96df6a..619a170a28e4 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -17,4 +17,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) and not source.asExpr() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash -select sink.getNode(), "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source , source.(Source).describe() +select sink.getNode(), source, sink, "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source , source.(Source).describe() diff --git a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql index 6d6720c65196..03383b1cf205 100644 --- a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql +++ b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql @@ -16,4 +16,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Cryptographically insecure $@ in a security context.", source, "random value" +select sink.getNode(), source, sink, "Cryptographically insecure $@ in a security context.", source, "random value" diff --git a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql index 78c0e13a3c77..64910083d863 100644 --- a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql +++ b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql @@ -17,6 +17,6 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "$@ leak vulnerability due to $@.", +select sink.getNode(), source, sink, "$@ leak vulnerability due to $@.", sink.(Sink).getCredentialsHeader(), "Credential", source, "a misconfigured CORS header value" diff --git a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql index c4f27c2bfc10..c69b4427f3af 100644 --- a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql +++ b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql @@ -18,5 +18,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "A $@ is used as" + sink.(Sink).getMessage(), +select sink.getNode(), source, sink, "A $@ is used as" + sink.(Sink).getMessage(), source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql index f72d04233c53..964e3bda6e19 100644 --- a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql +++ b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql @@ -16,4 +16,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Unsafe deserialization of $@.", source, "user input" +select sink.getNode(), source, sink, "Unsafe deserialization of $@.", source, "user input" diff --git a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql index 02ebbbd3372d..cda39882544d 100644 --- a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Untrusted URL redirection due to $@.", source, "user-provided value" +select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql index 7eb22e12eb93..da3c412e59ba 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql @@ -16,4 +16,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Untrusted URL redirection due to $@.", source, "user-provided value" +select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-611/Xxe.ql b/javascript/ql/src/Security/CWE-611/Xxe.ql index ef88aeaeaaab..db0bca561cab 100644 --- a/javascript/ql/src/Security/CWE-611/Xxe.ql +++ b/javascript/ql/src/Security/CWE-611/Xxe.ql @@ -17,5 +17,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "A $@ is parsed as XML without guarding against external entity expansion.", +select sink.getNode(), source, sink, "A $@ is parsed as XML without guarding against external entity expansion.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql index aae8e42badea..0d0db8cdbde8 100644 --- a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql +++ b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql @@ -16,4 +16,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Links in this email can be hijacked by poisoning the HTTP host header $@.", source, "here" +select sink.getNode(), source, sink, "Links in this email can be hijacked by poisoning the HTTP host header $@.", source, "here" diff --git a/javascript/ql/src/Security/CWE-643/XpathInjection.ql b/javascript/ql/src/Security/CWE-643/XpathInjection.ql index 2d56505efff0..f6ba0d956c18 100644 --- a/javascript/ql/src/Security/CWE-643/XpathInjection.ql +++ b/javascript/ql/src/Security/CWE-643/XpathInjection.ql @@ -16,4 +16,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "$@ flows here and is used in an XPath expression.", source, "User-provided value" +select sink.getNode(), source, sink, "$@ flows here and is used in an XPath expression.", source, "User-provided value" diff --git a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql index 27e482596b12..f77eb395f1ed 100644 --- a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql +++ b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "This regular expression is constructed from a $@.", source, "user-provided value" +select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-776/XmlBomb.ql b/javascript/ql/src/Security/CWE-776/XmlBomb.ql index fcff0c764c49..39b653d5e835 100644 --- a/javascript/ql/src/Security/CWE-776/XmlBomb.ql +++ b/javascript/ql/src/Security/CWE-776/XmlBomb.ql @@ -17,5 +17,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "A $@ is parsed as XML without guarding against uncontrolled entity expansion.", +select sink.getNode(), source, sink, "A $@ is parsed as XML without guarding against uncontrolled entity expansion.", source, "user-provided value" diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql index c29fd9d1b601..b249550c8c7c 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -23,4 +23,4 @@ where cfg.hasPathFlow(source, sink) and value = "The hard-coded value \"" + source.getNode().asExpr().(ConstantString).getStringValue() + "\"" else value = "This hard-coded value" -select source.getNode(), value + " is used as $@.", sink, sink.getNode().(Sink).getKind() +select source.getNode(), source, sink, value + " is used as $@.", sink, sink.getNode().(Sink).getKind() diff --git a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql index 13ae16d52cb1..e642d91ebed5 100644 --- a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql +++ b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql @@ -112,6 +112,6 @@ predicate isEarlyAbortGuard(DataFlow::PathNode e, SensitiveAction action) { from DataFlow::PathNode source, DataFlow::PathNode sink, SensitiveAction action where isTaintedGuardForSensitiveAction(sink, source, action) and not isEarlyAbortGuard(sink, action) -select sink.getNode(), "This condition guards a sensitive $@, but $@ controls it.", +select sink.getNode(), source, sink, "This condition guards a sensitive $@, but $@ controls it.", action, "action", source, "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql index 3e9f6e018bd6..e58bfc905fc8 100644 --- a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql +++ b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql @@ -15,4 +15,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Potential type confusion for $@.", source, "HTTP request parameter" +select sink.getNode(), source, sink, "Potential type confusion for $@.", source, "HTTP request parameter" diff --git a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql index e4aff3fc8d60..ea2a464ae806 100644 --- a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql +++ b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql @@ -14,4 +14,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "$@ flows to file system", source, "Untrusted data" +select sink.getNode(), source, sink, "$@ flows to file system", source, "Untrusted data" diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql index ba729c28a73c..71ec7cf9b5e4 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql @@ -15,4 +15,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), "Password from $@ is hashed insecurely.", source , source.(Source).describe() +select sink.getNode(), source, sink, "Password from $@ is hashed insecurely.", source , source.(Source).describe() diff --git a/javascript/ql/src/Security/CWE-918/RequestForgery.ql b/javascript/ql/src/Security/CWE-918/RequestForgery.ql index 831fb6522926..c71ba0f81c4e 100644 --- a/javascript/ql/src/Security/CWE-918/RequestForgery.ql +++ b/javascript/ql/src/Security/CWE-918/RequestForgery.ql @@ -16,4 +16,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node request where cfg.hasPathFlow(source, sink) and request = sink.getNode().(Sink).getARequest() -select request, "The $@ of this request depends on $@.", sink, sink.getNode().(Sink).getKind(), source, "a user-provided value" +select request, source, sink, "The $@ of this request depends on $@.", sink, sink.getNode().(Sink).getKind(), source, "a user-provided value" From 52ae75727992aa44ae24abe58e609f0dd67b89be Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 15:01:45 +0000 Subject: [PATCH 36/68] JavaScript: Select `Node`s (instead of `PathNode`s) everywhere. --- javascript/ql/src/Security/CWE-022/TaintedPath.ql | 3 ++- javascript/ql/src/Security/CWE-078/CommandInjection.ql | 3 ++- javascript/ql/src/Security/CWE-079/ReflectedXss.ql | 2 +- javascript/ql/src/Security/CWE-079/StoredXss.ql | 2 +- javascript/ql/src/Security/CWE-079/Xss.ql | 2 +- javascript/ql/src/Security/CWE-089/SqlInjection.ql | 3 ++- javascript/ql/src/Security/CWE-094/CodeInjection.ql | 3 ++- javascript/ql/src/Security/CWE-134/TaintedFormatString.ql | 3 ++- javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql | 3 ++- javascript/ql/src/Security/CWE-209/StackTraceExposure.ql | 2 +- javascript/ql/src/Security/CWE-312/CleartextLogging.ql | 3 ++- javascript/ql/src/Security/CWE-312/CleartextStorage.ql | 3 ++- javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql | 5 +++-- javascript/ql/src/Security/CWE-338/InsecureRandomness.ql | 3 ++- .../Security/CWE-346/CorsMisconfigurationForCredentials.ql | 4 ++-- .../ql/src/Security/CWE-400/RemotePropertyInjection.ql | 4 ++-- javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql | 3 ++- javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql | 3 ++- javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql | 3 ++- javascript/ql/src/Security/CWE-611/Xxe.ql | 2 +- .../Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql | 3 ++- javascript/ql/src/Security/CWE-643/XpathInjection.ql | 3 ++- javascript/ql/src/Security/CWE-730/RegExpInjection.ql | 3 ++- javascript/ql/src/Security/CWE-776/XmlBomb.ql | 2 +- javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql | 3 ++- javascript/ql/src/Security/CWE-807/ConditionalBypass.ql | 2 +- .../CWE-843/TypeConfusionThroughParameterTampering.ql | 3 ++- javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql | 2 +- .../ql/src/Security/CWE-916/InsufficientPasswordHash.ql | 3 ++- javascript/ql/src/Security/CWE-918/RequestForgery.ql | 3 ++- 30 files changed, 53 insertions(+), 33 deletions(-) diff --git a/javascript/ql/src/Security/CWE-022/TaintedPath.ql b/javascript/ql/src/Security/CWE-022/TaintedPath.ql index e1c44d535593..8a3e70752168 100644 --- a/javascript/ql/src/Security/CWE-022/TaintedPath.ql +++ b/javascript/ql/src/Security/CWE-022/TaintedPath.ql @@ -20,4 +20,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "This path depends on $@.", source, "a user-provided value" +select sink.getNode(), source, sink, "This path depends on $@.", + source.getNode(), "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-078/CommandInjection.ql b/javascript/ql/src/Security/CWE-078/CommandInjection.ql index bef7c596dff1..317c407003cd 100644 --- a/javascript/ql/src/Security/CWE-078/CommandInjection.ql +++ b/javascript/ql/src/Security/CWE-078/CommandInjection.ql @@ -22,4 +22,5 @@ where cfg.hasPathFlow(source, sink) and cfg.isSinkWithHighlight(sink.getNode(), highlight) else highlight = sink.getNode() -select highlight, source, sink, "This command depends on $@.", source, "a user-provided value" +select highlight, source, sink, "This command depends on $@.", + source.getNode(), "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql index a6f3a97e6169..5b308800209f 100644 --- a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", - source, "user-provided value" + source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-079/StoredXss.ql b/javascript/ql/src/Security/CWE-079/StoredXss.ql index 84e2c433fc11..f1e386c291b9 100644 --- a/javascript/ql/src/Security/CWE-079/StoredXss.ql +++ b/javascript/ql/src/Security/CWE-079/StoredXss.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) select sink.getNode(), source, sink, "Stored cross-site scripting vulnerability due to $@.", - source, "stored value" + source.getNode(), "stored value" diff --git a/javascript/ql/src/Security/CWE-079/Xss.ql b/javascript/ql/src/Security/CWE-079/Xss.ql index bed5436b0b53..b6ba13918cb6 100644 --- a/javascript/ql/src/Security/CWE-079/Xss.ql +++ b/javascript/ql/src/Security/CWE-079/Xss.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) select sink.getNode(), source, sink, sink.getNode().(Sink).getVulnerabilityKind() + " vulnerability due to $@.", - source, "user-provided value" + source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/Security/CWE-089/SqlInjection.ql index 7da69c8174ed..6ae6d0927233 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.ql @@ -19,4 +19,5 @@ from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode where (cfg instanceof SqlInjection::Configuration or cfg instanceof NosqlInjection::Configuration) and cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "This query depends on $@.", source, "a user-provided value" +select sink.getNode(), source, sink, "This query depends on $@.", + source.getNode(), "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-094/CodeInjection.ql b/javascript/ql/src/Security/CWE-094/CodeInjection.ql index 62e1ee05c77f..506e206bc0aa 100644 --- a/javascript/ql/src/Security/CWE-094/CodeInjection.ql +++ b/javascript/ql/src/Security/CWE-094/CodeInjection.ql @@ -18,4 +18,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "$@ flows to here and is interpreted as code.", source, "User-provided value" +select sink.getNode(), source, sink, "$@ flows to here and is interpreted as code.", + source.getNode(), "User-provided value" diff --git a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql index 0a277ccbb62e..78ab720d2359 100644 --- a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql +++ b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql @@ -15,4 +15,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "$@ flows here and is used in a format string.", source, "User-provided value" +select sink.getNode(), source, sink, "$@ flows here and is used in a format string.", + source.getNode(), "User-provided value" diff --git a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql index 836674f6e33a..22b254a8bd6a 100644 --- a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql +++ b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql @@ -14,4 +14,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "$@ flows directly to outbound network request", source, "File data" +select sink.getNode(), source, sink, "$@ flows directly to outbound network request", + source.getNode(), "File data" diff --git a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql index fac7de89b3d1..d67d9f643ab5 100644 --- a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql +++ b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) select sink.getNode(), source, sink, "Stack trace information from $@ may be exposed to an external user here.", - source, "here" + source.getNode(), "here" diff --git a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql index 556159065842..34a4f5414cfb 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql @@ -36,4 +36,5 @@ from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) and // ignore logging to the browser console (even though it is not a good practice) not inBrowserEnvironment(sink.getNode().asExpr().getTopLevel()) -select sink.getNode(), source, sink, "Sensitive data returned by $@ is logged here.", source, source.getNode().(Source).describe() +select sink.getNode(), source, sink, "Sensitive data returned by $@ is logged here.", + source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql index 060cf8abe951..b87b266ed36d 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql @@ -18,4 +18,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "Sensitive data returned by $@ is stored here.", source, source.getNode().(Source).describe() +select sink.getNode(), source, sink, "Sensitive data returned by $@ is stored here.", + source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index 619a170a28e4..533c81090183 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -16,5 +16,6 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) and - not source.asExpr() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash -select sink.getNode(), source, sink, "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source , source.(Source).describe() + not source.getNode().asExpr() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash +select sink.getNode(), source, sink, "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", + source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql index 03383b1cf205..3b9df3020088 100644 --- a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql +++ b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql @@ -16,4 +16,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "Cryptographically insecure $@ in a security context.", source, "random value" +select sink.getNode(), source, sink, "Cryptographically insecure $@ in a security context.", + source.getNode(), "random value" diff --git a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql index 64910083d863..44c478ea1c57 100644 --- a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql +++ b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql @@ -18,5 +18,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) select sink.getNode(), source, sink, "$@ leak vulnerability due to $@.", - sink.(Sink).getCredentialsHeader(), "Credential", - source, "a misconfigured CORS header value" + sink.getNode().(Sink).getCredentialsHeader(), "Credential", + source.getNode(), "a misconfigured CORS header value" diff --git a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql index c69b4427f3af..b9af490ffb67 100644 --- a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql +++ b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql @@ -18,5 +18,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "A $@ is used as" + sink.(Sink).getMessage(), - source, "user-provided value" +select sink.getNode(), source, sink, "A $@ is used as" + sink.getNode().(Sink).getMessage(), + source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql index 964e3bda6e19..107868857bd7 100644 --- a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql +++ b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql @@ -16,4 +16,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "Unsafe deserialization of $@.", source, "user input" +select sink.getNode(), source, sink, "Unsafe deserialization of $@.", + source.getNode(), "user input" diff --git a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql index cda39882544d..8080784e8943 100644 --- a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql @@ -18,4 +18,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source, "user-provided value" +select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", + source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql index da3c412e59ba..62d2671c8ea7 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql @@ -16,4 +16,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source, "user-provided value" +select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", + source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-611/Xxe.ql b/javascript/ql/src/Security/CWE-611/Xxe.ql index db0bca561cab..914f1e4a7268 100644 --- a/javascript/ql/src/Security/CWE-611/Xxe.ql +++ b/javascript/ql/src/Security/CWE-611/Xxe.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) select sink.getNode(), source, sink, "A $@ is parsed as XML without guarding against external entity expansion.", - source, "user-provided value" + source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql index 0d0db8cdbde8..c12f0e736f53 100644 --- a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql +++ b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql @@ -16,4 +16,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "Links in this email can be hijacked by poisoning the HTTP host header $@.", source, "here" +select sink.getNode(), source, sink, "Links in this email can be hijacked by poisoning the HTTP host header $@.", + source.getNode(), "here" diff --git a/javascript/ql/src/Security/CWE-643/XpathInjection.ql b/javascript/ql/src/Security/CWE-643/XpathInjection.ql index f6ba0d956c18..f212e4a7a1a6 100644 --- a/javascript/ql/src/Security/CWE-643/XpathInjection.ql +++ b/javascript/ql/src/Security/CWE-643/XpathInjection.ql @@ -16,4 +16,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "$@ flows here and is used in an XPath expression.", source, "User-provided value" +select sink.getNode(), source, sink, "$@ flows here and is used in an XPath expression.", + source.getNode(), "User-provided value" diff --git a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql index f77eb395f1ed..3053a64f53fb 100644 --- a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql +++ b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql @@ -18,4 +18,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", source, "user-provided value" +select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", + source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-776/XmlBomb.ql b/javascript/ql/src/Security/CWE-776/XmlBomb.ql index 39b653d5e835..733fe7fe4144 100644 --- a/javascript/ql/src/Security/CWE-776/XmlBomb.ql +++ b/javascript/ql/src/Security/CWE-776/XmlBomb.ql @@ -18,4 +18,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) select sink.getNode(), source, sink, "A $@ is parsed as XML without guarding against uncontrolled entity expansion.", - source, "user-provided value" + source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql index b249550c8c7c..b172e28edb93 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -23,4 +23,5 @@ where cfg.hasPathFlow(source, sink) and value = "The hard-coded value \"" + source.getNode().asExpr().(ConstantString).getStringValue() + "\"" else value = "This hard-coded value" -select source.getNode(), source, sink, value + " is used as $@.", sink, sink.getNode().(Sink).getKind() +select source.getNode(), source, sink, value + " is used as $@.", + sink.getNode(), sink.getNode().(Sink).getKind() diff --git a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql index e642d91ebed5..f31549d259c1 100644 --- a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql +++ b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql @@ -114,4 +114,4 @@ where isTaintedGuardForSensitiveAction(sink, source, action) and not isEarlyAbortGuard(sink, action) select sink.getNode(), source, sink, "This condition guards a sensitive $@, but $@ controls it.", action, "action", - source, "a user-provided value" + source.getNode(), "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql index e58bfc905fc8..d0499905a93a 100644 --- a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql +++ b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql @@ -15,4 +15,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "Potential type confusion for $@.", source, "HTTP request parameter" +select sink.getNode(), source, sink, "Potential type confusion for $@.", + source.getNode(), "HTTP request parameter" diff --git a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql index ea2a464ae806..3f913ea45302 100644 --- a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql +++ b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql @@ -14,4 +14,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "$@ flows to file system", source, "Untrusted data" +select sink.getNode(), source, sink, "$@ flows to file system", source.getNode(), "Untrusted data" diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql index 71ec7cf9b5e4..37d0bb8c8c2c 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql @@ -15,4 +15,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasPathFlow(source, sink) -select sink.getNode(), source, sink, "Password from $@ is hashed insecurely.", source , source.(Source).describe() +select sink.getNode(), source, sink, "Password from $@ is hashed insecurely.", + source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-918/RequestForgery.ql b/javascript/ql/src/Security/CWE-918/RequestForgery.ql index c71ba0f81c4e..24039a70a1a6 100644 --- a/javascript/ql/src/Security/CWE-918/RequestForgery.ql +++ b/javascript/ql/src/Security/CWE-918/RequestForgery.ql @@ -16,4 +16,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node request where cfg.hasPathFlow(source, sink) and request = sink.getNode().(Sink).getARequest() -select request, source, sink, "The $@ of this request depends on $@.", sink, sink.getNode().(Sink).getKind(), source, "a user-provided value" +select request, source, sink, "The $@ of this request depends on $@.", + sink.getNode(), sink.getNode().(Sink).getKind(), source, "a user-provided value" From d57b5d96286ad577a04933dddefc5aaebcb1d522 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 13:18:49 +0000 Subject: [PATCH 37/68] JavaScript: Remove `ReflectdXssPath.ql`, which is now spurious. --- .../CWE-079/ReflectedXssPath.expected | 47 ------------------- .../Security/CWE-079/ReflectedXssPath.ql | 21 --------- 2 files changed, 68 deletions(-) delete mode 100644 javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssPath.expected delete mode 100644 javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssPath.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssPath.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssPath.expected deleted file mode 100644 index 28682d23433a..000000000000 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssPath.expected +++ /dev/null @@ -1,47 +0,0 @@ -edges -| ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | -| etherpad.js:9:5:9:53 | response | etherpad.js:11:3:11:3 | response | -| etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:36 | req.que ... p + "(" | -| etherpad.js:9:16:9:36 | req.que ... p + "(" | etherpad.js:9:16:9:47 | req.que ... esponse | -| etherpad.js:9:16:9:47 | req.que ... esponse | etherpad.js:9:16:9:53 | req.que ... e + ")" | -| etherpad.js:9:16:9:53 | req.que ... e + ")" | etherpad.js:9:5:9:53 | response | -| etherpad.js:11:3:11:3 | response | etherpad.js:11:12:11:19 | response | -| formatting.js:4:9:4:29 | evil | formatting.js:6:43:6:46 | evil | -| formatting.js:4:9:4:29 | evil | formatting.js:7:49:7:52 | evil | -| formatting.js:4:16:4:29 | req.query.evil | formatting.js:4:9:4:29 | evil | -| formatting.js:6:43:6:46 | evil | formatting.js:6:14:6:47 | util.fo ... , evil) | -| formatting.js:7:49:7:52 | evil | formatting.js:7:14:7:53 | require ... , evil) | -| partial.js:9:25:9:25 | x | partial.js:10:14:10:14 | x | -| partial.js:10:14:10:14 | x | partial.js:10:14:10:18 | x + y | -| partial.js:13:42:13:48 | req.url | partial.js:9:25:9:25 | x | -| partial.js:18:25:18:25 | x | partial.js:19:14:19:14 | x | -| partial.js:19:14:19:14 | x | partial.js:19:14:19:18 | x + y | -| partial.js:22:51:22:57 | req.url | partial.js:18:25:18:25 | x | -| partial.js:27:25:27:25 | x | partial.js:28:14:28:14 | x | -| partial.js:28:14:28:14 | x | partial.js:28:14:28:18 | x + y | -| partial.js:31:47:31:53 | req.url | partial.js:27:25:27:25 | x | -| partial.js:36:25:36:25 | x | partial.js:37:14:37:14 | x | -| partial.js:37:14:37:14 | x | partial.js:37:14:37:18 | x + y | -| partial.js:40:43:40:49 | req.url | partial.js:36:25:36:25 | x | -| promises.js:5:3:5:59 | new Pro ... .data)) | promises.js:6:11:6:11 | x | -| promises.js:5:44:5:57 | req.query.data | promises.js:5:3:5:59 | new Pro ... .data)) | -| promises.js:5:44:5:57 | req.query.data | promises.js:6:11:6:11 | x | -| promises.js:6:11:6:11 | x | promises.js:6:25:6:25 | x | -| promises.js:6:11:6:11 | x | promises.js:6:25:6:25 | x | -| tst2.js:6:7:6:30 | p | tst2.js:7:12:7:12 | p | -| tst2.js:6:7:6:30 | r | tst2.js:8:12:8:12 | r | -| tst2.js:6:9:6:9 | p | tst2.js:6:7:6:30 | p | -| tst2.js:6:12:6:15 | q: r | tst2.js:6:7:6:30 | r | -#select -| ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value | -| etherpad.js:11:12:11:19 | response | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value | -| formatting.js:6:14:6:47 | util.fo ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | -| formatting.js:7:14:7:53 | require ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | -| partial.js:10:14:10:18 | x + y | partial.js:13:42:13:48 | req.url | partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value | -| partial.js:19:14:19:18 | x + y | partial.js:22:51:22:57 | req.url | partial.js:19:14:19:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:22:51:22:57 | req.url | user-provided value | -| partial.js:28:14:28:18 | x + y | partial.js:31:47:31:53 | req.url | partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:31:47:31:53 | req.url | user-provided value | -| partial.js:37:14:37:18 | x + y | partial.js:40:43:40:49 | req.url | partial.js:37:14:37:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:40:43:40:49 | req.url | user-provided value | -| promises.js:6:25:6:25 | x | promises.js:5:44:5:57 | req.query.data | promises.js:6:25:6:25 | x | Cross-site scripting vulnerability due to $@. | promises.js:5:44:5:57 | req.query.data | user-provided value | -| promises.js:6:25:6:25 | x | promises.js:5:44:5:57 | req.query.data | promises.js:6:25:6:25 | x | Cross-site scripting vulnerability due to $@. | promises.js:5:44:5:57 | req.query.data | user-provided value | -| tst2.js:7:12:7:12 | p | tst2.js:6:9:6:9 | p | tst2.js:7:12:7:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:6:9:6:9 | p | user-provided value | -| tst2.js:8:12:8:12 | r | tst2.js:6:12:6:15 | q: r | tst2.js:8:12:8:12 | r | Cross-site scripting vulnerability due to $@. | tst2.js:6:12:6:15 | q: r | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssPath.ql b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssPath.ql deleted file mode 100644 index 2c5cbad56d7f..000000000000 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssPath.ql +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @name Reflected cross-site scripting - * @description Writing user input directly to an HTTP response allows for - * a cross-site scripting vulnerability. - * @kind path-problem - * @problem.severity error - * @precision high - * @id js/reflected-xss-path - * @tags security - * external/cwe/cwe-079 - * external/cwe/cwe-116 - */ - -import javascript -import semmle.javascript.security.dataflow.ReflectedXss -import DataFlow::PathGraph - -from DataFlow::PathNode source, DataFlow::PathNode sink, ReflectedXss::Configuration cfg -where cfg.hasPathFlow(source, sink) -select sink, source, sink, "Cross-site scripting vulnerability due to $@.", - source, "user-provided value" From 9221b62ded66bda1e7528d64f23e69192fcaab09 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 8 Nov 2018 15:03:11 +0000 Subject: [PATCH 38/68] JavaScript: Update expectd test output for security path queries to include `nodes` and `edges` query predicates. --- .../Security/CWE-022/TaintedPath.expected | 220 ++++++++-- .../CWE-078/CommandInjection.expected | 87 +++- .../Security/CWE-079/ReflectedXss.expected | 102 ++++- .../Security/CWE-079/StoredXss.expected | 399 ++++++++++++++++- .../query-tests/Security/CWE-079/Xss.expected | 411 +++++++++++++++--- .../Security/CWE-089/SqlInjection.expected | 182 +++++++- .../Security/CWE-094/CodeInjection.expected | 109 +++-- .../CWE-134/TaintedFormatString.expected | 63 ++- .../CWE-200/FileAccessToHttp.expected | 118 ++++- .../CWE-209/StackTraceExposure.expected | 25 +- .../CWE-312/CleartextLogging.expected | 146 +++++-- .../CWE-312/CleartextStorage.expected | 43 +- .../CWE-327/BrokenCryptoAlgorithm.expected | 16 +- .../CWE-338/InsecureRandomness.expected | 89 +++- ...orsMisconfigurationForCredentials.expected | 22 +- .../CWE-400/RemotePropertyInjection.expected | 35 +- .../CWE-502/UnsafeDeserialization.expected | 15 +- .../ClientSideUrlRedirect.expected | 70 ++- .../ServerSideUrlRedirect.expected | 121 +++++- .../query-tests/Security/CWE-611/Xxe.expected | 25 +- ...tHeaderPoisoningInEmailGeneration.expected | 13 +- .../Security/CWE-643/XpathInjection.expected | 46 +- .../Security/CWE-730/RegExpInjection.expected | 95 +++- .../Security/CWE-776/XmlBomb.expected | 53 ++- .../CWE-798/HardcodedCredentials.expected | 158 ++++--- .../CWE-807/ConditionalBypass.expected | 65 ++- ...onfusionThroughParameterTampering.expected | 58 ++- .../CWE-912/HttpToFileAccess.expected | 18 +- .../CWE-916/InsufficientPasswordHash.expected | 12 +- .../Security/CWE-918/RequestForgery.expected | 42 +- 30 files changed, 2450 insertions(+), 408 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath.expected index 418873e5c6f0..7a73a250542c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath.expected @@ -1,29 +1,191 @@ -| TaintedPath-es6.js:10:26:10:45 | join("public", path) | This path depends on $@. | TaintedPath-es6.js:7:20:7:26 | req.url | a user-provided value | -| TaintedPath.js:12:29:12:32 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:15:29:15:48 | "/home/user/" + path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:19:33:19:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:23:33:23:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:27:33:27:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:39:31:39:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:47:29:47:53 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:51:29:51:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:59:29:59:56 | pathMod ... , path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:78:26:78:40 | document.cookie | This path depends on $@. | TaintedPath.js:78:26:78:40 | document.cookie | a user-provided value | -| TaintedPath.js:84:31:84:76 | require ... ).query | This path depends on $@. | TaintedPath.js:84:63:84:69 | req.url | a user-provided value | -| TaintedPath.js:85:31:85:74 | require ... ).query | This path depends on $@. | TaintedPath.js:85:61:85:67 | req.url | a user-provided value | -| TaintedPath.js:86:31:86:73 | require ... ).query | This path depends on $@. | TaintedPath.js:86:60:86:66 | req.url | a user-provided value | -| TaintedPath.js:94:48:94:60 | req.params[0] | This path depends on $@. | TaintedPath.js:94:48:94:60 | req.params[0] | a user-provided value | -| tainted-array-steps.js:11:29:11:54 | ['publi ... in('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value | -| tainted-array-steps.js:15:29:15:43 | parts.join('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value | -| tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | -| tainted-sendFile.js:7:16:7:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:7:16:7:33 | req.param("gimme") | a user-provided value | -| tainted-sendFile.js:9:16:9:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:9:16:9:33 | req.param("gimme") | a user-provided value | -| views.js:1:43:1:55 | req.params[0] | This path depends on $@. | views.js:1:43:1:55 | req.params[0] | a user-provided value | +nodes +| TaintedPath-es6.js:7:7:7:44 | path | +| TaintedPath-es6.js:7:14:7:33 | parse(req.url, true) | +| TaintedPath-es6.js:7:14:7:39 | parse(r ... ).query | +| TaintedPath-es6.js:7:14:7:44 | parse(r ... ry.path | +| TaintedPath-es6.js:7:20:7:26 | req.url | +| TaintedPath-es6.js:10:26:10:45 | join("public", path) | +| TaintedPath-es6.js:10:41:10:44 | path | +| TaintedPath.js:9:7:9:48 | path | +| TaintedPath.js:9:14:9:37 | url.par ... , true) | +| TaintedPath.js:9:14:9:43 | url.par ... ).query | +| TaintedPath.js:9:14:9:48 | url.par ... ry.path | +| TaintedPath.js:9:24:9:30 | req.url | +| TaintedPath.js:12:29:12:32 | path | +| TaintedPath.js:15:29:15:48 | "/home/user/" + path | +| TaintedPath.js:15:45:15:48 | path | +| TaintedPath.js:19:33:19:36 | path | +| TaintedPath.js:23:33:23:36 | path | +| TaintedPath.js:27:33:27:36 | path | +| TaintedPath.js:30:7:30:24 | path | +| TaintedPath.js:34:3:34:3 | path | +| TaintedPath.js:34:7:34:24 | path | +| TaintedPath.js:34:29:34:46 | path | +| TaintedPath.js:38:3:38:3 | path | +| TaintedPath.js:38:7:38:24 | path | +| TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:39:31:39:34 | path | +| TaintedPath.js:45:3:45:44 | path | +| TaintedPath.js:45:10:45:33 | url.par ... , true) | +| TaintedPath.js:45:10:45:39 | url.par ... ).query | +| TaintedPath.js:45:10:45:44 | url.par ... ry.path | +| TaintedPath.js:45:20:45:26 | req.url | +| TaintedPath.js:47:29:47:53 | pathMod ... e(path) | +| TaintedPath.js:47:49:47:52 | path | +| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | +| TaintedPath.js:49:48:49:51 | path | +| TaintedPath.js:51:29:51:52 | pathMod ... e(path) | +| TaintedPath.js:51:48:51:51 | path | +| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | +| TaintedPath.js:53:45:53:48 | path | +| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | +| TaintedPath.js:55:51:55:54 | path | +| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | +| TaintedPath.js:57:50:57:53 | path | +| TaintedPath.js:59:29:59:56 | pathMod ... , path) | +| TaintedPath.js:59:52:59:55 | path | +| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | +| TaintedPath.js:61:49:61:52 | path | +| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | +| TaintedPath.js:63:48:63:51 | path | +| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | +| TaintedPath.js:65:54:65:57 | path | +| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | +| TaintedPath.js:67:57:67:60 | path | +| TaintedPath.js:78:26:78:40 | document.cookie | +| TaintedPath.js:84:31:84:70 | require ... eq.url) | +| TaintedPath.js:84:31:84:76 | require ... ).query | +| TaintedPath.js:84:63:84:69 | req.url | +| TaintedPath.js:85:31:85:68 | require ... eq.url) | +| TaintedPath.js:85:31:85:74 | require ... ).query | +| TaintedPath.js:85:61:85:67 | req.url | +| TaintedPath.js:86:31:86:67 | require ... eq.url) | +| TaintedPath.js:86:31:86:73 | require ... ).query | +| TaintedPath.js:86:60:86:66 | req.url | +| TaintedPath.js:94:48:94:60 | req.params[0] | +| tainted-array-steps.js:9:7:9:48 | path | +| tainted-array-steps.js:9:14:9:37 | url.par ... , true) | +| tainted-array-steps.js:9:14:9:43 | url.par ... ).query | +| tainted-array-steps.js:9:14:9:48 | url.par ... ry.path | +| tainted-array-steps.js:9:24:9:30 | req.url | +| tainted-array-steps.js:11:29:11:44 | ['public', path] | +| tainted-array-steps.js:11:29:11:54 | ['publi ... in('/') | +| tainted-array-steps.js:11:40:11:43 | path | +| tainted-array-steps.js:13:15:13:30 | ['public', path] | +| tainted-array-steps.js:13:26:13:29 | path | +| tainted-array-steps.js:14:3:14:41 | parts | +| tainted-array-steps.js:14:11:14:41 | parts.m ... Case()) | +| tainted-array-steps.js:14:21:14:21 | x | +| tainted-array-steps.js:14:26:14:26 | x | +| tainted-array-steps.js:14:26:14:40 | x.toLowerCase() | +| tainted-array-steps.js:15:29:15:33 | parts | +| tainted-array-steps.js:15:29:15:43 | parts.join('/') | +| tainted-require.js:7:19:7:37 | req.param("module") | +| tainted-sendFile.js:7:16:7:33 | req.param("gimme") | +| tainted-sendFile.js:9:16:9:33 | req.param("gimme") | +| views.js:1:43:1:55 | req.params[0] | +edges +| TaintedPath-es6.js:7:7:7:44 | path | TaintedPath-es6.js:10:41:10:44 | path | +| TaintedPath-es6.js:7:14:7:33 | parse(req.url, true) | TaintedPath-es6.js:7:14:7:39 | parse(r ... ).query | +| TaintedPath-es6.js:7:14:7:39 | parse(r ... ).query | TaintedPath-es6.js:7:14:7:44 | parse(r ... ry.path | +| TaintedPath-es6.js:7:14:7:44 | parse(r ... ry.path | TaintedPath-es6.js:7:7:7:44 | path | +| TaintedPath-es6.js:7:20:7:26 | req.url | TaintedPath-es6.js:7:14:7:33 | parse(req.url, true) | +| TaintedPath-es6.js:10:41:10:44 | path | TaintedPath-es6.js:10:26:10:45 | join("public", path) | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:12:29:12:32 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:15:45:15:48 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:7:30:24 | path | +| TaintedPath.js:9:14:9:37 | url.par ... , true) | TaintedPath.js:9:14:9:43 | url.par ... ).query | +| TaintedPath.js:9:14:9:43 | url.par ... ).query | TaintedPath.js:9:14:9:48 | url.par ... ry.path | +| TaintedPath.js:9:14:9:48 | url.par ... ry.path | TaintedPath.js:9:7:9:48 | path | +| TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:9:14:9:37 | url.par ... , true) | +| TaintedPath.js:15:45:15:48 | path | TaintedPath.js:15:29:15:48 | "/home/user/" + path | +| TaintedPath.js:30:7:30:24 | path | TaintedPath.js:34:3:34:3 | path | +| TaintedPath.js:34:3:34:3 | path | TaintedPath.js:34:7:34:24 | path | +| TaintedPath.js:34:7:34:24 | path | TaintedPath.js:34:29:34:46 | path | +| TaintedPath.js:34:29:34:46 | path | TaintedPath.js:38:3:38:3 | path | +| TaintedPath.js:38:3:38:3 | path | TaintedPath.js:38:7:38:24 | path | +| TaintedPath.js:38:7:38:24 | path | TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:38:29:38:46 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:39:5:39:5 | path | TaintedPath.js:39:31:39:34 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:47:49:47:52 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:51:48:51:51 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | +| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | +| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | +| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | +| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | +| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | +| TaintedPath.js:47:49:47:52 | path | TaintedPath.js:47:29:47:53 | pathMod ... e(path) | +| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | +| TaintedPath.js:51:48:51:51 | path | TaintedPath.js:51:29:51:52 | pathMod ... e(path) | +| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | +| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | +| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | +| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | +| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | +| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | +| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | +| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | +| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | +| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | +| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | +| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | +| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | +| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | +| tainted-array-steps.js:9:7:9:48 | path | tainted-array-steps.js:11:40:11:43 | path | +| tainted-array-steps.js:9:7:9:48 | path | tainted-array-steps.js:13:26:13:29 | path | +| tainted-array-steps.js:9:14:9:37 | url.par ... , true) | tainted-array-steps.js:9:14:9:43 | url.par ... ).query | +| tainted-array-steps.js:9:14:9:43 | url.par ... ).query | tainted-array-steps.js:9:14:9:48 | url.par ... ry.path | +| tainted-array-steps.js:9:14:9:48 | url.par ... ry.path | tainted-array-steps.js:9:7:9:48 | path | +| tainted-array-steps.js:9:24:9:30 | req.url | tainted-array-steps.js:9:14:9:37 | url.par ... , true) | +| tainted-array-steps.js:11:29:11:44 | ['public', path] | tainted-array-steps.js:11:29:11:54 | ['publi ... in('/') | +| tainted-array-steps.js:11:40:11:43 | path | tainted-array-steps.js:11:29:11:44 | ['public', path] | +| tainted-array-steps.js:13:15:13:30 | ['public', path] | tainted-array-steps.js:14:21:14:21 | x | +| tainted-array-steps.js:13:26:13:29 | path | tainted-array-steps.js:13:15:13:30 | ['public', path] | +| tainted-array-steps.js:14:3:14:41 | parts | tainted-array-steps.js:15:29:15:33 | parts | +| tainted-array-steps.js:14:11:14:41 | parts.m ... Case()) | tainted-array-steps.js:14:3:14:41 | parts | +| tainted-array-steps.js:14:21:14:21 | x | tainted-array-steps.js:14:26:14:26 | x | +| tainted-array-steps.js:14:26:14:26 | x | tainted-array-steps.js:14:26:14:40 | x.toLowerCase() | +| tainted-array-steps.js:14:26:14:40 | x.toLowerCase() | tainted-array-steps.js:14:11:14:41 | parts.m ... Case()) | +| tainted-array-steps.js:15:29:15:33 | parts | tainted-array-steps.js:15:29:15:43 | parts.join('/') | +#select +| TaintedPath-es6.js:10:26:10:45 | join("public", path) | TaintedPath-es6.js:7:20:7:26 | req.url | TaintedPath-es6.js:10:26:10:45 | join("public", path) | This path depends on $@. | TaintedPath-es6.js:7:20:7:26 | req.url | a user-provided value | +| TaintedPath.js:12:29:12:32 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:12:29:12:32 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:15:29:15:48 | "/home/user/" + path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:15:29:15:48 | "/home/user/" + path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:19:33:19:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:19:33:19:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:23:33:23:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:23:33:23:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:27:33:27:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:27:33:27:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:39:31:39:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:39:31:39:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:47:29:47:53 | pathMod ... e(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:47:29:47:53 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:51:29:51:52 | pathMod ... e(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:51:29:51:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:59:29:59:56 | pathMod ... , path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:59:29:59:56 | pathMod ... , path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | +| TaintedPath.js:78:26:78:40 | document.cookie | TaintedPath.js:78:26:78:40 | document.cookie | TaintedPath.js:78:26:78:40 | document.cookie | This path depends on $@. | TaintedPath.js:78:26:78:40 | document.cookie | a user-provided value | +| TaintedPath.js:84:31:84:76 | require ... ).query | TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:76 | require ... ).query | This path depends on $@. | TaintedPath.js:84:63:84:69 | req.url | a user-provided value | +| TaintedPath.js:85:31:85:74 | require ... ).query | TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:74 | require ... ).query | This path depends on $@. | TaintedPath.js:85:61:85:67 | req.url | a user-provided value | +| TaintedPath.js:86:31:86:73 | require ... ).query | TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:73 | require ... ).query | This path depends on $@. | TaintedPath.js:86:60:86:66 | req.url | a user-provided value | +| TaintedPath.js:94:48:94:60 | req.params[0] | TaintedPath.js:94:48:94:60 | req.params[0] | TaintedPath.js:94:48:94:60 | req.params[0] | This path depends on $@. | TaintedPath.js:94:48:94:60 | req.params[0] | a user-provided value | +| tainted-array-steps.js:11:29:11:54 | ['publi ... in('/') | tainted-array-steps.js:9:24:9:30 | req.url | tainted-array-steps.js:11:29:11:54 | ['publi ... in('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value | +| tainted-array-steps.js:15:29:15:43 | parts.join('/') | tainted-array-steps.js:9:24:9:30 | req.url | tainted-array-steps.js:15:29:15:43 | parts.join('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value | +| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | +| tainted-sendFile.js:7:16:7:33 | req.param("gimme") | tainted-sendFile.js:7:16:7:33 | req.param("gimme") | tainted-sendFile.js:7:16:7:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:7:16:7:33 | req.param("gimme") | a user-provided value | +| tainted-sendFile.js:9:16:9:33 | req.param("gimme") | tainted-sendFile.js:9:16:9:33 | req.param("gimme") | tainted-sendFile.js:9:16:9:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:9:16:9:33 | req.param("gimme") | a user-provided value | +| views.js:1:43:1:55 | req.params[0] | views.js:1:43:1:55 | req.params[0] | views.js:1:43:1:55 | req.params[0] | This path depends on $@. | views.js:1:43:1:55 | req.params[0] | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 39a2e7d2ff26..135a30057b3a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -1,11 +1,76 @@ -| child_process-test.js:17:13:17:15 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:18:17:18:19 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:19:17:19:19 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:20:21:20:23 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:21:14:21:16 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:22:18:22:20 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:23:13:23:15 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:39:5:39:31 | cp.spaw ... cmd ]) | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:44:5:44:34 | cp.exec ... , args) | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | -| child_process-test.js:50:3:50:21 | cp.spawn(cmd, args) | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +nodes +| child_process-test.js:6:9:6:49 | cmd | +| child_process-test.js:6:15:6:38 | url.par ... , true) | +| child_process-test.js:6:15:6:44 | url.par ... ).query | +| child_process-test.js:6:15:6:49 | url.par ... ry.path | +| child_process-test.js:6:25:6:31 | req.url | +| child_process-test.js:17:13:17:15 | cmd | +| child_process-test.js:18:17:18:19 | cmd | +| child_process-test.js:19:17:19:19 | cmd | +| child_process-test.js:20:21:20:23 | cmd | +| child_process-test.js:21:14:21:16 | cmd | +| child_process-test.js:22:18:22:20 | cmd | +| child_process-test.js:23:13:23:15 | cmd | +| child_process-test.js:25:13:25:23 | "foo" + cmd | +| child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | +| child_process-test.js:25:21:25:23 | cmd | +| child_process-test.js:36:7:36:20 | sh | +| child_process-test.js:36:12:36:20 | 'cmd.exe' | +| child_process-test.js:38:7:38:20 | sh | +| child_process-test.js:38:12:38:20 | '/bin/sh' | +| child_process-test.js:39:5:39:5 | sh | +| child_process-test.js:39:14:39:15 | sh | +| child_process-test.js:39:18:39:30 | [ flag, cmd ] | +| child_process-test.js:39:26:39:28 | cmd | +| child_process-test.js:41:9:41:17 | args | +| child_process-test.js:41:16:41:17 | [] | +| child_process-test.js:43:15:43:17 | cmd | +| child_process-test.js:44:17:44:27 | "/bin/bash" | +| child_process-test.js:44:30:44:33 | args | +| child_process-test.js:46:9:46:12 | "sh" | +| child_process-test.js:46:15:46:18 | args | +| child_process-test.js:49:14:49:16 | cmd | +| child_process-test.js:49:19:49:22 | args | +| child_process-test.js:50:12:50:14 | cmd | +| child_process-test.js:50:17:50:20 | args | +edges +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:17:13:17:15 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:18:17:18:19 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:19:17:19:19 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:20:21:20:23 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:21:14:21:16 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:22:18:22:20 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:23:13:23:15 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:25:21:25:23 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:39:26:39:28 | cmd | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:43:15:43:17 | cmd | +| child_process-test.js:6:15:6:38 | url.par ... , true) | child_process-test.js:6:15:6:44 | url.par ... ).query | +| child_process-test.js:6:15:6:44 | url.par ... ).query | child_process-test.js:6:15:6:49 | url.par ... ry.path | +| child_process-test.js:6:15:6:49 | url.par ... ry.path | child_process-test.js:6:9:6:49 | cmd | +| child_process-test.js:6:25:6:31 | req.url | child_process-test.js:6:15:6:38 | url.par ... , true) | +| child_process-test.js:25:13:25:23 | "foo" + cmd | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | +| child_process-test.js:25:21:25:23 | cmd | child_process-test.js:25:13:25:23 | "foo" + cmd | +| child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:5:39:5 | sh | +| child_process-test.js:36:12:36:20 | 'cmd.exe' | child_process-test.js:36:7:36:20 | sh | +| child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:5:39:5 | sh | +| child_process-test.js:38:12:38:20 | '/bin/sh' | child_process-test.js:38:7:38:20 | sh | +| child_process-test.js:39:5:39:5 | sh | child_process-test.js:39:14:39:15 | sh | +| child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args | +| child_process-test.js:41:9:41:17 | args | child_process-test.js:46:15:46:18 | args | +| child_process-test.js:41:16:41:17 | [] | child_process-test.js:41:9:41:17 | args | +| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:49:14:49:16 | cmd | +| child_process-test.js:46:15:46:18 | args | child_process-test.js:49:19:49:22 | args | +| child_process-test.js:49:14:49:16 | cmd | child_process-test.js:50:12:50:14 | cmd | +| child_process-test.js:49:19:49:22 | args | child_process-test.js:50:17:50:20 | args | +#select +| child_process-test.js:17:13:17:15 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:17:13:17:15 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:18:17:18:19 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:18:17:18:19 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:19:17:19:19 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:19:17:19:19 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:20:21:20:23 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:20:21:20:23 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:21:14:21:16 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:21:14:21:16 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:22:18:22:20 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:22:18:22:20 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:23:13:23:15 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:23:13:23:15 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:39:5:39:31 | cp.spaw ... cmd ]) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:39:26:39:28 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:44:5:44:34 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:50:3:50:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected index be0c937c38f3..c530d853079f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected @@ -1,11 +1,91 @@ -| ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value | -| etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value | -| formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | -| formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | -| partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value | -| partial.js:19:14:19:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:22:51:22:57 | req.url | user-provided value | -| partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:31:47:31:53 | req.url | user-provided value | -| partial.js:37:14:37:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:40:43:40:49 | req.url | user-provided value | -| promises.js:6:25:6:25 | x | Cross-site scripting vulnerability due to $@. | promises.js:5:44:5:57 | req.query.data | user-provided value | -| tst2.js:7:12:7:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:6:9:6:9 | p | user-provided value | -| tst2.js:8:12:8:12 | r | Cross-site scripting vulnerability due to $@. | tst2.js:6:12:6:15 | q: r | user-provided value | +nodes +| ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | +| ReflectedXss.js:8:33:8:45 | req.params.id | +| etherpad.js:9:5:9:53 | response | +| etherpad.js:9:16:9:30 | req.query.jsonp | +| etherpad.js:9:16:9:36 | req.que ... p + "(" | +| etherpad.js:9:16:9:47 | req.que ... esponse | +| etherpad.js:9:16:9:53 | req.que ... e + ")" | +| etherpad.js:11:3:11:3 | response | +| etherpad.js:11:12:11:19 | response | +| formatting.js:4:9:4:29 | evil | +| formatting.js:4:16:4:29 | req.query.evil | +| formatting.js:6:14:6:47 | util.fo ... , evil) | +| formatting.js:6:43:6:46 | evil | +| formatting.js:7:14:7:53 | require ... , evil) | +| formatting.js:7:49:7:52 | evil | +| partial.js:9:25:9:25 | x | +| partial.js:10:14:10:14 | x | +| partial.js:10:14:10:18 | x + y | +| partial.js:13:42:13:48 | req.url | +| partial.js:18:25:18:25 | x | +| partial.js:19:14:19:14 | x | +| partial.js:19:14:19:18 | x + y | +| partial.js:22:51:22:57 | req.url | +| partial.js:27:25:27:25 | x | +| partial.js:28:14:28:14 | x | +| partial.js:28:14:28:18 | x + y | +| partial.js:31:47:31:53 | req.url | +| partial.js:36:25:36:25 | x | +| partial.js:37:14:37:14 | x | +| partial.js:37:14:37:18 | x + y | +| partial.js:40:43:40:49 | req.url | +| promises.js:5:3:5:59 | new Pro ... .data)) | +| promises.js:5:44:5:57 | req.query.data | +| promises.js:6:11:6:11 | x | +| promises.js:6:11:6:11 | x | +| promises.js:6:25:6:25 | x | +| promises.js:6:25:6:25 | x | +| tst2.js:6:7:6:30 | p | +| tst2.js:6:7:6:30 | r | +| tst2.js:6:9:6:9 | p | +| tst2.js:6:12:6:15 | q: r | +| tst2.js:7:12:7:12 | p | +| tst2.js:8:12:8:12 | r | +edges +| ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | +| etherpad.js:9:5:9:53 | response | etherpad.js:11:3:11:3 | response | +| etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:36 | req.que ... p + "(" | +| etherpad.js:9:16:9:36 | req.que ... p + "(" | etherpad.js:9:16:9:47 | req.que ... esponse | +| etherpad.js:9:16:9:47 | req.que ... esponse | etherpad.js:9:16:9:53 | req.que ... e + ")" | +| etherpad.js:9:16:9:53 | req.que ... e + ")" | etherpad.js:9:5:9:53 | response | +| etherpad.js:11:3:11:3 | response | etherpad.js:11:12:11:19 | response | +| formatting.js:4:9:4:29 | evil | formatting.js:6:43:6:46 | evil | +| formatting.js:4:9:4:29 | evil | formatting.js:7:49:7:52 | evil | +| formatting.js:4:16:4:29 | req.query.evil | formatting.js:4:9:4:29 | evil | +| formatting.js:6:43:6:46 | evil | formatting.js:6:14:6:47 | util.fo ... , evil) | +| formatting.js:7:49:7:52 | evil | formatting.js:7:14:7:53 | require ... , evil) | +| partial.js:9:25:9:25 | x | partial.js:10:14:10:14 | x | +| partial.js:10:14:10:14 | x | partial.js:10:14:10:18 | x + y | +| partial.js:13:42:13:48 | req.url | partial.js:9:25:9:25 | x | +| partial.js:18:25:18:25 | x | partial.js:19:14:19:14 | x | +| partial.js:19:14:19:14 | x | partial.js:19:14:19:18 | x + y | +| partial.js:22:51:22:57 | req.url | partial.js:18:25:18:25 | x | +| partial.js:27:25:27:25 | x | partial.js:28:14:28:14 | x | +| partial.js:28:14:28:14 | x | partial.js:28:14:28:18 | x + y | +| partial.js:31:47:31:53 | req.url | partial.js:27:25:27:25 | x | +| partial.js:36:25:36:25 | x | partial.js:37:14:37:14 | x | +| partial.js:37:14:37:14 | x | partial.js:37:14:37:18 | x + y | +| partial.js:40:43:40:49 | req.url | partial.js:36:25:36:25 | x | +| promises.js:5:3:5:59 | new Pro ... .data)) | promises.js:6:11:6:11 | x | +| promises.js:5:44:5:57 | req.query.data | promises.js:5:3:5:59 | new Pro ... .data)) | +| promises.js:5:44:5:57 | req.query.data | promises.js:6:11:6:11 | x | +| promises.js:6:11:6:11 | x | promises.js:6:25:6:25 | x | +| promises.js:6:11:6:11 | x | promises.js:6:25:6:25 | x | +| tst2.js:6:7:6:30 | p | tst2.js:7:12:7:12 | p | +| tst2.js:6:7:6:30 | r | tst2.js:8:12:8:12 | r | +| tst2.js:6:9:6:9 | p | tst2.js:6:7:6:30 | p | +| tst2.js:6:12:6:15 | q: r | tst2.js:6:7:6:30 | r | +#select +| ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value | +| etherpad.js:11:12:11:19 | response | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value | +| formatting.js:6:14:6:47 | util.fo ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | +| formatting.js:7:14:7:53 | require ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | +| partial.js:10:14:10:18 | x + y | partial.js:13:42:13:48 | req.url | partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value | +| partial.js:19:14:19:18 | x + y | partial.js:22:51:22:57 | req.url | partial.js:19:14:19:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:22:51:22:57 | req.url | user-provided value | +| partial.js:28:14:28:18 | x + y | partial.js:31:47:31:53 | req.url | partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:31:47:31:53 | req.url | user-provided value | +| partial.js:37:14:37:18 | x + y | partial.js:40:43:40:49 | req.url | partial.js:37:14:37:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:40:43:40:49 | req.url | user-provided value | +| promises.js:6:25:6:25 | x | promises.js:5:44:5:57 | req.query.data | promises.js:6:25:6:25 | x | Cross-site scripting vulnerability due to $@. | promises.js:5:44:5:57 | req.query.data | user-provided value | +| promises.js:6:25:6:25 | x | promises.js:5:44:5:57 | req.query.data | promises.js:6:25:6:25 | x | Cross-site scripting vulnerability due to $@. | promises.js:5:44:5:57 | req.query.data | user-provided value | +| tst2.js:7:12:7:12 | p | tst2.js:6:9:6:9 | p | tst2.js:7:12:7:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:6:9:6:9 | p | user-provided value | +| tst2.js:8:12:8:12 | r | tst2.js:6:12:6:15 | q: r | tst2.js:8:12:8:12 | r | Cross-site scripting vulnerability due to $@. | tst2.js:6:12:6:15 | q: r | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/StoredXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/StoredXss.expected index 9d9a94ff27ea..4b941d5e730b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/StoredXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/StoredXss.expected @@ -1,4 +1,395 @@ -| xss-through-filenames.js:8:18:8:23 | files1 | Stored cross-site scripting vulnerability due to $@. | xss-through-filenames.js:7:43:7:48 | files1 | stored value | -| xss-through-filenames.js:26:19:26:24 | files1 | Stored cross-site scripting vulnerability due to $@. | xss-through-filenames.js:25:43:25:48 | files1 | stored value | -| xss-through-filenames.js:33:19:33:24 | files2 | Stored cross-site scripting vulnerability due to $@. | xss-through-filenames.js:25:43:25:48 | files1 | stored value | -| xss-through-filenames.js:37:19:37:24 | files3 | Stored cross-site scripting vulnerability due to $@. | xss-through-filenames.js:25:43:25:48 | files1 | stored value | +nodes +| ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | +| ReflectedXss.js:8:33:8:45 | req.params.id | +| addEventListener.js:1:43:1:47 | event | +| addEventListener.js:2:20:2:24 | event | +| addEventListener.js:2:20:2:29 | event.data | +| etherpad.js:9:5:9:53 | response | +| etherpad.js:9:16:9:30 | req.query.jsonp | +| etherpad.js:9:16:9:36 | req.que ... p + "(" | +| etherpad.js:9:16:9:47 | req.que ... esponse | +| etherpad.js:9:16:9:53 | req.que ... e + ")" | +| etherpad.js:11:3:11:3 | response | +| etherpad.js:11:12:11:19 | response | +| formatting.js:4:9:4:29 | evil | +| formatting.js:4:16:4:29 | req.query.evil | +| formatting.js:6:14:6:47 | util.fo ... , evil) | +| formatting.js:6:43:6:46 | evil | +| formatting.js:7:14:7:53 | require ... , evil) | +| formatting.js:7:49:7:52 | evil | +| jquery.js:2:7:2:40 | tainted | +| jquery.js:2:17:2:33 | document.location | +| jquery.js:2:17:2:40 | documen ... .search | +| jquery.js:4:5:4:11 | tainted | +| jquery.js:7:5:7:26 | "
    " | +| jquery.js:7:20:7:26 | tainted | +| jquery.js:8:18:8:34 | "XSS: " + tainted | +| jquery.js:8:28:8:34 | tainted | +| nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | +| nodemailer.js:13:50:13:66 | req.query.message | +| partial.js:9:25:9:25 | x | +| partial.js:10:14:10:14 | x | +| partial.js:10:14:10:18 | x + y | +| partial.js:13:42:13:48 | req.url | +| partial.js:18:25:18:25 | x | +| partial.js:19:14:19:14 | x | +| partial.js:19:14:19:18 | x + y | +| partial.js:22:51:22:57 | req.url | +| partial.js:27:25:27:25 | x | +| partial.js:28:14:28:14 | x | +| partial.js:28:14:28:18 | x + y | +| partial.js:31:47:31:53 | req.url | +| partial.js:36:25:36:25 | x | +| partial.js:37:14:37:14 | x | +| partial.js:37:14:37:18 | x + y | +| partial.js:40:43:40:49 | req.url | +| promises.js:5:3:5:59 | new Pro ... .data)) | +| promises.js:5:44:5:57 | req.query.data | +| promises.js:6:11:6:11 | x | +| promises.js:6:11:6:11 | x | +| promises.js:6:25:6:25 | x | +| promises.js:6:25:6:25 | x | +| react-native.js:7:7:7:33 | tainted | +| react-native.js:7:17:7:33 | req.param("code") | +| react-native.js:8:18:8:24 | tainted | +| react-native.js:9:27:9:33 | tainted | +| string-manipulations.js:3:16:3:32 | document.location | +| string-manipulations.js:4:16:4:32 | document.location | +| string-manipulations.js:4:16:4:37 | documen ... on.href | +| string-manipulations.js:5:16:5:32 | document.location | +| string-manipulations.js:5:16:5:37 | documen ... on.href | +| string-manipulations.js:5:16:5:47 | documen ... lueOf() | +| string-manipulations.js:6:16:6:32 | document.location | +| string-manipulations.js:6:16:6:37 | documen ... on.href | +| string-manipulations.js:6:16:6:43 | documen ... f.sup() | +| string-manipulations.js:7:16:7:32 | document.location | +| string-manipulations.js:7:16:7:37 | documen ... on.href | +| string-manipulations.js:7:16:7:51 | documen ... rCase() | +| string-manipulations.js:8:16:8:32 | document.location | +| string-manipulations.js:8:16:8:37 | documen ... on.href | +| string-manipulations.js:8:16:8:48 | documen ... mLeft() | +| string-manipulations.js:9:16:9:58 | String. ... n.href) | +| string-manipulations.js:9:36:9:52 | document.location | +| string-manipulations.js:9:36:9:57 | documen ... on.href | +| string-manipulations.js:10:16:10:45 | String( ... n.href) | +| string-manipulations.js:10:23:10:39 | document.location | +| string-manipulations.js:10:23:10:44 | documen ... on.href | +| translate.js:6:7:6:39 | target | +| translate.js:6:16:6:32 | document.location | +| translate.js:6:16:6:39 | documen ... .search | +| translate.js:7:42:7:47 | target | +| translate.js:7:42:7:60 | target.substring(1) | +| translate.js:9:27:9:50 | searchP ... 'term') | +| tst2.js:6:7:6:30 | p | +| tst2.js:6:7:6:30 | r | +| tst2.js:6:9:6:9 | p | +| tst2.js:6:12:6:15 | q: r | +| tst2.js:7:12:7:12 | p | +| tst2.js:8:12:8:12 | r | +| tst.js:2:7:2:39 | target | +| tst.js:2:16:2:32 | document.location | +| tst.js:2:16:2:39 | documen ... .search | +| tst.js:5:18:5:23 | target | +| tst.js:8:18:8:114 | "" | +| tst.js:8:37:8:53 | document.location | +| tst.js:8:37:8:58 | documen ... on.href | +| tst.js:8:37:8:114 | documen ... t=")+8) | +| tst.js:12:5:12:33 | '
    ' | +| tst.js:12:28:12:33 | target | +| tst.js:19:25:19:41 | document.location | +| tst.js:20:18:20:35 | params.get('name') | +| tst.js:23:42:23:47 | target | +| tst.js:23:42:23:60 | target.substring(1) | +| tst.js:24:18:24:41 | searchP ... 'name') | +| tst.js:27:14:27:19 | target | +| tst.js:29:18:29:23 | target | +| tst.js:31:5:31:21 | document.location | +| tst.js:31:5:31:28 | documen ... .search | +| tst.js:34:10:34:26 | document.location | +| tst.js:34:10:34:33 | documen ... .search | +| tst.js:37:16:37:20 | bar() | +| tst.js:43:16:43:44 | baz(doc ... search) | +| tst.js:43:20:43:36 | document.location | +| tst.js:43:20:43:43 | documen ... .search | +| tst.js:49:16:49:45 | wrap(do ... search) | +| tst.js:49:21:49:37 | document.location | +| tst.js:49:21:49:44 | documen ... .search | +| tst.js:57:16:57:45 | chop(do ... search) | +| tst.js:57:21:57:37 | document.location | +| tst.js:57:21:57:44 | documen ... .search | +| tst.js:59:16:59:45 | chop(do ... search) | +| tst.js:59:21:59:37 | document.location | +| tst.js:59:21:59:44 | documen ... .search | +| tst.js:61:16:61:32 | wrap(chop(bar())) | +| tst.js:61:21:61:31 | chop(bar()) | +| tst.js:61:26:61:30 | bar() | +| tst.js:63:34:63:34 | s | +| tst.js:65:18:65:18 | s | +| tst.js:67:25:67:41 | document.location | +| tst.js:67:25:67:48 | documen ... .search | +| tst.js:68:25:68:41 | document.location | +| tst.js:68:25:68:48 | documen ... .search | +| tst.js:71:16:71:20 | bar() | +| tst.js:73:1:73:27 | [,docum ... search] | +| tst.js:73:3:73:19 | document.location | +| tst.js:73:3:73:26 | documen ... .search | +| tst.js:73:46:73:46 | x | +| tst.js:74:7:74:7 | x | +| tst.js:76:20:76:20 | x | +| tst.js:80:49:80:65 | document.location | +| tst.js:80:49:80:72 | documen ... .search | +| tst.js:84:26:84:42 | document.location | +| tst.js:84:26:84:49 | documen ... .search | +| tst.js:85:25:85:41 | document.location | +| tst.js:85:25:85:48 | documen ... .search | +| tst.js:87:33:87:49 | document.location | +| tst.js:87:33:87:56 | documen ... .search | +| tst.js:88:32:88:48 | document.location | +| tst.js:88:32:88:55 | documen ... .search | +| tst.js:93:39:93:55 | document.location | +| tst.js:93:39:93:62 | documen ... .search | +| tst.js:99:30:99:46 | document.location | +| tst.js:99:30:99:53 | documen ... .search | +| tst.js:105:25:105:41 | document.location | +| tst.js:105:25:105:48 | documen ... .search | +| tst.js:110:7:110:44 | v | +| tst.js:110:11:110:27 | document.location | +| tst.js:110:11:110:34 | documen ... .search | +| tst.js:110:11:110:44 | documen ... bstr(1) | +| tst.js:113:18:113:18 | v | +| tst.js:145:29:145:43 | window.location | +| tst.js:145:29:145:50 | window. ... .search | +| tst.js:148:29:148:29 | v | +| tst.js:148:49:148:49 | v | +| tst.js:152:29:152:46 | xssSourceService() | +| tst.js:155:40:155:54 | window.location | +| tst.js:155:40:155:61 | window. ... .search | +| tst.js:174:9:174:41 | target | +| tst.js:174:18:174:34 | document.location | +| tst.js:174:18:174:41 | documen ... .search | +| tst.js:177:28:177:33 | target | +| tst.js:181:9:181:42 | tainted | +| tst.js:181:19:181:35 | document.location | +| tst.js:181:19:181:42 | documen ... .search | +| tst.js:183:31:183:37 | tainted | +| tst.js:185:42:185:48 | tainted | +| tst.js:186:33:186:39 | tainted | +| tst.js:188:54:188:60 | tainted | +| tst.js:189:45:189:51 | tainted | +| tst.js:194:9:194:42 | tainted | +| tst.js:194:19:194:35 | document.location | +| tst.js:194:19:194:42 | documen ... .search | +| tst.js:196:67:196:73 | tainted | +| tst.js:197:67:197:73 | tainted | +| tst.js:200:20:200:19 | tainted | +| tst.js:201:35:201:41 | tainted | +| tst.js:203:27:203:26 | tainted | +| tst.js:203:46:203:52 | tainted | +| tst.js:204:38:204:44 | tainted | +| tst.js:205:35:205:41 | tainted | +| tst.js:209:28:209:46 | this.state.tainted1 | +| tst.js:210:28:210:46 | this.state.tainted2 | +| tst.js:211:28:211:46 | this.state.tainted3 | +| tst.js:215:32:215:49 | prevState.tainted4 | +| tst.js:222:28:222:46 | this.props.tainted1 | +| tst.js:223:28:223:46 | this.props.tainted2 | +| tst.js:224:28:224:46 | this.props.tainted3 | +| tst.js:228:32:228:49 | prevProps.tainted4 | +| tst.js:233:35:233:41 | tainted | +| tst.js:235:20:235:26 | tainted | +| tst.js:237:23:237:29 | tainted | +| tst.js:238:23:238:29 | tainted | +| tst.js:244:39:244:55 | props.propTainted | +| tst.js:248:60:248:82 | this.st ... Tainted | +| tst.js:252:23:252:29 | tainted | +| xss-through-filenames.js:7:43:7:48 | files1 | +| xss-through-filenames.js:8:18:8:23 | files1 | +| xss-through-filenames.js:25:43:25:48 | files1 | +| xss-through-filenames.js:26:19:26:24 | files1 | +| xss-through-filenames.js:29:13:29:23 | files2 | +| xss-through-filenames.js:29:22:29:23 | [] | +| xss-through-filenames.js:30:34:30:37 | file | +| xss-through-filenames.js:31:25:31:28 | file | +| xss-through-filenames.js:33:19:33:24 | files2 | +| xss-through-filenames.js:35:13:35:35 | files3 | +| xss-through-filenames.js:35:22:35:35 | format(files2) | +| xss-through-filenames.js:35:29:35:34 | files2 | +| xss-through-filenames.js:37:19:37:24 | files3 | +edges +| ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | +| addEventListener.js:1:43:1:47 | event | addEventListener.js:2:20:2:24 | event | +| addEventListener.js:2:20:2:24 | event | addEventListener.js:2:20:2:29 | event.data | +| etherpad.js:9:5:9:53 | response | etherpad.js:11:3:11:3 | response | +| etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:36 | req.que ... p + "(" | +| etherpad.js:9:16:9:36 | req.que ... p + "(" | etherpad.js:9:16:9:47 | req.que ... esponse | +| etherpad.js:9:16:9:47 | req.que ... esponse | etherpad.js:9:16:9:53 | req.que ... e + ")" | +| etherpad.js:9:16:9:53 | req.que ... e + ")" | etherpad.js:9:5:9:53 | response | +| etherpad.js:11:3:11:3 | response | etherpad.js:11:12:11:19 | response | +| formatting.js:4:9:4:29 | evil | formatting.js:6:43:6:46 | evil | +| formatting.js:4:9:4:29 | evil | formatting.js:7:49:7:52 | evil | +| formatting.js:4:16:4:29 | req.query.evil | formatting.js:4:9:4:29 | evil | +| formatting.js:6:43:6:46 | evil | formatting.js:6:14:6:47 | util.fo ... , evil) | +| formatting.js:7:49:7:52 | evil | formatting.js:7:14:7:53 | require ... , evil) | +| jquery.js:2:7:2:40 | tainted | jquery.js:4:5:4:11 | tainted | +| jquery.js:2:7:2:40 | tainted | jquery.js:7:20:7:26 | tainted | +| jquery.js:2:7:2:40 | tainted | jquery.js:8:28:8:34 | tainted | +| jquery.js:2:17:2:33 | document.location | jquery.js:2:17:2:40 | documen ... .search | +| jquery.js:2:17:2:40 | documen ... .search | jquery.js:2:7:2:40 | tainted | +| jquery.js:7:5:7:26 | "
    " | +| jquery.js:7:20:7:26 | tainted | jquery.js:7:5:7:26 | "
    " | +| tst.js:8:37:8:53 | document.location | tst.js:8:37:8:58 | documen ... on.href | +| tst.js:8:37:8:58 | documen ... on.href | tst.js:8:37:8:114 | documen ... t=")+8) | +| tst.js:8:37:8:114 | documen ... t=")+8) | tst.js:8:18:8:114 | "' | +| tst.js:12:28:12:33 | target | tst.js:12:5:12:33 | '
    " | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value | -| jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value | -| nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | HTML injection vulnerability due to $@. | nodemailer.js:13:50:13:66 | req.query.message | user-provided value | -| react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | -| react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | -| string-manipulations.js:3:16:3:32 | document.location | Cross-site scripting vulnerability due to $@. | string-manipulations.js:3:16:3:32 | document.location | user-provided value | -| string-manipulations.js:4:16:4:37 | documen ... on.href | Cross-site scripting vulnerability due to $@. | string-manipulations.js:4:16:4:32 | document.location | user-provided value | -| string-manipulations.js:5:16:5:47 | documen ... lueOf() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:5:16:5:32 | document.location | user-provided value | -| string-manipulations.js:6:16:6:43 | documen ... f.sup() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:6:16:6:32 | document.location | user-provided value | -| string-manipulations.js:7:16:7:51 | documen ... rCase() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:7:16:7:32 | document.location | user-provided value | -| string-manipulations.js:8:16:8:48 | documen ... mLeft() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:8:16:8:32 | document.location | user-provided value | -| string-manipulations.js:9:16:9:58 | String. ... n.href) | Cross-site scripting vulnerability due to $@. | string-manipulations.js:9:36:9:52 | document.location | user-provided value | -| string-manipulations.js:10:16:10:45 | String( ... n.href) | Cross-site scripting vulnerability due to $@. | string-manipulations.js:10:23:10:39 | document.location | user-provided value | -| translate.js:9:27:9:50 | searchP ... 'term') | Cross-site scripting vulnerability due to $@. | translate.js:6:16:6:32 | document.location | user-provided value | -| tst.js:5:18:5:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:2:16:2:32 | document.location | user-provided value | -| tst.js:8:18:8:126 | "" | Cross-site scripting vulnerability due to $@. | tst.js:8:37:8:53 | document.location | user-provided value | -| tst.js:12:5:12:42 | '
    ' | Cross-site scripting vulnerability due to $@. | tst.js:2:16:2:32 | document.location | user-provided value | -| tst.js:20:18:20:35 | params.get('name') | Cross-site scripting vulnerability due to $@. | tst.js:19:25:19:41 | document.location | user-provided value | -| tst.js:24:18:24:41 | searchP ... 'name') | Cross-site scripting vulnerability due to $@. | tst.js:2:16:2:32 | document.location | user-provided value | -| tst.js:29:18:29:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:31:5:31:21 | document.location | user-provided value | -| tst.js:37:16:37:20 | bar() | Cross-site scripting vulnerability due to $@. | tst.js:34:10:34:26 | document.location | user-provided value | -| tst.js:43:16:43:44 | baz(doc ... search) | Cross-site scripting vulnerability due to $@. | tst.js:43:20:43:36 | document.location | user-provided value | -| tst.js:49:16:49:45 | wrap(do ... search) | Cross-site scripting vulnerability due to $@. | tst.js:49:21:49:37 | document.location | user-provided value | -| tst.js:57:16:57:45 | chop(do ... search) | Cross-site scripting vulnerability due to $@. | tst.js:57:21:57:37 | document.location | user-provided value | -| tst.js:59:16:59:45 | chop(do ... search) | Cross-site scripting vulnerability due to $@. | tst.js:59:21:59:37 | document.location | user-provided value | -| tst.js:61:16:61:32 | wrap(chop(bar())) | Cross-site scripting vulnerability due to $@. | tst.js:34:10:34:26 | document.location | user-provided value | -| tst.js:65:18:65:18 | s | Cross-site scripting vulnerability due to $@. | tst.js:67:25:67:41 | document.location | user-provided value | -| tst.js:65:18:65:18 | s | Cross-site scripting vulnerability due to $@. | tst.js:68:25:68:41 | document.location | user-provided value | -| tst.js:71:16:71:20 | bar() | Cross-site scripting vulnerability due to $@. | tst.js:34:10:34:26 | document.location | user-provided value | -| tst.js:76:20:76:20 | x | Cross-site scripting vulnerability due to $@. | tst.js:73:3:73:19 | document.location | user-provided value | -| tst.js:80:49:80:72 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:80:49:80:65 | document.location | user-provided value | -| tst.js:84:26:84:49 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:84:26:84:42 | document.location | user-provided value | -| tst.js:85:25:85:48 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:85:25:85:41 | document.location | user-provided value | -| tst.js:87:33:87:56 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:87:33:87:49 | document.location | user-provided value | -| tst.js:88:32:88:55 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:88:32:88:48 | document.location | user-provided value | -| tst.js:93:39:93:62 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:93:39:93:55 | document.location | user-provided value | -| tst.js:99:30:99:53 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:99:30:99:46 | document.location | user-provided value | -| tst.js:105:25:105:48 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:105:25:105:41 | document.location | user-provided value | -| tst.js:113:18:113:18 | v | Cross-site scripting vulnerability due to $@. | tst.js:110:11:110:27 | document.location | user-provided value | -| tst.js:148:49:148:49 | v | Cross-site scripting vulnerability due to $@. | tst.js:145:29:145:43 | window.location | user-provided value | -| tst.js:152:29:152:46 | xssSourceService() | Cross-site scripting vulnerability due to $@. | tst.js:155:40:155:54 | window.location | user-provided value | -| tst.js:177:28:177:33 | target | Cross-site scripting vulnerability due to $@. | tst.js:174:18:174:34 | document.location | user-provided value | -| tst.js:183:31:183:37 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | -| tst.js:185:42:185:48 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | -| tst.js:186:33:186:39 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | -| tst.js:188:54:188:60 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | -| tst.js:189:45:189:51 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | -| tst.js:196:67:196:73 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:197:67:197:73 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:209:28:209:46 | this.state.tainted1 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:210:28:210:46 | this.state.tainted2 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:211:28:211:46 | this.state.tainted3 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:215:32:215:49 | prevState.tainted4 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:222:28:222:46 | this.props.tainted1 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:223:28:223:46 | this.props.tainted2 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:224:28:224:46 | this.props.tainted3 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:228:32:228:49 | prevProps.tainted4 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | -| tst.js:248:60:248:82 | this.st ... Tainted | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +nodes +| addEventListener.js:1:43:1:47 | event | +| addEventListener.js:2:20:2:24 | event | +| addEventListener.js:2:20:2:29 | event.data | +| jquery.js:2:7:2:40 | tainted | +| jquery.js:2:17:2:33 | document.location | +| jquery.js:2:17:2:40 | documen ... .search | +| jquery.js:4:5:4:11 | tainted | +| jquery.js:7:5:7:26 | "
    " | +| jquery.js:7:20:7:26 | tainted | +| jquery.js:8:18:8:34 | "XSS: " + tainted | +| jquery.js:8:28:8:34 | tainted | +| nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | +| nodemailer.js:13:50:13:66 | req.query.message | +| react-native.js:7:7:7:33 | tainted | +| react-native.js:7:17:7:33 | req.param("code") | +| react-native.js:8:18:8:24 | tainted | +| react-native.js:9:27:9:33 | tainted | +| string-manipulations.js:3:16:3:32 | document.location | +| string-manipulations.js:4:16:4:32 | document.location | +| string-manipulations.js:4:16:4:37 | documen ... on.href | +| string-manipulations.js:5:16:5:32 | document.location | +| string-manipulations.js:5:16:5:37 | documen ... on.href | +| string-manipulations.js:5:16:5:47 | documen ... lueOf() | +| string-manipulations.js:6:16:6:32 | document.location | +| string-manipulations.js:6:16:6:37 | documen ... on.href | +| string-manipulations.js:6:16:6:43 | documen ... f.sup() | +| string-manipulations.js:7:16:7:32 | document.location | +| string-manipulations.js:7:16:7:37 | documen ... on.href | +| string-manipulations.js:7:16:7:51 | documen ... rCase() | +| string-manipulations.js:8:16:8:32 | document.location | +| string-manipulations.js:8:16:8:37 | documen ... on.href | +| string-manipulations.js:8:16:8:48 | documen ... mLeft() | +| string-manipulations.js:9:16:9:58 | String. ... n.href) | +| string-manipulations.js:9:36:9:52 | document.location | +| string-manipulations.js:9:36:9:57 | documen ... on.href | +| string-manipulations.js:10:16:10:45 | String( ... n.href) | +| string-manipulations.js:10:23:10:39 | document.location | +| string-manipulations.js:10:23:10:44 | documen ... on.href | +| translate.js:6:7:6:39 | target | +| translate.js:6:16:6:32 | document.location | +| translate.js:6:16:6:39 | documen ... .search | +| translate.js:7:42:7:47 | target | +| translate.js:7:42:7:60 | target.substring(1) | +| translate.js:9:27:9:50 | searchP ... 'term') | +| tst.js:2:7:2:39 | target | +| tst.js:2:16:2:32 | document.location | +| tst.js:2:16:2:39 | documen ... .search | +| tst.js:5:18:5:23 | target | +| tst.js:8:18:8:114 | "" | +| tst.js:8:37:8:53 | document.location | +| tst.js:8:37:8:58 | documen ... on.href | +| tst.js:8:37:8:114 | documen ... t=")+8) | +| tst.js:12:5:12:33 | '
    ' | +| tst.js:12:28:12:33 | target | +| tst.js:19:25:19:41 | document.location | +| tst.js:20:18:20:35 | params.get('name') | +| tst.js:23:42:23:47 | target | +| tst.js:23:42:23:60 | target.substring(1) | +| tst.js:24:18:24:41 | searchP ... 'name') | +| tst.js:27:14:27:19 | target | +| tst.js:29:18:29:23 | target | +| tst.js:31:5:31:21 | document.location | +| tst.js:31:5:31:28 | documen ... .search | +| tst.js:34:10:34:26 | document.location | +| tst.js:34:10:34:33 | documen ... .search | +| tst.js:37:16:37:20 | bar() | +| tst.js:43:16:43:44 | baz(doc ... search) | +| tst.js:43:20:43:36 | document.location | +| tst.js:43:20:43:43 | documen ... .search | +| tst.js:49:16:49:45 | wrap(do ... search) | +| tst.js:49:21:49:37 | document.location | +| tst.js:49:21:49:44 | documen ... .search | +| tst.js:57:16:57:45 | chop(do ... search) | +| tst.js:57:21:57:37 | document.location | +| tst.js:57:21:57:44 | documen ... .search | +| tst.js:59:16:59:45 | chop(do ... search) | +| tst.js:59:21:59:37 | document.location | +| tst.js:59:21:59:44 | documen ... .search | +| tst.js:61:16:61:32 | wrap(chop(bar())) | +| tst.js:61:21:61:31 | chop(bar()) | +| tst.js:61:26:61:30 | bar() | +| tst.js:63:34:63:34 | s | +| tst.js:65:18:65:18 | s | +| tst.js:67:25:67:41 | document.location | +| tst.js:67:25:67:48 | documen ... .search | +| tst.js:68:25:68:41 | document.location | +| tst.js:68:25:68:48 | documen ... .search | +| tst.js:71:16:71:20 | bar() | +| tst.js:73:1:73:27 | [,docum ... search] | +| tst.js:73:3:73:19 | document.location | +| tst.js:73:3:73:26 | documen ... .search | +| tst.js:73:46:73:46 | x | +| tst.js:74:7:74:7 | x | +| tst.js:76:20:76:20 | x | +| tst.js:80:49:80:65 | document.location | +| tst.js:80:49:80:72 | documen ... .search | +| tst.js:84:26:84:42 | document.location | +| tst.js:84:26:84:49 | documen ... .search | +| tst.js:85:25:85:41 | document.location | +| tst.js:85:25:85:48 | documen ... .search | +| tst.js:87:33:87:49 | document.location | +| tst.js:87:33:87:56 | documen ... .search | +| tst.js:88:32:88:48 | document.location | +| tst.js:88:32:88:55 | documen ... .search | +| tst.js:93:39:93:55 | document.location | +| tst.js:93:39:93:62 | documen ... .search | +| tst.js:99:30:99:46 | document.location | +| tst.js:99:30:99:53 | documen ... .search | +| tst.js:105:25:105:41 | document.location | +| tst.js:105:25:105:48 | documen ... .search | +| tst.js:110:7:110:44 | v | +| tst.js:110:11:110:27 | document.location | +| tst.js:110:11:110:34 | documen ... .search | +| tst.js:110:11:110:44 | documen ... bstr(1) | +| tst.js:113:18:113:18 | v | +| tst.js:145:29:145:43 | window.location | +| tst.js:145:29:145:50 | window. ... .search | +| tst.js:148:29:148:29 | v | +| tst.js:148:49:148:49 | v | +| tst.js:152:29:152:46 | xssSourceService() | +| tst.js:155:40:155:54 | window.location | +| tst.js:155:40:155:61 | window. ... .search | +| tst.js:174:9:174:41 | target | +| tst.js:174:18:174:34 | document.location | +| tst.js:174:18:174:41 | documen ... .search | +| tst.js:177:28:177:33 | target | +| tst.js:181:9:181:42 | tainted | +| tst.js:181:19:181:35 | document.location | +| tst.js:181:19:181:42 | documen ... .search | +| tst.js:183:31:183:37 | tainted | +| tst.js:185:42:185:48 | tainted | +| tst.js:186:33:186:39 | tainted | +| tst.js:188:54:188:60 | tainted | +| tst.js:189:45:189:51 | tainted | +| tst.js:194:9:194:42 | tainted | +| tst.js:194:19:194:35 | document.location | +| tst.js:194:19:194:42 | documen ... .search | +| tst.js:196:67:196:73 | tainted | +| tst.js:197:67:197:73 | tainted | +| tst.js:200:20:200:19 | tainted | +| tst.js:201:35:201:41 | tainted | +| tst.js:203:27:203:26 | tainted | +| tst.js:203:46:203:52 | tainted | +| tst.js:204:38:204:44 | tainted | +| tst.js:205:35:205:41 | tainted | +| tst.js:209:28:209:46 | this.state.tainted1 | +| tst.js:210:28:210:46 | this.state.tainted2 | +| tst.js:211:28:211:46 | this.state.tainted3 | +| tst.js:215:32:215:49 | prevState.tainted4 | +| tst.js:222:28:222:46 | this.props.tainted1 | +| tst.js:223:28:223:46 | this.props.tainted2 | +| tst.js:224:28:224:46 | this.props.tainted3 | +| tst.js:228:32:228:49 | prevProps.tainted4 | +| tst.js:233:35:233:41 | tainted | +| tst.js:235:20:235:26 | tainted | +| tst.js:237:23:237:29 | tainted | +| tst.js:238:23:238:29 | tainted | +| tst.js:244:39:244:55 | props.propTainted | +| tst.js:248:60:248:82 | this.st ... Tainted | +| tst.js:252:23:252:29 | tainted | +edges +| addEventListener.js:1:43:1:47 | event | addEventListener.js:2:20:2:24 | event | +| addEventListener.js:2:20:2:24 | event | addEventListener.js:2:20:2:29 | event.data | +| jquery.js:2:7:2:40 | tainted | jquery.js:4:5:4:11 | tainted | +| jquery.js:2:7:2:40 | tainted | jquery.js:7:20:7:26 | tainted | +| jquery.js:2:7:2:40 | tainted | jquery.js:8:28:8:34 | tainted | +| jquery.js:2:17:2:33 | document.location | jquery.js:2:17:2:40 | documen ... .search | +| jquery.js:2:17:2:40 | documen ... .search | jquery.js:2:7:2:40 | tainted | +| jquery.js:7:5:7:26 | "
    " | +| jquery.js:7:20:7:26 | tainted | jquery.js:7:5:7:26 | "
    " | +| tst.js:8:37:8:53 | document.location | tst.js:8:37:8:58 | documen ... on.href | +| tst.js:8:37:8:58 | documen ... on.href | tst.js:8:37:8:114 | documen ... t=")+8) | +| tst.js:8:37:8:114 | documen ... t=")+8) | tst.js:8:18:8:114 | "' | +| tst.js:12:28:12:33 | target | tst.js:12:5:12:33 | '
    " | jquery.js:2:17:2:33 | document.location | jquery.js:7:5:7:34 | "
    " | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value | +| jquery.js:8:18:8:34 | "XSS: " + tainted | jquery.js:2:17:2:33 | document.location | jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value | +| nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | HTML injection vulnerability due to $@. | nodemailer.js:13:50:13:66 | req.query.message | user-provided value | +| react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | +| react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | +| string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | Cross-site scripting vulnerability due to $@. | string-manipulations.js:3:16:3:32 | document.location | user-provided value | +| string-manipulations.js:4:16:4:37 | documen ... on.href | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | Cross-site scripting vulnerability due to $@. | string-manipulations.js:4:16:4:32 | document.location | user-provided value | +| string-manipulations.js:5:16:5:47 | documen ... lueOf() | string-manipulations.js:5:16:5:32 | document.location | string-manipulations.js:5:16:5:47 | documen ... lueOf() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:5:16:5:32 | document.location | user-provided value | +| string-manipulations.js:6:16:6:43 | documen ... f.sup() | string-manipulations.js:6:16:6:32 | document.location | string-manipulations.js:6:16:6:43 | documen ... f.sup() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:6:16:6:32 | document.location | user-provided value | +| string-manipulations.js:7:16:7:51 | documen ... rCase() | string-manipulations.js:7:16:7:32 | document.location | string-manipulations.js:7:16:7:51 | documen ... rCase() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:7:16:7:32 | document.location | user-provided value | +| string-manipulations.js:8:16:8:48 | documen ... mLeft() | string-manipulations.js:8:16:8:32 | document.location | string-manipulations.js:8:16:8:48 | documen ... mLeft() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:8:16:8:32 | document.location | user-provided value | +| string-manipulations.js:9:16:9:58 | String. ... n.href) | string-manipulations.js:9:36:9:52 | document.location | string-manipulations.js:9:16:9:58 | String. ... n.href) | Cross-site scripting vulnerability due to $@. | string-manipulations.js:9:36:9:52 | document.location | user-provided value | +| string-manipulations.js:10:16:10:45 | String( ... n.href) | string-manipulations.js:10:23:10:39 | document.location | string-manipulations.js:10:16:10:45 | String( ... n.href) | Cross-site scripting vulnerability due to $@. | string-manipulations.js:10:23:10:39 | document.location | user-provided value | +| translate.js:9:27:9:50 | searchP ... 'term') | translate.js:6:16:6:32 | document.location | translate.js:9:27:9:50 | searchP ... 'term') | Cross-site scripting vulnerability due to $@. | translate.js:6:16:6:32 | document.location | user-provided value | +| tst.js:5:18:5:23 | target | tst.js:2:16:2:32 | document.location | tst.js:5:18:5:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:2:16:2:32 | document.location | user-provided value | +| tst.js:8:18:8:126 | "" | tst.js:8:37:8:53 | document.location | tst.js:8:18:8:126 | "" | Cross-site scripting vulnerability due to $@. | tst.js:8:37:8:53 | document.location | user-provided value | +| tst.js:12:5:12:42 | '
    ' | tst.js:2:16:2:32 | document.location | tst.js:12:5:12:42 | '
    ' | Cross-site scripting vulnerability due to $@. | tst.js:2:16:2:32 | document.location | user-provided value | +| tst.js:20:18:20:35 | params.get('name') | tst.js:19:25:19:41 | document.location | tst.js:20:18:20:35 | params.get('name') | Cross-site scripting vulnerability due to $@. | tst.js:19:25:19:41 | document.location | user-provided value | +| tst.js:24:18:24:41 | searchP ... 'name') | tst.js:2:16:2:32 | document.location | tst.js:24:18:24:41 | searchP ... 'name') | Cross-site scripting vulnerability due to $@. | tst.js:2:16:2:32 | document.location | user-provided value | +| tst.js:29:18:29:23 | target | tst.js:31:5:31:21 | document.location | tst.js:29:18:29:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:31:5:31:21 | document.location | user-provided value | +| tst.js:37:16:37:20 | bar() | tst.js:34:10:34:26 | document.location | tst.js:37:16:37:20 | bar() | Cross-site scripting vulnerability due to $@. | tst.js:34:10:34:26 | document.location | user-provided value | +| tst.js:43:16:43:44 | baz(doc ... search) | tst.js:43:20:43:36 | document.location | tst.js:43:16:43:44 | baz(doc ... search) | Cross-site scripting vulnerability due to $@. | tst.js:43:20:43:36 | document.location | user-provided value | +| tst.js:49:16:49:45 | wrap(do ... search) | tst.js:49:21:49:37 | document.location | tst.js:49:16:49:45 | wrap(do ... search) | Cross-site scripting vulnerability due to $@. | tst.js:49:21:49:37 | document.location | user-provided value | +| tst.js:57:16:57:45 | chop(do ... search) | tst.js:57:21:57:37 | document.location | tst.js:57:16:57:45 | chop(do ... search) | Cross-site scripting vulnerability due to $@. | tst.js:57:21:57:37 | document.location | user-provided value | +| tst.js:59:16:59:45 | chop(do ... search) | tst.js:59:21:59:37 | document.location | tst.js:59:16:59:45 | chop(do ... search) | Cross-site scripting vulnerability due to $@. | tst.js:59:21:59:37 | document.location | user-provided value | +| tst.js:61:16:61:32 | wrap(chop(bar())) | tst.js:34:10:34:26 | document.location | tst.js:61:16:61:32 | wrap(chop(bar())) | Cross-site scripting vulnerability due to $@. | tst.js:34:10:34:26 | document.location | user-provided value | +| tst.js:65:18:65:18 | s | tst.js:67:25:67:41 | document.location | tst.js:65:18:65:18 | s | Cross-site scripting vulnerability due to $@. | tst.js:67:25:67:41 | document.location | user-provided value | +| tst.js:65:18:65:18 | s | tst.js:68:25:68:41 | document.location | tst.js:65:18:65:18 | s | Cross-site scripting vulnerability due to $@. | tst.js:68:25:68:41 | document.location | user-provided value | +| tst.js:71:16:71:20 | bar() | tst.js:34:10:34:26 | document.location | tst.js:71:16:71:20 | bar() | Cross-site scripting vulnerability due to $@. | tst.js:34:10:34:26 | document.location | user-provided value | +| tst.js:76:20:76:20 | x | tst.js:73:3:73:19 | document.location | tst.js:76:20:76:20 | x | Cross-site scripting vulnerability due to $@. | tst.js:73:3:73:19 | document.location | user-provided value | +| tst.js:80:49:80:72 | documen ... .search | tst.js:80:49:80:65 | document.location | tst.js:80:49:80:72 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:80:49:80:65 | document.location | user-provided value | +| tst.js:84:26:84:49 | documen ... .search | tst.js:84:26:84:42 | document.location | tst.js:84:26:84:49 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:84:26:84:42 | document.location | user-provided value | +| tst.js:85:25:85:48 | documen ... .search | tst.js:85:25:85:41 | document.location | tst.js:85:25:85:48 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:85:25:85:41 | document.location | user-provided value | +| tst.js:87:33:87:56 | documen ... .search | tst.js:87:33:87:49 | document.location | tst.js:87:33:87:56 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:87:33:87:49 | document.location | user-provided value | +| tst.js:88:32:88:55 | documen ... .search | tst.js:88:32:88:48 | document.location | tst.js:88:32:88:55 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:88:32:88:48 | document.location | user-provided value | +| tst.js:93:39:93:62 | documen ... .search | tst.js:93:39:93:55 | document.location | tst.js:93:39:93:62 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:93:39:93:55 | document.location | user-provided value | +| tst.js:99:30:99:53 | documen ... .search | tst.js:99:30:99:46 | document.location | tst.js:99:30:99:53 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:99:30:99:46 | document.location | user-provided value | +| tst.js:105:25:105:48 | documen ... .search | tst.js:105:25:105:41 | document.location | tst.js:105:25:105:48 | documen ... .search | Cross-site scripting vulnerability due to $@. | tst.js:105:25:105:41 | document.location | user-provided value | +| tst.js:113:18:113:18 | v | tst.js:110:11:110:27 | document.location | tst.js:113:18:113:18 | v | Cross-site scripting vulnerability due to $@. | tst.js:110:11:110:27 | document.location | user-provided value | +| tst.js:148:49:148:49 | v | tst.js:145:29:145:43 | window.location | tst.js:148:49:148:49 | v | Cross-site scripting vulnerability due to $@. | tst.js:145:29:145:43 | window.location | user-provided value | +| tst.js:152:29:152:46 | xssSourceService() | tst.js:155:40:155:54 | window.location | tst.js:152:29:152:46 | xssSourceService() | Cross-site scripting vulnerability due to $@. | tst.js:155:40:155:54 | window.location | user-provided value | +| tst.js:177:28:177:33 | target | tst.js:174:18:174:34 | document.location | tst.js:177:28:177:33 | target | Cross-site scripting vulnerability due to $@. | tst.js:174:18:174:34 | document.location | user-provided value | +| tst.js:183:31:183:37 | tainted | tst.js:181:19:181:35 | document.location | tst.js:183:31:183:37 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | +| tst.js:185:42:185:48 | tainted | tst.js:181:19:181:35 | document.location | tst.js:185:42:185:48 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | +| tst.js:186:33:186:39 | tainted | tst.js:181:19:181:35 | document.location | tst.js:186:33:186:39 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | +| tst.js:188:54:188:60 | tainted | tst.js:181:19:181:35 | document.location | tst.js:188:54:188:60 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | +| tst.js:189:45:189:51 | tainted | tst.js:181:19:181:35 | document.location | tst.js:189:45:189:51 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:181:19:181:35 | document.location | user-provided value | +| tst.js:196:67:196:73 | tainted | tst.js:194:19:194:35 | document.location | tst.js:196:67:196:73 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:197:67:197:73 | tainted | tst.js:194:19:194:35 | document.location | tst.js:197:67:197:73 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:209:28:209:46 | this.state.tainted1 | tst.js:194:19:194:35 | document.location | tst.js:209:28:209:46 | this.state.tainted1 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:210:28:210:46 | this.state.tainted2 | tst.js:194:19:194:35 | document.location | tst.js:210:28:210:46 | this.state.tainted2 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:211:28:211:46 | this.state.tainted3 | tst.js:194:19:194:35 | document.location | tst.js:211:28:211:46 | this.state.tainted3 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:215:32:215:49 | prevState.tainted4 | tst.js:194:19:194:35 | document.location | tst.js:215:32:215:49 | prevState.tainted4 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:222:28:222:46 | this.props.tainted1 | tst.js:194:19:194:35 | document.location | tst.js:222:28:222:46 | this.props.tainted1 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:223:28:223:46 | this.props.tainted2 | tst.js:194:19:194:35 | document.location | tst.js:223:28:223:46 | this.props.tainted2 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:224:28:224:46 | this.props.tainted3 | tst.js:194:19:194:35 | document.location | tst.js:224:28:224:46 | this.props.tainted3 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:228:32:228:49 | prevProps.tainted4 | tst.js:194:19:194:35 | document.location | tst.js:228:32:228:49 | prevProps.tainted4 | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | +| tst.js:248:60:248:82 | this.st ... Tainted | tst.js:194:19:194:35 | document.location | tst.js:248:60:248:82 | this.st ... Tainted | Cross-site scripting vulnerability due to $@. | tst.js:194:19:194:35 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/SqlInjection.expected index e6c84156dd0c..319e938aecdb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/SqlInjection.expected @@ -1,22 +1,160 @@ -| mongodb.js:18:16:18:20 | query | This query depends on $@. | mongodb.js:13:19:13:26 | req.body | a user-provided value | -| mongodb.js:32:18:32:45 | { title ... itle) } | This query depends on $@. | mongodb.js:26:19:26:26 | req.body | a user-provided value | -| mongodb.js:54:16:54:20 | query | This query depends on $@. | mongodb.js:49:19:49:33 | req.query.title | a user-provided value | -| mongodb_bodySafe.js:29:16:29:20 | query | This query depends on $@. | mongodb_bodySafe.js:24:19:24:33 | req.query.title | a user-provided value | -| mongoose.js:27:20:27:24 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:30:25:30:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:33:24:33:28 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:36:31:36:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:39:19:39:23 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:42:22:42:26 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:45:31:45:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:48:31:48:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:51:31:51:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:54:25:54:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:57:21:57:25 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:60:25:60:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongoose.js:63:24:63:28 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | -| mongooseJsonParse.js:23:19:23:23 | query | This query depends on $@. | mongooseJsonParse.js:20:30:20:43 | req.query.data | a user-provided value | -| tst2.js:9:27:9:84 | "select ... d + "'" | This query depends on $@. | tst2.js:9:66:9:78 | req.params.id | a user-provided value | -| tst3.js:10:14:10:19 | query1 | This query depends on $@. | tst3.js:9:16:9:34 | req.params.category | a user-provided value | -| tst4.js:8:10:8:66 | 'SELECT ... d + '"' | This query depends on $@. | tst4.js:8:46:8:60 | $routeParams.id | a user-provided value | -| tst.js:10:10:10:64 | 'SELECT ... d + '"' | This query depends on $@. | tst.js:10:46:10:58 | req.params.id | a user-provided value | +nodes +| mongodb.js:12:11:12:20 | query | +| mongodb.js:12:19:12:20 | {} | +| mongodb.js:13:19:13:26 | req.body | +| mongodb.js:13:19:13:32 | req.body.title | +| mongodb.js:14:59:14:58 | query | +| mongodb.js:18:16:18:20 | query | +| mongodb.js:26:11:26:32 | title | +| mongodb.js:26:19:26:26 | req.body | +| mongodb.js:26:19:26:32 | req.body.title | +| mongodb.js:27:11:27:35 | title | +| mongodb.js:32:18:32:45 | { title ... itle) } | +| mongodb.js:32:27:32:43 | JSON.parse(title) | +| mongodb.js:32:38:32:42 | title | +| mongodb.js:48:11:48:20 | query | +| mongodb.js:48:19:48:20 | {} | +| mongodb.js:49:19:49:33 | req.query.title | +| mongodb.js:50:59:50:58 | query | +| mongodb.js:54:16:54:20 | query | +| mongodb_bodySafe.js:23:11:23:20 | query | +| mongodb_bodySafe.js:23:19:23:20 | {} | +| mongodb_bodySafe.js:24:19:24:33 | req.query.title | +| mongodb_bodySafe.js:25:59:25:58 | query | +| mongodb_bodySafe.js:29:16:29:20 | query | +| mongoose.js:20:11:20:20 | query | +| mongoose.js:20:19:20:20 | {} | +| mongoose.js:21:19:21:26 | req.body | +| mongoose.js:21:19:21:32 | req.body.title | +| mongoose.js:27:20:27:24 | query | +| mongoose.js:30:25:30:29 | query | +| mongoose.js:33:24:33:28 | query | +| mongoose.js:36:31:36:35 | query | +| mongoose.js:39:19:39:23 | query | +| mongoose.js:42:22:42:26 | query | +| mongoose.js:45:31:45:35 | query | +| mongoose.js:48:31:48:35 | query | +| mongoose.js:51:31:51:35 | query | +| mongoose.js:54:25:54:29 | query | +| mongoose.js:57:21:57:25 | query | +| mongoose.js:60:25:60:29 | query | +| mongoose.js:63:24:63:28 | query | +| mongooseJsonParse.js:19:11:19:20 | query | +| mongooseJsonParse.js:19:19:19:20 | {} | +| mongooseJsonParse.js:20:19:20:44 | JSON.pa ... y.data) | +| mongooseJsonParse.js:20:19:20:50 | JSON.pa ... ).title | +| mongooseJsonParse.js:20:30:20:43 | req.query.data | +| mongooseJsonParse.js:23:19:23:23 | query | +| tst2.js:9:27:9:78 | "select ... rams.id | +| tst2.js:9:27:9:84 | "select ... d + "'" | +| tst2.js:9:66:9:78 | req.params.id | +| tst3.js:8:7:9:55 | query1 | +| tst3.js:8:16:9:34 | "SELECT ... ategory | +| tst3.js:8:16:9:55 | "SELECT ... PRICE" | +| tst3.js:9:16:9:34 | req.params.category | +| tst3.js:10:14:10:19 | query1 | +| tst4.js:8:10:8:60 | 'SELECT ... rams.id | +| tst4.js:8:10:8:66 | 'SELECT ... d + '"' | +| tst4.js:8:46:8:60 | $routeParams.id | +| tst.js:10:10:10:58 | 'SELECT ... rams.id | +| tst.js:10:10:10:64 | 'SELECT ... d + '"' | +| tst.js:10:46:10:58 | req.params.id | +edges +| mongodb.js:12:11:12:20 | query | mongodb.js:14:59:14:58 | query | +| mongodb.js:12:19:12:20 | {} | mongodb.js:12:11:12:20 | query | +| mongodb.js:13:19:13:26 | req.body | mongodb.js:13:19:13:32 | req.body.title | +| mongodb.js:13:19:13:32 | req.body.title | mongodb.js:12:11:12:20 | query | +| mongodb.js:13:19:13:32 | req.body.title | mongodb.js:12:19:12:20 | {} | +| mongodb.js:13:19:13:32 | req.body.title | mongodb.js:14:59:14:58 | query | +| mongodb.js:13:19:13:32 | req.body.title | mongodb.js:18:16:18:20 | query | +| mongodb.js:14:59:14:58 | query | mongodb.js:18:16:18:20 | query | +| mongodb.js:26:11:26:32 | title | mongodb.js:27:11:27:35 | title | +| mongodb.js:26:19:26:26 | req.body | mongodb.js:26:19:26:32 | req.body.title | +| mongodb.js:26:19:26:32 | req.body.title | mongodb.js:26:11:26:32 | title | +| mongodb.js:27:11:27:35 | title | mongodb.js:32:38:32:42 | title | +| mongodb.js:32:27:32:43 | JSON.parse(title) | mongodb.js:32:18:32:45 | { title ... itle) } | +| mongodb.js:32:38:32:42 | title | mongodb.js:32:27:32:43 | JSON.parse(title) | +| mongodb.js:48:11:48:20 | query | mongodb.js:50:59:50:58 | query | +| mongodb.js:48:19:48:20 | {} | mongodb.js:48:11:48:20 | query | +| mongodb.js:49:19:49:33 | req.query.title | mongodb.js:48:11:48:20 | query | +| mongodb.js:49:19:49:33 | req.query.title | mongodb.js:48:19:48:20 | {} | +| mongodb.js:49:19:49:33 | req.query.title | mongodb.js:50:59:50:58 | query | +| mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query | +| mongodb.js:50:59:50:58 | query | mongodb.js:54:16:54:20 | query | +| mongodb_bodySafe.js:23:11:23:20 | query | mongodb_bodySafe.js:25:59:25:58 | query | +| mongodb_bodySafe.js:23:19:23:20 | {} | mongodb_bodySafe.js:23:11:23:20 | query | +| mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:23:11:23:20 | query | +| mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:23:19:23:20 | {} | +| mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:25:59:25:58 | query | +| mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query | +| mongodb_bodySafe.js:25:59:25:58 | query | mongodb_bodySafe.js:29:16:29:20 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:27:20:27:24 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:30:25:30:29 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:33:24:33:28 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:36:31:36:35 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:39:19:39:23 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:42:22:42:26 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:45:31:45:35 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:48:31:48:35 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:51:31:51:35 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:54:25:54:29 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:57:21:57:25 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:60:25:60:29 | query | +| mongoose.js:20:11:20:20 | query | mongoose.js:63:24:63:28 | query | +| mongoose.js:20:19:20:20 | {} | mongoose.js:20:11:20:20 | query | +| mongoose.js:21:19:21:26 | req.body | mongoose.js:21:19:21:32 | req.body.title | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:20:11:20:20 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:20:19:20:20 | {} | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:27:20:27:24 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:30:25:30:29 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:33:24:33:28 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:36:31:36:35 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:39:19:39:23 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:42:22:42:26 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:45:31:45:35 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:48:31:48:35 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:51:31:51:35 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:54:25:54:29 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:57:21:57:25 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:60:25:60:29 | query | +| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:63:24:63:28 | query | +| mongooseJsonParse.js:19:11:19:20 | query | mongooseJsonParse.js:23:19:23:23 | query | +| mongooseJsonParse.js:19:19:19:20 | {} | mongooseJsonParse.js:19:11:19:20 | query | +| mongooseJsonParse.js:20:19:20:44 | JSON.pa ... y.data) | mongooseJsonParse.js:20:19:20:50 | JSON.pa ... ).title | +| mongooseJsonParse.js:20:19:20:50 | JSON.pa ... ).title | mongooseJsonParse.js:19:11:19:20 | query | +| mongooseJsonParse.js:20:19:20:50 | JSON.pa ... ).title | mongooseJsonParse.js:19:19:19:20 | {} | +| mongooseJsonParse.js:20:19:20:50 | JSON.pa ... ).title | mongooseJsonParse.js:23:19:23:23 | query | +| mongooseJsonParse.js:20:30:20:43 | req.query.data | mongooseJsonParse.js:20:19:20:44 | JSON.pa ... y.data) | +| tst2.js:9:27:9:78 | "select ... rams.id | tst2.js:9:27:9:84 | "select ... d + "'" | +| tst2.js:9:66:9:78 | req.params.id | tst2.js:9:27:9:78 | "select ... rams.id | +| tst3.js:8:7:9:55 | query1 | tst3.js:10:14:10:19 | query1 | +| tst3.js:8:16:9:34 | "SELECT ... ategory | tst3.js:8:16:9:55 | "SELECT ... PRICE" | +| tst3.js:8:16:9:55 | "SELECT ... PRICE" | tst3.js:8:7:9:55 | query1 | +| tst3.js:9:16:9:34 | req.params.category | tst3.js:8:16:9:34 | "SELECT ... ategory | +| tst4.js:8:10:8:60 | 'SELECT ... rams.id | tst4.js:8:10:8:66 | 'SELECT ... d + '"' | +| tst4.js:8:46:8:60 | $routeParams.id | tst4.js:8:10:8:60 | 'SELECT ... rams.id | +| tst.js:10:10:10:58 | 'SELECT ... rams.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | +| tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:58 | 'SELECT ... rams.id | +#select +| mongodb.js:18:16:18:20 | query | mongodb.js:13:19:13:26 | req.body | mongodb.js:18:16:18:20 | query | This query depends on $@. | mongodb.js:13:19:13:26 | req.body | a user-provided value | +| mongodb.js:32:18:32:45 | { title ... itle) } | mongodb.js:26:19:26:26 | req.body | mongodb.js:32:18:32:45 | { title ... itle) } | This query depends on $@. | mongodb.js:26:19:26:26 | req.body | a user-provided value | +| mongodb.js:54:16:54:20 | query | mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query | This query depends on $@. | mongodb.js:49:19:49:33 | req.query.title | a user-provided value | +| mongodb_bodySafe.js:29:16:29:20 | query | mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query | This query depends on $@. | mongodb_bodySafe.js:24:19:24:33 | req.query.title | a user-provided value | +| mongoose.js:27:20:27:24 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:27:20:27:24 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:30:25:30:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:30:25:30:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:33:24:33:28 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:33:24:33:28 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:36:31:36:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:36:31:36:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:39:19:39:23 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:39:19:39:23 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:42:22:42:26 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:42:22:42:26 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:45:31:45:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:45:31:45:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:48:31:48:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:48:31:48:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:51:31:51:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:51:31:51:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:54:25:54:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:54:25:54:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:57:21:57:25 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:57:21:57:25 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:60:25:60:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:60:25:60:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongoose.js:63:24:63:28 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:63:24:63:28 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | +| mongooseJsonParse.js:23:19:23:23 | query | mongooseJsonParse.js:20:30:20:43 | req.query.data | mongooseJsonParse.js:23:19:23:23 | query | This query depends on $@. | mongooseJsonParse.js:20:30:20:43 | req.query.data | a user-provided value | +| tst2.js:9:27:9:84 | "select ... d + "'" | tst2.js:9:66:9:78 | req.params.id | tst2.js:9:27:9:84 | "select ... d + "'" | This query depends on $@. | tst2.js:9:66:9:78 | req.params.id | a user-provided value | +| tst3.js:10:14:10:19 | query1 | tst3.js:9:16:9:34 | req.params.category | tst3.js:10:14:10:19 | query1 | This query depends on $@. | tst3.js:9:16:9:34 | req.params.category | a user-provided value | +| tst4.js:8:10:8:66 | 'SELECT ... d + '"' | tst4.js:8:46:8:60 | $routeParams.id | tst4.js:8:10:8:66 | 'SELECT ... d + '"' | This query depends on $@. | tst4.js:8:46:8:60 | $routeParams.id | a user-provided value | +| tst.js:10:10:10:64 | 'SELECT ... d + '"' | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | This query depends on $@. | tst.js:10:46:10:58 | req.params.id | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection.expected index 988c4d5e2e39..3abab2036520 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection.expected @@ -1,25 +1,84 @@ -| angularjs.js:10:22:10:36 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:10:22:10:36 | document.cookie | User-provided value | -| angularjs.js:13:23:13:37 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:13:23:13:37 | document.cookie | User-provided value | -| angularjs.js:16:28:16:42 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:16:28:16:42 | document.cookie | User-provided value | -| angularjs.js:19:22:19:36 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:19:22:19:36 | document.cookie | User-provided value | -| angularjs.js:22:27:22:41 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:22:27:22:41 | document.cookie | User-provided value | -| angularjs.js:25:23:25:37 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:25:23:25:37 | document.cookie | User-provided value | -| angularjs.js:28:33:28:47 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:28:33:28:47 | document.cookie | User-provided value | -| angularjs.js:31:28:31:42 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:31:28:31:42 | document.cookie | User-provided value | -| angularjs.js:34:18:34:32 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:34:18:34:32 | document.cookie | User-provided value | -| angularjs.js:40:18:40:32 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:40:18:40:32 | document.cookie | User-provided value | -| angularjs.js:44:17:44:31 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:44:17:44:31 | document.cookie | User-provided value | -| angularjs.js:47:16:47:30 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:47:16:47:30 | document.cookie | User-provided value | -| angularjs.js:50:22:50:36 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:50:22:50:36 | document.cookie | User-provided value | -| angularjs.js:53:32:53:46 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:53:32:53:46 | document.cookie | User-provided value | -| eslint-escope-build.js:21:16:21:16 | c | $@ flows to here and is interpreted as code. | eslint-escope-build.js:20:22:20:22 | c | User-provided value | -| express.js:7:24:7:69 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:7:44:7:62 | req.param("wobble") | User-provided value | -| express.js:9:34:9:79 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:9:54:9:72 | req.param("wobble") | User-provided value | -| express.js:12:8:12:53 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:12:28:12:46 | req.param("wobble") | User-provided value | -| react-native.js:8:32:8:38 | tainted | $@ flows to here and is interpreted as code. | react-native.js:7:17:7:33 | req.param("code") | User-provided value | -| react-native.js:10:23:10:29 | tainted | $@ flows to here and is interpreted as code. | react-native.js:7:17:7:33 | req.param("code") | User-provided value | -| tst.js:2:6:2:83 | documen ... t=")+8) | $@ flows to here and is interpreted as code. | tst.js:2:6:2:22 | document.location | User-provided value | -| tst.js:5:12:5:33 | documen ... on.hash | $@ flows to here and is interpreted as code. | tst.js:5:12:5:28 | document.location | User-provided value | -| tst.js:14:10:14:65 | documen ... , "$1") | $@ flows to here and is interpreted as code. | tst.js:14:10:14:24 | document.cookie | User-provided value | -| tst.js:17:21:17:42 | documen ... on.hash | $@ flows to here and is interpreted as code. | tst.js:17:21:17:37 | document.location | User-provided value | -| tst.js:20:30:20:51 | documen ... on.hash | $@ flows to here and is interpreted as code. | tst.js:20:30:20:46 | document.location | User-provided value | +nodes +| angularjs.js:10:22:10:36 | document.cookie | +| angularjs.js:13:23:13:37 | document.cookie | +| angularjs.js:16:28:16:42 | document.cookie | +| angularjs.js:19:22:19:36 | document.cookie | +| angularjs.js:22:27:22:41 | document.cookie | +| angularjs.js:25:23:25:37 | document.cookie | +| angularjs.js:28:33:28:47 | document.cookie | +| angularjs.js:31:28:31:42 | document.cookie | +| angularjs.js:34:18:34:32 | document.cookie | +| angularjs.js:40:18:40:32 | document.cookie | +| angularjs.js:44:17:44:31 | document.cookie | +| angularjs.js:47:16:47:30 | document.cookie | +| angularjs.js:50:22:50:36 | document.cookie | +| angularjs.js:53:32:53:46 | document.cookie | +| eslint-escope-build.js:20:22:20:22 | c | +| eslint-escope-build.js:21:16:21:16 | c | +| express.js:7:24:7:62 | "return ... obble") | +| express.js:7:24:7:69 | "return ... + "];" | +| express.js:7:44:7:62 | req.param("wobble") | +| express.js:9:34:9:72 | "return ... obble") | +| express.js:9:34:9:79 | "return ... + "];" | +| express.js:9:54:9:72 | req.param("wobble") | +| express.js:12:8:12:46 | "return ... obble") | +| express.js:12:8:12:53 | "return ... + "];" | +| express.js:12:28:12:46 | req.param("wobble") | +| react-native.js:7:7:7:33 | tainted | +| react-native.js:7:17:7:33 | req.param("code") | +| react-native.js:8:32:8:38 | tainted | +| react-native.js:10:23:10:29 | tainted | +| tst.js:2:6:2:22 | document.location | +| tst.js:2:6:2:27 | documen ... on.href | +| tst.js:2:6:2:83 | documen ... t=")+8) | +| tst.js:5:12:5:28 | document.location | +| tst.js:5:12:5:33 | documen ... on.hash | +| tst.js:14:10:14:24 | document.cookie | +| tst.js:14:10:14:65 | documen ... , "$1") | +| tst.js:17:21:17:37 | document.location | +| tst.js:17:21:17:42 | documen ... on.hash | +| tst.js:20:30:20:46 | document.location | +| tst.js:20:30:20:51 | documen ... on.hash | +edges +| eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | +| express.js:7:24:7:62 | "return ... obble") | express.js:7:24:7:69 | "return ... + "];" | +| express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:62 | "return ... obble") | +| express.js:9:34:9:72 | "return ... obble") | express.js:9:34:9:79 | "return ... + "];" | +| express.js:9:54:9:72 | req.param("wobble") | express.js:9:34:9:72 | "return ... obble") | +| express.js:12:8:12:46 | "return ... obble") | express.js:12:8:12:53 | "return ... + "];" | +| express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:46 | "return ... obble") | +| react-native.js:7:7:7:33 | tainted | react-native.js:8:32:8:38 | tainted | +| react-native.js:7:7:7:33 | tainted | react-native.js:10:23:10:29 | tainted | +| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | +| tst.js:2:6:2:22 | document.location | tst.js:2:6:2:27 | documen ... on.href | +| tst.js:2:6:2:27 | documen ... on.href | tst.js:2:6:2:83 | documen ... t=")+8) | +| tst.js:5:12:5:28 | document.location | tst.js:5:12:5:33 | documen ... on.hash | +| tst.js:14:10:14:24 | document.cookie | tst.js:14:10:14:65 | documen ... , "$1") | +| tst.js:17:21:17:37 | document.location | tst.js:17:21:17:42 | documen ... on.hash | +| tst.js:20:30:20:46 | document.location | tst.js:20:30:20:51 | documen ... on.hash | +#select +| angularjs.js:10:22:10:36 | document.cookie | angularjs.js:10:22:10:36 | document.cookie | angularjs.js:10:22:10:36 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:10:22:10:36 | document.cookie | User-provided value | +| angularjs.js:13:23:13:37 | document.cookie | angularjs.js:13:23:13:37 | document.cookie | angularjs.js:13:23:13:37 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:13:23:13:37 | document.cookie | User-provided value | +| angularjs.js:16:28:16:42 | document.cookie | angularjs.js:16:28:16:42 | document.cookie | angularjs.js:16:28:16:42 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:16:28:16:42 | document.cookie | User-provided value | +| angularjs.js:19:22:19:36 | document.cookie | angularjs.js:19:22:19:36 | document.cookie | angularjs.js:19:22:19:36 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:19:22:19:36 | document.cookie | User-provided value | +| angularjs.js:22:27:22:41 | document.cookie | angularjs.js:22:27:22:41 | document.cookie | angularjs.js:22:27:22:41 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:22:27:22:41 | document.cookie | User-provided value | +| angularjs.js:25:23:25:37 | document.cookie | angularjs.js:25:23:25:37 | document.cookie | angularjs.js:25:23:25:37 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:25:23:25:37 | document.cookie | User-provided value | +| angularjs.js:28:33:28:47 | document.cookie | angularjs.js:28:33:28:47 | document.cookie | angularjs.js:28:33:28:47 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:28:33:28:47 | document.cookie | User-provided value | +| angularjs.js:31:28:31:42 | document.cookie | angularjs.js:31:28:31:42 | document.cookie | angularjs.js:31:28:31:42 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:31:28:31:42 | document.cookie | User-provided value | +| angularjs.js:34:18:34:32 | document.cookie | angularjs.js:34:18:34:32 | document.cookie | angularjs.js:34:18:34:32 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:34:18:34:32 | document.cookie | User-provided value | +| angularjs.js:40:18:40:32 | document.cookie | angularjs.js:40:18:40:32 | document.cookie | angularjs.js:40:18:40:32 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:40:18:40:32 | document.cookie | User-provided value | +| angularjs.js:44:17:44:31 | document.cookie | angularjs.js:44:17:44:31 | document.cookie | angularjs.js:44:17:44:31 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:44:17:44:31 | document.cookie | User-provided value | +| angularjs.js:47:16:47:30 | document.cookie | angularjs.js:47:16:47:30 | document.cookie | angularjs.js:47:16:47:30 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:47:16:47:30 | document.cookie | User-provided value | +| angularjs.js:50:22:50:36 | document.cookie | angularjs.js:50:22:50:36 | document.cookie | angularjs.js:50:22:50:36 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:50:22:50:36 | document.cookie | User-provided value | +| angularjs.js:53:32:53:46 | document.cookie | angularjs.js:53:32:53:46 | document.cookie | angularjs.js:53:32:53:46 | document.cookie | $@ flows to here and is interpreted as code. | angularjs.js:53:32:53:46 | document.cookie | User-provided value | +| eslint-escope-build.js:21:16:21:16 | c | eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | $@ flows to here and is interpreted as code. | eslint-escope-build.js:20:22:20:22 | c | User-provided value | +| express.js:7:24:7:69 | "return ... + "];" | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:7:44:7:62 | req.param("wobble") | User-provided value | +| express.js:9:34:9:79 | "return ... + "];" | express.js:9:54:9:72 | req.param("wobble") | express.js:9:34:9:79 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:9:54:9:72 | req.param("wobble") | User-provided value | +| express.js:12:8:12:53 | "return ... + "];" | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:12:28:12:46 | req.param("wobble") | User-provided value | +| react-native.js:8:32:8:38 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:32:8:38 | tainted | $@ flows to here and is interpreted as code. | react-native.js:7:17:7:33 | req.param("code") | User-provided value | +| react-native.js:10:23:10:29 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:10:23:10:29 | tainted | $@ flows to here and is interpreted as code. | react-native.js:7:17:7:33 | req.param("code") | User-provided value | +| tst.js:2:6:2:83 | documen ... t=")+8) | tst.js:2:6:2:22 | document.location | tst.js:2:6:2:83 | documen ... t=")+8) | $@ flows to here and is interpreted as code. | tst.js:2:6:2:22 | document.location | User-provided value | +| tst.js:5:12:5:33 | documen ... on.hash | tst.js:5:12:5:28 | document.location | tst.js:5:12:5:33 | documen ... on.hash | $@ flows to here and is interpreted as code. | tst.js:5:12:5:28 | document.location | User-provided value | +| tst.js:14:10:14:65 | documen ... , "$1") | tst.js:14:10:14:24 | document.cookie | tst.js:14:10:14:65 | documen ... , "$1") | $@ flows to here and is interpreted as code. | tst.js:14:10:14:24 | document.cookie | User-provided value | +| tst.js:17:21:17:42 | documen ... on.hash | tst.js:17:21:17:37 | document.location | tst.js:17:21:17:42 | documen ... on.hash | $@ flows to here and is interpreted as code. | tst.js:17:21:17:37 | document.location | User-provided value | +| tst.js:20:30:20:51 | documen ... on.hash | tst.js:20:30:20:46 | document.location | tst.js:20:30:20:51 | documen ... on.hash | $@ flows to here and is interpreted as code. | tst.js:20:30:20:46 | document.location | User-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-134/TaintedFormatString.expected b/javascript/ql/test/query-tests/Security/CWE-134/TaintedFormatString.expected index 92190be6b619..161ad1ecbbb7 100644 --- a/javascript/ql/test/query-tests/Security/CWE-134/TaintedFormatString.expected +++ b/javascript/ql/test/query-tests/Security/CWE-134/TaintedFormatString.expected @@ -1,20 +1,43 @@ -| tst.js:5:15:5:30 | req.query.format | $@ flows here and is used in a format string. | tst.js:5:15:5:30 | req.query.format | User-provided value | -| tst.js:6:26:6:41 | req.query.format | $@ flows here and is used in a format string. | tst.js:6:26:6:41 | req.query.format | User-provided value | -| tst.js:7:15:7:30 | req.query.format | $@ flows here and is used in a format string. | tst.js:7:15:7:30 | req.query.format | User-provided value | -| tst.js:8:17:8:32 | req.query.format | $@ flows here and is used in a format string. | tst.js:8:17:8:32 | req.query.format | User-provided value | -| tst.js:9:16:9:31 | req.query.format | $@ flows here and is used in a format string. | tst.js:9:16:9:31 | req.query.format | User-provided value | -| tst.js:10:12:10:27 | req.query.format | $@ flows here and is used in a format string. | tst.js:10:12:10:27 | req.query.format | User-provided value | -| tst.js:11:32:11:47 | req.query.format | $@ flows here and is used in a format string. | tst.js:11:32:11:47 | req.query.format | User-provided value | -| tst.js:12:21:12:36 | req.query.format | $@ flows here and is used in a format string. | tst.js:12:21:12:36 | req.query.format | User-provided value | -| tst.js:13:35:13:50 | req.query.format | $@ flows here and is used in a format string. | tst.js:13:35:13:50 | req.query.format | User-provided value | -| tst.js:14:29:14:44 | req.query.format | $@ flows here and is used in a format string. | tst.js:14:29:14:44 | req.query.format | User-provided value | -| tst.js:15:30:15:45 | req.query.format | $@ flows here and is used in a format string. | tst.js:15:30:15:45 | req.query.format | User-provided value | -| tst.js:16:26:16:41 | req.query.format | $@ flows here and is used in a format string. | tst.js:16:26:16:41 | req.query.format | User-provided value | -| tst.js:17:30:17:45 | req.query.format | $@ flows here and is used in a format string. | tst.js:17:30:17:45 | req.query.format | User-provided value | -| tst.js:18:38:18:53 | req.query.format | $@ flows here and is used in a format string. | tst.js:18:38:18:53 | req.query.format | User-provided value | -| tst.js:20:17:20:32 | req.query.format | $@ flows here and is used in a format string. | tst.js:20:17:20:32 | req.query.format | User-provided value | -| tst.js:21:16:21:31 | req.query.format | $@ flows here and is used in a format string. | tst.js:21:16:21:31 | req.query.format | User-provided value | -| tst.js:22:17:22:32 | req.query.format | $@ flows here and is used in a format string. | tst.js:22:17:22:32 | req.query.format | User-provided value | -| tst.js:24:25:24:40 | req.query.format | $@ flows here and is used in a format string. | tst.js:24:25:24:40 | req.query.format | User-provided value | -| tst.js:25:33:25:48 | req.query.format | $@ flows here and is used in a format string. | tst.js:25:33:25:48 | req.query.format | User-provided value | -| tst.js:26:34:26:49 | req.query.format | $@ flows here and is used in a format string. | tst.js:26:34:26:49 | req.query.format | User-provided value | +nodes +| tst.js:5:15:5:30 | req.query.format | +| tst.js:6:26:6:41 | req.query.format | +| tst.js:7:15:7:30 | req.query.format | +| tst.js:8:17:8:32 | req.query.format | +| tst.js:9:16:9:31 | req.query.format | +| tst.js:10:12:10:27 | req.query.format | +| tst.js:11:32:11:47 | req.query.format | +| tst.js:12:21:12:36 | req.query.format | +| tst.js:13:35:13:50 | req.query.format | +| tst.js:14:29:14:44 | req.query.format | +| tst.js:15:30:15:45 | req.query.format | +| tst.js:16:26:16:41 | req.query.format | +| tst.js:17:30:17:45 | req.query.format | +| tst.js:18:38:18:53 | req.query.format | +| tst.js:20:17:20:32 | req.query.format | +| tst.js:21:16:21:31 | req.query.format | +| tst.js:22:17:22:32 | req.query.format | +| tst.js:24:25:24:40 | req.query.format | +| tst.js:25:33:25:48 | req.query.format | +| tst.js:26:34:26:49 | req.query.format | +edges +#select +| tst.js:5:15:5:30 | req.query.format | tst.js:5:15:5:30 | req.query.format | tst.js:5:15:5:30 | req.query.format | $@ flows here and is used in a format string. | tst.js:5:15:5:30 | req.query.format | User-provided value | +| tst.js:6:26:6:41 | req.query.format | tst.js:6:26:6:41 | req.query.format | tst.js:6:26:6:41 | req.query.format | $@ flows here and is used in a format string. | tst.js:6:26:6:41 | req.query.format | User-provided value | +| tst.js:7:15:7:30 | req.query.format | tst.js:7:15:7:30 | req.query.format | tst.js:7:15:7:30 | req.query.format | $@ flows here and is used in a format string. | tst.js:7:15:7:30 | req.query.format | User-provided value | +| tst.js:8:17:8:32 | req.query.format | tst.js:8:17:8:32 | req.query.format | tst.js:8:17:8:32 | req.query.format | $@ flows here and is used in a format string. | tst.js:8:17:8:32 | req.query.format | User-provided value | +| tst.js:9:16:9:31 | req.query.format | tst.js:9:16:9:31 | req.query.format | tst.js:9:16:9:31 | req.query.format | $@ flows here and is used in a format string. | tst.js:9:16:9:31 | req.query.format | User-provided value | +| tst.js:10:12:10:27 | req.query.format | tst.js:10:12:10:27 | req.query.format | tst.js:10:12:10:27 | req.query.format | $@ flows here and is used in a format string. | tst.js:10:12:10:27 | req.query.format | User-provided value | +| tst.js:11:32:11:47 | req.query.format | tst.js:11:32:11:47 | req.query.format | tst.js:11:32:11:47 | req.query.format | $@ flows here and is used in a format string. | tst.js:11:32:11:47 | req.query.format | User-provided value | +| tst.js:12:21:12:36 | req.query.format | tst.js:12:21:12:36 | req.query.format | tst.js:12:21:12:36 | req.query.format | $@ flows here and is used in a format string. | tst.js:12:21:12:36 | req.query.format | User-provided value | +| tst.js:13:35:13:50 | req.query.format | tst.js:13:35:13:50 | req.query.format | tst.js:13:35:13:50 | req.query.format | $@ flows here and is used in a format string. | tst.js:13:35:13:50 | req.query.format | User-provided value | +| tst.js:14:29:14:44 | req.query.format | tst.js:14:29:14:44 | req.query.format | tst.js:14:29:14:44 | req.query.format | $@ flows here and is used in a format string. | tst.js:14:29:14:44 | req.query.format | User-provided value | +| tst.js:15:30:15:45 | req.query.format | tst.js:15:30:15:45 | req.query.format | tst.js:15:30:15:45 | req.query.format | $@ flows here and is used in a format string. | tst.js:15:30:15:45 | req.query.format | User-provided value | +| tst.js:16:26:16:41 | req.query.format | tst.js:16:26:16:41 | req.query.format | tst.js:16:26:16:41 | req.query.format | $@ flows here and is used in a format string. | tst.js:16:26:16:41 | req.query.format | User-provided value | +| tst.js:17:30:17:45 | req.query.format | tst.js:17:30:17:45 | req.query.format | tst.js:17:30:17:45 | req.query.format | $@ flows here and is used in a format string. | tst.js:17:30:17:45 | req.query.format | User-provided value | +| tst.js:18:38:18:53 | req.query.format | tst.js:18:38:18:53 | req.query.format | tst.js:18:38:18:53 | req.query.format | $@ flows here and is used in a format string. | tst.js:18:38:18:53 | req.query.format | User-provided value | +| tst.js:20:17:20:32 | req.query.format | tst.js:20:17:20:32 | req.query.format | tst.js:20:17:20:32 | req.query.format | $@ flows here and is used in a format string. | tst.js:20:17:20:32 | req.query.format | User-provided value | +| tst.js:21:16:21:31 | req.query.format | tst.js:21:16:21:31 | req.query.format | tst.js:21:16:21:31 | req.query.format | $@ flows here and is used in a format string. | tst.js:21:16:21:31 | req.query.format | User-provided value | +| tst.js:22:17:22:32 | req.query.format | tst.js:22:17:22:32 | req.query.format | tst.js:22:17:22:32 | req.query.format | $@ flows here and is used in a format string. | tst.js:22:17:22:32 | req.query.format | User-provided value | +| tst.js:24:25:24:40 | req.query.format | tst.js:24:25:24:40 | req.query.format | tst.js:24:25:24:40 | req.query.format | $@ flows here and is used in a format string. | tst.js:24:25:24:40 | req.query.format | User-provided value | +| tst.js:25:33:25:48 | req.query.format | tst.js:25:33:25:48 | req.query.format | tst.js:25:33:25:48 | req.query.format | $@ flows here and is used in a format string. | tst.js:25:33:25:48 | req.query.format | User-provided value | +| tst.js:26:34:26:49 | req.query.format | tst.js:26:34:26:49 | req.query.format | tst.js:26:34:26:49 | req.query.format | $@ flows here and is used in a format string. | tst.js:26:34:26:49 | req.query.format | User-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-200/FileAccessToHttp.expected b/javascript/ql/test/query-tests/Security/CWE-200/FileAccessToHttp.expected index 34dbdec53817..eaabdbaf5d2c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-200/FileAccessToHttp.expected +++ b/javascript/ql/test/query-tests/Security/CWE-200/FileAccessToHttp.expected @@ -1,8 +1,110 @@ -| bufferRead.js:33:21:33:28 | postData | $@ flows directly to outbound network request | bufferRead.js:12:22:12:43 | new Buf ... s.size) | File data | -| googlecompiler.js:38:18:38:26 | post_data | $@ flows directly to outbound network request | googlecompiler.js:44:54:44:57 | data | File data | -| readFileSync.js:26:18:26:18 | s | $@ flows directly to outbound network request | readFileSync.js:5:12:5:39 | fs.read ... t.txt") | File data | -| readStreamRead.js:30:19:30:23 | chunk | $@ flows directly to outbound network request | readStreamRead.js:13:21:13:35 | readable.read() | File data | -| request.js:8:11:8:20 | {jsonData} | $@ flows directly to outbound network request | request.js:28:52:28:55 | data | File data | -| request.js:16:11:23:3 | {\\n u ... ody\\n } | $@ flows directly to outbound network request | request.js:43:51:43:54 | data | File data | -| sentAsHeaders.js:14:20:19:9 | {\\n ... } | $@ flows directly to outbound network request | sentAsHeaders.js:10:79:10:84 | buffer | File data | -| sentAsHeaders.js:20:20:25:9 | {\\n ... } | $@ flows directly to outbound network request | sentAsHeaders.js:10:79:10:84 | buffer | File data | +nodes +| bufferRead.js:12:13:12:43 | buffer | +| bufferRead.js:12:22:12:43 | new Buf ... s.size) | +| bufferRead.js:13:53:13:52 | buffer | +| bufferRead.js:15:15:15:62 | postData | +| bufferRead.js:15:26:15:31 | buffer | +| bufferRead.js:15:26:15:62 | buffer. ... esRead) | +| bufferRead.js:33:21:33:28 | postData | +| googlecompiler.js:7:19:7:28 | codestring | +| googlecompiler.js:9:7:15:4 | post_data | +| googlecompiler.js:9:19:15:4 | queryst ... dy\\n }) | +| googlecompiler.js:9:41:15:3 | {\\n ... ody\\n } | +| googlecompiler.js:14:21:14:30 | codestring | +| googlecompiler.js:38:18:38:26 | post_data | +| googlecompiler.js:44:54:44:57 | data | +| googlecompiler.js:55:6:55:9 | data | +| googlecompiler.js:56:14:56:17 | data | +| readFileSync.js:5:5:5:39 | data | +| readFileSync.js:5:12:5:39 | fs.read ... t.txt") | +| readFileSync.js:7:7:7:25 | s | +| readFileSync.js:7:11:7:14 | data | +| readFileSync.js:7:11:7:25 | data.toString() | +| readFileSync.js:26:18:26:18 | s | +| readStreamRead.js:13:13:13:35 | chunk | +| readStreamRead.js:13:21:13:35 | readable.read() | +| readStreamRead.js:30:19:30:23 | chunk | +| request.js:6:19:6:26 | jsonData | +| request.js:8:11:8:20 | {jsonData} | +| request.js:8:12:8:19 | jsonData | +| request.js:13:18:13:24 | xmlData | +| request.js:16:11:23:3 | {\\n u ... ody\\n } | +| request.js:22:11:22:17 | xmlData | +| request.js:28:52:28:55 | data | +| request.js:34:6:34:9 | data | +| request.js:35:14:35:17 | data | +| request.js:43:51:43:54 | data | +| request.js:49:6:49:9 | data | +| request.js:50:13:50:16 | data | +| sentAsHeaders.js:10:79:10:84 | buffer | +| sentAsHeaders.js:11:13:11:59 | content | +| sentAsHeaders.js:11:23:11:28 | buffer | +| sentAsHeaders.js:11:23:11:59 | buffer. ... esRead) | +| sentAsHeaders.js:12:9:12:81 | content | +| sentAsHeaders.js:12:19:12:25 | content | +| sentAsHeaders.js:12:19:12:74 | content ... =", "") | +| sentAsHeaders.js:12:19:12:81 | content ... .trim() | +| sentAsHeaders.js:14:20:19:9 | {\\n ... } | +| sentAsHeaders.js:18:20:18:55 | { Refer ... ntent } | +| sentAsHeaders.js:18:31:18:53 | "http:/ ... content | +| sentAsHeaders.js:18:47:18:53 | content | +| sentAsHeaders.js:20:20:25:9 | {\\n ... } | +| sentAsHeaders.js:24:20:24:55 | { Refer ... ntent } | +| sentAsHeaders.js:24:31:24:53 | "http:/ ... content | +| sentAsHeaders.js:24:47:24:53 | content | +edges +| bufferRead.js:12:13:12:43 | buffer | bufferRead.js:13:53:13:52 | buffer | +| bufferRead.js:12:22:12:43 | new Buf ... s.size) | bufferRead.js:12:13:12:43 | buffer | +| bufferRead.js:13:53:13:52 | buffer | bufferRead.js:15:26:15:31 | buffer | +| bufferRead.js:15:15:15:62 | postData | bufferRead.js:33:21:33:28 | postData | +| bufferRead.js:15:26:15:31 | buffer | bufferRead.js:15:26:15:62 | buffer. ... esRead) | +| bufferRead.js:15:26:15:62 | buffer. ... esRead) | bufferRead.js:15:15:15:62 | postData | +| googlecompiler.js:7:19:7:28 | codestring | googlecompiler.js:14:21:14:30 | codestring | +| googlecompiler.js:9:7:15:4 | post_data | googlecompiler.js:38:18:38:26 | post_data | +| googlecompiler.js:9:19:15:4 | queryst ... dy\\n }) | googlecompiler.js:9:7:15:4 | post_data | +| googlecompiler.js:9:41:15:3 | {\\n ... ody\\n } | googlecompiler.js:9:19:15:4 | queryst ... dy\\n }) | +| googlecompiler.js:14:21:14:30 | codestring | googlecompiler.js:9:41:15:3 | {\\n ... ody\\n } | +| googlecompiler.js:44:54:44:57 | data | googlecompiler.js:55:6:55:9 | data | +| googlecompiler.js:55:6:55:9 | data | googlecompiler.js:56:14:56:17 | data | +| googlecompiler.js:56:14:56:17 | data | googlecompiler.js:7:19:7:28 | codestring | +| readFileSync.js:5:5:5:39 | data | readFileSync.js:7:11:7:14 | data | +| readFileSync.js:5:12:5:39 | fs.read ... t.txt") | readFileSync.js:5:5:5:39 | data | +| readFileSync.js:7:7:7:25 | s | readFileSync.js:26:18:26:18 | s | +| readFileSync.js:7:11:7:14 | data | readFileSync.js:7:11:7:25 | data.toString() | +| readFileSync.js:7:11:7:25 | data.toString() | readFileSync.js:7:7:7:25 | s | +| readStreamRead.js:13:13:13:35 | chunk | readStreamRead.js:30:19:30:23 | chunk | +| readStreamRead.js:13:21:13:35 | readable.read() | readStreamRead.js:13:13:13:35 | chunk | +| request.js:6:19:6:26 | jsonData | request.js:8:12:8:19 | jsonData | +| request.js:8:12:8:19 | jsonData | request.js:8:11:8:20 | {jsonData} | +| request.js:13:18:13:24 | xmlData | request.js:22:11:22:17 | xmlData | +| request.js:22:11:22:17 | xmlData | request.js:16:11:23:3 | {\\n u ... ody\\n } | +| request.js:28:52:28:55 | data | request.js:34:6:34:9 | data | +| request.js:34:6:34:9 | data | request.js:35:14:35:17 | data | +| request.js:35:14:35:17 | data | request.js:6:19:6:26 | jsonData | +| request.js:43:51:43:54 | data | request.js:49:6:49:9 | data | +| request.js:49:6:49:9 | data | request.js:50:13:50:16 | data | +| request.js:50:13:50:16 | data | request.js:13:18:13:24 | xmlData | +| sentAsHeaders.js:10:79:10:84 | buffer | sentAsHeaders.js:11:23:11:28 | buffer | +| sentAsHeaders.js:11:13:11:59 | content | sentAsHeaders.js:12:19:12:25 | content | +| sentAsHeaders.js:11:23:11:28 | buffer | sentAsHeaders.js:11:23:11:59 | buffer. ... esRead) | +| sentAsHeaders.js:11:23:11:59 | buffer. ... esRead) | sentAsHeaders.js:11:13:11:59 | content | +| sentAsHeaders.js:12:9:12:81 | content | sentAsHeaders.js:18:47:18:53 | content | +| sentAsHeaders.js:12:9:12:81 | content | sentAsHeaders.js:24:47:24:53 | content | +| sentAsHeaders.js:12:19:12:25 | content | sentAsHeaders.js:12:19:12:74 | content ... =", "") | +| sentAsHeaders.js:12:19:12:74 | content ... =", "") | sentAsHeaders.js:12:19:12:81 | content ... .trim() | +| sentAsHeaders.js:12:19:12:81 | content ... .trim() | sentAsHeaders.js:12:9:12:81 | content | +| sentAsHeaders.js:18:20:18:55 | { Refer ... ntent } | sentAsHeaders.js:14:20:19:9 | {\\n ... } | +| sentAsHeaders.js:18:31:18:53 | "http:/ ... content | sentAsHeaders.js:18:20:18:55 | { Refer ... ntent } | +| sentAsHeaders.js:18:47:18:53 | content | sentAsHeaders.js:18:31:18:53 | "http:/ ... content | +| sentAsHeaders.js:24:20:24:55 | { Refer ... ntent } | sentAsHeaders.js:20:20:25:9 | {\\n ... } | +| sentAsHeaders.js:24:31:24:53 | "http:/ ... content | sentAsHeaders.js:24:20:24:55 | { Refer ... ntent } | +| sentAsHeaders.js:24:47:24:53 | content | sentAsHeaders.js:24:31:24:53 | "http:/ ... content | +#select +| bufferRead.js:33:21:33:28 | postData | bufferRead.js:12:22:12:43 | new Buf ... s.size) | bufferRead.js:33:21:33:28 | postData | $@ flows directly to outbound network request | bufferRead.js:12:22:12:43 | new Buf ... s.size) | File data | +| googlecompiler.js:38:18:38:26 | post_data | googlecompiler.js:44:54:44:57 | data | googlecompiler.js:38:18:38:26 | post_data | $@ flows directly to outbound network request | googlecompiler.js:44:54:44:57 | data | File data | +| readFileSync.js:26:18:26:18 | s | readFileSync.js:5:12:5:39 | fs.read ... t.txt") | readFileSync.js:26:18:26:18 | s | $@ flows directly to outbound network request | readFileSync.js:5:12:5:39 | fs.read ... t.txt") | File data | +| readStreamRead.js:30:19:30:23 | chunk | readStreamRead.js:13:21:13:35 | readable.read() | readStreamRead.js:30:19:30:23 | chunk | $@ flows directly to outbound network request | readStreamRead.js:13:21:13:35 | readable.read() | File data | +| request.js:8:11:8:20 | {jsonData} | request.js:28:52:28:55 | data | request.js:8:11:8:20 | {jsonData} | $@ flows directly to outbound network request | request.js:28:52:28:55 | data | File data | +| request.js:16:11:23:3 | {\\n u ... ody\\n } | request.js:43:51:43:54 | data | request.js:16:11:23:3 | {\\n u ... ody\\n } | $@ flows directly to outbound network request | request.js:43:51:43:54 | data | File data | +| sentAsHeaders.js:14:20:19:9 | {\\n ... } | sentAsHeaders.js:10:79:10:84 | buffer | sentAsHeaders.js:14:20:19:9 | {\\n ... } | $@ flows directly to outbound network request | sentAsHeaders.js:10:79:10:84 | buffer | File data | +| sentAsHeaders.js:20:20:25:9 | {\\n ... } | sentAsHeaders.js:10:79:10:84 | buffer | sentAsHeaders.js:20:20:25:9 | {\\n ... } | $@ flows directly to outbound network request | sentAsHeaders.js:10:79:10:84 | buffer | File data | diff --git a/javascript/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected b/javascript/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected index 8ec5b31e6e9d..e85b168c31eb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected +++ b/javascript/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected @@ -1,3 +1,22 @@ -| node.js:11:13:11:21 | err.stack | Stack trace information from $@ may be exposed to an external user here. | node.js:8:10:8:12 | err | here | -| tst.js:7:13:7:13 | e | Stack trace information from $@ may be exposed to an external user here. | tst.js:6:12:6:12 | e | here | -| tst.js:17:11:17:17 | e.stack | Stack trace information from $@ may be exposed to an external user here. | tst.js:6:12:6:12 | e | here | +nodes +| node.js:8:10:8:12 | err | +| node.js:11:13:11:15 | err | +| node.js:11:13:11:21 | err.stack | +| tst.js:6:12:6:12 | e | +| tst.js:7:13:7:13 | e | +| tst.js:8:15:8:15 | e | +| tst.js:16:20:16:20 | e | +| tst.js:17:11:17:11 | e | +| tst.js:17:11:17:17 | e.stack | +edges +| node.js:8:10:8:12 | err | node.js:11:13:11:15 | err | +| node.js:11:13:11:15 | err | node.js:11:13:11:21 | err.stack | +| tst.js:6:12:6:12 | e | tst.js:7:13:7:13 | e | +| tst.js:6:12:6:12 | e | tst.js:8:15:8:15 | e | +| tst.js:8:15:8:15 | e | tst.js:16:20:16:20 | e | +| tst.js:16:20:16:20 | e | tst.js:17:11:17:11 | e | +| tst.js:17:11:17:11 | e | tst.js:17:11:17:17 | e.stack | +#select +| node.js:11:13:11:21 | err.stack | node.js:8:10:8:12 | err | node.js:11:13:11:21 | err.stack | Stack trace information from $@ may be exposed to an external user here. | node.js:8:10:8:12 | err | here | +| tst.js:7:13:7:13 | e | tst.js:6:12:6:12 | e | tst.js:7:13:7:13 | e | Stack trace information from $@ may be exposed to an external user here. | tst.js:6:12:6:12 | e | here | +| tst.js:17:11:17:17 | e.stack | tst.js:6:12:6:12 | e | tst.js:17:11:17:17 | e.stack | Stack trace information from $@ may be exposed to an external user here. | tst.js:6:12:6:12 | e | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected b/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected index 61b46506f0a9..fb3e8e11bba8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected +++ b/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected @@ -1,26 +1,120 @@ -| passwords.js:2:17:2:24 | password | Sensitive data returned by $@ is logged here. | passwords.js:2:17:2:24 | password | an access to password | -| passwords.js:3:17:3:26 | o.password | Sensitive data returned by $@ is logged here. | passwords.js:3:17:3:26 | o.password | an access to password | -| passwords.js:4:17:4:29 | getPassword() | Sensitive data returned by $@ is logged here. | passwords.js:4:17:4:29 | getPassword() | a call to getPassword | -| passwords.js:5:17:5:31 | o.getPassword() | Sensitive data returned by $@ is logged here. | passwords.js:5:17:5:31 | o.getPassword() | a call to getPassword | -| passwords.js:8:21:8:21 | x | Sensitive data returned by $@ is logged here. | passwords.js:10:11:10:18 | password | an access to password | -| passwords.js:12:18:12:25 | password | Sensitive data returned by $@ is logged here. | passwords.js:12:18:12:25 | password | an access to password | -| passwords.js:14:17:14:38 | name + ... assword | Sensitive data returned by $@ is logged here. | passwords.js:14:31:14:38 | password | an access to password | -| passwords.js:16:17:16:38 | `${name ... sword}` | Sensitive data returned by $@ is logged here. | passwords.js:16:29:16:36 | password | an access to password | -| passwords.js:21:17:21:20 | obj1 | Sensitive data returned by $@ is logged here. | passwords.js:18:16:20:5 | {\\n ... x\\n } | an access to password | -| passwords.js:26:17:26:20 | obj2 | Sensitive data returned by $@ is logged here. | passwords.js:24:12:24:19 | password | an access to password | -| passwords.js:29:17:29:20 | obj3 | Sensitive data returned by $@ is logged here. | passwords.js:30:14:30:21 | password | an access to password | -| passwords.js:78:17:78:38 | temp.en ... assword | Sensitive data returned by $@ is logged here. | passwords.js:77:37:77:53 | req.body.password | an access to password | -| passwords.js:81:17:81:31 | `pw: ${secret}` | Sensitive data returned by $@ is logged here. | passwords.js:80:18:80:25 | password | an access to password | -| passwords.js:93:21:93:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:93:39:93:46 | password | an access to password | -| passwords.js:98:21:98:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:98:39:98:46 | password | an access to password | -| passwords.js:105:21:105:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:105:39:105:46 | password | an access to password | -| passwords.js:110:21:110:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:110:39:110:46 | password | an access to password | -| passwords.js:114:25:114:50 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:114:43:114:50 | password | an access to password | -| passwords.js:119:21:119:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:119:39:119:46 | password | an access to password | -| passwords.js:122:17:122:49 | name + ... tring() | Sensitive data returned by $@ is logged here. | passwords.js:122:31:122:38 | password | an access to password | -| passwords.js:123:17:123:48 | name + ... lueOf() | Sensitive data returned by $@ is logged here. | passwords.js:123:31:123:38 | password | an access to password | -| passwords_in_server_1.js:6:13:6:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_1.js:6:13:6:20 | password | an access to password | -| passwords_in_server_2.js:3:13:3:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_2.js:3:13:3:20 | password | an access to password | -| passwords_in_server_3.js:2:13:2:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_3.js:2:13:2:20 | password | an access to password | -| passwords_in_server_4.js:2:13:2:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_4.js:2:13:2:20 | password | an access to password | -| passwords_in_server_5.js:8:17:8:17 | x | Sensitive data returned by $@ is logged here. | passwords_in_server_5.js:4:7:4:24 | req.query.password | an access to password | +nodes +| passwords.js:2:17:2:24 | password | +| passwords.js:3:17:3:26 | o.password | +| passwords.js:4:17:4:29 | getPassword() | +| passwords.js:5:17:5:31 | o.getPassword() | +| passwords.js:7:20:7:20 | x | +| passwords.js:8:21:8:21 | x | +| passwords.js:10:11:10:18 | password | +| passwords.js:12:18:12:25 | password | +| passwords.js:14:17:14:38 | name + ... assword | +| passwords.js:14:31:14:38 | password | +| passwords.js:16:17:16:38 | `${name ... sword}` | +| passwords.js:16:29:16:36 | password | +| passwords.js:18:9:20:5 | obj1 | +| passwords.js:18:16:20:5 | {\\n ... x\\n } | +| passwords.js:21:17:21:20 | obj1 | +| passwords.js:23:9:25:5 | obj2 | +| passwords.js:23:16:25:5 | {\\n ... d\\n } | +| passwords.js:24:12:24:19 | password | +| passwords.js:26:17:26:20 | obj2 | +| passwords.js:28:9:28:17 | obj3 | +| passwords.js:28:16:28:17 | {} | +| passwords.js:29:17:29:20 | obj3 | +| passwords.js:30:14:30:21 | password | +| passwords.js:77:9:77:55 | temp | +| passwords.js:77:16:77:55 | { encry ... sword } | +| passwords.js:77:37:77:53 | req.body.password | +| passwords.js:78:17:78:20 | temp | +| passwords.js:78:17:78:38 | temp.en ... assword | +| passwords.js:80:9:80:25 | secret | +| passwords.js:80:18:80:25 | password | +| passwords.js:81:17:81:31 | `pw: ${secret}` | +| passwords.js:81:24:81:29 | secret | +| passwords.js:93:21:93:46 | "Passwo ... assword | +| passwords.js:93:39:93:46 | password | +| passwords.js:98:21:98:46 | "Passwo ... assword | +| passwords.js:98:39:98:46 | password | +| passwords.js:105:21:105:46 | "Passwo ... assword | +| passwords.js:105:39:105:46 | password | +| passwords.js:110:21:110:46 | "Passwo ... assword | +| passwords.js:110:39:110:46 | password | +| passwords.js:114:25:114:50 | "Passwo ... assword | +| passwords.js:114:43:114:50 | password | +| passwords.js:119:21:119:46 | "Passwo ... assword | +| passwords.js:119:39:119:46 | password | +| passwords.js:122:17:122:49 | name + ... tring() | +| passwords.js:122:31:122:38 | password | +| passwords.js:122:31:122:49 | password.toString() | +| passwords.js:123:17:123:48 | name + ... lueOf() | +| passwords.js:123:31:123:38 | password | +| passwords.js:123:31:123:48 | password.valueOf() | +| passwords_in_browser1.js:2:13:2:20 | password | +| passwords_in_browser2.js:2:13:2:20 | password | +| passwords_in_server_1.js:6:13:6:20 | password | +| passwords_in_server_2.js:3:13:3:20 | password | +| passwords_in_server_3.js:2:13:2:20 | password | +| passwords_in_server_4.js:2:13:2:20 | password | +| passwords_in_server_5.js:4:7:4:24 | req.query.password | +| passwords_in_server_5.js:7:12:7:12 | x | +| passwords_in_server_5.js:8:17:8:17 | x | +edges +| passwords.js:7:20:7:20 | x | passwords.js:8:21:8:21 | x | +| passwords.js:10:11:10:18 | password | passwords.js:7:20:7:20 | x | +| passwords.js:14:31:14:38 | password | passwords.js:14:17:14:38 | name + ... assword | +| passwords.js:16:29:16:36 | password | passwords.js:16:17:16:38 | `${name ... sword}` | +| passwords.js:18:9:20:5 | obj1 | passwords.js:21:17:21:20 | obj1 | +| passwords.js:18:16:20:5 | {\\n ... x\\n } | passwords.js:18:9:20:5 | obj1 | +| passwords.js:23:9:25:5 | obj2 | passwords.js:26:17:26:20 | obj2 | +| passwords.js:23:16:25:5 | {\\n ... d\\n } | passwords.js:23:9:25:5 | obj2 | +| passwords.js:24:12:24:19 | password | passwords.js:23:16:25:5 | {\\n ... d\\n } | +| passwords.js:28:9:28:17 | obj3 | passwords.js:29:17:29:20 | obj3 | +| passwords.js:28:16:28:17 | {} | passwords.js:28:9:28:17 | obj3 | +| passwords.js:30:14:30:21 | password | passwords.js:28:16:28:17 | {} | +| passwords.js:77:9:77:55 | temp | passwords.js:78:17:78:20 | temp | +| passwords.js:77:16:77:55 | { encry ... sword } | passwords.js:77:9:77:55 | temp | +| passwords.js:77:37:77:53 | req.body.password | passwords.js:77:16:77:55 | { encry ... sword } | +| passwords.js:77:37:77:53 | req.body.password | passwords.js:78:17:78:38 | temp.en ... assword | +| passwords.js:78:17:78:20 | temp | passwords.js:78:17:78:38 | temp.en ... assword | +| passwords.js:80:9:80:25 | secret | passwords.js:81:24:81:29 | secret | +| passwords.js:80:18:80:25 | password | passwords.js:80:9:80:25 | secret | +| passwords.js:81:24:81:29 | secret | passwords.js:81:17:81:31 | `pw: ${secret}` | +| passwords.js:93:39:93:46 | password | passwords.js:93:21:93:46 | "Passwo ... assword | +| passwords.js:98:39:98:46 | password | passwords.js:98:21:98:46 | "Passwo ... assword | +| passwords.js:105:39:105:46 | password | passwords.js:105:21:105:46 | "Passwo ... assword | +| passwords.js:110:39:110:46 | password | passwords.js:110:21:110:46 | "Passwo ... assword | +| passwords.js:114:43:114:50 | password | passwords.js:114:25:114:50 | "Passwo ... assword | +| passwords.js:119:39:119:46 | password | passwords.js:119:21:119:46 | "Passwo ... assword | +| passwords.js:122:31:122:38 | password | passwords.js:122:31:122:49 | password.toString() | +| passwords.js:122:31:122:49 | password.toString() | passwords.js:122:17:122:49 | name + ... tring() | +| passwords.js:123:31:123:38 | password | passwords.js:123:31:123:48 | password.valueOf() | +| passwords.js:123:31:123:48 | password.valueOf() | passwords.js:123:17:123:48 | name + ... lueOf() | +| passwords_in_server_5.js:4:7:4:24 | req.query.password | passwords_in_server_5.js:7:12:7:12 | x | +| passwords_in_server_5.js:7:12:7:12 | x | passwords_in_server_5.js:8:17:8:17 | x | +#select +| passwords.js:2:17:2:24 | password | passwords.js:2:17:2:24 | password | passwords.js:2:17:2:24 | password | Sensitive data returned by $@ is logged here. | passwords.js:2:17:2:24 | password | an access to password | +| passwords.js:3:17:3:26 | o.password | passwords.js:3:17:3:26 | o.password | passwords.js:3:17:3:26 | o.password | Sensitive data returned by $@ is logged here. | passwords.js:3:17:3:26 | o.password | an access to password | +| passwords.js:4:17:4:29 | getPassword() | passwords.js:4:17:4:29 | getPassword() | passwords.js:4:17:4:29 | getPassword() | Sensitive data returned by $@ is logged here. | passwords.js:4:17:4:29 | getPassword() | a call to getPassword | +| passwords.js:5:17:5:31 | o.getPassword() | passwords.js:5:17:5:31 | o.getPassword() | passwords.js:5:17:5:31 | o.getPassword() | Sensitive data returned by $@ is logged here. | passwords.js:5:17:5:31 | o.getPassword() | a call to getPassword | +| passwords.js:8:21:8:21 | x | passwords.js:10:11:10:18 | password | passwords.js:8:21:8:21 | x | Sensitive data returned by $@ is logged here. | passwords.js:10:11:10:18 | password | an access to password | +| passwords.js:12:18:12:25 | password | passwords.js:12:18:12:25 | password | passwords.js:12:18:12:25 | password | Sensitive data returned by $@ is logged here. | passwords.js:12:18:12:25 | password | an access to password | +| passwords.js:14:17:14:38 | name + ... assword | passwords.js:14:31:14:38 | password | passwords.js:14:17:14:38 | name + ... assword | Sensitive data returned by $@ is logged here. | passwords.js:14:31:14:38 | password | an access to password | +| passwords.js:16:17:16:38 | `${name ... sword}` | passwords.js:16:29:16:36 | password | passwords.js:16:17:16:38 | `${name ... sword}` | Sensitive data returned by $@ is logged here. | passwords.js:16:29:16:36 | password | an access to password | +| passwords.js:21:17:21:20 | obj1 | passwords.js:18:16:20:5 | {\\n ... x\\n } | passwords.js:21:17:21:20 | obj1 | Sensitive data returned by $@ is logged here. | passwords.js:18:16:20:5 | {\\n ... x\\n } | an access to password | +| passwords.js:26:17:26:20 | obj2 | passwords.js:24:12:24:19 | password | passwords.js:26:17:26:20 | obj2 | Sensitive data returned by $@ is logged here. | passwords.js:24:12:24:19 | password | an access to password | +| passwords.js:29:17:29:20 | obj3 | passwords.js:30:14:30:21 | password | passwords.js:29:17:29:20 | obj3 | Sensitive data returned by $@ is logged here. | passwords.js:30:14:30:21 | password | an access to password | +| passwords.js:78:17:78:38 | temp.en ... assword | passwords.js:77:37:77:53 | req.body.password | passwords.js:78:17:78:38 | temp.en ... assword | Sensitive data returned by $@ is logged here. | passwords.js:77:37:77:53 | req.body.password | an access to password | +| passwords.js:81:17:81:31 | `pw: ${secret}` | passwords.js:80:18:80:25 | password | passwords.js:81:17:81:31 | `pw: ${secret}` | Sensitive data returned by $@ is logged here. | passwords.js:80:18:80:25 | password | an access to password | +| passwords.js:93:21:93:46 | "Passwo ... assword | passwords.js:93:39:93:46 | password | passwords.js:93:21:93:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:93:39:93:46 | password | an access to password | +| passwords.js:98:21:98:46 | "Passwo ... assword | passwords.js:98:39:98:46 | password | passwords.js:98:21:98:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:98:39:98:46 | password | an access to password | +| passwords.js:105:21:105:46 | "Passwo ... assword | passwords.js:105:39:105:46 | password | passwords.js:105:21:105:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:105:39:105:46 | password | an access to password | +| passwords.js:110:21:110:46 | "Passwo ... assword | passwords.js:110:39:110:46 | password | passwords.js:110:21:110:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:110:39:110:46 | password | an access to password | +| passwords.js:114:25:114:50 | "Passwo ... assword | passwords.js:114:43:114:50 | password | passwords.js:114:25:114:50 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:114:43:114:50 | password | an access to password | +| passwords.js:119:21:119:46 | "Passwo ... assword | passwords.js:119:39:119:46 | password | passwords.js:119:21:119:46 | "Passwo ... assword | Sensitive data returned by $@ is logged here. | passwords.js:119:39:119:46 | password | an access to password | +| passwords.js:122:17:122:49 | name + ... tring() | passwords.js:122:31:122:38 | password | passwords.js:122:17:122:49 | name + ... tring() | Sensitive data returned by $@ is logged here. | passwords.js:122:31:122:38 | password | an access to password | +| passwords.js:123:17:123:48 | name + ... lueOf() | passwords.js:123:31:123:38 | password | passwords.js:123:17:123:48 | name + ... lueOf() | Sensitive data returned by $@ is logged here. | passwords.js:123:31:123:38 | password | an access to password | +| passwords_in_server_1.js:6:13:6:20 | password | passwords_in_server_1.js:6:13:6:20 | password | passwords_in_server_1.js:6:13:6:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_1.js:6:13:6:20 | password | an access to password | +| passwords_in_server_2.js:3:13:3:20 | password | passwords_in_server_2.js:3:13:3:20 | password | passwords_in_server_2.js:3:13:3:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_2.js:3:13:3:20 | password | an access to password | +| passwords_in_server_3.js:2:13:2:20 | password | passwords_in_server_3.js:2:13:2:20 | password | passwords_in_server_3.js:2:13:2:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_3.js:2:13:2:20 | password | an access to password | +| passwords_in_server_4.js:2:13:2:20 | password | passwords_in_server_4.js:2:13:2:20 | password | passwords_in_server_4.js:2:13:2:20 | password | Sensitive data returned by $@ is logged here. | passwords_in_server_4.js:2:13:2:20 | password | an access to password | +| passwords_in_server_5.js:8:17:8:17 | x | passwords_in_server_5.js:4:7:4:24 | req.query.password | passwords_in_server_5.js:8:17:8:17 | x | Sensitive data returned by $@ is logged here. | passwords_in_server_5.js:4:7:4:24 | req.query.password | an access to password | diff --git a/javascript/ql/test/query-tests/Security/CWE-312/CleartextStorage.expected b/javascript/ql/test/query-tests/Security/CWE-312/CleartextStorage.expected index c78fa28340d2..94c95115969d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-312/CleartextStorage.expected +++ b/javascript/ql/test/query-tests/Security/CWE-312/CleartextStorage.expected @@ -1,10 +1,33 @@ -| CleartextStorage2.js:7:19:7:36 | 'AccountName=' + a | Sensitive data returned by $@ is stored here. | CleartextStorage2.js:5:11:5:52 | url.par ... untName | an access to AccountName | -| CleartextStorage.js:7:29:7:29 | a | Sensitive data returned by $@ is stored here. | CleartextStorage.js:5:11:5:34 | req.par ... tName") | a call to param | -| tst-angularjs.js:3:32:3:45 | data1.password | Sensitive data returned by $@ is stored here. | tst-angularjs.js:3:32:3:45 | data1.password | an access to password | -| tst-angularjs.js:4:33:4:46 | data2.password | Sensitive data returned by $@ is stored here. | tst-angularjs.js:4:33:4:46 | data2.password | an access to password | -| tst-angularjs.js:5:27:5:40 | data3.password | Sensitive data returned by $@ is stored here. | tst-angularjs.js:5:27:5:40 | data3.password | an access to password | -| tst-angularjs.js:6:33:6:46 | data4.password | Sensitive data returned by $@ is stored here. | tst-angularjs.js:6:33:6:46 | data4.password | an access to password | -| tst-webstorage.js:1:18:1:30 | data.password | Sensitive data returned by $@ is stored here. | tst-webstorage.js:1:18:1:30 | data.password | an access to password | -| tst-webstorage.js:2:27:2:39 | data.password | Sensitive data returned by $@ is stored here. | tst-webstorage.js:2:27:2:39 | data.password | an access to password | -| tst-webstorage.js:3:20:3:32 | data.password | Sensitive data returned by $@ is stored here. | tst-webstorage.js:3:20:3:32 | data.password | an access to password | -| tst-webstorage.js:4:29:4:41 | data.password | Sensitive data returned by $@ is stored here. | tst-webstorage.js:4:29:4:41 | data.password | an access to password | +nodes +| CleartextStorage2.js:5:7:5:52 | a | +| CleartextStorage2.js:5:11:5:52 | url.par ... untName | +| CleartextStorage2.js:7:19:7:36 | 'AccountName=' + a | +| CleartextStorage2.js:7:36:7:36 | a | +| CleartextStorage.js:5:7:5:34 | a | +| CleartextStorage.js:5:11:5:34 | req.par ... tName") | +| CleartextStorage.js:7:29:7:29 | a | +| tst-angularjs.js:3:32:3:45 | data1.password | +| tst-angularjs.js:4:33:4:46 | data2.password | +| tst-angularjs.js:5:27:5:40 | data3.password | +| tst-angularjs.js:6:33:6:46 | data4.password | +| tst-webstorage.js:1:18:1:30 | data.password | +| tst-webstorage.js:2:27:2:39 | data.password | +| tst-webstorage.js:3:20:3:32 | data.password | +| tst-webstorage.js:4:29:4:41 | data.password | +edges +| CleartextStorage2.js:5:7:5:52 | a | CleartextStorage2.js:7:36:7:36 | a | +| CleartextStorage2.js:5:11:5:52 | url.par ... untName | CleartextStorage2.js:5:7:5:52 | a | +| CleartextStorage2.js:7:36:7:36 | a | CleartextStorage2.js:7:19:7:36 | 'AccountName=' + a | +| CleartextStorage.js:5:7:5:34 | a | CleartextStorage.js:7:29:7:29 | a | +| CleartextStorage.js:5:11:5:34 | req.par ... tName") | CleartextStorage.js:5:7:5:34 | a | +#select +| CleartextStorage2.js:7:19:7:36 | 'AccountName=' + a | CleartextStorage2.js:5:11:5:52 | url.par ... untName | CleartextStorage2.js:7:19:7:36 | 'AccountName=' + a | Sensitive data returned by $@ is stored here. | CleartextStorage2.js:5:11:5:52 | url.par ... untName | an access to AccountName | +| CleartextStorage.js:7:29:7:29 | a | CleartextStorage.js:5:11:5:34 | req.par ... tName") | CleartextStorage.js:7:29:7:29 | a | Sensitive data returned by $@ is stored here. | CleartextStorage.js:5:11:5:34 | req.par ... tName") | a call to param | +| tst-angularjs.js:3:32:3:45 | data1.password | tst-angularjs.js:3:32:3:45 | data1.password | tst-angularjs.js:3:32:3:45 | data1.password | Sensitive data returned by $@ is stored here. | tst-angularjs.js:3:32:3:45 | data1.password | an access to password | +| tst-angularjs.js:4:33:4:46 | data2.password | tst-angularjs.js:4:33:4:46 | data2.password | tst-angularjs.js:4:33:4:46 | data2.password | Sensitive data returned by $@ is stored here. | tst-angularjs.js:4:33:4:46 | data2.password | an access to password | +| tst-angularjs.js:5:27:5:40 | data3.password | tst-angularjs.js:5:27:5:40 | data3.password | tst-angularjs.js:5:27:5:40 | data3.password | Sensitive data returned by $@ is stored here. | tst-angularjs.js:5:27:5:40 | data3.password | an access to password | +| tst-angularjs.js:6:33:6:46 | data4.password | tst-angularjs.js:6:33:6:46 | data4.password | tst-angularjs.js:6:33:6:46 | data4.password | Sensitive data returned by $@ is stored here. | tst-angularjs.js:6:33:6:46 | data4.password | an access to password | +| tst-webstorage.js:1:18:1:30 | data.password | tst-webstorage.js:1:18:1:30 | data.password | tst-webstorage.js:1:18:1:30 | data.password | Sensitive data returned by $@ is stored here. | tst-webstorage.js:1:18:1:30 | data.password | an access to password | +| tst-webstorage.js:2:27:2:39 | data.password | tst-webstorage.js:2:27:2:39 | data.password | tst-webstorage.js:2:27:2:39 | data.password | Sensitive data returned by $@ is stored here. | tst-webstorage.js:2:27:2:39 | data.password | an access to password | +| tst-webstorage.js:3:20:3:32 | data.password | tst-webstorage.js:3:20:3:32 | data.password | tst-webstorage.js:3:20:3:32 | data.password | Sensitive data returned by $@ is stored here. | tst-webstorage.js:3:20:3:32 | data.password | an access to password | +| tst-webstorage.js:4:29:4:41 | data.password | tst-webstorage.js:4:29:4:41 | data.password | tst-webstorage.js:4:29:4:41 | data.password | Sensitive data returned by $@ is stored here. | tst-webstorage.js:4:29:4:41 | data.password | an access to password | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected b/javascript/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected index 9ef08fe441b8..a8b7a6f3598d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected @@ -1,3 +1,13 @@ -| tst.js:11:17:11:26 | secretText | Sensitive data from $@ is used in a broken or weak cryptographic algorithm. | tst.js:3:18:3:24 | trusted | an access to trusted | -| tst.js:11:17:11:26 | secretText | Sensitive data from $@ is used in a broken or weak cryptographic algorithm. | tst.js:11:17:11:26 | secretText | an access to secretText | -| tst.js:17:17:17:25 | o.trusted | Sensitive data from $@ is used in a broken or weak cryptographic algorithm. | tst.js:17:17:17:25 | o.trusted | an access to trusted | +nodes +| tst.js:3:5:3:24 | secretText | +| tst.js:3:18:3:24 | trusted | +| tst.js:11:17:11:26 | secretText | +| tst.js:17:17:17:25 | o.trusted | +| tst.js:19:17:19:24 | password | +edges +| tst.js:3:5:3:24 | secretText | tst.js:11:17:11:26 | secretText | +| tst.js:3:18:3:24 | trusted | tst.js:3:5:3:24 | secretText | +#select +| tst.js:11:17:11:26 | secretText | tst.js:3:18:3:24 | trusted | tst.js:11:17:11:26 | secretText | Sensitive data from $@ is used in a broken or weak cryptographic algorithm. | tst.js:3:18:3:24 | trusted | an access to trusted | +| tst.js:11:17:11:26 | secretText | tst.js:11:17:11:26 | secretText | tst.js:11:17:11:26 | secretText | Sensitive data from $@ is used in a broken or weak cryptographic algorithm. | tst.js:11:17:11:26 | secretText | an access to secretText | +| tst.js:17:17:17:25 | o.trusted | tst.js:17:17:17:25 | o.trusted | tst.js:17:17:17:25 | o.trusted | Sensitive data from $@ is used in a broken or weak cryptographic algorithm. | tst.js:17:17:17:25 | o.trusted | an access to trusted | diff --git a/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected index 7b250dc08ab6..3b4f56f3326d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected @@ -1,16 +1,73 @@ -| tst.js:2:20:2:32 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:2:20:2:32 | Math.random() | random value | -| tst.js:6:20:6:43 | "prefix ... andom() | Cryptographically insecure $@ in a security context. | tst.js:6:31:6:43 | Math.random() | random value | -| tst.js:10:20:10:32 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:10:20:10:32 | Math.random() | random value | -| tst.js:20:20:20:36 | "prefix" + suffix | Cryptographically insecure $@ in a security context. | tst.js:19:18:19:30 | Math.random() | random value | -| tst.js:29:20:29:21 | pw | Cryptographically insecure $@ in a security context. | tst.js:28:14:28:26 | Math.random() | random value | -| tst.js:41:20:41:33 | !Math.random() | Cryptographically insecure $@ in a security context. | tst.js:41:21:41:33 | Math.random() | random value | -| tst.js:45:18:45:30 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:45:18:45:30 | Math.random() | random value | -| tst.js:50:16:50:28 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:50:16:50:28 | Math.random() | random value | -| tst.js:55:17:55:29 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:55:17:55:29 | Math.random() | random value | -| tst.js:61:17:61:34 | '' + Math.random() | Cryptographically insecure $@ in a security context. | tst.js:61:22:61:34 | Math.random() | random value | -| tst.js:66:18:66:42 | Math.fl ... ndom()) | Cryptographically insecure $@ in a security context. | tst.js:66:29:66:41 | Math.random() | random value | -| tst.js:73:23:73:28 | concat | Cryptographically insecure $@ in a security context. | tst.js:71:27:71:39 | Math.random() | random value | -| tst.js:77:16:77:21 | secret | Cryptographically insecure $@ in a security context. | tst.js:80:7:80:19 | Math.random() | random value | -| tst.js:84:19:84:31 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:84:19:84:31 | Math.random() | random value | -| tst.js:90:32:90:44 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:90:32:90:44 | Math.random() | random value | -| tst.js:95:33:95:45 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:95:33:95:45 | Math.random() | random value | +nodes +| tst.js:2:20:2:32 | Math.random() | +| tst.js:6:20:6:43 | "prefix ... andom() | +| tst.js:6:31:6:43 | Math.random() | +| tst.js:10:20:10:32 | Math.random() | +| tst.js:19:9:19:36 | suffix | +| tst.js:19:18:19:30 | Math.random() | +| tst.js:19:18:19:36 | Math.random() % 255 | +| tst.js:20:20:20:36 | "prefix" + suffix | +| tst.js:20:31:20:36 | suffix | +| tst.js:28:9:28:26 | pw | +| tst.js:28:14:28:26 | Math.random() | +| tst.js:29:20:29:21 | pw | +| tst.js:41:20:41:33 | !Math.random() | +| tst.js:41:21:41:33 | Math.random() | +| tst.js:45:18:45:30 | Math.random() | +| tst.js:50:16:50:28 | Math.random() | +| tst.js:55:17:55:29 | Math.random() | +| tst.js:61:17:61:34 | '' + Math.random() | +| tst.js:61:22:61:34 | Math.random() | +| tst.js:66:18:66:42 | Math.fl ... ndom()) | +| tst.js:66:29:66:41 | Math.random() | +| tst.js:71:9:71:48 | rand | +| tst.js:71:16:71:48 | Math.fl ... 999999) | +| tst.js:71:27:71:39 | Math.random() | +| tst.js:71:27:71:47 | Math.ra ... 9999999 | +| tst.js:72:9:72:48 | concat | +| tst.js:72:18:72:48 | ts.toSt ... tring() | +| tst.js:72:34:72:37 | rand | +| tst.js:72:34:72:48 | rand.toString() | +| tst.js:73:23:73:28 | concat | +| tst.js:77:16:77:21 | secret | +| tst.js:80:7:80:19 | Math.random() | +| tst.js:84:19:84:31 | Math.random() | +| tst.js:90:32:90:44 | Math.random() | +| tst.js:95:33:95:45 | Math.random() | +edges +| tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() | +| tst.js:19:9:19:36 | suffix | tst.js:20:31:20:36 | suffix | +| tst.js:19:18:19:30 | Math.random() | tst.js:19:18:19:36 | Math.random() % 255 | +| tst.js:19:18:19:36 | Math.random() % 255 | tst.js:19:9:19:36 | suffix | +| tst.js:20:31:20:36 | suffix | tst.js:20:20:20:36 | "prefix" + suffix | +| tst.js:28:9:28:26 | pw | tst.js:29:20:29:21 | pw | +| tst.js:28:14:28:26 | Math.random() | tst.js:28:9:28:26 | pw | +| tst.js:41:21:41:33 | Math.random() | tst.js:41:20:41:33 | !Math.random() | +| tst.js:61:22:61:34 | Math.random() | tst.js:61:17:61:34 | '' + Math.random() | +| tst.js:66:29:66:41 | Math.random() | tst.js:66:18:66:42 | Math.fl ... ndom()) | +| tst.js:71:9:71:48 | rand | tst.js:72:34:72:37 | rand | +| tst.js:71:16:71:48 | Math.fl ... 999999) | tst.js:71:9:71:48 | rand | +| tst.js:71:27:71:39 | Math.random() | tst.js:71:27:71:47 | Math.ra ... 9999999 | +| tst.js:71:27:71:47 | Math.ra ... 9999999 | tst.js:71:16:71:48 | Math.fl ... 999999) | +| tst.js:72:9:72:48 | concat | tst.js:73:23:73:28 | concat | +| tst.js:72:18:72:48 | ts.toSt ... tring() | tst.js:72:9:72:48 | concat | +| tst.js:72:34:72:37 | rand | tst.js:72:34:72:48 | rand.toString() | +| tst.js:72:34:72:48 | rand.toString() | tst.js:72:18:72:48 | ts.toSt ... tring() | +| tst.js:80:7:80:19 | Math.random() | tst.js:77:16:77:21 | secret | +#select +| tst.js:2:20:2:32 | Math.random() | tst.js:2:20:2:32 | Math.random() | tst.js:2:20:2:32 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:2:20:2:32 | Math.random() | random value | +| tst.js:6:20:6:43 | "prefix ... andom() | tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() | Cryptographically insecure $@ in a security context. | tst.js:6:31:6:43 | Math.random() | random value | +| tst.js:10:20:10:32 | Math.random() | tst.js:10:20:10:32 | Math.random() | tst.js:10:20:10:32 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:10:20:10:32 | Math.random() | random value | +| tst.js:20:20:20:36 | "prefix" + suffix | tst.js:19:18:19:30 | Math.random() | tst.js:20:20:20:36 | "prefix" + suffix | Cryptographically insecure $@ in a security context. | tst.js:19:18:19:30 | Math.random() | random value | +| tst.js:29:20:29:21 | pw | tst.js:28:14:28:26 | Math.random() | tst.js:29:20:29:21 | pw | Cryptographically insecure $@ in a security context. | tst.js:28:14:28:26 | Math.random() | random value | +| tst.js:41:20:41:33 | !Math.random() | tst.js:41:21:41:33 | Math.random() | tst.js:41:20:41:33 | !Math.random() | Cryptographically insecure $@ in a security context. | tst.js:41:21:41:33 | Math.random() | random value | +| tst.js:45:18:45:30 | Math.random() | tst.js:45:18:45:30 | Math.random() | tst.js:45:18:45:30 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:45:18:45:30 | Math.random() | random value | +| tst.js:50:16:50:28 | Math.random() | tst.js:50:16:50:28 | Math.random() | tst.js:50:16:50:28 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:50:16:50:28 | Math.random() | random value | +| tst.js:55:17:55:29 | Math.random() | tst.js:55:17:55:29 | Math.random() | tst.js:55:17:55:29 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:55:17:55:29 | Math.random() | random value | +| tst.js:61:17:61:34 | '' + Math.random() | tst.js:61:22:61:34 | Math.random() | tst.js:61:17:61:34 | '' + Math.random() | Cryptographically insecure $@ in a security context. | tst.js:61:22:61:34 | Math.random() | random value | +| tst.js:66:18:66:42 | Math.fl ... ndom()) | tst.js:66:29:66:41 | Math.random() | tst.js:66:18:66:42 | Math.fl ... ndom()) | Cryptographically insecure $@ in a security context. | tst.js:66:29:66:41 | Math.random() | random value | +| tst.js:73:23:73:28 | concat | tst.js:71:27:71:39 | Math.random() | tst.js:73:23:73:28 | concat | Cryptographically insecure $@ in a security context. | tst.js:71:27:71:39 | Math.random() | random value | +| tst.js:77:16:77:21 | secret | tst.js:80:7:80:19 | Math.random() | tst.js:77:16:77:21 | secret | Cryptographically insecure $@ in a security context. | tst.js:80:7:80:19 | Math.random() | random value | +| tst.js:84:19:84:31 | Math.random() | tst.js:84:19:84:31 | Math.random() | tst.js:84:19:84:31 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:84:19:84:31 | Math.random() | random value | +| tst.js:90:32:90:44 | Math.random() | tst.js:90:32:90:44 | Math.random() | tst.js:90:32:90:44 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:90:32:90:44 | Math.random() | random value | +| tst.js:95:33:95:45 | Math.random() | tst.js:95:33:95:45 | Math.random() | tst.js:95:33:95:45 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:95:33:95:45 | Math.random() | random value | diff --git a/javascript/ql/test/query-tests/Security/CWE-346/CorsMisconfigurationForCredentials.expected b/javascript/ql/test/query-tests/Security/CWE-346/CorsMisconfigurationForCredentials.expected index 15be8b44c96b..e1c2b8765012 100644 --- a/javascript/ql/test/query-tests/Security/CWE-346/CorsMisconfigurationForCredentials.expected +++ b/javascript/ql/test/query-tests/Security/CWE-346/CorsMisconfigurationForCredentials.expected @@ -1,3 +1,19 @@ -| tst.js:13:50:13:55 | origin | $@ leak vulnerability due to $@. | tst.js:14:5:14:59 | res.set ... , true) | Credential | tst.js:12:28:12:34 | req.url | a misconfigured CORS header value | -| tst.js:18:50:18:53 | null | $@ leak vulnerability due to $@. | tst.js:19:5:19:59 | res.set ... , true) | Credential | tst.js:18:50:18:53 | null | a misconfigured CORS header value | -| tst.js:23:50:23:55 | "null" | $@ leak vulnerability due to $@. | tst.js:24:5:24:59 | res.set ... , true) | Credential | tst.js:23:50:23:55 | "null" | a misconfigured CORS header value | +nodes +| tst.js:12:9:12:54 | origin | +| tst.js:12:18:12:41 | url.par ... , true) | +| tst.js:12:18:12:47 | url.par ... ).query | +| tst.js:12:18:12:54 | url.par ... .origin | +| tst.js:12:28:12:34 | req.url | +| tst.js:13:50:13:55 | origin | +| tst.js:18:50:18:53 | null | +| tst.js:23:50:23:55 | "null" | +edges +| tst.js:12:9:12:54 | origin | tst.js:13:50:13:55 | origin | +| tst.js:12:18:12:41 | url.par ... , true) | tst.js:12:18:12:47 | url.par ... ).query | +| tst.js:12:18:12:47 | url.par ... ).query | tst.js:12:18:12:54 | url.par ... .origin | +| tst.js:12:18:12:54 | url.par ... .origin | tst.js:12:9:12:54 | origin | +| tst.js:12:28:12:34 | req.url | tst.js:12:18:12:41 | url.par ... , true) | +#select +| tst.js:13:50:13:55 | origin | tst.js:12:28:12:34 | req.url | tst.js:13:50:13:55 | origin | $@ leak vulnerability due to $@. | tst.js:14:5:14:59 | res.set ... , true) | Credential | tst.js:12:28:12:34 | req.url | a misconfigured CORS header value | +| tst.js:18:50:18:53 | null | tst.js:18:50:18:53 | null | tst.js:18:50:18:53 | null | $@ leak vulnerability due to $@. | tst.js:19:5:19:59 | res.set ... , true) | Credential | tst.js:18:50:18:53 | null | a misconfigured CORS header value | +| tst.js:23:50:23:55 | "null" | tst.js:23:50:23:55 | "null" | tst.js:23:50:23:55 | "null" | $@ leak vulnerability due to $@. | tst.js:24:5:24:59 | res.set ... , true) | Credential | tst.js:23:50:23:55 | "null" | a misconfigured CORS header value | diff --git a/javascript/ql/test/query-tests/Security/CWE-400/RemotePropertyInjection.expected b/javascript/ql/test/query-tests/Security/CWE-400/RemotePropertyInjection.expected index 02de1bddcf4c..db2cbb1288c8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/RemotePropertyInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-400/RemotePropertyInjection.expected @@ -1,6 +1,29 @@ -| tst.js:9:8:9:11 | prop | A $@ is used as a property name to write to. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | -| tst.js:11:16:11:19 | prop | A $@ is used as a method name to be called. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | -| tst.js:13:15:13:18 | prop | A $@ is used as a property name to write to. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | -| tst.js:14:31:14:34 | prop | A $@ is used as a property name to write to. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | -| tst.js:16:10:16:13 | prop | A $@ is used as a property name to write to. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | -| tstNonExpr.js:8:17:8:23 | userVal | A $@ is used as a header name. | tstNonExpr.js:5:17:5:23 | req.url | user-provided value | +nodes +| tst.js:8:6:8:52 | prop | +| tst.js:8:13:8:52 | myCoolL ... rolled) | +| tst.js:8:28:8:51 | req.que ... trolled | +| tst.js:9:8:9:11 | prop | +| tst.js:11:16:11:19 | prop | +| tst.js:13:15:13:18 | prop | +| tst.js:14:31:14:34 | prop | +| tst.js:16:10:16:13 | prop | +| tstNonExpr.js:5:7:5:23 | userVal | +| tstNonExpr.js:5:17:5:23 | req.url | +| tstNonExpr.js:8:17:8:23 | userVal | +edges +| tst.js:8:6:8:52 | prop | tst.js:9:8:9:11 | prop | +| tst.js:8:6:8:52 | prop | tst.js:11:16:11:19 | prop | +| tst.js:8:6:8:52 | prop | tst.js:13:15:13:18 | prop | +| tst.js:8:6:8:52 | prop | tst.js:14:31:14:34 | prop | +| tst.js:8:6:8:52 | prop | tst.js:16:10:16:13 | prop | +| tst.js:8:13:8:52 | myCoolL ... rolled) | tst.js:8:6:8:52 | prop | +| tst.js:8:28:8:51 | req.que ... trolled | tst.js:8:13:8:52 | myCoolL ... rolled) | +| tstNonExpr.js:5:7:5:23 | userVal | tstNonExpr.js:8:17:8:23 | userVal | +| tstNonExpr.js:5:17:5:23 | req.url | tstNonExpr.js:5:7:5:23 | userVal | +#select +| tst.js:9:8:9:11 | prop | tst.js:8:28:8:51 | req.que ... trolled | tst.js:9:8:9:11 | prop | A $@ is used as a property name to write to. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | +| tst.js:11:16:11:19 | prop | tst.js:8:28:8:51 | req.que ... trolled | tst.js:11:16:11:19 | prop | A $@ is used as a method name to be called. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | +| tst.js:13:15:13:18 | prop | tst.js:8:28:8:51 | req.que ... trolled | tst.js:13:15:13:18 | prop | A $@ is used as a property name to write to. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | +| tst.js:14:31:14:34 | prop | tst.js:8:28:8:51 | req.que ... trolled | tst.js:14:31:14:34 | prop | A $@ is used as a property name to write to. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | +| tst.js:16:10:16:13 | prop | tst.js:8:28:8:51 | req.que ... trolled | tst.js:16:10:16:13 | prop | A $@ is used as a property name to write to. | tst.js:8:28:8:51 | req.que ... trolled | user-provided value | +| tstNonExpr.js:8:17:8:23 | userVal | tstNonExpr.js:5:17:5:23 | req.url | tstNonExpr.js:8:17:8:23 | userVal | A $@ is used as a header name. | tstNonExpr.js:5:17:5:23 | req.url | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected b/javascript/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected index d3703e8796c9..d898f17eb60f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected +++ b/javascript/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected @@ -1,4 +1,11 @@ -| tst.js:7:22:7:36 | req.params.data | Unsafe deserialization of $@. | tst.js:7:22:7:36 | req.params.data | user input | -| tst.js:8:25:8:39 | req.params.data | Unsafe deserialization of $@. | tst.js:8:25:8:39 | req.params.data | user input | -| tst.js:12:26:12:40 | req.params.data | Unsafe deserialization of $@. | tst.js:12:26:12:40 | req.params.data | user input | -| tst.js:13:29:13:43 | req.params.data | Unsafe deserialization of $@. | tst.js:13:29:13:43 | req.params.data | user input | +nodes +| tst.js:7:22:7:36 | req.params.data | +| tst.js:8:25:8:39 | req.params.data | +| tst.js:12:26:12:40 | req.params.data | +| tst.js:13:29:13:43 | req.params.data | +edges +#select +| tst.js:7:22:7:36 | req.params.data | tst.js:7:22:7:36 | req.params.data | tst.js:7:22:7:36 | req.params.data | Unsafe deserialization of $@. | tst.js:7:22:7:36 | req.params.data | user input | +| tst.js:8:25:8:39 | req.params.data | tst.js:8:25:8:39 | req.params.data | tst.js:8:25:8:39 | req.params.data | Unsafe deserialization of $@. | tst.js:8:25:8:39 | req.params.data | user input | +| tst.js:12:26:12:40 | req.params.data | tst.js:12:26:12:40 | req.params.data | tst.js:12:26:12:40 | req.params.data | Unsafe deserialization of $@. | tst.js:12:26:12:40 | req.params.data | user input | +| tst.js:13:29:13:43 | req.params.data | tst.js:13:29:13:43 | req.params.data | tst.js:13:29:13:43 | req.params.data | Unsafe deserialization of $@. | tst.js:13:29:13:43 | req.params.data | user input | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected index a2b2d6f8dce6..b9427528e411 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected @@ -1,8 +1,62 @@ -| tst2.js:4:21:4:55 | href.su ... '?')+1) | Untrusted URL redirection due to $@. | tst2.js:2:14:2:28 | window.location | user-provided value | -| tst6.js:4:21:4:28 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value | -| tst6.js:6:17:6:24 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value | -| tst6.js:8:21:8:56 | $locati ... + "foo" | Untrusted URL redirection due to $@. | tst6.js:8:21:8:48 | $locati ... irect') | user-provided value | -| tst7.js:2:12:2:35 | documen ... .search | Untrusted URL redirection due to $@. | tst7.js:2:12:2:28 | document.location | user-provided value | -| tst7.js:5:27:5:50 | documen ... .search | Untrusted URL redirection due to $@. | tst7.js:5:27:5:43 | document.location | user-provided value | -| tst9.js:2:21:2:55 | documen ... ring(1) | Untrusted URL redirection due to $@. | tst9.js:2:21:2:37 | document.location | user-provided value | -| tst.js:2:19:2:72 | /.*redi ... ref)[1] | Untrusted URL redirection due to $@. | tst.js:2:47:2:63 | document.location | user-provided value | +nodes +| tst2.js:2:7:2:33 | href | +| tst2.js:2:7:2:33 | href | +| tst2.js:2:14:2:28 | window.location | +| tst2.js:2:14:2:28 | window.location | +| tst2.js:2:14:2:33 | window.location.href | +| tst2.js:2:14:2:33 | window.location.href | +| tst2.js:4:21:4:24 | href | +| tst2.js:4:21:4:24 | href | +| tst2.js:4:21:4:55 | href.su ... '?')+1) | +| tst6.js:2:7:2:45 | redirect | +| tst6.js:2:18:2:45 | $locati ... irect') | +| tst6.js:4:21:4:28 | redirect | +| tst6.js:6:17:6:24 | redirect | +| tst6.js:8:21:8:48 | $locati ... irect') | +| tst6.js:8:21:8:56 | $locati ... + "foo" | +| tst7.js:2:12:2:28 | document.location | +| tst7.js:2:12:2:35 | documen ... .search | +| tst7.js:5:27:5:43 | document.location | +| tst7.js:5:27:5:50 | documen ... .search | +| tst9.js:2:21:2:37 | document.location | +| tst9.js:2:21:2:37 | document.location | +| tst9.js:2:21:2:42 | documen ... on.hash | +| tst9.js:2:21:2:55 | documen ... ring(1) | +| tst.js:2:19:2:69 | /.*redi ... n.href) | +| tst.js:2:19:2:72 | /.*redi ... ref)[1] | +| tst.js:2:47:2:63 | document.location | +| tst.js:2:47:2:68 | documen ... on.href | +edges +| tst2.js:2:7:2:33 | href | tst2.js:4:21:4:24 | href | +| tst2.js:2:7:2:33 | href | tst2.js:4:21:4:24 | href | +| tst2.js:2:14:2:28 | window.location | tst2.js:2:14:2:33 | window.location.href | +| tst2.js:2:14:2:28 | window.location | tst2.js:2:14:2:33 | window.location.href | +| tst2.js:2:14:2:33 | window.location.href | tst2.js:2:7:2:33 | href | +| tst2.js:2:14:2:33 | window.location.href | tst2.js:2:7:2:33 | href | +| tst2.js:4:21:4:24 | href | tst2.js:4:21:4:55 | href.su ... '?')+1) | +| tst2.js:4:21:4:24 | href | tst2.js:4:21:4:55 | href.su ... '?')+1) | +| tst2.js:4:21:4:55 | href.su ... '?')+1) | tst2.js:2:14:2:28 | window.location | +| tst6.js:2:7:2:45 | redirect | tst6.js:4:21:4:28 | redirect | +| tst6.js:2:7:2:45 | redirect | tst6.js:6:17:6:24 | redirect | +| tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:2:7:2:45 | redirect | +| tst6.js:8:21:8:48 | $locati ... irect') | tst6.js:8:21:8:56 | $locati ... + "foo" | +| tst7.js:2:12:2:28 | document.location | tst7.js:2:12:2:35 | documen ... .search | +| tst7.js:5:27:5:43 | document.location | tst7.js:5:27:5:50 | documen ... .search | +| tst9.js:2:21:2:37 | document.location | tst9.js:2:21:2:42 | documen ... on.hash | +| tst9.js:2:21:2:37 | document.location | tst9.js:2:21:2:42 | documen ... on.hash | +| tst9.js:2:21:2:42 | documen ... on.hash | tst9.js:2:21:2:55 | documen ... ring(1) | +| tst9.js:2:21:2:55 | documen ... ring(1) | tst9.js:2:21:2:37 | document.location | +| tst.js:2:19:2:69 | /.*redi ... n.href) | tst.js:2:19:2:72 | /.*redi ... ref)[1] | +| tst.js:2:47:2:63 | document.location | tst.js:2:47:2:68 | documen ... on.href | +| tst.js:2:47:2:68 | documen ... on.href | tst.js:2:19:2:69 | /.*redi ... n.href) | +#select +| tst2.js:4:21:4:55 | href.su ... '?')+1) | tst2.js:2:14:2:28 | window.location | tst2.js:4:21:4:55 | href.su ... '?')+1) | Untrusted URL redirection due to $@. | tst2.js:2:14:2:28 | window.location | user-provided value | +| tst2.js:4:21:4:55 | href.su ... '?')+1) | tst2.js:2:14:2:28 | window.location | tst2.js:4:21:4:55 | href.su ... '?')+1) | Untrusted URL redirection due to $@. | tst2.js:2:14:2:28 | window.location | user-provided value | +| tst6.js:4:21:4:28 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:4:21:4:28 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value | +| tst6.js:6:17:6:24 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:6:17:6:24 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value | +| tst6.js:8:21:8:56 | $locati ... + "foo" | tst6.js:8:21:8:48 | $locati ... irect') | tst6.js:8:21:8:56 | $locati ... + "foo" | Untrusted URL redirection due to $@. | tst6.js:8:21:8:48 | $locati ... irect') | user-provided value | +| tst7.js:2:12:2:35 | documen ... .search | tst7.js:2:12:2:28 | document.location | tst7.js:2:12:2:35 | documen ... .search | Untrusted URL redirection due to $@. | tst7.js:2:12:2:28 | document.location | user-provided value | +| tst7.js:5:27:5:50 | documen ... .search | tst7.js:5:27:5:43 | document.location | tst7.js:5:27:5:50 | documen ... .search | Untrusted URL redirection due to $@. | tst7.js:5:27:5:43 | document.location | user-provided value | +| tst9.js:2:21:2:55 | documen ... ring(1) | tst9.js:2:21:2:37 | document.location | tst9.js:2:21:2:55 | documen ... ring(1) | Untrusted URL redirection due to $@. | tst9.js:2:21:2:37 | document.location | user-provided value | +| tst9.js:2:21:2:55 | documen ... ring(1) | tst9.js:2:21:2:37 | document.location | tst9.js:2:21:2:55 | documen ... ring(1) | Untrusted URL redirection due to $@. | tst9.js:2:21:2:37 | document.location | user-provided value | +| tst.js:2:19:2:72 | /.*redi ... ref)[1] | tst.js:2:47:2:63 | document.location | tst.js:2:19:2:72 | /.*redi ... ref)[1] | Untrusted URL redirection due to $@. | tst.js:2:47:2:63 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected index 012bb85379fe..2d57e091ba27 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected @@ -1,15 +1,106 @@ -| express.js:7:16:7:34 | req.param("target") | Untrusted URL redirection due to $@. | express.js:7:16:7:34 | req.param("target") | user-provided value | -| express.js:12:26:12:44 | req.param("target") | Untrusted URL redirection due to $@. | express.js:12:26:12:44 | req.param("target") | user-provided value | -| express.js:33:18:33:23 | target | Untrusted URL redirection due to $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | -| express.js:35:16:35:21 | target | Untrusted URL redirection due to $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | -| express.js:40:16:40:108 | (req.pa ... ntacts" | Untrusted URL redirection due to $@. | express.js:40:69:40:87 | req.param('action') | user-provided value | -| express.js:49:26:49:28 | url | Untrusted URL redirection due to $@. | express.js:44:16:44:28 | req.params[0] | user-provided value | -| express.js:74:16:74:43 | `${req. ... )}/foo` | Untrusted URL redirection due to $@. | express.js:74:19:74:37 | req.param("target") | user-provided value | -| express.js:90:18:90:23 | target | Untrusted URL redirection due to $@. | express.js:83:16:83:34 | req.param("target") | user-provided value | -| express.js:97:16:97:21 | target | Untrusted URL redirection due to $@. | express.js:83:16:83:34 | req.param("target") | user-provided value | -| express.js:118:16:118:72 | [req.qu ... oin('') | Untrusted URL redirection due to $@. | express.js:118:17:118:30 | req.query.page | user-provided value | -| node.js:7:34:7:39 | target | Untrusted URL redirection due to $@. | node.js:6:26:6:32 | req.url | user-provided value | -| node.js:15:34:15:45 | '/' + target | Untrusted URL redirection due to $@. | node.js:11:26:11:32 | req.url | user-provided value | -| node.js:32:34:32:55 | target ... =" + me | Untrusted URL redirection due to $@. | node.js:29:26:29:32 | req.url | user-provided value | -| react-native.js:8:17:8:23 | tainted | Untrusted URL redirection due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | -| react-native.js:9:26:9:32 | tainted | Untrusted URL redirection due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | +nodes +| express.js:7:16:7:34 | req.param("target") | +| express.js:12:26:12:44 | req.param("target") | +| express.js:27:7:27:34 | target | +| express.js:27:16:27:34 | req.param("target") | +| express.js:33:18:33:23 | target | +| express.js:35:16:35:21 | target | +| express.js:40:16:40:108 | (req.pa ... ntacts" | +| express.js:40:69:40:87 | req.param('action') | +| express.js:44:7:44:28 | handle | +| express.js:44:16:44:28 | req.params[0] | +| express.js:45:7:45:33 | url | +| express.js:45:13:45:27 | "/Me/" + handle | +| express.js:45:13:45:33 | "/Me/" ... e + "/" | +| express.js:45:22:45:27 | handle | +| express.js:49:3:49:3 | url | +| express.js:49:26:49:28 | url | +| express.js:74:16:74:43 | `${req. ... )}/foo` | +| express.js:74:19:74:37 | req.param("target") | +| express.js:83:7:83:34 | target | +| express.js:83:16:83:34 | req.param("target") | +| express.js:90:18:90:23 | target | +| express.js:97:16:97:21 | target | +| express.js:118:16:118:63 | [req.qu ... ection] | +| express.js:118:16:118:72 | [req.qu ... oin('') | +| express.js:118:17:118:30 | req.query.page | +| node.js:6:7:6:52 | target | +| node.js:6:16:6:39 | url.par ... , true) | +| node.js:6:16:6:45 | url.par ... ).query | +| node.js:6:16:6:52 | url.par ... .target | +| node.js:6:26:6:32 | req.url | +| node.js:7:34:7:39 | target | +| node.js:11:7:11:52 | target | +| node.js:11:16:11:39 | url.par ... , true) | +| node.js:11:16:11:45 | url.par ... ).query | +| node.js:11:16:11:52 | url.par ... .target | +| node.js:11:26:11:32 | req.url | +| node.js:15:34:15:45 | '/' + target | +| node.js:15:40:15:45 | target | +| node.js:29:7:29:52 | target | +| node.js:29:16:29:39 | url.par ... , true) | +| node.js:29:16:29:45 | url.par ... ).query | +| node.js:29:16:29:52 | url.par ... .target | +| node.js:29:26:29:32 | req.url | +| node.js:32:34:32:39 | target | +| node.js:32:34:32:50 | target + "?from=" | +| node.js:32:34:32:55 | target ... =" + me | +| react-native.js:7:7:7:33 | tainted | +| react-native.js:7:17:7:33 | req.param("code") | +| react-native.js:8:17:8:23 | tainted | +| react-native.js:9:26:9:32 | tainted | +edges +| express.js:27:7:27:34 | target | express.js:33:18:33:23 | target | +| express.js:27:7:27:34 | target | express.js:35:16:35:21 | target | +| express.js:27:16:27:34 | req.param("target") | express.js:27:7:27:34 | target | +| express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | +| express.js:44:7:44:28 | handle | express.js:45:22:45:27 | handle | +| express.js:44:16:44:28 | req.params[0] | express.js:44:7:44:28 | handle | +| express.js:45:7:45:33 | url | express.js:49:3:49:3 | url | +| express.js:45:13:45:27 | "/Me/" + handle | express.js:45:13:45:33 | "/Me/" ... e + "/" | +| express.js:45:13:45:33 | "/Me/" ... e + "/" | express.js:45:7:45:33 | url | +| express.js:45:22:45:27 | handle | express.js:45:13:45:27 | "/Me/" + handle | +| express.js:49:3:49:3 | url | express.js:49:26:49:28 | url | +| express.js:74:19:74:37 | req.param("target") | express.js:74:16:74:43 | `${req. ... )}/foo` | +| express.js:83:7:83:34 | target | express.js:90:18:90:23 | target | +| express.js:83:7:83:34 | target | express.js:97:16:97:21 | target | +| express.js:83:16:83:34 | req.param("target") | express.js:83:7:83:34 | target | +| express.js:118:16:118:63 | [req.qu ... ection] | express.js:118:16:118:72 | [req.qu ... oin('') | +| express.js:118:17:118:30 | req.query.page | express.js:118:16:118:63 | [req.qu ... ection] | +| node.js:6:7:6:52 | target | node.js:7:34:7:39 | target | +| node.js:6:16:6:39 | url.par ... , true) | node.js:6:16:6:45 | url.par ... ).query | +| node.js:6:16:6:45 | url.par ... ).query | node.js:6:16:6:52 | url.par ... .target | +| node.js:6:16:6:52 | url.par ... .target | node.js:6:7:6:52 | target | +| node.js:6:26:6:32 | req.url | node.js:6:16:6:39 | url.par ... , true) | +| node.js:11:7:11:52 | target | node.js:15:40:15:45 | target | +| node.js:11:16:11:39 | url.par ... , true) | node.js:11:16:11:45 | url.par ... ).query | +| node.js:11:16:11:45 | url.par ... ).query | node.js:11:16:11:52 | url.par ... .target | +| node.js:11:16:11:52 | url.par ... .target | node.js:11:7:11:52 | target | +| node.js:11:26:11:32 | req.url | node.js:11:16:11:39 | url.par ... , true) | +| node.js:15:40:15:45 | target | node.js:15:34:15:45 | '/' + target | +| node.js:29:7:29:52 | target | node.js:32:34:32:39 | target | +| node.js:29:16:29:39 | url.par ... , true) | node.js:29:16:29:45 | url.par ... ).query | +| node.js:29:16:29:45 | url.par ... ).query | node.js:29:16:29:52 | url.par ... .target | +| node.js:29:16:29:52 | url.par ... .target | node.js:29:7:29:52 | target | +| node.js:29:26:29:32 | req.url | node.js:29:16:29:39 | url.par ... , true) | +| node.js:32:34:32:39 | target | node.js:32:34:32:50 | target + "?from=" | +| node.js:32:34:32:50 | target + "?from=" | node.js:32:34:32:55 | target ... =" + me | +| react-native.js:7:7:7:33 | tainted | react-native.js:8:17:8:23 | tainted | +| react-native.js:7:7:7:33 | tainted | react-native.js:9:26:9:32 | tainted | +| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | +#select +| express.js:7:16:7:34 | req.param("target") | express.js:7:16:7:34 | req.param("target") | express.js:7:16:7:34 | req.param("target") | Untrusted URL redirection due to $@. | express.js:7:16:7:34 | req.param("target") | user-provided value | +| express.js:12:26:12:44 | req.param("target") | express.js:12:26:12:44 | req.param("target") | express.js:12:26:12:44 | req.param("target") | Untrusted URL redirection due to $@. | express.js:12:26:12:44 | req.param("target") | user-provided value | +| express.js:33:18:33:23 | target | express.js:27:16:27:34 | req.param("target") | express.js:33:18:33:23 | target | Untrusted URL redirection due to $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | +| express.js:35:16:35:21 | target | express.js:27:16:27:34 | req.param("target") | express.js:35:16:35:21 | target | Untrusted URL redirection due to $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | +| express.js:40:16:40:108 | (req.pa ... ntacts" | express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | Untrusted URL redirection due to $@. | express.js:40:69:40:87 | req.param('action') | user-provided value | +| express.js:49:26:49:28 | url | express.js:44:16:44:28 | req.params[0] | express.js:49:26:49:28 | url | Untrusted URL redirection due to $@. | express.js:44:16:44:28 | req.params[0] | user-provided value | +| express.js:74:16:74:43 | `${req. ... )}/foo` | express.js:74:19:74:37 | req.param("target") | express.js:74:16:74:43 | `${req. ... )}/foo` | Untrusted URL redirection due to $@. | express.js:74:19:74:37 | req.param("target") | user-provided value | +| express.js:90:18:90:23 | target | express.js:83:16:83:34 | req.param("target") | express.js:90:18:90:23 | target | Untrusted URL redirection due to $@. | express.js:83:16:83:34 | req.param("target") | user-provided value | +| express.js:97:16:97:21 | target | express.js:83:16:83:34 | req.param("target") | express.js:97:16:97:21 | target | Untrusted URL redirection due to $@. | express.js:83:16:83:34 | req.param("target") | user-provided value | +| express.js:118:16:118:72 | [req.qu ... oin('') | express.js:118:17:118:30 | req.query.page | express.js:118:16:118:72 | [req.qu ... oin('') | Untrusted URL redirection due to $@. | express.js:118:17:118:30 | req.query.page | user-provided value | +| node.js:7:34:7:39 | target | node.js:6:26:6:32 | req.url | node.js:7:34:7:39 | target | Untrusted URL redirection due to $@. | node.js:6:26:6:32 | req.url | user-provided value | +| node.js:15:34:15:45 | '/' + target | node.js:11:26:11:32 | req.url | node.js:15:34:15:45 | '/' + target | Untrusted URL redirection due to $@. | node.js:11:26:11:32 | req.url | user-provided value | +| node.js:32:34:32:55 | target ... =" + me | node.js:29:26:29:32 | req.url | node.js:32:34:32:55 | target ... =" + me | Untrusted URL redirection due to $@. | node.js:29:26:29:32 | req.url | user-provided value | +| react-native.js:8:17:8:23 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:17:8:23 | tainted | Untrusted URL redirection due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | +| react-native.js:9:26:9:32 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:26:9:32 | tainted | Untrusted URL redirection due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-611/Xxe.expected b/javascript/ql/test/query-tests/Security/CWE-611/Xxe.expected index c02efeef5e9e..982bd6ee841d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-611/Xxe.expected +++ b/javascript/ql/test/query-tests/Security/CWE-611/Xxe.expected @@ -1,5 +1,20 @@ -| domparser.js:11:55:11:57 | src | A $@ is parsed as XML without guarding against external entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | -| domparser.js:14:57:14:59 | src | A $@ is parsed as XML without guarding against external entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | -| libxml.noent.js:6:21:6:41 | req.par ... e-xml") | A $@ is parsed as XML without guarding against external entity expansion. | libxml.noent.js:6:21:6:41 | req.par ... e-xml") | user-provided value | -| libxml.sax.js:7:22:7:42 | req.par ... e-xml") | A $@ is parsed as XML without guarding against external entity expansion. | libxml.sax.js:7:22:7:42 | req.par ... e-xml") | user-provided value | -| libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | A $@ is parsed as XML without guarding against external entity expansion. | libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | user-provided value | +nodes +| domparser.js:2:7:2:36 | src | +| domparser.js:2:13:2:29 | document.location | +| domparser.js:2:13:2:36 | documen ... .search | +| domparser.js:11:55:11:57 | src | +| domparser.js:14:57:14:59 | src | +| libxml.noent.js:6:21:6:41 | req.par ... e-xml") | +| libxml.sax.js:7:22:7:42 | req.par ... e-xml") | +| libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | +edges +| domparser.js:2:7:2:36 | src | domparser.js:11:55:11:57 | src | +| domparser.js:2:7:2:36 | src | domparser.js:14:57:14:59 | src | +| domparser.js:2:13:2:29 | document.location | domparser.js:2:13:2:36 | documen ... .search | +| domparser.js:2:13:2:36 | documen ... .search | domparser.js:2:7:2:36 | src | +#select +| domparser.js:11:55:11:57 | src | domparser.js:2:13:2:29 | document.location | domparser.js:11:55:11:57 | src | A $@ is parsed as XML without guarding against external entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | +| domparser.js:14:57:14:59 | src | domparser.js:2:13:2:29 | document.location | domparser.js:14:57:14:59 | src | A $@ is parsed as XML without guarding against external entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | +| libxml.noent.js:6:21:6:41 | req.par ... e-xml") | libxml.noent.js:6:21:6:41 | req.par ... e-xml") | libxml.noent.js:6:21:6:41 | req.par ... e-xml") | A $@ is parsed as XML without guarding against external entity expansion. | libxml.noent.js:6:21:6:41 | req.par ... e-xml") | user-provided value | +| libxml.sax.js:7:22:7:42 | req.par ... e-xml") | libxml.sax.js:7:22:7:42 | req.par ... e-xml") | libxml.sax.js:7:22:7:42 | req.par ... e-xml") | A $@ is parsed as XML without guarding against external entity expansion. | libxml.sax.js:7:22:7:42 | req.par ... e-xml") | user-provided value | +| libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | A $@ is parsed as XML without guarding against external entity expansion. | libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.expected b/javascript/ql/test/query-tests/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.expected index 78488fcd732e..0fe75f2e75e5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.expected +++ b/javascript/ql/test/query-tests/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.expected @@ -1,2 +1,11 @@ -| tst.js:17:11:17:113 | `Hi, lo ... token}` | Links in this email can be hijacked by poisoning the HTTP host header $@. | tst.js:17:84:17:91 | req.host | here | -| tst.js:18:11:18:127 | `Hi, lo ... reset.` | Links in this email can be hijacked by poisoning the HTTP host header $@. | tst.js:18:78:18:85 | req.host | here | +nodes +| tst.js:17:11:17:113 | `Hi, lo ... token}` | +| tst.js:17:84:17:91 | req.host | +| tst.js:18:11:18:127 | `Hi, lo ... reset.` | +| tst.js:18:78:18:85 | req.host | +edges +| tst.js:17:84:17:91 | req.host | tst.js:17:11:17:113 | `Hi, lo ... token}` | +| tst.js:18:78:18:85 | req.host | tst.js:18:11:18:127 | `Hi, lo ... reset.` | +#select +| tst.js:17:11:17:113 | `Hi, lo ... token}` | tst.js:17:84:17:91 | req.host | tst.js:17:11:17:113 | `Hi, lo ... token}` | Links in this email can be hijacked by poisoning the HTTP host header $@. | tst.js:17:84:17:91 | req.host | here | +| tst.js:18:11:18:127 | `Hi, lo ... reset.` | tst.js:18:78:18:85 | req.host | tst.js:18:11:18:127 | `Hi, lo ... reset.` | Links in this email can be hijacked by poisoning the HTTP host header $@. | tst.js:18:78:18:85 | req.host | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-643/XpathInjection.expected b/javascript/ql/test/query-tests/Security/CWE-643/XpathInjection.expected index c97516665743..06e027f70dc4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-643/XpathInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-643/XpathInjection.expected @@ -1,7 +1,39 @@ -| XpathInjectionBad.js:9:34:9:96 | "//user ... text()" | $@ flows here and is used in an XPath expression. | XpathInjectionBad.js:6:18:6:38 | req.par ... rName") | User-provided value | -| tst2.js:2:27:2:31 | query | $@ flows here and is used in an XPath expression. | tst2.js:1:13:1:29 | document.location | User-provided value | -| tst2.js:3:19:3:23 | query | $@ flows here and is used in an XPath expression. | tst2.js:1:13:1:29 | document.location | User-provided value | -| tst.js:7:15:7:21 | tainted | $@ flows here and is used in an XPath expression. | tst.js:6:17:6:37 | req.par ... rName") | User-provided value | -| tst.js:8:16:8:22 | tainted | $@ flows here and is used in an XPath expression. | tst.js:6:17:6:37 | req.par ... rName") | User-provided value | -| tst.js:9:17:9:23 | tainted | $@ flows here and is used in an XPath expression. | tst.js:6:17:6:37 | req.par ... rName") | User-provided value | -| tst.js:11:8:11:14 | tainted | $@ flows here and is used in an XPath expression. | tst.js:6:17:6:37 | req.par ... rName") | User-provided value | +nodes +| XpathInjectionBad.js:6:7:6:38 | userName | +| XpathInjectionBad.js:6:18:6:38 | req.par ... rName") | +| XpathInjectionBad.js:9:34:9:73 | "//user ... serName | +| XpathInjectionBad.js:9:34:9:96 | "//user ... text()" | +| XpathInjectionBad.js:9:66:9:73 | userName | +| tst2.js:1:13:1:29 | document.location | +| tst2.js:1:13:1:34 | documen ... on.hash | +| tst2.js:1:13:1:47 | documen ... ring(1) | +| tst2.js:2:27:2:31 | query | +| tst2.js:3:19:3:23 | query | +| tst.js:6:7:6:37 | tainted | +| tst.js:6:17:6:37 | req.par ... rName") | +| tst.js:7:15:7:21 | tainted | +| tst.js:8:16:8:22 | tainted | +| tst.js:9:17:9:23 | tainted | +| tst.js:11:8:11:14 | tainted | +edges +| XpathInjectionBad.js:6:7:6:38 | userName | XpathInjectionBad.js:9:66:9:73 | userName | +| XpathInjectionBad.js:6:18:6:38 | req.par ... rName") | XpathInjectionBad.js:6:7:6:38 | userName | +| XpathInjectionBad.js:9:34:9:73 | "//user ... serName | XpathInjectionBad.js:9:34:9:96 | "//user ... text()" | +| XpathInjectionBad.js:9:66:9:73 | userName | XpathInjectionBad.js:9:34:9:73 | "//user ... serName | +| tst2.js:1:13:1:29 | document.location | tst2.js:1:13:1:34 | documen ... on.hash | +| tst2.js:1:13:1:34 | documen ... on.hash | tst2.js:1:13:1:47 | documen ... ring(1) | +| tst2.js:1:13:1:47 | documen ... ring(1) | tst2.js:2:27:2:31 | query | +| tst2.js:1:13:1:47 | documen ... ring(1) | tst2.js:3:19:3:23 | query | +| tst.js:6:7:6:37 | tainted | tst.js:7:15:7:21 | tainted | +| tst.js:6:7:6:37 | tainted | tst.js:8:16:8:22 | tainted | +| tst.js:6:7:6:37 | tainted | tst.js:9:17:9:23 | tainted | +| tst.js:6:7:6:37 | tainted | tst.js:11:8:11:14 | tainted | +| tst.js:6:17:6:37 | req.par ... rName") | tst.js:6:7:6:37 | tainted | +#select +| XpathInjectionBad.js:9:34:9:96 | "//user ... text()" | XpathInjectionBad.js:6:18:6:38 | req.par ... rName") | XpathInjectionBad.js:9:34:9:96 | "//user ... text()" | $@ flows here and is used in an XPath expression. | XpathInjectionBad.js:6:18:6:38 | req.par ... rName") | User-provided value | +| tst2.js:2:27:2:31 | query | tst2.js:1:13:1:29 | document.location | tst2.js:2:27:2:31 | query | $@ flows here and is used in an XPath expression. | tst2.js:1:13:1:29 | document.location | User-provided value | +| tst2.js:3:19:3:23 | query | tst2.js:1:13:1:29 | document.location | tst2.js:3:19:3:23 | query | $@ flows here and is used in an XPath expression. | tst2.js:1:13:1:29 | document.location | User-provided value | +| tst.js:7:15:7:21 | tainted | tst.js:6:17:6:37 | req.par ... rName") | tst.js:7:15:7:21 | tainted | $@ flows here and is used in an XPath expression. | tst.js:6:17:6:37 | req.par ... rName") | User-provided value | +| tst.js:8:16:8:22 | tainted | tst.js:6:17:6:37 | req.par ... rName") | tst.js:8:16:8:22 | tainted | $@ flows here and is used in an XPath expression. | tst.js:6:17:6:37 | req.par ... rName") | User-provided value | +| tst.js:9:17:9:23 | tainted | tst.js:6:17:6:37 | req.par ... rName") | tst.js:9:17:9:23 | tainted | $@ flows here and is used in an XPath expression. | tst.js:6:17:6:37 | req.par ... rName") | User-provided value | +| tst.js:11:8:11:14 | tainted | tst.js:6:17:6:37 | req.par ... rName") | tst.js:11:8:11:14 | tainted | $@ flows here and is used in an XPath expression. | tst.js:6:17:6:37 | req.par ... rName") | User-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected index 669b363a45db..c4bd46ed4e73 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected @@ -1,14 +1,81 @@ -| RegExpInjection.js:8:23:8:45 | "\\\\b" + ... (.*)\\n" | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | -| RegExpInjection.js:19:14:19:22 | wrap(key) | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | -| RegExpInjection.js:21:14:21:22 | wrap(key) | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | -| RegExpInjection.js:27:14:27:21 | getKey() | This regular expression is constructed from a $@. | RegExpInjection.js:24:12:24:27 | req.param("key") | user-provided value | -| RegExpInjection.js:31:23:31:23 | s | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | -| RegExpInjection.js:31:23:31:23 | s | This regular expression is constructed from a $@. | RegExpInjection.js:24:12:24:27 | req.param("key") | user-provided value | -| RegExpInjection.js:40:19:40:23 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:41:22:41:26 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:42:21:42:25 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:45:20:45:24 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:46:23:46:27 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:47:22:47:26 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:50:46:50:50 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| tst.js:3:16:3:35 | "^"+ data.name + "$" | This regular expression is constructed from a $@. | tst.js:1:46:1:46 | e | user-provided value | +nodes +| RegExpInjection.js:5:7:5:28 | key | +| RegExpInjection.js:5:13:5:28 | req.param("key") | +| RegExpInjection.js:5:31:5:56 | input | +| RegExpInjection.js:5:39:5:56 | req.param("input") | +| RegExpInjection.js:8:23:8:33 | "\\\\b" + key | +| RegExpInjection.js:8:23:8:45 | "\\\\b" + ... (.*)\\n" | +| RegExpInjection.js:8:31:8:33 | key | +| RegExpInjection.js:19:14:19:22 | wrap(key) | +| RegExpInjection.js:19:19:19:21 | key | +| RegExpInjection.js:21:14:21:22 | wrap(key) | +| RegExpInjection.js:21:19:21:21 | key | +| RegExpInjection.js:24:12:24:27 | req.param("key") | +| RegExpInjection.js:27:14:27:21 | getKey() | +| RegExpInjection.js:29:21:29:21 | s | +| RegExpInjection.js:29:21:29:21 | s | +| RegExpInjection.js:31:23:31:23 | s | +| RegExpInjection.js:31:23:31:23 | s | +| RegExpInjection.js:33:12:33:14 | key | +| RegExpInjection.js:34:12:34:19 | getKey() | +| RegExpInjection.js:40:19:40:23 | input | +| RegExpInjection.js:41:22:41:26 | input | +| RegExpInjection.js:42:21:42:25 | input | +| RegExpInjection.js:45:20:45:24 | input | +| RegExpInjection.js:46:23:46:27 | input | +| RegExpInjection.js:47:22:47:26 | input | +| RegExpInjection.js:50:46:50:50 | input | +| tst.js:1:46:1:46 | e | +| tst.js:2:9:2:21 | data | +| tst.js:2:16:2:16 | e | +| tst.js:2:16:2:21 | e.data | +| tst.js:3:16:3:29 | "^"+ data.name | +| tst.js:3:16:3:35 | "^"+ data.name + "$" | +| tst.js:3:21:3:24 | data | +| tst.js:3:21:3:29 | data.name | +edges +| RegExpInjection.js:5:7:5:28 | key | RegExpInjection.js:8:31:8:33 | key | +| RegExpInjection.js:5:7:5:28 | key | RegExpInjection.js:19:19:19:21 | key | +| RegExpInjection.js:5:7:5:28 | key | RegExpInjection.js:21:19:21:21 | key | +| RegExpInjection.js:5:7:5:28 | key | RegExpInjection.js:33:12:33:14 | key | +| RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:5:7:5:28 | key | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:40:19:40:23 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:41:22:41:26 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:42:21:42:25 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:45:20:45:24 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:46:23:46:27 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:47:22:47:26 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:50:46:50:50 | input | +| RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:5:31:5:56 | input | +| RegExpInjection.js:8:23:8:33 | "\\\\b" + key | RegExpInjection.js:8:23:8:45 | "\\\\b" + ... (.*)\\n" | +| RegExpInjection.js:8:31:8:33 | key | RegExpInjection.js:8:23:8:33 | "\\\\b" + key | +| RegExpInjection.js:19:19:19:21 | key | RegExpInjection.js:19:14:19:22 | wrap(key) | +| RegExpInjection.js:21:19:21:21 | key | RegExpInjection.js:21:14:21:22 | wrap(key) | +| RegExpInjection.js:24:12:24:27 | req.param("key") | RegExpInjection.js:27:14:27:21 | getKey() | +| RegExpInjection.js:24:12:24:27 | req.param("key") | RegExpInjection.js:34:12:34:19 | getKey() | +| RegExpInjection.js:29:21:29:21 | s | RegExpInjection.js:31:23:31:23 | s | +| RegExpInjection.js:29:21:29:21 | s | RegExpInjection.js:31:23:31:23 | s | +| RegExpInjection.js:33:12:33:14 | key | RegExpInjection.js:29:21:29:21 | s | +| RegExpInjection.js:34:12:34:19 | getKey() | RegExpInjection.js:29:21:29:21 | s | +| tst.js:1:46:1:46 | e | tst.js:2:16:2:16 | e | +| tst.js:2:9:2:21 | data | tst.js:3:21:3:24 | data | +| tst.js:2:16:2:16 | e | tst.js:2:16:2:21 | e.data | +| tst.js:2:16:2:21 | e.data | tst.js:2:9:2:21 | data | +| tst.js:3:16:3:29 | "^"+ data.name | tst.js:3:16:3:35 | "^"+ data.name + "$" | +| tst.js:3:21:3:24 | data | tst.js:3:21:3:29 | data.name | +| tst.js:3:21:3:29 | data.name | tst.js:3:16:3:29 | "^"+ data.name | +#select +| RegExpInjection.js:8:23:8:45 | "\\\\b" + ... (.*)\\n" | RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:8:23:8:45 | "\\\\b" + ... (.*)\\n" | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | +| RegExpInjection.js:19:14:19:22 | wrap(key) | RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:19:14:19:22 | wrap(key) | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | +| RegExpInjection.js:21:14:21:22 | wrap(key) | RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:21:14:21:22 | wrap(key) | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | +| RegExpInjection.js:27:14:27:21 | getKey() | RegExpInjection.js:24:12:24:27 | req.param("key") | RegExpInjection.js:27:14:27:21 | getKey() | This regular expression is constructed from a $@. | RegExpInjection.js:24:12:24:27 | req.param("key") | user-provided value | +| RegExpInjection.js:31:23:31:23 | s | RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:31:23:31:23 | s | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | +| RegExpInjection.js:31:23:31:23 | s | RegExpInjection.js:24:12:24:27 | req.param("key") | RegExpInjection.js:31:23:31:23 | s | This regular expression is constructed from a $@. | RegExpInjection.js:24:12:24:27 | req.param("key") | user-provided value | +| RegExpInjection.js:40:19:40:23 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:40:19:40:23 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:41:22:41:26 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:41:22:41:26 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:42:21:42:25 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:42:21:42:25 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:45:20:45:24 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:45:20:45:24 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:46:23:46:27 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:46:23:46:27 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:47:22:47:26 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:47:22:47:26 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:50:46:50:50 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:50:46:50:50 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| tst.js:3:16:3:35 | "^"+ data.name + "$" | tst.js:1:46:1:46 | e | tst.js:3:16:3:35 | "^"+ data.name + "$" | This regular expression is constructed from a $@. | tst.js:1:46:1:46 | e | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-776/XmlBomb.expected b/javascript/ql/test/query-tests/Security/CWE-776/XmlBomb.expected index 38c27d211441..483d2d585c7a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-776/XmlBomb.expected +++ b/javascript/ql/test/query-tests/Security/CWE-776/XmlBomb.expected @@ -1,10 +1,43 @@ -| closure.js:4:24:4:26 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | closure.js:2:13:2:29 | document.location | user-provided value | -| domparser.js:6:37:6:39 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | -| domparser.js:11:55:11:57 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | -| domparser.js:14:57:14:59 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | -| expat.js:7:16:7:36 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | expat.js:7:16:7:36 | req.par ... e-xml") | user-provided value | -| jquery.js:5:14:5:16 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | jquery.js:2:13:2:29 | document.location | user-provided value | -| libxml.js:6:21:6:41 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | libxml.js:6:21:6:41 | req.par ... e-xml") | user-provided value | -| libxml.noent.js:6:21:6:41 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | libxml.noent.js:6:21:6:41 | req.par ... e-xml") | user-provided value | -| libxml.sax.js:7:22:7:42 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | libxml.sax.js:7:22:7:42 | req.par ... e-xml") | user-provided value | -| libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | user-provided value | +nodes +| closure.js:2:7:2:36 | src | +| closure.js:2:13:2:29 | document.location | +| closure.js:2:13:2:36 | documen ... .search | +| closure.js:4:24:4:26 | src | +| domparser.js:2:7:2:36 | src | +| domparser.js:2:13:2:29 | document.location | +| domparser.js:2:13:2:36 | documen ... .search | +| domparser.js:6:37:6:39 | src | +| domparser.js:11:55:11:57 | src | +| domparser.js:14:57:14:59 | src | +| expat.js:7:16:7:36 | req.par ... e-xml") | +| jquery.js:2:7:2:36 | src | +| jquery.js:2:13:2:29 | document.location | +| jquery.js:2:13:2:36 | documen ... .search | +| jquery.js:5:14:5:16 | src | +| libxml.js:6:21:6:41 | req.par ... e-xml") | +| libxml.noent.js:6:21:6:41 | req.par ... e-xml") | +| libxml.sax.js:7:22:7:42 | req.par ... e-xml") | +| libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | +edges +| closure.js:2:7:2:36 | src | closure.js:4:24:4:26 | src | +| closure.js:2:13:2:29 | document.location | closure.js:2:13:2:36 | documen ... .search | +| closure.js:2:13:2:36 | documen ... .search | closure.js:2:7:2:36 | src | +| domparser.js:2:7:2:36 | src | domparser.js:6:37:6:39 | src | +| domparser.js:2:7:2:36 | src | domparser.js:11:55:11:57 | src | +| domparser.js:2:7:2:36 | src | domparser.js:14:57:14:59 | src | +| domparser.js:2:13:2:29 | document.location | domparser.js:2:13:2:36 | documen ... .search | +| domparser.js:2:13:2:36 | documen ... .search | domparser.js:2:7:2:36 | src | +| jquery.js:2:7:2:36 | src | jquery.js:5:14:5:16 | src | +| jquery.js:2:13:2:29 | document.location | jquery.js:2:13:2:36 | documen ... .search | +| jquery.js:2:13:2:36 | documen ... .search | jquery.js:2:7:2:36 | src | +#select +| closure.js:4:24:4:26 | src | closure.js:2:13:2:29 | document.location | closure.js:4:24:4:26 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | closure.js:2:13:2:29 | document.location | user-provided value | +| domparser.js:6:37:6:39 | src | domparser.js:2:13:2:29 | document.location | domparser.js:6:37:6:39 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | +| domparser.js:11:55:11:57 | src | domparser.js:2:13:2:29 | document.location | domparser.js:11:55:11:57 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | +| domparser.js:14:57:14:59 | src | domparser.js:2:13:2:29 | document.location | domparser.js:14:57:14:59 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | domparser.js:2:13:2:29 | document.location | user-provided value | +| expat.js:7:16:7:36 | req.par ... e-xml") | expat.js:7:16:7:36 | req.par ... e-xml") | expat.js:7:16:7:36 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | expat.js:7:16:7:36 | req.par ... e-xml") | user-provided value | +| jquery.js:5:14:5:16 | src | jquery.js:2:13:2:29 | document.location | jquery.js:5:14:5:16 | src | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | jquery.js:2:13:2:29 | document.location | user-provided value | +| libxml.js:6:21:6:41 | req.par ... e-xml") | libxml.js:6:21:6:41 | req.par ... e-xml") | libxml.js:6:21:6:41 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | libxml.js:6:21:6:41 | req.par ... e-xml") | user-provided value | +| libxml.noent.js:6:21:6:41 | req.par ... e-xml") | libxml.noent.js:6:21:6:41 | req.par ... e-xml") | libxml.noent.js:6:21:6:41 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | libxml.noent.js:6:21:6:41 | req.par ... e-xml") | user-provided value | +| libxml.sax.js:7:22:7:42 | req.par ... e-xml") | libxml.sax.js:7:22:7:42 | req.par ... e-xml") | libxml.sax.js:7:22:7:42 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | libxml.sax.js:7:22:7:42 | req.par ... e-xml") | user-provided value | +| libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | A $@ is parsed as XML without guarding against uncontrolled entity expansion. | libxml.saxpush.js:7:15:7:35 | req.par ... e-xml") | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected index a6f208d1ea85..44cca50c842b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected @@ -1,51 +1,107 @@ -| HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name | -| HardcodedCredentials.js:8:19:8:34 | 'secretpassword' | The hard-coded value "secretpassword" is used as $@. | HardcodedCredentials.js:8:19:8:34 | 'secretpassword' | password | -| HardcodedCredentials.js:15:36:15:50 | "user:password" | The hard-coded value "user:password" is used as $@. | HardcodedCredentials.js:15:36:15:50 | "user:password" | credentials | -| HardcodedCredentials.js:16:37:16:51 | "user:password" | The hard-coded value "user:password" is used as $@. | HardcodedCredentials.js:16:37:16:51 | "user:password" | credentials | -| HardcodedCredentials.js:18:16:18:30 | "user:password" | The hard-coded value "user:password" is used as $@. | HardcodedCredentials.js:20:36:20:51 | getCredentials() | credentials | -| HardcodedCredentials.js:27:25:27:31 | 'admin' | The hard-coded value "admin" is used as $@. | HardcodedCredentials.js:27:25:27:31 | 'admin' | user name | -| HardcodedCredentials.js:27:34:27:46 | 'supersecret' | The hard-coded value "supersecret" is used as $@. | HardcodedCredentials.js:27:34:27:46 | 'supersecret' | password | -| HardcodedCredentials.js:29:11:29:30 | 'unknown-admin-name' | The hard-coded value "unknown-admin-name" is used as $@. | HardcodedCredentials.js:29:11:29:30 | 'unknown-admin-name' | user name | -| HardcodedCredentials.js:29:35:29:47 | 'supersecret' | The hard-coded value "supersecret" is used as $@. | HardcodedCredentials.js:29:35:29:47 | 'supersecret' | password | -| HardcodedCredentials.js:35:15:35:24 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:35:15:35:24 | 'username' | user name | -| HardcodedCredentials.js:35:27:35:36 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:35:27:35:36 | 'password' | password | -| HardcodedCredentials.js:41:38:41:47 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:41:38:41:47 | 'username' | user name | -| HardcodedCredentials.js:41:67:41:76 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:41:67:41:76 | 'password' | password | -| HardcodedCredentials.js:42:35:42:44 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:42:35:42:44 | 'username' | user name | -| HardcodedCredentials.js:42:64:42:73 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:42:64:42:73 | 'password' | password | -| HardcodedCredentials.js:44:34:44:43 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:44:34:44:43 | 'username' | user name | -| HardcodedCredentials.js:44:63:44:72 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:44:63:44:72 | 'password' | password | -| HardcodedCredentials.js:46:25:46:34 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:46:25:46:34 | 'password' | password | -| HardcodedCredentials.js:53:27:53:36 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:53:27:53:36 | 'username' | user name | -| HardcodedCredentials.js:53:39:53:48 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:53:39:53:48 | 'password' | password | -| HardcodedCredentials.js:56:21:56:30 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:56:21:56:30 | 'username' | user name | -| HardcodedCredentials.js:57:21:57:30 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:57:21:57:30 | 'password' | password | -| HardcodedCredentials.js:61:42:61:54 | 'bearerToken' | The hard-coded value "bearerToken" is used as $@. | HardcodedCredentials.js:61:42:61:54 | 'bearerToken' | token | -| HardcodedCredentials.js:65:23:65:35 | 'bearerToken' | The hard-coded value "bearerToken" is used as $@. | HardcodedCredentials.js:65:23:65:35 | 'bearerToken' | token | -| HardcodedCredentials.js:69:28:69:37 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:69:28:69:37 | 'username' | user name | -| HardcodedCredentials.js:69:40:69:49 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:69:40:69:49 | 'password' | password | -| HardcodedCredentials.js:70:28:70:37 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:70:28:70:37 | 'username' | user name | -| HardcodedCredentials.js:70:40:70:49 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:70:40:70:49 | 'password' | password | -| HardcodedCredentials.js:72:23:72:32 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:72:23:72:32 | 'username' | user name | -| HardcodedCredentials.js:72:35:72:44 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:72:35:72:44 | 'password' | password | -| HardcodedCredentials.js:75:21:75:30 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:75:21:75:30 | 'username' | user name | -| HardcodedCredentials.js:76:21:76:30 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:76:21:76:30 | 'password' | password | -| HardcodedCredentials.js:84:38:84:47 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:84:38:84:47 | 'username' | user name | -| HardcodedCredentials.js:84:50:84:59 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:84:50:84:59 | 'password' | password | -| HardcodedCredentials.js:86:44:86:53 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:86:44:86:53 | 'username' | user name | -| HardcodedCredentials.js:86:56:86:65 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:86:56:86:65 | 'password' | password | -| HardcodedCredentials.js:91:25:91:31 | 'TOKEN' | The hard-coded value "TOKEN" is used as $@. | HardcodedCredentials.js:91:25:91:31 | 'TOKEN' | token | -| HardcodedCredentials.js:98:18:98:21 | 'x1' | The hard-coded value "x1" is used as $@. | HardcodedCredentials.js:98:18:98:21 | 'x1' | user name | -| HardcodedCredentials.js:99:16:99:19 | 'x2' | The hard-coded value "x2" is used as $@. | HardcodedCredentials.js:99:16:99:19 | 'x2' | user name | -| HardcodedCredentials.js:100:25:100:28 | 'x3' | The hard-coded value "x3" is used as $@. | HardcodedCredentials.js:100:25:100:28 | 'x3' | user name | -| HardcodedCredentials.js:101:19:101:22 | 'x4' | The hard-coded value "x4" is used as $@. | HardcodedCredentials.js:101:19:101:22 | 'x4' | user name | -| HardcodedCredentials.js:102:14:102:17 | 'y1' | The hard-coded value "y1" is used as $@. | HardcodedCredentials.js:102:14:102:17 | 'y1' | password | -| HardcodedCredentials.js:103:17:103:20 | 'y2' | The hard-coded value "y2" is used as $@. | HardcodedCredentials.js:103:17:103:20 | 'y2' | password | -| HardcodedCredentials.js:104:27:104:30 | 'y3' | The hard-coded value "y3" is used as $@. | HardcodedCredentials.js:104:27:104:30 | 'y3' | password | -| HardcodedCredentials.js:105:19:105:22 | 'y4' | The hard-coded value "y4" is used as $@. | HardcodedCredentials.js:105:19:105:22 | 'y4' | password | -| HardcodedCredentials.js:106:16:106:19 | 'z1' | The hard-coded value "z1" is used as $@. | HardcodedCredentials.js:106:16:106:19 | 'z1' | token | -| HardcodedCredentials.js:112:19:112:22 | 'x5' | The hard-coded value "x5" is used as $@. | HardcodedCredentials.js:112:19:112:22 | 'x5' | user name | -| HardcodedCredentials.js:113:19:113:22 | 'y5' | The hard-coded value "y5" is used as $@. | HardcodedCredentials.js:113:19:113:22 | 'y5' | password | -| HardcodedCredentials.js:130:44:130:58 | 'crypto secret' | The hard-coded value "crypto secret" is used as $@. | HardcodedCredentials.js:130:44:130:58 | 'crypto secret' | key | -| HardcodedCredentials.js:131:52:131:73 | 'crypto ... secret' | The hard-coded value "crypto-js/aes secret" is used as $@. | HardcodedCredentials.js:131:52:131:73 | 'crypto ... secret' | key | -| HardcodedCredentials.js:135:41:135:63 | "cookie ... secret" | The hard-coded value "cookie-session secret" is used as $@. | HardcodedCredentials.js:135:41:135:63 | "cookie ... secret" | key | +nodes +| HardcodedCredentials.js:5:15:5:22 | 'dbuser' | +| HardcodedCredentials.js:8:19:8:34 | 'secretpassword' | +| HardcodedCredentials.js:15:36:15:50 | "user:password" | +| HardcodedCredentials.js:16:37:16:51 | "user:password" | +| HardcodedCredentials.js:18:16:18:30 | "user:password" | +| HardcodedCredentials.js:20:36:20:51 | getCredentials() | +| HardcodedCredentials.js:27:25:27:31 | 'admin' | +| HardcodedCredentials.js:27:34:27:46 | 'supersecret' | +| HardcodedCredentials.js:29:11:29:30 | 'unknown-admin-name' | +| HardcodedCredentials.js:29:35:29:47 | 'supersecret' | +| HardcodedCredentials.js:35:15:35:24 | 'username' | +| HardcodedCredentials.js:35:27:35:36 | 'password' | +| HardcodedCredentials.js:41:38:41:47 | 'username' | +| HardcodedCredentials.js:41:67:41:76 | 'password' | +| HardcodedCredentials.js:42:35:42:44 | 'username' | +| HardcodedCredentials.js:42:64:42:73 | 'password' | +| HardcodedCredentials.js:44:34:44:43 | 'username' | +| HardcodedCredentials.js:44:63:44:72 | 'password' | +| HardcodedCredentials.js:46:25:46:34 | 'password' | +| HardcodedCredentials.js:53:27:53:36 | 'username' | +| HardcodedCredentials.js:53:39:53:48 | 'password' | +| HardcodedCredentials.js:56:21:56:30 | 'username' | +| HardcodedCredentials.js:57:21:57:30 | 'password' | +| HardcodedCredentials.js:61:42:61:54 | 'bearerToken' | +| HardcodedCredentials.js:65:23:65:35 | 'bearerToken' | +| HardcodedCredentials.js:69:28:69:37 | 'username' | +| HardcodedCredentials.js:69:40:69:49 | 'password' | +| HardcodedCredentials.js:70:28:70:37 | 'username' | +| HardcodedCredentials.js:70:40:70:49 | 'password' | +| HardcodedCredentials.js:72:23:72:32 | 'username' | +| HardcodedCredentials.js:72:35:72:44 | 'password' | +| HardcodedCredentials.js:75:21:75:30 | 'username' | +| HardcodedCredentials.js:76:21:76:30 | 'password' | +| HardcodedCredentials.js:84:38:84:47 | 'username' | +| HardcodedCredentials.js:84:50:84:59 | 'password' | +| HardcodedCredentials.js:86:44:86:53 | 'username' | +| HardcodedCredentials.js:86:56:86:65 | 'password' | +| HardcodedCredentials.js:91:25:91:31 | 'TOKEN' | +| HardcodedCredentials.js:98:18:98:21 | 'x1' | +| HardcodedCredentials.js:99:16:99:19 | 'x2' | +| HardcodedCredentials.js:100:25:100:28 | 'x3' | +| HardcodedCredentials.js:101:19:101:22 | 'x4' | +| HardcodedCredentials.js:102:14:102:17 | 'y1' | +| HardcodedCredentials.js:103:17:103:20 | 'y2' | +| HardcodedCredentials.js:104:27:104:30 | 'y3' | +| HardcodedCredentials.js:105:19:105:22 | 'y4' | +| HardcodedCredentials.js:106:16:106:19 | 'z1' | +| HardcodedCredentials.js:112:19:112:22 | 'x5' | +| HardcodedCredentials.js:113:19:113:22 | 'y5' | +| HardcodedCredentials.js:130:44:130:58 | 'crypto secret' | +| HardcodedCredentials.js:131:52:131:73 | 'crypto ... secret' | +| HardcodedCredentials.js:135:41:135:63 | "cookie ... secret" | +edges +| HardcodedCredentials.js:18:16:18:30 | "user:password" | HardcodedCredentials.js:20:36:20:51 | getCredentials() | +#select +| HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name | +| HardcodedCredentials.js:8:19:8:34 | 'secretpassword' | HardcodedCredentials.js:8:19:8:34 | 'secretpassword' | HardcodedCredentials.js:8:19:8:34 | 'secretpassword' | The hard-coded value "secretpassword" is used as $@. | HardcodedCredentials.js:8:19:8:34 | 'secretpassword' | password | +| HardcodedCredentials.js:15:36:15:50 | "user:password" | HardcodedCredentials.js:15:36:15:50 | "user:password" | HardcodedCredentials.js:15:36:15:50 | "user:password" | The hard-coded value "user:password" is used as $@. | HardcodedCredentials.js:15:36:15:50 | "user:password" | credentials | +| HardcodedCredentials.js:16:37:16:51 | "user:password" | HardcodedCredentials.js:16:37:16:51 | "user:password" | HardcodedCredentials.js:16:37:16:51 | "user:password" | The hard-coded value "user:password" is used as $@. | HardcodedCredentials.js:16:37:16:51 | "user:password" | credentials | +| HardcodedCredentials.js:18:16:18:30 | "user:password" | HardcodedCredentials.js:18:16:18:30 | "user:password" | HardcodedCredentials.js:20:36:20:51 | getCredentials() | The hard-coded value "user:password" is used as $@. | HardcodedCredentials.js:20:36:20:51 | getCredentials() | credentials | +| HardcodedCredentials.js:27:25:27:31 | 'admin' | HardcodedCredentials.js:27:25:27:31 | 'admin' | HardcodedCredentials.js:27:25:27:31 | 'admin' | The hard-coded value "admin" is used as $@. | HardcodedCredentials.js:27:25:27:31 | 'admin' | user name | +| HardcodedCredentials.js:27:34:27:46 | 'supersecret' | HardcodedCredentials.js:27:34:27:46 | 'supersecret' | HardcodedCredentials.js:27:34:27:46 | 'supersecret' | The hard-coded value "supersecret" is used as $@. | HardcodedCredentials.js:27:34:27:46 | 'supersecret' | password | +| HardcodedCredentials.js:29:11:29:30 | 'unknown-admin-name' | HardcodedCredentials.js:29:11:29:30 | 'unknown-admin-name' | HardcodedCredentials.js:29:11:29:30 | 'unknown-admin-name' | The hard-coded value "unknown-admin-name" is used as $@. | HardcodedCredentials.js:29:11:29:30 | 'unknown-admin-name' | user name | +| HardcodedCredentials.js:29:35:29:47 | 'supersecret' | HardcodedCredentials.js:29:35:29:47 | 'supersecret' | HardcodedCredentials.js:29:35:29:47 | 'supersecret' | The hard-coded value "supersecret" is used as $@. | HardcodedCredentials.js:29:35:29:47 | 'supersecret' | password | +| HardcodedCredentials.js:35:15:35:24 | 'username' | HardcodedCredentials.js:35:15:35:24 | 'username' | HardcodedCredentials.js:35:15:35:24 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:35:15:35:24 | 'username' | user name | +| HardcodedCredentials.js:35:27:35:36 | 'password' | HardcodedCredentials.js:35:27:35:36 | 'password' | HardcodedCredentials.js:35:27:35:36 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:35:27:35:36 | 'password' | password | +| HardcodedCredentials.js:41:38:41:47 | 'username' | HardcodedCredentials.js:41:38:41:47 | 'username' | HardcodedCredentials.js:41:38:41:47 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:41:38:41:47 | 'username' | user name | +| HardcodedCredentials.js:41:67:41:76 | 'password' | HardcodedCredentials.js:41:67:41:76 | 'password' | HardcodedCredentials.js:41:67:41:76 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:41:67:41:76 | 'password' | password | +| HardcodedCredentials.js:42:35:42:44 | 'username' | HardcodedCredentials.js:42:35:42:44 | 'username' | HardcodedCredentials.js:42:35:42:44 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:42:35:42:44 | 'username' | user name | +| HardcodedCredentials.js:42:64:42:73 | 'password' | HardcodedCredentials.js:42:64:42:73 | 'password' | HardcodedCredentials.js:42:64:42:73 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:42:64:42:73 | 'password' | password | +| HardcodedCredentials.js:44:34:44:43 | 'username' | HardcodedCredentials.js:44:34:44:43 | 'username' | HardcodedCredentials.js:44:34:44:43 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:44:34:44:43 | 'username' | user name | +| HardcodedCredentials.js:44:63:44:72 | 'password' | HardcodedCredentials.js:44:63:44:72 | 'password' | HardcodedCredentials.js:44:63:44:72 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:44:63:44:72 | 'password' | password | +| HardcodedCredentials.js:46:25:46:34 | 'password' | HardcodedCredentials.js:46:25:46:34 | 'password' | HardcodedCredentials.js:46:25:46:34 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:46:25:46:34 | 'password' | password | +| HardcodedCredentials.js:53:27:53:36 | 'username' | HardcodedCredentials.js:53:27:53:36 | 'username' | HardcodedCredentials.js:53:27:53:36 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:53:27:53:36 | 'username' | user name | +| HardcodedCredentials.js:53:39:53:48 | 'password' | HardcodedCredentials.js:53:39:53:48 | 'password' | HardcodedCredentials.js:53:39:53:48 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:53:39:53:48 | 'password' | password | +| HardcodedCredentials.js:56:21:56:30 | 'username' | HardcodedCredentials.js:56:21:56:30 | 'username' | HardcodedCredentials.js:56:21:56:30 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:56:21:56:30 | 'username' | user name | +| HardcodedCredentials.js:57:21:57:30 | 'password' | HardcodedCredentials.js:57:21:57:30 | 'password' | HardcodedCredentials.js:57:21:57:30 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:57:21:57:30 | 'password' | password | +| HardcodedCredentials.js:61:42:61:54 | 'bearerToken' | HardcodedCredentials.js:61:42:61:54 | 'bearerToken' | HardcodedCredentials.js:61:42:61:54 | 'bearerToken' | The hard-coded value "bearerToken" is used as $@. | HardcodedCredentials.js:61:42:61:54 | 'bearerToken' | token | +| HardcodedCredentials.js:65:23:65:35 | 'bearerToken' | HardcodedCredentials.js:65:23:65:35 | 'bearerToken' | HardcodedCredentials.js:65:23:65:35 | 'bearerToken' | The hard-coded value "bearerToken" is used as $@. | HardcodedCredentials.js:65:23:65:35 | 'bearerToken' | token | +| HardcodedCredentials.js:69:28:69:37 | 'username' | HardcodedCredentials.js:69:28:69:37 | 'username' | HardcodedCredentials.js:69:28:69:37 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:69:28:69:37 | 'username' | user name | +| HardcodedCredentials.js:69:40:69:49 | 'password' | HardcodedCredentials.js:69:40:69:49 | 'password' | HardcodedCredentials.js:69:40:69:49 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:69:40:69:49 | 'password' | password | +| HardcodedCredentials.js:70:28:70:37 | 'username' | HardcodedCredentials.js:70:28:70:37 | 'username' | HardcodedCredentials.js:70:28:70:37 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:70:28:70:37 | 'username' | user name | +| HardcodedCredentials.js:70:40:70:49 | 'password' | HardcodedCredentials.js:70:40:70:49 | 'password' | HardcodedCredentials.js:70:40:70:49 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:70:40:70:49 | 'password' | password | +| HardcodedCredentials.js:72:23:72:32 | 'username' | HardcodedCredentials.js:72:23:72:32 | 'username' | HardcodedCredentials.js:72:23:72:32 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:72:23:72:32 | 'username' | user name | +| HardcodedCredentials.js:72:35:72:44 | 'password' | HardcodedCredentials.js:72:35:72:44 | 'password' | HardcodedCredentials.js:72:35:72:44 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:72:35:72:44 | 'password' | password | +| HardcodedCredentials.js:75:21:75:30 | 'username' | HardcodedCredentials.js:75:21:75:30 | 'username' | HardcodedCredentials.js:75:21:75:30 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:75:21:75:30 | 'username' | user name | +| HardcodedCredentials.js:76:21:76:30 | 'password' | HardcodedCredentials.js:76:21:76:30 | 'password' | HardcodedCredentials.js:76:21:76:30 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:76:21:76:30 | 'password' | password | +| HardcodedCredentials.js:84:38:84:47 | 'username' | HardcodedCredentials.js:84:38:84:47 | 'username' | HardcodedCredentials.js:84:38:84:47 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:84:38:84:47 | 'username' | user name | +| HardcodedCredentials.js:84:50:84:59 | 'password' | HardcodedCredentials.js:84:50:84:59 | 'password' | HardcodedCredentials.js:84:50:84:59 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:84:50:84:59 | 'password' | password | +| HardcodedCredentials.js:86:44:86:53 | 'username' | HardcodedCredentials.js:86:44:86:53 | 'username' | HardcodedCredentials.js:86:44:86:53 | 'username' | The hard-coded value "username" is used as $@. | HardcodedCredentials.js:86:44:86:53 | 'username' | user name | +| HardcodedCredentials.js:86:56:86:65 | 'password' | HardcodedCredentials.js:86:56:86:65 | 'password' | HardcodedCredentials.js:86:56:86:65 | 'password' | The hard-coded value "password" is used as $@. | HardcodedCredentials.js:86:56:86:65 | 'password' | password | +| HardcodedCredentials.js:91:25:91:31 | 'TOKEN' | HardcodedCredentials.js:91:25:91:31 | 'TOKEN' | HardcodedCredentials.js:91:25:91:31 | 'TOKEN' | The hard-coded value "TOKEN" is used as $@. | HardcodedCredentials.js:91:25:91:31 | 'TOKEN' | token | +| HardcodedCredentials.js:98:18:98:21 | 'x1' | HardcodedCredentials.js:98:18:98:21 | 'x1' | HardcodedCredentials.js:98:18:98:21 | 'x1' | The hard-coded value "x1" is used as $@. | HardcodedCredentials.js:98:18:98:21 | 'x1' | user name | +| HardcodedCredentials.js:99:16:99:19 | 'x2' | HardcodedCredentials.js:99:16:99:19 | 'x2' | HardcodedCredentials.js:99:16:99:19 | 'x2' | The hard-coded value "x2" is used as $@. | HardcodedCredentials.js:99:16:99:19 | 'x2' | user name | +| HardcodedCredentials.js:100:25:100:28 | 'x3' | HardcodedCredentials.js:100:25:100:28 | 'x3' | HardcodedCredentials.js:100:25:100:28 | 'x3' | The hard-coded value "x3" is used as $@. | HardcodedCredentials.js:100:25:100:28 | 'x3' | user name | +| HardcodedCredentials.js:101:19:101:22 | 'x4' | HardcodedCredentials.js:101:19:101:22 | 'x4' | HardcodedCredentials.js:101:19:101:22 | 'x4' | The hard-coded value "x4" is used as $@. | HardcodedCredentials.js:101:19:101:22 | 'x4' | user name | +| HardcodedCredentials.js:102:14:102:17 | 'y1' | HardcodedCredentials.js:102:14:102:17 | 'y1' | HardcodedCredentials.js:102:14:102:17 | 'y1' | The hard-coded value "y1" is used as $@. | HardcodedCredentials.js:102:14:102:17 | 'y1' | password | +| HardcodedCredentials.js:103:17:103:20 | 'y2' | HardcodedCredentials.js:103:17:103:20 | 'y2' | HardcodedCredentials.js:103:17:103:20 | 'y2' | The hard-coded value "y2" is used as $@. | HardcodedCredentials.js:103:17:103:20 | 'y2' | password | +| HardcodedCredentials.js:104:27:104:30 | 'y3' | HardcodedCredentials.js:104:27:104:30 | 'y3' | HardcodedCredentials.js:104:27:104:30 | 'y3' | The hard-coded value "y3" is used as $@. | HardcodedCredentials.js:104:27:104:30 | 'y3' | password | +| HardcodedCredentials.js:105:19:105:22 | 'y4' | HardcodedCredentials.js:105:19:105:22 | 'y4' | HardcodedCredentials.js:105:19:105:22 | 'y4' | The hard-coded value "y4" is used as $@. | HardcodedCredentials.js:105:19:105:22 | 'y4' | password | +| HardcodedCredentials.js:106:16:106:19 | 'z1' | HardcodedCredentials.js:106:16:106:19 | 'z1' | HardcodedCredentials.js:106:16:106:19 | 'z1' | The hard-coded value "z1" is used as $@. | HardcodedCredentials.js:106:16:106:19 | 'z1' | token | +| HardcodedCredentials.js:112:19:112:22 | 'x5' | HardcodedCredentials.js:112:19:112:22 | 'x5' | HardcodedCredentials.js:112:19:112:22 | 'x5' | The hard-coded value "x5" is used as $@. | HardcodedCredentials.js:112:19:112:22 | 'x5' | user name | +| HardcodedCredentials.js:113:19:113:22 | 'y5' | HardcodedCredentials.js:113:19:113:22 | 'y5' | HardcodedCredentials.js:113:19:113:22 | 'y5' | The hard-coded value "y5" is used as $@. | HardcodedCredentials.js:113:19:113:22 | 'y5' | password | +| HardcodedCredentials.js:130:44:130:58 | 'crypto secret' | HardcodedCredentials.js:130:44:130:58 | 'crypto secret' | HardcodedCredentials.js:130:44:130:58 | 'crypto secret' | The hard-coded value "crypto secret" is used as $@. | HardcodedCredentials.js:130:44:130:58 | 'crypto secret' | key | +| HardcodedCredentials.js:131:52:131:73 | 'crypto ... secret' | HardcodedCredentials.js:131:52:131:73 | 'crypto ... secret' | HardcodedCredentials.js:131:52:131:73 | 'crypto ... secret' | The hard-coded value "crypto-js/aes secret" is used as $@. | HardcodedCredentials.js:131:52:131:73 | 'crypto ... secret' | key | +| HardcodedCredentials.js:135:41:135:63 | "cookie ... secret" | HardcodedCredentials.js:135:41:135:63 | "cookie ... secret" | HardcodedCredentials.js:135:41:135:63 | "cookie ... secret" | The hard-coded value "cookie-session secret" is used as $@. | HardcodedCredentials.js:135:41:135:63 | "cookie ... secret" | key | diff --git a/javascript/ql/test/query-tests/Security/CWE-807/ConditionalBypass.expected b/javascript/ql/test/query-tests/Security/CWE-807/ConditionalBypass.expected index 0ee7194b924b..8c2d94e0a9d1 100644 --- a/javascript/ql/test/query-tests/Security/CWE-807/ConditionalBypass.expected +++ b/javascript/ql/test/query-tests/Security/CWE-807/ConditionalBypass.expected @@ -1,14 +1,51 @@ -| tst.js:9:8:9:26 | req.params.shutDown | This condition guards a sensitive $@, but $@ controls it. | tst.js:11:9:11:22 | process.exit() | action | tst.js:9:8:9:26 | req.params.shutDown | a user-provided value | -| tst.js:14:9:14:30 | req.coo ... inThing | This condition guards a sensitive $@, but $@ controls it. | tst.js:16:9:16:17 | o.login() | action | tst.js:14:9:14:19 | req.cookies | a user-provided value | -| tst.js:31:9:31:10 | v3 | This condition guards a sensitive $@, but $@ controls it. | tst.js:33:9:33:22 | process.exit() | action | tst.js:30:17:30:27 | req.cookies | a user-provided value | -| tst.js:37:13:37:32 | req.cookies.cookieId | This condition guards a sensitive $@, but $@ controls it. | tst.js:39:13:39:26 | process.exit() | action | tst.js:37:13:37:23 | req.cookies | a user-provided value | -| tst.js:43:9:43:28 | req.cookies.cookieId | This condition guards a sensitive $@, but $@ controls it. | tst.js:46:13:46:26 | process.exit() | action | tst.js:43:9:43:19 | req.cookies | a user-provided value | -| tst.js:50:8:50:23 | req.params.login | This condition guards a sensitive $@, but $@ controls it. | tst.js:54:9:54:15 | login() | action | tst.js:50:8:50:23 | req.params.login | a user-provided value | -| tst.js:65:8:65:23 | req.params.login | This condition guards a sensitive $@, but $@ controls it. | tst.js:67:9:67:15 | login() | action | tst.js:65:8:65:23 | req.params.login | a user-provided value | -| tst.js:70:9:70:53 | req.coo ... questId | This condition guards a sensitive $@, but $@ controls it. | tst.js:72:9:72:22 | process.exit() | action | tst.js:70:9:70:19 | req.cookies | a user-provided value | -| tst.js:70:9:70:53 | req.coo ... questId | This condition guards a sensitive $@, but $@ controls it. | tst.js:72:9:72:22 | process.exit() | action | tst.js:70:34:70:53 | req.params.requestId | a user-provided value | -| tst.js:76:9:76:10 | v1 | This condition guards a sensitive $@, but $@ controls it. | tst.js:78:9:78:22 | process.exit() | action | tst.js:75:14:75:24 | req.cookies | a user-provided value | -| tst.js:76:9:76:10 | v1 | This condition guards a sensitive $@, but $@ controls it. | tst.js:78:9:78:22 | process.exit() | action | tst.js:75:39:75:58 | req.params.requestId | a user-provided value | -| tst.js:90:9:90:41 | req.coo ... secret" | This condition guards a sensitive $@, but $@ controls it. | tst.js:92:9:92:22 | process.exit() | action | tst.js:90:9:90:19 | req.cookies | a user-provided value | -| tst.js:111:13:111:32 | req.query.vulnerable | This condition guards a sensitive $@, but $@ controls it. | tst.js:114:9:114:16 | verify() | action | tst.js:111:13:111:32 | req.query.vulnerable | a user-provided value | -| tst.js:118:13:118:32 | req.query.vulnerable | This condition guards a sensitive $@, but $@ controls it. | tst.js:121:13:121:20 | verify() | action | tst.js:118:13:118:32 | req.query.vulnerable | a user-provided value | +nodes +| tst.js:9:8:9:26 | req.params.shutDown | +| tst.js:14:9:14:19 | req.cookies | +| tst.js:14:9:14:30 | req.coo ... inThing | +| tst.js:30:9:30:37 | v3 | +| tst.js:30:14:30:37 | id(req. ... okieId) | +| tst.js:30:17:30:27 | req.cookies | +| tst.js:30:17:30:36 | req.cookies.cookieId | +| tst.js:31:9:31:10 | v3 | +| tst.js:37:13:37:23 | req.cookies | +| tst.js:37:13:37:32 | req.cookies.cookieId | +| tst.js:43:9:43:19 | req.cookies | +| tst.js:43:9:43:28 | req.cookies.cookieId | +| tst.js:50:8:50:23 | req.params.login | +| tst.js:65:8:65:23 | req.params.login | +| tst.js:70:9:70:19 | req.cookies | +| tst.js:70:9:70:28 | req.cookies.cookieId | +| tst.js:70:34:70:53 | req.params.requestId | +| tst.js:75:14:75:24 | req.cookies | +| tst.js:75:14:75:33 | req.cookies.cookieId | +| tst.js:75:39:75:58 | req.params.requestId | +| tst.js:90:9:90:19 | req.cookies | +| tst.js:90:9:90:28 | req.cookies.cookieId | +| tst.js:90:9:90:41 | req.coo ... secret" | +| tst.js:104:10:104:17 | req.body | +| tst.js:111:13:111:32 | req.query.vulnerable | +| tst.js:118:13:118:32 | req.query.vulnerable | +| tst.js:126:13:126:32 | req.query.vulnerable | +edges +| tst.js:14:9:14:19 | req.cookies | tst.js:14:9:14:30 | req.coo ... inThing | +| tst.js:30:9:30:37 | v3 | tst.js:31:9:31:10 | v3 | +| tst.js:30:14:30:37 | id(req. ... okieId) | tst.js:30:9:30:37 | v3 | +| tst.js:30:17:30:27 | req.cookies | tst.js:30:17:30:36 | req.cookies.cookieId | +| tst.js:30:17:30:36 | req.cookies.cookieId | tst.js:30:14:30:37 | id(req. ... okieId) | +| tst.js:37:13:37:23 | req.cookies | tst.js:37:13:37:32 | req.cookies.cookieId | +| tst.js:43:9:43:19 | req.cookies | tst.js:43:9:43:28 | req.cookies.cookieId | +| tst.js:70:9:70:19 | req.cookies | tst.js:70:9:70:28 | req.cookies.cookieId | +| tst.js:75:14:75:24 | req.cookies | tst.js:75:14:75:33 | req.cookies.cookieId | +| tst.js:90:9:90:19 | req.cookies | tst.js:90:9:90:28 | req.cookies.cookieId | +| tst.js:90:9:90:28 | req.cookies.cookieId | tst.js:90:9:90:41 | req.coo ... secret" | +#select +| tst.js:9:8:9:26 | req.params.shutDown | tst.js:9:8:9:26 | req.params.shutDown | tst.js:9:8:9:26 | req.params.shutDown | This condition guards a sensitive $@, but $@ controls it. | tst.js:11:9:11:22 | process.exit() | action | tst.js:9:8:9:26 | req.params.shutDown | a user-provided value | +| tst.js:14:9:14:30 | req.coo ... inThing | tst.js:14:9:14:19 | req.cookies | tst.js:14:9:14:30 | req.coo ... inThing | This condition guards a sensitive $@, but $@ controls it. | tst.js:16:9:16:17 | o.login() | action | tst.js:14:9:14:19 | req.cookies | a user-provided value | +| tst.js:31:9:31:10 | v3 | tst.js:30:17:30:27 | req.cookies | tst.js:31:9:31:10 | v3 | This condition guards a sensitive $@, but $@ controls it. | tst.js:33:9:33:22 | process.exit() | action | tst.js:30:17:30:27 | req.cookies | a user-provided value | +| tst.js:37:13:37:32 | req.cookies.cookieId | tst.js:37:13:37:23 | req.cookies | tst.js:37:13:37:32 | req.cookies.cookieId | This condition guards a sensitive $@, but $@ controls it. | tst.js:39:13:39:26 | process.exit() | action | tst.js:37:13:37:23 | req.cookies | a user-provided value | +| tst.js:43:9:43:28 | req.cookies.cookieId | tst.js:43:9:43:19 | req.cookies | tst.js:43:9:43:28 | req.cookies.cookieId | This condition guards a sensitive $@, but $@ controls it. | tst.js:46:13:46:26 | process.exit() | action | tst.js:43:9:43:19 | req.cookies | a user-provided value | +| tst.js:50:8:50:23 | req.params.login | tst.js:50:8:50:23 | req.params.login | tst.js:50:8:50:23 | req.params.login | This condition guards a sensitive $@, but $@ controls it. | tst.js:54:9:54:15 | login() | action | tst.js:50:8:50:23 | req.params.login | a user-provided value | +| tst.js:65:8:65:23 | req.params.login | tst.js:65:8:65:23 | req.params.login | tst.js:65:8:65:23 | req.params.login | This condition guards a sensitive $@, but $@ controls it. | tst.js:67:9:67:15 | login() | action | tst.js:65:8:65:23 | req.params.login | a user-provided value | +| tst.js:90:9:90:41 | req.coo ... secret" | tst.js:90:9:90:19 | req.cookies | tst.js:90:9:90:41 | req.coo ... secret" | This condition guards a sensitive $@, but $@ controls it. | tst.js:92:9:92:22 | process.exit() | action | tst.js:90:9:90:19 | req.cookies | a user-provided value | +| tst.js:111:13:111:32 | req.query.vulnerable | tst.js:111:13:111:32 | req.query.vulnerable | tst.js:111:13:111:32 | req.query.vulnerable | This condition guards a sensitive $@, but $@ controls it. | tst.js:114:9:114:16 | verify() | action | tst.js:111:13:111:32 | req.query.vulnerable | a user-provided value | +| tst.js:118:13:118:32 | req.query.vulnerable | tst.js:118:13:118:32 | req.query.vulnerable | tst.js:118:13:118:32 | req.query.vulnerable | This condition guards a sensitive $@, but $@ controls it. | tst.js:121:13:121:20 | verify() | action | tst.js:118:13:118:32 | req.query.vulnerable | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-843/TypeConfusionThroughParameterTampering.expected b/javascript/ql/test/query-tests/Security/CWE-843/TypeConfusionThroughParameterTampering.expected index 7431c4677138..8eace9eab8e9 100644 --- a/javascript/ql/test/query-tests/Security/CWE-843/TypeConfusionThroughParameterTampering.expected +++ b/javascript/ql/test/query-tests/Security/CWE-843/TypeConfusionThroughParameterTampering.expected @@ -1,9 +1,49 @@ -| tst.js:6:5:6:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | -| tst.js:8:5:8:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | -| tst.js:11:9:11:11 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | -| tst.js:15:9:15:11 | bar | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | -| tst.js:27:5:27:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | -| tst.js:28:5:28:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | -| tst.js:36:9:36:11 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | -| tst.js:41:5:41:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | -| tst.js:46:5:46:7 | foo | Potential type confusion for $@. | tst.js:45:15:45:35 | ctx.req ... ery.foo | HTTP request parameter | +nodes +| tst.js:5:9:5:27 | foo | +| tst.js:5:15:5:27 | req.query.foo | +| tst.js:6:5:6:7 | foo | +| tst.js:8:5:8:7 | foo | +| tst.js:10:5:10:4 | foo | +| tst.js:11:9:11:11 | foo | +| tst.js:14:16:14:18 | bar | +| tst.js:15:9:15:11 | bar | +| tst.js:17:7:17:9 | foo | +| tst.js:27:5:27:7 | foo | +| tst.js:28:5:28:7 | foo | +| tst.js:30:9:30:31 | foo | +| tst.js:30:9:30:31 | foo | +| tst.js:35:5:35:5 | foo | +| tst.js:36:9:36:11 | foo | +| tst.js:41:5:41:7 | foo | +| tst.js:45:9:45:35 | foo | +| tst.js:45:15:45:35 | ctx.req ... ery.foo | +| tst.js:46:5:46:7 | foo | +edges +| tst.js:5:9:5:27 | foo | tst.js:6:5:6:7 | foo | +| tst.js:5:9:5:27 | foo | tst.js:8:5:8:7 | foo | +| tst.js:5:9:5:27 | foo | tst.js:10:5:10:4 | foo | +| tst.js:5:9:5:27 | foo | tst.js:17:7:17:9 | foo | +| tst.js:5:9:5:27 | foo | tst.js:27:5:27:7 | foo | +| tst.js:5:9:5:27 | foo | tst.js:28:5:28:7 | foo | +| tst.js:5:9:5:27 | foo | tst.js:30:9:30:31 | foo | +| tst.js:5:9:5:27 | foo | tst.js:30:9:30:31 | foo | +| tst.js:5:15:5:27 | req.query.foo | tst.js:5:9:5:27 | foo | +| tst.js:10:5:10:4 | foo | tst.js:11:9:11:11 | foo | +| tst.js:14:16:14:18 | bar | tst.js:15:9:15:11 | bar | +| tst.js:17:7:17:9 | foo | tst.js:14:16:14:18 | bar | +| tst.js:30:9:30:31 | foo | tst.js:35:5:35:5 | foo | +| tst.js:30:9:30:31 | foo | tst.js:35:5:35:5 | foo | +| tst.js:35:5:35:5 | foo | tst.js:36:9:36:11 | foo | +| tst.js:35:5:35:5 | foo | tst.js:41:5:41:7 | foo | +| tst.js:45:9:45:35 | foo | tst.js:46:5:46:7 | foo | +| tst.js:45:15:45:35 | ctx.req ... ery.foo | tst.js:45:9:45:35 | foo | +#select +| tst.js:6:5:6:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:6:5:6:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | +| tst.js:8:5:8:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:8:5:8:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | +| tst.js:11:9:11:11 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:11:9:11:11 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | +| tst.js:15:9:15:11 | bar | tst.js:5:15:5:27 | req.query.foo | tst.js:15:9:15:11 | bar | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | +| tst.js:27:5:27:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:27:5:27:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | +| tst.js:28:5:28:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:28:5:28:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | +| tst.js:36:9:36:11 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:36:9:36:11 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | +| tst.js:41:5:41:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:41:5:41:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter | +| tst.js:46:5:46:7 | foo | tst.js:45:15:45:35 | ctx.req ... ery.foo | tst.js:46:5:46:7 | foo | Potential type confusion for $@. | tst.js:45:15:45:35 | ctx.req ... ery.foo | HTTP request parameter | diff --git a/javascript/ql/test/query-tests/Security/CWE-912/HttpToFileAccess.expected b/javascript/ql/test/query-tests/Security/CWE-912/HttpToFileAccess.expected index 5799343dd262..05b6a4a08495 100644 --- a/javascript/ql/test/query-tests/Security/CWE-912/HttpToFileAccess.expected +++ b/javascript/ql/test/query-tests/Security/CWE-912/HttpToFileAccess.expected @@ -1,3 +1,15 @@ -| tst.js:16:33:16:33 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data | -| tst.js:19:25:19:25 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data | -| tst.js:24:22:24:22 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data | +nodes +| tst.js:15:26:15:26 | c | +| tst.js:16:33:16:33 | c | +| tst.js:19:25:19:25 | c | +| tst.js:23:27:23:26 | c | +| tst.js:24:22:24:22 | c | +edges +| tst.js:15:26:15:26 | c | tst.js:16:33:16:33 | c | +| tst.js:15:26:15:26 | c | tst.js:19:25:19:25 | c | +| tst.js:15:26:15:26 | c | tst.js:23:27:23:26 | c | +| tst.js:23:27:23:26 | c | tst.js:24:22:24:22 | c | +#select +| tst.js:16:33:16:33 | c | tst.js:15:26:15:26 | c | tst.js:16:33:16:33 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data | +| tst.js:19:25:19:25 | c | tst.js:15:26:15:26 | c | tst.js:19:25:19:25 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data | +| tst.js:24:22:24:22 | c | tst.js:15:26:15:26 | c | tst.js:24:22:24:22 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data | diff --git a/javascript/ql/test/query-tests/Security/CWE-916/InsufficientPasswordHash.expected b/javascript/ql/test/query-tests/Security/CWE-916/InsufficientPasswordHash.expected index 947e48dd2598..cdd69e35a19b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-916/InsufficientPasswordHash.expected +++ b/javascript/ql/test/query-tests/Security/CWE-916/InsufficientPasswordHash.expected @@ -1,3 +1,9 @@ -| tst.js:5:48:5:55 | password | Password from $@ is hashed insecurely. | tst.js:5:48:5:55 | password | an access to password | -| tst.js:7:46:7:53 | password | Password from $@ is hashed insecurely. | tst.js:7:46:7:53 | password | an access to password | -| tst.js:9:43:9:50 | password | Password from $@ is hashed insecurely. | tst.js:9:43:9:50 | password | an access to password | +nodes +| tst.js:5:48:5:55 | password | +| tst.js:7:46:7:53 | password | +| tst.js:9:43:9:50 | password | +edges +#select +| tst.js:5:48:5:55 | password | tst.js:5:48:5:55 | password | tst.js:5:48:5:55 | password | Password from $@ is hashed insecurely. | tst.js:5:48:5:55 | password | an access to password | +| tst.js:7:46:7:53 | password | tst.js:7:46:7:53 | password | tst.js:7:46:7:53 | password | Password from $@ is hashed insecurely. | tst.js:7:46:7:53 | password | an access to password | +| tst.js:9:43:9:50 | password | tst.js:9:43:9:50 | password | tst.js:9:43:9:50 | password | Password from $@ is hashed insecurely. | tst.js:9:43:9:50 | password | an access to password | diff --git a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected index d114b6a8e389..b4368363730a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected +++ b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected @@ -1,6 +1,36 @@ -| tst.js:16:5:16:20 | request(tainted) | The $@ of this request depends on $@. | tst.js:16:13:16:19 | tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | -| tst.js:18:5:18:24 | request.get(tainted) | The $@ of this request depends on $@. | tst.js:18:17:18:23 | tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | -| tst.js:22:5:22:20 | request(options) | The $@ of this request depends on $@. | tst.js:21:19:21:25 | tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | -| tst.js:24:5:24:32 | request ... ainted) | The $@ of this request depends on $@. | tst.js:24:13:24:31 | "http://" + tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | -| tst.js:26:5:26:43 | request ... ainted) | The $@ of this request depends on $@. | tst.js:26:13:26:42 | "http:/ ... tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | -| tst.js:28:5:28:44 | request ... ainted) | The $@ of this request depends on $@. | tst.js:28:13:28:43 | "http:/ ... tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | +nodes +| tst.js:12:9:12:52 | tainted | +| tst.js:12:19:12:42 | url.par ... , true) | +| tst.js:12:19:12:48 | url.par ... ).query | +| tst.js:12:19:12:52 | url.par ... ery.url | +| tst.js:12:29:12:35 | req.url | +| tst.js:16:13:16:19 | tainted | +| tst.js:18:17:18:23 | tainted | +| tst.js:21:19:21:25 | tainted | +| tst.js:24:13:24:31 | "http://" + tainted | +| tst.js:24:25:24:31 | tainted | +| tst.js:26:13:26:42 | "http:/ ... tainted | +| tst.js:26:36:26:42 | tainted | +| tst.js:28:13:28:43 | "http:/ ... tainted | +| tst.js:28:37:28:43 | tainted | +edges +| tst.js:12:9:12:52 | tainted | tst.js:16:13:16:19 | tainted | +| tst.js:12:9:12:52 | tainted | tst.js:18:17:18:23 | tainted | +| tst.js:12:9:12:52 | tainted | tst.js:21:19:21:25 | tainted | +| tst.js:12:9:12:52 | tainted | tst.js:24:25:24:31 | tainted | +| tst.js:12:9:12:52 | tainted | tst.js:26:36:26:42 | tainted | +| tst.js:12:9:12:52 | tainted | tst.js:28:37:28:43 | tainted | +| tst.js:12:19:12:42 | url.par ... , true) | tst.js:12:19:12:48 | url.par ... ).query | +| tst.js:12:19:12:48 | url.par ... ).query | tst.js:12:19:12:52 | url.par ... ery.url | +| tst.js:12:19:12:52 | url.par ... ery.url | tst.js:12:9:12:52 | tainted | +| tst.js:12:29:12:35 | req.url | tst.js:12:19:12:42 | url.par ... , true) | +| tst.js:24:25:24:31 | tainted | tst.js:24:13:24:31 | "http://" + tainted | +| tst.js:26:36:26:42 | tainted | tst.js:26:13:26:42 | "http:/ ... tainted | +| tst.js:28:37:28:43 | tainted | tst.js:28:13:28:43 | "http:/ ... tainted | +#select +| tst.js:16:5:16:20 | request(tainted) | tst.js:12:29:12:35 | req.url | tst.js:16:13:16:19 | tainted | The $@ of this request depends on $@. | tst.js:16:13:16:19 | tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | +| tst.js:18:5:18:24 | request.get(tainted) | tst.js:12:29:12:35 | req.url | tst.js:18:17:18:23 | tainted | The $@ of this request depends on $@. | tst.js:18:17:18:23 | tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | +| tst.js:22:5:22:20 | request(options) | tst.js:12:29:12:35 | req.url | tst.js:21:19:21:25 | tainted | The $@ of this request depends on $@. | tst.js:21:19:21:25 | tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | +| tst.js:24:5:24:32 | request ... ainted) | tst.js:12:29:12:35 | req.url | tst.js:24:13:24:31 | "http://" + tainted | The $@ of this request depends on $@. | tst.js:24:13:24:31 | "http://" + tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | +| tst.js:26:5:26:43 | request ... ainted) | tst.js:12:29:12:35 | req.url | tst.js:26:13:26:42 | "http:/ ... tainted | The $@ of this request depends on $@. | tst.js:26:13:26:42 | "http:/ ... tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | +| tst.js:28:5:28:44 | request ... ainted) | tst.js:12:29:12:35 | req.url | tst.js:28:13:28:43 | "http:/ ... tainted | The $@ of this request depends on $@. | tst.js:28:13:28:43 | "http:/ ... tainted | URL | tst.js:12:29:12:35 | req.url | a user-provided value | From d6198fcc2a9a6ad48f8234ba57ce5e62ef3c1076 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 17 Oct 2018 15:21:33 +0100 Subject: [PATCH 39/68] JavaScript: Introduce two more short-circuiting conjuncts. --- javascript/ql/src/semmle/javascript/dataflow/Configuration.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index b74e317bd10f..9f23ef9c5e22 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -744,6 +744,7 @@ private predicate onPath(DataFlow::Node nd, DataFlow::Configuration cfg, */ private newtype TPathNode = MkPathNode(DataFlow::Node nd, DataFlow::Configuration cfg, PathSummary summary) { + isSource(_, cfg, _) and isSink(_, cfg, _) and onPath(nd, cfg, summary) } From 4112af5b3f9bb3735c923bde5b5aa762fb45a14d Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 14 Nov 2018 09:35:17 +0000 Subject: [PATCH 40/68] JavaScript: Add change note. --- change-notes/1.19/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.19/analysis-javascript.md b/change-notes/1.19/analysis-javascript.md index d60034662f2b..06c64b76cbac 100644 --- a/change-notes/1.19/analysis-javascript.md +++ b/change-notes/1.19/analysis-javascript.md @@ -13,6 +13,8 @@ * Type inference for function calls has been improved. This may give additional results for queries that rely on type inference. +* Where applicable, path explanations have been added to the security queries. + ## New queries | **Query** | **Tags** | **Purpose** | From 3fcd02ab0e226f9563a302c847c4acfbec038db9 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 14 Nov 2018 11:23:17 +0000 Subject: [PATCH 41/68] JavaScript: Rename `hasPathFlow` to `hasFlowPath` for consistency with other languages. --- javascript/ql/src/Security/CWE-022/TaintedPath.ql | 2 +- .../ql/src/Security/CWE-078/CommandInjection.ql | 2 +- javascript/ql/src/Security/CWE-079/ReflectedXss.ql | 2 +- javascript/ql/src/Security/CWE-079/StoredXss.ql | 2 +- javascript/ql/src/Security/CWE-079/Xss.ql | 2 +- javascript/ql/src/Security/CWE-089/SqlInjection.ql | 2 +- javascript/ql/src/Security/CWE-094/CodeInjection.ql | 2 +- .../ql/src/Security/CWE-134/TaintedFormatString.ql | 2 +- .../ql/src/Security/CWE-200/FileAccessToHttp.ql | 2 +- .../ql/src/Security/CWE-209/StackTraceExposure.ql | 2 +- .../ql/src/Security/CWE-312/CleartextLogging.ql | 2 +- .../ql/src/Security/CWE-312/CleartextStorage.ql | 2 +- .../src/Security/CWE-327/BrokenCryptoAlgorithm.ql | 2 +- .../ql/src/Security/CWE-338/InsecureRandomness.ql | 2 +- .../CWE-346/CorsMisconfigurationForCredentials.ql | 2 +- .../src/Security/CWE-400/RemotePropertyInjection.ql | 2 +- .../src/Security/CWE-502/UnsafeDeserialization.ql | 2 +- .../src/Security/CWE-601/ClientSideUrlRedirect.ql | 2 +- .../src/Security/CWE-601/ServerSideUrlRedirect.ql | 2 +- javascript/ql/src/Security/CWE-611/Xxe.ql | 2 +- .../CWE-640/HostHeaderPoisoningInEmailGeneration.ql | 2 +- .../ql/src/Security/CWE-643/XpathInjection.ql | 2 +- .../ql/src/Security/CWE-730/RegExpInjection.ql | 2 +- javascript/ql/src/Security/CWE-776/XmlBomb.ql | 2 +- .../ql/src/Security/CWE-798/HardcodedCredentials.ql | 2 +- .../ql/src/Security/CWE-807/ConditionalBypass.ql | 6 +++--- .../TypeConfusionThroughParameterTampering.ql | 2 +- .../ql/src/Security/CWE-912/HttpToFileAccess.ql | 2 +- .../Security/CWE-916/InsufficientPasswordHash.ql | 2 +- .../ql/src/Security/CWE-918/RequestForgery.ql | 2 +- .../semmle/javascript/dataflow/Configuration.qll | 13 +++++++++++-- 31 files changed, 43 insertions(+), 34 deletions(-) diff --git a/javascript/ql/src/Security/CWE-022/TaintedPath.ql b/javascript/ql/src/Security/CWE-022/TaintedPath.ql index 8a3e70752168..b545fabafedd 100644 --- a/javascript/ql/src/Security/CWE-022/TaintedPath.ql +++ b/javascript/ql/src/Security/CWE-022/TaintedPath.ql @@ -19,6 +19,6 @@ import semmle.javascript.security.dataflow.TaintedPath::TaintedPath import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "This path depends on $@.", source.getNode(), "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-078/CommandInjection.ql b/javascript/ql/src/Security/CWE-078/CommandInjection.ql index 317c407003cd..2e356e9fdc3a 100644 --- a/javascript/ql/src/Security/CWE-078/CommandInjection.ql +++ b/javascript/ql/src/Security/CWE-078/CommandInjection.ql @@ -17,7 +17,7 @@ import semmle.javascript.security.dataflow.CommandInjection::CommandInjection import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node highlight -where cfg.hasPathFlow(source, sink) and +where cfg.hasFlowPath(source, sink) and if cfg.isSinkWithHighlight(sink.getNode(), _) then cfg.isSinkWithHighlight(sink.getNode(), highlight) else diff --git a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql index 5b308800209f..c9ed51c35cd0 100644 --- a/javascript/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/javascript/ql/src/Security/CWE-079/ReflectedXss.ql @@ -16,6 +16,6 @@ import semmle.javascript.security.dataflow.ReflectedXss::ReflectedXss import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-079/StoredXss.ql b/javascript/ql/src/Security/CWE-079/StoredXss.ql index f1e386c291b9..e0deee47b71b 100644 --- a/javascript/ql/src/Security/CWE-079/StoredXss.ql +++ b/javascript/ql/src/Security/CWE-079/StoredXss.ql @@ -16,6 +16,6 @@ import semmle.javascript.security.dataflow.StoredXss::StoredXss import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Stored cross-site scripting vulnerability due to $@.", source.getNode(), "stored value" diff --git a/javascript/ql/src/Security/CWE-079/Xss.ql b/javascript/ql/src/Security/CWE-079/Xss.ql index b6ba13918cb6..c1e5f1f376b3 100644 --- a/javascript/ql/src/Security/CWE-079/Xss.ql +++ b/javascript/ql/src/Security/CWE-079/Xss.ql @@ -16,6 +16,6 @@ import semmle.javascript.security.dataflow.DomBasedXss::DomBasedXss import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, sink.getNode().(Sink).getVulnerabilityKind() + " vulnerability due to $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/Security/CWE-089/SqlInjection.ql index 6ae6d0927233..4df8b41a06f2 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.ql @@ -18,6 +18,6 @@ import DataFlow::PathGraph from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where (cfg instanceof SqlInjection::Configuration or cfg instanceof NosqlInjection::Configuration) and - cfg.hasPathFlow(source, sink) + cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "This query depends on $@.", source.getNode(), "a user-provided value" diff --git a/javascript/ql/src/Security/CWE-094/CodeInjection.ql b/javascript/ql/src/Security/CWE-094/CodeInjection.ql index 506e206bc0aa..745dd2cd62ea 100644 --- a/javascript/ql/src/Security/CWE-094/CodeInjection.ql +++ b/javascript/ql/src/Security/CWE-094/CodeInjection.ql @@ -17,6 +17,6 @@ import semmle.javascript.security.dataflow.CodeInjection::CodeInjection import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ flows to here and is interpreted as code.", source.getNode(), "User-provided value" diff --git a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql index 78ab720d2359..bd7e9c869c79 100644 --- a/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql +++ b/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql @@ -14,6 +14,6 @@ import semmle.javascript.security.dataflow.TaintedFormatString::TaintedFormatStr import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ flows here and is used in a format string.", source.getNode(), "User-provided value" diff --git a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql index 22b254a8bd6a..05a28eba3c65 100644 --- a/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql +++ b/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql @@ -13,6 +13,6 @@ import semmle.javascript.security.dataflow.FileAccessToHttp::FileAccessToHttp import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ flows directly to outbound network request", source.getNode(), "File data" diff --git a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql index d67d9f643ab5..24bb60be541b 100644 --- a/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql +++ b/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql @@ -16,6 +16,6 @@ import semmle.javascript.security.dataflow.StackTraceExposure::StackTraceExposur import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Stack trace information from $@ may be exposed to an external user here.", source.getNode(), "here" diff --git a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql index 34a4f5414cfb..03c86d327556 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextLogging.ql @@ -33,7 +33,7 @@ predicate inBrowserEnvironment(TopLevel tl) { } from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) and +where cfg.hasFlowPath(source, sink) and // ignore logging to the browser console (even though it is not a good practice) not inBrowserEnvironment(sink.getNode().asExpr().getTopLevel()) select sink.getNode(), source, sink, "Sensitive data returned by $@ is logged here.", diff --git a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql index b87b266ed36d..d54d51b024ce 100644 --- a/javascript/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/javascript/ql/src/Security/CWE-312/CleartextStorage.ql @@ -17,6 +17,6 @@ import semmle.javascript.security.dataflow.CleartextStorage::CleartextStorage import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Sensitive data returned by $@ is stored here.", source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index 533c81090183..501041a4b2fb 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -15,7 +15,7 @@ import semmle.javascript.security.SensitiveActions import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) and +where cfg.hasFlowPath(source, sink) and not source.getNode().asExpr() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash select sink.getNode(), source, sink, "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql index 3b9df3020088..5b48a98740ea 100644 --- a/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql +++ b/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql @@ -15,6 +15,6 @@ import semmle.javascript.security.dataflow.InsecureRandomness::InsecureRandomnes import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Cryptographically insecure $@ in a security context.", source.getNode(), "random value" diff --git a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql index 44c478ea1c57..2c1aef77795a 100644 --- a/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql +++ b/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql @@ -16,7 +16,7 @@ import semmle.javascript.security.dataflow.CorsMisconfigurationForCredentials::C import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ leak vulnerability due to $@.", sink.getNode().(Sink).getCredentialsHeader(), "Credential", source.getNode(), "a misconfigured CORS header value" diff --git a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql index b9af490ffb67..4457899f6b33 100644 --- a/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql +++ b/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql @@ -17,6 +17,6 @@ import semmle.javascript.security.dataflow.RemotePropertyInjection::RemoteProper import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "A $@ is used as" + sink.getNode().(Sink).getMessage(), source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql index 107868857bd7..8795546883e5 100644 --- a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql +++ b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql @@ -15,6 +15,6 @@ import semmle.javascript.security.dataflow.UnsafeDeserialization::UnsafeDeserial import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Unsafe deserialization of $@.", source.getNode(), "user input" diff --git a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql index 8080784e8943..9edc3e739d8a 100644 --- a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql @@ -17,6 +17,6 @@ import semmle.javascript.security.dataflow.ClientSideUrlRedirect::ClientSideUrlR import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql index 62d2671c8ea7..a591f9d1d52b 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql @@ -15,6 +15,6 @@ import semmle.javascript.security.dataflow.ServerSideUrlRedirect::ServerSideUrlR import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-611/Xxe.ql b/javascript/ql/src/Security/CWE-611/Xxe.ql index 914f1e4a7268..3f2cb797e1c6 100644 --- a/javascript/ql/src/Security/CWE-611/Xxe.ql +++ b/javascript/ql/src/Security/CWE-611/Xxe.ql @@ -16,6 +16,6 @@ import semmle.javascript.security.dataflow.Xxe::Xxe import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "A $@ is parsed as XML without guarding against external entity expansion.", source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql index c12f0e736f53..c5749967e2c2 100644 --- a/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql +++ b/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql @@ -15,6 +15,6 @@ import semmle.javascript.security.dataflow.HostHeaderPoisoningInEmailGeneration: import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Links in this email can be hijacked by poisoning the HTTP host header $@.", source.getNode(), "here" diff --git a/javascript/ql/src/Security/CWE-643/XpathInjection.ql b/javascript/ql/src/Security/CWE-643/XpathInjection.ql index f212e4a7a1a6..8fe847b8f16c 100644 --- a/javascript/ql/src/Security/CWE-643/XpathInjection.ql +++ b/javascript/ql/src/Security/CWE-643/XpathInjection.ql @@ -15,6 +15,6 @@ import semmle.javascript.security.dataflow.XpathInjection::XpathInjection import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ flows here and is used in an XPath expression.", source.getNode(), "User-provided value" diff --git a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql index 3053a64f53fb..578733974470 100644 --- a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql +++ b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql @@ -17,6 +17,6 @@ import semmle.javascript.security.dataflow.RegExpInjection::RegExpInjection import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-776/XmlBomb.ql b/javascript/ql/src/Security/CWE-776/XmlBomb.ql index 733fe7fe4144..878d01d6f4df 100644 --- a/javascript/ql/src/Security/CWE-776/XmlBomb.ql +++ b/javascript/ql/src/Security/CWE-776/XmlBomb.ql @@ -16,6 +16,6 @@ import semmle.javascript.security.dataflow.XmlBomb::XmlBomb import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "A $@ is parsed as XML without guarding against uncontrolled entity expansion.", source.getNode(), "user-provided value" diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql index b172e28edb93..9c6959989e76 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -17,7 +17,7 @@ private import semmle.javascript.security.dataflow.HardcodedCredentials::Hardcod import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, string value -where cfg.hasPathFlow(source, sink) and +where cfg.hasFlowPath(source, sink) and // use source value in message if it's available if source.getNode().asExpr() instanceof ConstantString then value = "The hard-coded value \"" + source.getNode().asExpr().(ConstantString).getStringValue() + "\"" diff --git a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql index f31549d259c1..8470dc7a4c38 100644 --- a/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql +++ b/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql @@ -73,13 +73,13 @@ predicate isTaintedGuardForSensitiveAction(DataFlow::PathNode sink, DataFlow::Pa not sink.getNode() instanceof SensitiveActionGuardComparisonOperand and exists (Configuration cfg | // ordinary taint tracking to a guard - cfg.hasPathFlow(source, sink) or + cfg.hasFlowPath(source, sink) or // taint tracking to both operands of a guard comparison exists (SensitiveActionGuardComparison cmp, DataFlow::PathNode lSource, DataFlow::PathNode rSource, DataFlow::PathNode lSink, DataFlow::PathNode rSink | sink.getNode() = cmp.getGuard() and - cfg.hasPathFlow(lSource, lSink) and lSink.getNode() = DataFlow::valueNode(cmp.getLeftOperand()) and - cfg.hasPathFlow(rSource, rSink) and rSink.getNode() = DataFlow::valueNode(cmp.getRightOperand()) | + cfg.hasFlowPath(lSource, lSink) and lSink.getNode() = DataFlow::valueNode(cmp.getLeftOperand()) and + cfg.hasFlowPath(rSource, rSink) and rSink.getNode() = DataFlow::valueNode(cmp.getRightOperand()) | source = lSource or source = rSource ) diff --git a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql index d0499905a93a..c2bad5090151 100644 --- a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql +++ b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql @@ -14,6 +14,6 @@ import semmle.javascript.security.dataflow.TypeConfusionThroughParameterTamperin import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Potential type confusion for $@.", source.getNode(), "HTTP request parameter" diff --git a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql index 3f913ea45302..fe42fe8ef04a 100644 --- a/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql +++ b/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql @@ -13,5 +13,5 @@ import semmle.javascript.security.dataflow.HttpToFileAccess::HttpToFileAccess import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ flows to file system", source.getNode(), "Untrusted data" diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql index 37d0bb8c8c2c..e2a94d06ae07 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql @@ -14,6 +14,6 @@ import semmle.javascript.security.dataflow.InsufficientPasswordHash::Insufficien import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasPathFlow(source, sink) +where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Password from $@ is hashed insecurely.", source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-918/RequestForgery.ql b/javascript/ql/src/Security/CWE-918/RequestForgery.ql index 24039a70a1a6..c1d80a78a3e9 100644 --- a/javascript/ql/src/Security/CWE-918/RequestForgery.ql +++ b/javascript/ql/src/Security/CWE-918/RequestForgery.ql @@ -14,7 +14,7 @@ import semmle.javascript.security.dataflow.RequestForgery::RequestForgery import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node request -where cfg.hasPathFlow(source, sink) and +where cfg.hasFlowPath(source, sink) and request = sink.getNode().(Sink).getARequest() select request, source, sink, "The $@ of this request depends on $@.", sink.getNode(), sink.getNode().(Sink).getKind(), source, "a user-provided value" diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 9f23ef9c5e22..681b252f0857 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -189,7 +189,7 @@ abstract class Configuration extends string { predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { isSource(_, this, _) and isSink(_, this, _) and exists (SourcePathNode flowsource, SinkPathNode flowsink | - hasPathFlow(flowsource, flowsink) and + hasFlowPath(flowsource, flowsink) and source = flowsource.getNode() and sink = flowsink.getNode() ) @@ -198,10 +198,19 @@ abstract class Configuration extends string { /** * Holds if data may flow from `source` to `sink` for this configuration. */ - predicate hasPathFlow(SourcePathNode source, SinkPathNode sink) { + predicate hasFlowPath(SourcePathNode source, SinkPathNode sink) { flowsTo(source, _, sink, _, this) } + /** + * DEPRECATED: Use `hasFlowPath` instead. + * + * Holds if data may flow from `source` to `sink` for this configuration. + */ + deprecated predicate hasPathFlow(SourcePathNode source, SinkPathNode sink) { + hasFlowPath(source, sink) + } + /** * DEPRECATED: Use `hasFlow` instead. * From a441bfb751b9fc0dcd37838847b6a1e4facc1cd2 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 14 Nov 2018 11:36:28 +0000 Subject: [PATCH 42/68] JavaScript: Add a convenience method to `AMDModuleDefinition`. --- javascript/ql/src/semmle/javascript/AMD.qll | 5 +++++ .../ql/test/library-tests/AMD/AMDModuleExpr.expected | 8 ++++---- javascript/ql/test/library-tests/AMD/AMDModuleExpr.ql | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/AMD.qll b/javascript/ql/src/semmle/javascript/AMD.qll index 0d622b16cf3f..cfdc5c12d332 100644 --- a/javascript/ql/src/semmle/javascript/AMD.qll +++ b/javascript/ql/src/semmle/javascript/AMD.qll @@ -83,6 +83,11 @@ class AMDModuleDefinition extends CallExpr { ) } + /** Gets a source node whose value becomes the definition of this module. */ + DataFlow::SourceNode getAModuleSource() { + result.flowsToExpr(getModuleExpr()) + } + /** * Holds if `p` is the parameter corresponding to dependency `dep`. */ diff --git a/javascript/ql/test/library-tests/AMD/AMDModuleExpr.expected b/javascript/ql/test/library-tests/AMD/AMDModuleExpr.expected index c0a62b189281..70bf4bce8856 100644 --- a/javascript/ql/test/library-tests/AMD/AMDModuleExpr.expected +++ b/javascript/ql/test/library-tests/AMD/AMDModuleExpr.expected @@ -1,4 +1,4 @@ -| a.js:1:1:3:2 | define( ... 2 };\\n}) | a.js:2:12:2:22 | { foo: 42 } | -| dir/b.js:1:1:3:2 | define( ... : 42\\n}) | dir/b.js:1:8:3:1 | {\\n bar: 42\\n} | -| tst.js:1:1:6:2 | define( ... };\\n}) | tst.js:2:12:5:5 | {\\n ... r\\n } | -| umd.js:4:9:4:43 | define( ... actory) | umd.js:10:12:13:5 | {\\n ... r\\n } | +| a.js:1:1:3:2 | define( ... 2 };\\n}) | a.js:2:12:2:22 | { foo: 42 } | a.js:2:12:2:22 | { foo: 42 } | +| dir/b.js:1:1:3:2 | define( ... : 42\\n}) | dir/b.js:1:8:3:1 | {\\n bar: 42\\n} | dir/b.js:1:8:3:1 | {\\n bar: 42\\n} | +| tst.js:1:1:6:2 | define( ... };\\n}) | tst.js:2:12:5:5 | {\\n ... r\\n } | tst.js:2:12:5:5 | {\\n ... r\\n } | +| umd.js:4:9:4:43 | define( ... actory) | umd.js:10:12:13:5 | {\\n ... r\\n } | umd.js:10:12:13:5 | {\\n ... r\\n } | diff --git a/javascript/ql/test/library-tests/AMD/AMDModuleExpr.ql b/javascript/ql/test/library-tests/AMD/AMDModuleExpr.ql index bec108a77eed..8a7ba1fe976a 100644 --- a/javascript/ql/test/library-tests/AMD/AMDModuleExpr.ql +++ b/javascript/ql/test/library-tests/AMD/AMDModuleExpr.ql @@ -1,4 +1,4 @@ import javascript from AMDModuleDefinition d -select d, d.getModuleExpr() \ No newline at end of file +select d, d.getModuleExpr(), d.getAModuleSource() From 6f6b3b0d5e8d904b700f0dbe46f02c4e2fc12c1a Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 14 Nov 2018 11:49:16 +0000 Subject: [PATCH 43/68] JavaScript: Add a convenience method to `SourceNode` and use it in a few places. --- .../src/Expressions/UnboundEventHandlerReceiver.ql | 5 ++--- .../ql/src/semmle/javascript/dataflow/Sources.qll | 7 +++++++ .../frameworks/AngularJS/AngularJSCore.qll | 12 ++++++------ .../frameworks/AngularJS/ServiceDefinitions.qll | 5 ++--- .../PropWrite/getAPropertySource.expected | 4 ++++ .../library-tests/PropWrite/getAPropertySource.ql | 4 ++++ 6 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 javascript/ql/test/library-tests/PropWrite/getAPropertySource.expected create mode 100644 javascript/ql/test/library-tests/PropWrite/getAPropertySource.ql diff --git a/javascript/ql/src/Expressions/UnboundEventHandlerReceiver.ql b/javascript/ql/src/Expressions/UnboundEventHandlerReceiver.ql index 443e3adeca8c..a0940d777279 100644 --- a/javascript/ql/src/Expressions/UnboundEventHandlerReceiver.ql +++ b/javascript/ql/src/Expressions/UnboundEventHandlerReceiver.ql @@ -22,10 +22,9 @@ private predicate isBoundInMethod(MethodDeclaration method) { or exists (string name | name = method.getName() | - exists (DataFlow::Node rhs, DataFlow::MethodCallNode bind | + exists (DataFlow::MethodCallNode bind | // this. = .bind(...) - thiz.hasPropertyWrite(name, rhs) and - bind.flowsTo(rhs) and + bind = thiz.getAPropertySource(name) and bind.getMethodName() = "bind" ) or diff --git a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll index bc7a4b1fbd2f..5c381d29eca3 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll @@ -178,6 +178,13 @@ abstract class SourceNode extends DataFlow::Node { DataFlow::NewNode getAnInstantiation() { result = getAnInvocation() } + + /** + * Gets a source node whose value is stored in property `prop` of this node. + */ + DataFlow::SourceNode getAPropertySource(string prop) { + result.flowsTo(getAPropertyWrite(prop).getRhs()) + } } /** diff --git a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll index 530527e86ac4..84b238b1890b 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll @@ -439,9 +439,9 @@ class GeneralDirective extends CustomDirective, MkCustomDirective { result = getMember("link") or // { link: { pre: function preLink() { ... }, post: function postLink() { ... } } } - exists (DataFlow::PropWrite pwn | kind = "pre" or kind = "post" | - pwn = getMember("link").getAPropertyWrite(kind) and - result.flowsTo(pwn.getRhs()) + ( + (kind = "pre" or kind = "post") and + result = getMember("link").getAPropertySource(kind) ) or // { compile: function() { ... return link; } } @@ -453,9 +453,9 @@ class GeneralDirective extends CustomDirective, MkCustomDirective { result = compileReturnSrc or // link = { pre: function preLink() { ... }, post: function postLink() { ... } } - exists (DataFlow::PropWrite pwn | kind = "pre" or kind = "post" | - pwn = compileReturnSrc.getAPropertyWrite(kind) and - result.flowsTo(pwn.getRhs()) + ( + (kind = "pre" or kind = "post") and + result = compileReturnSrc.getAPropertySource(kind) ) ) } diff --git a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll index f6bca2b6d838..93309abf659d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll @@ -718,11 +718,10 @@ class ProviderRecipeDefinition extends RecipeDefinition { method set to your factory function is automatically created under the hood. */ - exists(DataFlow::ThisNode thiz, DataFlow::Node rhs, InjectableFunction f | + exists(DataFlow::ThisNode thiz, InjectableFunction f | f = getAFactoryFunction() and thiz.getBinder().getFunction() = f.asFunction() and - thiz.hasPropertyWrite("$get", rhs) and - result.flowsTo(rhs) + result = thiz.getAPropertySource("$get") ) } diff --git a/javascript/ql/test/library-tests/PropWrite/getAPropertySource.expected b/javascript/ql/test/library-tests/PropWrite/getAPropertySource.expected new file mode 100644 index 000000000000..70e6e98360c7 --- /dev/null +++ b/javascript/ql/test/library-tests/PropWrite/getAPropertySource.expected @@ -0,0 +1,4 @@ +| tst.js:2:11:10:1 | {\\n x ... }\\n} | f | tst.js:7:6:9:5 | () {\\n ... ;\\n } | +| tst.js:2:11:10:1 | {\\n x ... }\\n} | func | tst.js:4:11:6:5 | functio ... ;\\n } | +| tst.js:12:1:19:1 | class C ... ;\\n }\\n} | func | tst.js:13:14:15:3 | (x) {\\n ... x);\\n } | +| tst.js:24:8:24:57 |
    | onClick | tst.js:24:22:24:26 | click | diff --git a/javascript/ql/test/library-tests/PropWrite/getAPropertySource.ql b/javascript/ql/test/library-tests/PropWrite/getAPropertySource.ql new file mode 100644 index 000000000000..4b2f7f8d98f1 --- /dev/null +++ b/javascript/ql/test/library-tests/PropWrite/getAPropertySource.ql @@ -0,0 +1,4 @@ +import javascript + +from DataFlow::SourceNode nd, string prop +select nd, prop, nd.getAPropertySource(prop) From 19b9b85c22e65ca9763ee6dc87941e442af0bf43 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 14 Nov 2018 12:03:04 +0000 Subject: [PATCH 44/68] JavaScript: Add change note. --- change-notes/1.19/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.19/analysis-javascript.md b/change-notes/1.19/analysis-javascript.md index 9e2c73dd3d46..638d6528d09e 100644 --- a/change-notes/1.19/analysis-javascript.md +++ b/change-notes/1.19/analysis-javascript.md @@ -6,6 +6,8 @@ * The taint tracking library now recognizes additional sanitization patterns. This may give fewer false-positive results for the security queries. +* Support for AMD modules has been improved. This may give additional results for the security queries as well as any queries that use type inference on code bases that use such modules. + * Support for popular libraries has been improved. Consequently, queries may produce more results on code bases that use the following features: - file system access, for example through [fs-extra](https://github.com/jprichardson/node-fs-extra) or [globby](https://www.npmjs.com/package/globby) - outbound network access, for example through the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) From 5506cec35e53d69d8159b2c77e36c0dfb5ee2aa8 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 9 Nov 2018 08:59:42 +0000 Subject: [PATCH 45/68] JavaScript: Remove `esregex`. --- javascript/extractor/lib/esregex/.gitignore | 1 - javascript/extractor/lib/esregex/README.md | 4 - javascript/extractor/lib/esregex/package.json | 13 - .../extractor/lib/esregex/regexparser.js | 477 ------------- .../extractor/lib/esregex/tests/runtests.js | 638 ------------------ .../semmle/js/extractor/RegExpExtractor.java | 1 - 6 files changed, 1134 deletions(-) delete mode 100644 javascript/extractor/lib/esregex/.gitignore delete mode 100644 javascript/extractor/lib/esregex/README.md delete mode 100644 javascript/extractor/lib/esregex/package.json delete mode 100644 javascript/extractor/lib/esregex/regexparser.js delete mode 100644 javascript/extractor/lib/esregex/tests/runtests.js diff --git a/javascript/extractor/lib/esregex/.gitignore b/javascript/extractor/lib/esregex/.gitignore deleted file mode 100644 index b512c09d4766..000000000000 --- a/javascript/extractor/lib/esregex/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules \ No newline at end of file diff --git a/javascript/extractor/lib/esregex/README.md b/javascript/extractor/lib/esregex/README.md deleted file mode 100644 index c0d5763ad7db..000000000000 --- a/javascript/extractor/lib/esregex/README.md +++ /dev/null @@ -1,4 +0,0 @@ -esregex -======= - -Parser for ECMAScript 2018 regular expressions. diff --git a/javascript/extractor/lib/esregex/package.json b/javascript/extractor/lib/esregex/package.json deleted file mode 100644 index da9170e6f91d..000000000000 --- a/javascript/extractor/lib/esregex/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "esregex", - "version": "1.0.0", - "author": "Semmle", - "description": "Parser for ECMAScript 2018 regular expressions", - "devDependencies": { - "nodeunit": "*" - }, - "scripts": { - "test": "node tests/runtests.js" - }, - "license": "Apache 2.0" -} diff --git a/javascript/extractor/lib/esregex/regexparser.js b/javascript/extractor/lib/esregex/regexparser.js deleted file mode 100644 index 0afd4a19460b..000000000000 --- a/javascript/extractor/lib/esregex/regexparser.js +++ /dev/null @@ -1,477 +0,0 @@ -function RegExpParser(src) { - this.src = src; - this.pos = 0; - this.errors = []; - this.backrefs = []; - this.maxbackref = 0; -} - -RegExpParser.prototype.parse = function() { - var res = this.Pattern(); - this.backrefs.forEach(function(backref) { - if (backref.value > this.maxbackref) - this.error(RegExpParser.INVALID_BACKREF, backref.range[0], backref.range[1]); - }, this); - return res; -}; - -RegExpParser.prototype.setRange = function(start, node) { - node.range = [start, this.pos]; - return node; -}; - -RegExpParser.UNEXPECTED_EOS = 0; -RegExpParser.UNEXPECTED_CHARACTER = 1; -RegExpParser.EXPECTED_DIGIT = 2; -RegExpParser.EXPECTED_HEX_DIGIT = 3; -RegExpParser.EXPECTED_CONTROL_LETTER = 4; -RegExpParser.EXPECTED_CLOSING_PAREN = 5; -RegExpParser.EXPECTED_CLOSING_BRACE = 6; -RegExpParser.EXPECTED_EOS = 7; -RegExpParser.OCTAL_ESCAPE = 8; -RegExpParser.INVALID_BACKREF = 9; -RegExpParser.EXPECTED_RBRACKET = 10; -RegExpParser.EXPECTED_IDENTIFIER = 11; -RegExpParser.EXPECTED_CLOSING_ANGLE = 12; - -RegExpParser.prototype.error = function(code, start, end) { - if (typeof start !== 'number') - start = this.pos; - if (typeof end !== 'number') - end = start+1; - this.errors.push({ - type: 'Error', - code: code, - range: [start, end || start+1] - }); -}; - -RegExpParser.prototype.atEOS = function() { - return this.pos >= this.src.length; -}; - -RegExpParser.prototype.nextChar = function() { - if (this.atEOS()) { - this.error(RegExpParser.UNEXPECTED_EOS); - return '\0'; - } else { - return this.src.substring(this.pos, ++this.pos); - } -}; - -RegExpParser.prototype.readHexDigit = function() { - if (/[0-9a-fA-F]/.test(this.src[this.pos])) - return this.nextChar(); - this.error(RegExpParser.EXPECTED_HEX_DIGIT, this.pos); - return ''; -}; - -RegExpParser.prototype.readHexDigits = function(n) { - var res = ''; - while (n-->0) - res += this.readHexDigit(); - return res || '0'; -}; - -RegExpParser.prototype.readDigits = function(opt) { - var res = ""; - for (var c=this.src[this.pos]; /\d/.test(c); this.nextChar(), c=this.src[this.pos]) - res += c; - if (!res.length && !opt) - this.error(RegExpParser.EXPECTED_DIGIT); - return res; -}; - -RegExpParser.prototype.readIdentifier = function() { - var res = ''; - for (var c=this.src[this.pos]; c && /\w/.test(c); this.nextChar(), c=this.src[this.pos]) - res += c; - if (!res.length) - this.error(RegExpParser.EXPECTED_IDENTIFIER); - return res; -}; - -RegExpParser.prototype.expectRParen = function() { - if (!this.match(")")) - this.error(RegExpParser.EXPECTED_CLOSING_PAREN, this.pos-1); -}; - -RegExpParser.prototype.expectRBrace = function() { - if (!this.match("}")) - this.error(RegExpParser.EXPECTED_CLOSING_BRACE, this.pos-1); -}; - -RegExpParser.prototype.expectRAngle = function() { - if (!this.match(">")) - this.error(RegExpParser.EXPECTED_CLOSING_ANGLE, this.pos-1); -} - -RegExpParser.prototype.lookahead = function() { - for (var i=0,n=arguments.length; i" - }; - } - - if (this.match("p{", "P{")) { - var name = this.readIdentifier(), value = null; - if (this.match("=")) - value = this.readIdentifier(); - this.expectRBrace(); - return { - type: 'UnicodePropertyEscape', - name: name, - value: value, - raw: '\\p{' + name + (value ? '=' + value : '') + '}' - }; - } - - var startpos = this.pos-1, - c = this.nextChar(); - - if (/[0-9]/.test(c)) { - raw = c + this.readDigits(true); - if (c === '0' || inCharClass) { - var base = c === '0' && raw.length > 1 ? 8 : 10; - codepoint = parseInt(raw, base); - value = String.fromCharCode(codepoint); - var type; - if (base === 8) { - type = 'OctalEscape'; - this.error(RegExpParser.OCTAL_ESCAPE, startpos, this.pos); - } else { - type = 'DecimalEscape'; - } - - return { - type: type, - value: value, - codepoint: codepoint, - raw: '\\' + raw - }; - } else { - var br = { - type: 'BackReference', - value: parseInt(raw, 10), - raw: '\\' + raw - }; - this.backrefs.push(br); - return br; - } - } - - var ctrltab = "f\fn\nr\rt\tv\v", idx; - if ((idx=ctrltab.indexOf(c)) % 2 == 0) { - value = ctrltab.charAt(idx+1); - return { - type: 'ControlEscape', - value: value, - codepoint: value.charCodeAt(0), - raw: '\\' + c - }; - } - - if (c === 'c') { - c = this.nextChar(); - if (!/[a-zA-Z]/.test(c)) - this.error(RegExpParser.EXPECTED_CONTROL_LETTER, this.pos-1); - codepoint = c.charCodeAt(0) % 32; - return { - type: 'ControlLetter', - value: String.fromCharCode(codepoint), - codepoint: codepoint, - raw: '\\c' + c - }; - } - - if (/[dsw]/i.test(c)) { - return { - type: 'CharacterClassEscape', - class: c, - raw: '\\' + c - }; - } - - return { - type: 'IdentityEscape', - value: c, - codepoint: c.charCodeAt(0), - raw: '\\' + c - }; -}; - -RegExpParser.prototype.CharacterClass = function() { - var start = this.pos, - elements = []; - - this.match("["); - var inverted = this.match("^"); - while (!this.match("]")) { - if (this.atEOS()) { - this.error(RegExpParser.EXPECTED_RBRACKET); - break; - } - elements.push(this.CharacterClassElement()); - } - return this.setRange(start, { - type: 'CharacterClass', - elements: elements, - inverted: inverted - }); -}; - -RegExpParser.prototype.CharacterClassElement = function() { - var start = this.pos, - atom = this.CharacterClassAtom(); - if (!this.lookahead("-]") && this.match("-")) - return this.setRange(start, { - type: 'CharacterClassRange', - left: atom, - right: this.CharacterClassAtom() - }); - return atom; -}; - -RegExpParser.prototype.CharacterClassAtom = function() { - var start = this.pos, - c = this.nextChar(); - if (c === "\\") { - if (this.match("b")) - return this.setRange(start, { - type: 'ControlEscape', - value: '\b', - codepoint: 8, - raw: '\\b' - }); - return this.setRange(start, this.AtomEscape(true)); - } - return this.setRange(start, { type: 'Constant', value: c }); -}; - -if (typeof exports !== 'undefined') - exports.RegExpParser = RegExpParser; diff --git a/javascript/extractor/lib/esregex/tests/runtests.js b/javascript/extractor/lib/esregex/tests/runtests.js deleted file mode 100644 index bbe6945302da..000000000000 --- a/javascript/extractor/lib/esregex/tests/runtests.js +++ /dev/null @@ -1,638 +0,0 @@ -var reporter = require('nodeunit').reporters['default'], - RegExpParser = require('../regexparser').RegExpParser; - -function runtest(test, input, expected_output, expected_errors) { - var parser = new RegExpParser(input), - actual_output; - - try { - actual_output = parser.parse(); - } catch(e) { - test.fail(e.message); - test.done(); - return; - } - - expected_errors = expected_errors || []; - - test.deepEqual(actual_output, expected_output); - test.equal(parser.errors.length, expected_errors.length); - for (var i=0,n=parser.errors.length; i\\w+)", - { type: 'Group', - capture: true, - number: 1, - name: 'ws', - operand: - { type: 'Plus', - operand: - { type: 'CharacterClassEscape', - class: 'w', - raw: '\\w', - range: [ 6, 8 ] }, - greedy: true, - range: [ 6, 9 ] }, - range: [ 0, 10 ] }, - []); - }, - named_capture_group_empty_name: function(test) { - runtest(test, - "(?<>\\w+)", - { type: 'Group', - capture: true, - number: 1, - name: '', - operand: - { type: 'Plus', - operand: - { type: 'CharacterClassEscape', - class: 'w', - raw: '\\w', - range: [ 4, 6 ] }, - greedy: true, - range: [ 4, 7 ] }, - range: [ 0, 8 ] }, - [ { type: 'Error', code: 11, range: [ 3, 4 ] } ]); - }, - named_capture_group_missing_rangle: function(test) { - runtest(test, - "(?\\w+", - { type: 'Group', - capture: true, - number: 1, - name: 'ws', - operand: - { type: 'Plus', - operand: - { type: 'CharacterClassEscape', - class: 'w', - raw: '\\w', - range: [ 6, 8 ] }, - greedy: true, - range: [ 6, 9 ] }, - range: [ 0, 9 ] }, - [ { type: 'Error', code: 5, range: [ 8, 9 ] } ]); - }, - named_backref: function(test) { - runtest(test, - "\\k", - { type: 'NamedBackReference', - name: 'ws', - raw: '\\k', - range: [ 0, 6 ] }, - []); - }, - named_backref_empty_name: function(test) { - runtest(test, - "\\k<>", - { type: 'NamedBackReference', - name: '', - raw: '\\k<>', - range: [ 0, 4 ] }, - [ { type: 'Error', code: 11, range: [ 3, 4 ] } ]); - }, - named_backref_missing_rangle: function(test) { - runtest(test, - "\\k', - range: [ 0, 5 ] }, - [ { type: 'Error', code: 12, range: [ 4, 5 ] } ]); - }, - positive_lookbehind: function(test) { - runtest(test, - "(?<=\$)0", - { type: 'Sequence', - elements: - [ { type: 'ZeroWidthPositiveLookbehind', - operand: { type: 'Dollar', range: [ 4, 5 ] }, - range: [ 0, 6 ] }, - { type: 'Constant', value: '0', range: [ 6, 7 ] } ], - range: [ 0, 7 ] }, - []); - }, - negative_lookbehind: function(test) { - runtest(test, - "(? Date: Fri, 9 Nov 2018 08:59:56 +0000 Subject: [PATCH 46/68] JavaScript: Remove `doctrine`. --- javascript/extractor/.classpath | 1 - .../lib/external/doctrine/.gitignore | 3 - .../extractor/lib/external/doctrine/.scripted | 6 - .../lib/external/doctrine/.travis.yml | 4 - .../lib/external/doctrine/CONTRIBUTING.md | 5 - .../lib/external/doctrine/LICENSE.BSD | 19 - .../doctrine/LICENSE.closure-compiler | 202 -- .../lib/external/doctrine/LICENSE.esprima | 19 - .../extractor/lib/external/doctrine/README.md | 173 -- .../lib/external/doctrine/doctrine.js | 2146 ----------------- .../lib/external/doctrine/eslint.json | 22 - .../lib/external/doctrine/package.json | 34 - .../lib/external/doctrine/test/parse.js | 1888 --------------- .../lib/external/doctrine/test/strict.js | 165 -- .../lib/external/doctrine/test/stringify.js | 410 ---- .../lib/external/doctrine/test/test.html | 31 - .../lib/external/doctrine/test/unwrap.js | 57 - 17 files changed, 5185 deletions(-) delete mode 100644 javascript/extractor/lib/external/doctrine/.gitignore delete mode 100644 javascript/extractor/lib/external/doctrine/.scripted delete mode 100644 javascript/extractor/lib/external/doctrine/.travis.yml delete mode 100644 javascript/extractor/lib/external/doctrine/CONTRIBUTING.md delete mode 100644 javascript/extractor/lib/external/doctrine/LICENSE.BSD delete mode 100644 javascript/extractor/lib/external/doctrine/LICENSE.closure-compiler delete mode 100644 javascript/extractor/lib/external/doctrine/LICENSE.esprima delete mode 100644 javascript/extractor/lib/external/doctrine/README.md delete mode 100644 javascript/extractor/lib/external/doctrine/doctrine.js delete mode 100644 javascript/extractor/lib/external/doctrine/eslint.json delete mode 100644 javascript/extractor/lib/external/doctrine/package.json delete mode 100644 javascript/extractor/lib/external/doctrine/test/parse.js delete mode 100644 javascript/extractor/lib/external/doctrine/test/strict.js delete mode 100644 javascript/extractor/lib/external/doctrine/test/stringify.js delete mode 100644 javascript/extractor/lib/external/doctrine/test/test.html delete mode 100644 javascript/extractor/lib/external/doctrine/test/unwrap.js diff --git a/javascript/extractor/.classpath b/javascript/extractor/.classpath index 73c9db8bc49b..e4c64231cf4b 100644 --- a/javascript/extractor/.classpath +++ b/javascript/extractor/.classpath @@ -6,7 +6,6 @@ - diff --git a/javascript/extractor/lib/external/doctrine/.gitignore b/javascript/extractor/lib/external/doctrine/.gitignore deleted file mode 100644 index ba73eea15408..000000000000 --- a/javascript/extractor/lib/external/doctrine/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules - -*.iml \ No newline at end of file diff --git a/javascript/extractor/lib/external/doctrine/.scripted b/javascript/extractor/lib/external/doctrine/.scripted deleted file mode 100644 index 89683cd30f25..000000000000 --- a/javascript/extractor/lib/external/doctrine/.scripted +++ /dev/null @@ -1,6 +0,0 @@ -{ - "editor": { - "expandtab": true, - "tabsize": 4 - } -} \ No newline at end of file diff --git a/javascript/extractor/lib/external/doctrine/.travis.yml b/javascript/extractor/lib/external/doctrine/.travis.yml deleted file mode 100644 index 155fbfa9bf10..000000000000 --- a/javascript/extractor/lib/external/doctrine/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: node_js -node_js: - - 0.10 - diff --git a/javascript/extractor/lib/external/doctrine/CONTRIBUTING.md b/javascript/extractor/lib/external/doctrine/CONTRIBUTING.md deleted file mode 100644 index 6e0978475e0f..000000000000 --- a/javascript/extractor/lib/external/doctrine/CONTRIBUTING.md +++ /dev/null @@ -1,5 +0,0 @@ -Project license(s): 2-clause BSD license - -* You will only Submit Contributions where You have authored 100% of the content. -* You will only Submit Contributions to which You have the necessary rights. This means that if You are employed You have received the necessary permissions from Your employer to make the Contributions. -* Whatever content You Contribute will be provided under the Project License(s). diff --git a/javascript/extractor/lib/external/doctrine/LICENSE.BSD b/javascript/extractor/lib/external/doctrine/LICENSE.BSD deleted file mode 100644 index 3e580c355a96..000000000000 --- a/javascript/extractor/lib/external/doctrine/LICENSE.BSD +++ /dev/null @@ -1,19 +0,0 @@ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/javascript/extractor/lib/external/doctrine/LICENSE.closure-compiler b/javascript/extractor/lib/external/doctrine/LICENSE.closure-compiler deleted file mode 100644 index d64569567334..000000000000 --- a/javascript/extractor/lib/external/doctrine/LICENSE.closure-compiler +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/javascript/extractor/lib/external/doctrine/LICENSE.esprima b/javascript/extractor/lib/external/doctrine/LICENSE.esprima deleted file mode 100644 index 3e580c355a96..000000000000 --- a/javascript/extractor/lib/external/doctrine/LICENSE.esprima +++ /dev/null @@ -1,19 +0,0 @@ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/javascript/extractor/lib/external/doctrine/README.md b/javascript/extractor/lib/external/doctrine/README.md deleted file mode 100644 index 5be6fa932991..000000000000 --- a/javascript/extractor/lib/external/doctrine/README.md +++ /dev/null @@ -1,173 +0,0 @@ -doctrine ([doctrine](http://github.com/Constellation/doctrine)) is JSDoc parser. [![Build Status](https://secure.travis-ci.org/Constellation/doctrine.png)](http://travis-ci.org/Constellation/doctrine) - -It is now used by content assist system of [Eclipse Orion](http://www.eclipse.org/orion/) ([detail](http://planetorion.org/news/2012/10/orion-1-0-release/)) - -Doctrine can be used in a web browser: - - - -or in a Node.js application via the package manager: - - npm install doctrine - -simple example: - - doctrine.parse( - [ - "/**", - " * This function comment is parsed by doctrine", - " * @param {{ok:String}} userName", - "*/" - ].join('\n'), { unwrap: true }); - -and gets following information - - { - "description": "This function comment is parsed by doctrine", - "tags": [ - { - "title": "param", - "description": null, - "type": { - "type": "RecordType", - "fields": [ - { - "type": "FieldType", - "key": "ok", - "value": { - "type": "NameExpression", - "name": "String" - } - } - ] - }, - "name": "userName" - } - ] - } - -see [demo page](http://constellation.github.com/doctrine/demo/index.html) more detail. - -### Options - -#### doctrine.parse -We can pass options to `doctrine.parse(comment, options)`. -```js -{ - unwrap: boolean, // default: false - tags: [ string ] | null, // default: null - recoverable: boolean, // default: false - sloppy: boolean, // default: false - lineNumbers: boolean // default: false -} -``` - -##### unwrap - -When `unwrap` is `true`, doctrine attempt to unwrap comment specific string from a provided comment text. (removes `/**`, `*/` and `*`) -For example, `unwrap` transforms -``` -/** - * @param use - */ -``` -to -``` -@param use -``` -If a provided comment has these comment specific strings, you need to specify this `unwrap` option to `true`. - -##### tags - -When `tags` array is specified, doctrine only produce tags that is specified in this array. -For example, if you specify `[ 'param' ]`, doctrine only produces `param` tags. -If null is specified, doctrine produces all tags that doctrine can recognize. - -##### recoverable - -When `recoverable` is `true`, doctrine becomes `recoverable` - When failing to parse jsdoc comment, doctrine recovers its state and attempt to continue parsing. - -##### sloppy - -When `sloppy` is `true`, -``` -@param String [foo] -``` -'s `[foo]` is interpreted as a optional parameter, not interpreted as a name of this `@param`. - -##### lineNumbers - -When `lineNumbers` is `true`, parsed tags will include a `lineNumber` property indicating the line (relative to the start of the comment block) where each tag is located in the source. So, given the following comment: -``` -/** - * @param {String} foo - * @return {number} - */ -``` -The `@param` tag will have `lineNumber: 1`, and the `@return` tag will have `lineNumber: 2`. - - -### License - -#### doctrine - -Copyright (C) 2012 [Yusuke Suzuki](http://github.com/Constellation) - (twitter: [@Constellation](http://twitter.com/Constellation)) and other contributors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#### esprima - -some of functions is derived from esprima - -Copyright (C) 2012, 2011 [Ariya Hidayat](http://ariya.ofilabs.com/about) - (twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)) and other contributors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -#### closure-compiler - -some of extensions is derived from closure-compiler - -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ diff --git a/javascript/extractor/lib/external/doctrine/doctrine.js b/javascript/extractor/lib/external/doctrine/doctrine.js deleted file mode 100644 index 1c1dd1e62f29..000000000000 --- a/javascript/extractor/lib/external/doctrine/doctrine.js +++ /dev/null @@ -1,2146 +0,0 @@ -/* - Copyright (C) 2012-2014 Yusuke Suzuki - Copyright (C) 2014 Dan Tao - Copyright (C) 2013 Andrew Eisenberg - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/*jslint bitwise:true plusplus:true eqeq:true nomen:true*/ -/*global doctrine:true, exports:true, parseTypeExpression:true, parseTop:true*/ - -(function (exports) { - 'use strict'; - - var VERSION, - Regex, - CanAccessStringByIndex, - typed, - jsdoc, - isArray, - hasOwnProperty; - - // Sync with package.json. - VERSION = '0.5.2-dev'; - - // See also tools/generate-unicode-regex.py. - Regex = { - NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'), - NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') - }; - - CanAccessStringByIndex = typeof 'doctrine'[0] !== undefined; - - function sliceSource(source, index, last) { - var output; - if (!CanAccessStringByIndex) { - output = source.slice(index, last).join(''); - } else { - output = source.slice(index, last); - } - return output; - } - - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(ary) { - return Object.prototype.toString.call(ary) === '[object Array]'; - }; - } - - hasOwnProperty = (function () { - var func = Object.prototype.hasOwnProperty; - return function hasOwnProperty(obj, name) { - return func.call(obj, name); - }; - }()); - - function shallowCopy(obj) { - var ret = {}, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - ret[key] = obj[key]; - } - } - return ret; - } - - function isLineTerminator(ch) { - return ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029'; - } - - function isWhiteSpace(ch) { - return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') || - (ch === '\u000C') || (ch === '\u00A0') || - (ch.charCodeAt(0) >= 0x1680 && - '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0); - } - - function isDecimalDigit(ch) { - return '0123456789'.indexOf(ch) >= 0; - } - - function isHexDigit(ch) { - return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; - } - - function isOctalDigit(ch) { - return '01234567'.indexOf(ch) >= 0; - } - - function isASCIIAlphanumeric(ch) { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'); - } - - function isIdentifierStart(ch) { - return (ch === '$') || (ch === '_') || (ch === '\\') || - (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch)); - } - - function isIdentifierPart(ch) { - return (ch === '$') || (ch === '_') || (ch === '\\') || - (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - ((ch >= '0') && (ch <= '9')) || - ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch)); - } - - function isTypeName(ch) { - return '><(){}[],:*|?!='.indexOf(ch) === -1 && !isWhiteSpace(ch) && !isLineTerminator(ch); - } - - function isParamTitle(title) { - return title === 'param' || title === 'argument' || title === 'arg'; - } - - function isProperty(title) { - return title === 'property' || title === 'prop'; - } - - function isNameParameterRequired(title) { - return isParamTitle(title) || isProperty(title) || - title === 'alias' || title === 'this' || title === 'mixes' || title === 'requires'; - } - - function isAllowedName(title) { - return isNameParameterRequired(title) || title === 'const' || title === 'constant'; - } - - function isAllowedNested(title) { - return isProperty(title) || isParamTitle(title); - } - - function isTypeParameterRequired(title) { - return isParamTitle(title) || title === 'define' || title === 'enum' || - title === 'implements' || title === 'return' || - title === 'this' || title === 'type' || title === 'typedef' || - title === 'returns' || isProperty(title); - } - - // Consider deprecation instead using 'isTypeParameterRequired' and 'Rules' declaration to pick when a type is optional/required - // This would require changes to 'parseType' - function isAllowedType(title) { - return isTypeParameterRequired(title) || title === 'throws' || title === 'const' || title === 'constant' || - title === 'namespace' || title === 'member' || title === 'var' || title === 'module' || - title === 'constructor' || title === 'class' || title === 'extends' || title === 'augments' || - title === 'public' || title === 'private' || title === 'protected'; - } - - function DoctrineError(message) { - this.name = 'DoctrineError'; - this.message = message; - } - DoctrineError.prototype = new Error(); - DoctrineError.prototype.constructor = DoctrineError; - - function throwError(message) { - throw new DoctrineError(message); - } - - function assert(cond, text) { - if (VERSION.slice(-3) === 'dev') { - if (!cond) { - throwError(text); - } - } - } - - function trim(str) { - return str.replace(/^\s+/, '').replace(/\s+$/, ''); - } - - function unwrapComment(doc) { - // JSDoc comment is following form - // /** - // * ....... - // */ - // remove /**, */ and * - var BEFORE_STAR = 0, - STAR = 1, - AFTER_STAR = 2, - index, - len, - mode, - result, - ch; - - doc = doc.replace(/^\/\*\*?/, '').replace(/\*\/$/, ''); - index = 0; - len = doc.length; - mode = BEFORE_STAR; - result = ''; - - while (index < len) { - ch = doc[index]; - switch (mode) { - case BEFORE_STAR: - if (isLineTerminator(ch)) { - result += ch; - } else if (ch === '*') { - mode = STAR; - } else if (!isWhiteSpace(ch)) { - result += ch; - mode = AFTER_STAR; - } - break; - - case STAR: - if (!isWhiteSpace(ch)) { - result += ch; - } - mode = isLineTerminator(ch) ? BEFORE_STAR : AFTER_STAR; - break; - - case AFTER_STAR: - result += ch; - if (isLineTerminator(ch)) { - mode = BEFORE_STAR; - } - break; - } - index += 1; - } - - return result; - } - - // Type Expression Parser - - (function (exports) { - var Syntax, - Token, - source, - length, - index, - previous, - token, - value; - - Syntax = { - NullableLiteral: 'NullableLiteral', - AllLiteral: 'AllLiteral', - NullLiteral: 'NullLiteral', - UndefinedLiteral: 'UndefinedLiteral', - VoidLiteral: 'VoidLiteral', - UnionType: 'UnionType', - ArrayType: 'ArrayType', - RecordType: 'RecordType', - FieldType: 'FieldType', - FunctionType: 'FunctionType', - ParameterType: 'ParameterType', - RestType: 'RestType', - NonNullableType: 'NonNullableType', - OptionalType: 'OptionalType', - NullableType: 'NullableType', - NameExpression: 'NameExpression', - TypeApplication: 'TypeApplication' - }; - - Token = { - ILLEGAL: 0, // ILLEGAL - DOT: 1, // . - DOT_LT: 2, // .< - REST: 3, // ... - LT: 4, // < - GT: 5, // > - LPAREN: 6, // ( - RPAREN: 7, // ) - LBRACE: 8, // { - RBRACE: 9, // } - LBRACK: 10, // [ - RBRACK: 11, // ] - COMMA: 12, // , - COLON: 13, // : - STAR: 14, // * - PIPE: 15, // | - QUESTION: 16, // ? - BANG: 17, // ! - EQUAL: 18, // = - NAME: 19, // name token - STRING: 20, // string - NUMBER: 21, // number - EOF: 22 - }; - - function Context(previous, index, token, value) { - this._previous = previous; - this._index = index; - this._token = token; - this._value = value; - } - - Context.prototype.restore = function () { - previous = this._previous; - index = this._index; - token = this._token; - value = this._value; - }; - - Context.save = function () { - return new Context(previous, index, token, value); - }; - - function advance() { - var ch = source[index]; - index += 1; - return ch; - } - - function scanHexEscape(prefix) { - var i, len, ch, code = 0; - - len = (prefix === 'u') ? 4 : 2; - for (i = 0; i < len; ++i) { - if (index < length && isHexDigit(source[index])) { - ch = advance(); - code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); - } else { - return ''; - } - } - return String.fromCharCode(code); - } - - function scanString() { - var str = '', quote, ch, code, unescaped, restore; //TODO review removal octal = false - quote = source[index]; - ++index; - - while (index < length) { - ch = advance(); - - if (ch === quote) { - quote = ''; - break; - } else if (ch === '\\') { - ch = advance(); - if (!isLineTerminator(ch)) { - switch (ch) { - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; - case 'u': - case 'x': - restore = index; - unescaped = scanHexEscape(ch); - if (unescaped) { - str += unescaped; - } else { - index = restore; - str += ch; - } - break; - case 'b': - str += '\b'; - break; - case 'f': - str += '\f'; - break; - case 'v': - str += '\v'; - break; - - default: - if (isOctalDigit(ch)) { - code = '01234567'.indexOf(ch); - - // \0 is not octal escape sequence - // Deprecating unused code. TODO review removal - //if (code !== 0) { - // octal = true; - //} - - if (index < length && isOctalDigit(source[index])) { - //TODO Review Removal octal = true; - code = code * 8 + '01234567'.indexOf(advance()); - - // 3 digits are only allowed when string starts - // with 0, 1, 2, 3 - if ('0123'.indexOf(ch) >= 0 && - index < length && - isOctalDigit(source[index])) { - code = code * 8 + '01234567'.indexOf(advance()); - } - } - str += String.fromCharCode(code); - } else { - str += ch; - } - break; - } - } else { - if (ch === '\r' && source[index] === '\n') { - ++index; - } - } - } else if (isLineTerminator(ch)) { - break; - } else { - str += ch; - } - } - - if (quote !== '') { - throwError('unexpected quote'); - } - - value = str; - return Token.STRING; - } - - function scanNumber() { - var number, ch; - - number = ''; - if (ch !== '.') { - number = advance(); - ch = source[index]; - - if (number === '0') { - if (ch === 'x' || ch === 'X') { - number += advance(); - while (index < length) { - ch = source[index]; - if (!isHexDigit(ch)) { - break; - } - number += advance(); - } - - if (number.length <= 2) { - // only 0x - throwError('unexpected token'); - } - - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch)) { - throwError('unexpected token'); - } - } - value = parseInt(number, 16); - return Token.NUMBER; - } - - if (isOctalDigit(ch)) { - number += advance(); - while (index < length) { - ch = source[index]; - if (!isOctalDigit(ch)) { - break; - } - number += advance(); - } - - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch) || isDecimalDigit(ch)) { - throwError('unexpected token'); - } - } - value = parseInt(number, 8); - return Token.NUMBER; - } - - if (isDecimalDigit(ch)) { - throwError('unexpected token'); - } - } - - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } - number += advance(); - } - } - - if (ch === '.') { - number += advance(); - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } - number += advance(); - } - } - - if (ch === 'e' || ch === 'E') { - number += advance(); - - ch = source[index]; - if (ch === '+' || ch === '-') { - number += advance(); - } - - ch = source[index]; - if (isDecimalDigit(ch)) { - number += advance(); - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } - number += advance(); - } - } else { - throwError('unexpected token'); - } - } - - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch)) { - throwError('unexpected token'); - } - } - - value = parseFloat(number); - return Token.NUMBER; - } - - - function scanTypeName() { - var ch, ch2; - - value = advance(); - while (index < length && isTypeName(source[index])) { - ch = source[index]; - if (ch === '.') { - if ((index + 1) < length) { - ch2 = source[index + 1]; - if (ch2 === '<') { - break; - } - } - } - value += advance(); - } - return Token.NAME; - } - - function next() { - var ch; - - previous = index; - - while (index < length && isWhiteSpace(source[index])) { - advance(); - } - if (index >= length) { - token = Token.EOF; - return token; - } - - ch = source[index]; - switch (ch) { - case '"': - token = scanString(); - return token; - - case ':': - advance(); - token = Token.COLON; - return token; - - case ',': - advance(); - token = Token.COMMA; - return token; - - case '(': - advance(); - token = Token.LPAREN; - return token; - - case ')': - advance(); - token = Token.RPAREN; - return token; - - case '[': - advance(); - token = Token.LBRACK; - return token; - - case ']': - advance(); - token = Token.RBRACK; - return token; - - case '{': - advance(); - token = Token.LBRACE; - return token; - - case '}': - advance(); - token = Token.RBRACE; - return token; - - case '.': - advance(); - if (index < length) { - ch = source[index]; - if (ch === '<') { - advance(); - token = Token.DOT_LT; - return token; - } - - if (ch === '.' && index + 1 < length && source[index + 1] === '.') { - advance(); - advance(); - token = Token.REST; - return token; - } - - if (isDecimalDigit(ch)) { - token = scanNumber(); - return token; - } - } - token = Token.DOT; - return token; - - case '<': - advance(); - token = Token.LT; - return token; - - case '>': - advance(); - token = Token.GT; - return token; - - case '*': - advance(); - token = Token.STAR; - return token; - - case '|': - advance(); - token = Token.PIPE; - return token; - - case '?': - advance(); - token = Token.QUESTION; - return token; - - case '!': - advance(); - token = Token.BANG; - return token; - - case '=': - advance(); - token = Token.EQUAL; - return token; - - default: - if (isDecimalDigit(ch)) { - token = scanNumber(); - return token; - } - - // type string permits following case, - // - // namespace.module.MyClass - // - // this reduced 1 token TK_NAME - if (isTypeName(ch)) { - token = scanTypeName(); - return token; - } - - token = Token.ILLEGAL; - return token; - } - } - - function consume(target, text) { - assert(token === target, text || 'consumed token not matched'); - next(); - } - - function expect(target) { - if (token !== target) { - throwError('unexpected token'); - } - next(); - } - - // UnionType := '(' TypeUnionList ')' - // - // TypeUnionList := - // <> - // | NonemptyTypeUnionList - // - // NonemptyTypeUnionList := - // TypeExpression - // | TypeExpression '|' NonemptyTypeUnionList - function parseUnionType() { - var elements; - consume(Token.LPAREN, 'UnionType should start with ('); - elements = []; - if (token !== Token.RPAREN) { - while (true) { - elements.push(parseTypeExpression()); - if (token === Token.RPAREN) { - break; - } - expect(Token.PIPE); - } - } - consume(Token.RPAREN, 'UnionType should end with )'); - return { - type: Syntax.UnionType, - elements: elements - }; - } - - // ArrayType := '[' ElementTypeList ']' - // - // ElementTypeList := - // <> - // | TypeExpression - // | '...' TypeExpression - // | TypeExpression ',' ElementTypeList - function parseArrayType() { - var elements; - consume(Token.LBRACK, 'ArrayType should start with ['); - elements = []; - while (token !== Token.RBRACK) { - if (token === Token.REST) { - consume(Token.REST); - elements.push({ - type: Syntax.RestType, - expression: parseTypeExpression() - }); - break; - } else { - elements.push(parseTypeExpression()); - } - if (token !== Token.RBRACK) { - expect(Token.COMMA); - } - } - expect(Token.RBRACK); - return { - type: Syntax.ArrayType, - elements: elements - }; - } - - function parseFieldName() { - var v = value; - if (token === Token.NAME || token === Token.STRING) { - next(); - return v; - } - - if (token === Token.NUMBER) { - consume(Token.NUMBER); - return String(v); - } - - throwError('unexpected token'); - } - - // FieldType := - // FieldName - // | FieldName ':' TypeExpression - // - // FieldName := - // NameExpression - // | StringLiteral - // | NumberLiteral - // | ReservedIdentifier - function parseFieldType() { - var key; - - key = parseFieldName(); - if (token === Token.COLON) { - consume(Token.COLON); - return { - type: Syntax.FieldType, - key: key, - value: parseTypeExpression() - }; - } - return { - type: Syntax.FieldType, - key: key, - value: null - }; - } - - // RecordType := '{' FieldTypeList '}' - // - // FieldTypeList := - // <> - // | FieldType - // | FieldType ',' FieldTypeList - function parseRecordType() { - var fields; - - consume(Token.LBRACE, 'RecordType should start with {'); - fields = []; - if (token === Token.COMMA) { - consume(Token.COMMA); - } else { - while (token !== Token.RBRACE) { - fields.push(parseFieldType()); - if (token !== Token.RBRACE) { - expect(Token.COMMA); - } - } - } - expect(Token.RBRACE); - return { - type: Syntax.RecordType, - fields: fields - }; - } - - function parseNameExpression() { - var name = value; - expect(Token.NAME); - return { - type: Syntax.NameExpression, - name: name - }; - } - - // TypeExpressionList := - // TopLevelTypeExpression - // | TopLevelTypeExpression ',' TypeExpressionList - function parseTypeExpressionList() { - var elements = []; - - elements.push(parseTop()); - while (token === Token.COMMA) { - consume(Token.COMMA); - elements.push(parseTop()); - } - return elements; - } - - // TypeName := - // NameExpression - // | NameExpression TypeApplication - // - // TypeApplication := - // '.<' TypeExpressionList '>' - // | '<' TypeExpressionList '>' // this is extension of doctrine - function parseTypeName() { - var expr, applications; - - expr = parseNameExpression(); - if (token === Token.DOT_LT || token === Token.LT) { - next(); - applications = parseTypeExpressionList(); - expect(Token.GT); - return { - type: Syntax.TypeApplication, - expression: expr, - applications: applications - }; - } - return expr; - } - - // ResultType := - // <> - // | ':' void - // | ':' TypeExpression - // - // BNF is above - // but, we remove <> pattern, so token is always TypeToken::COLON - function parseResultType() { - consume(Token.COLON, 'ResultType should start with :'); - if (token === Token.NAME && value === 'void') { - consume(Token.NAME); - return { - type: Syntax.VoidLiteral - }; - } - return parseTypeExpression(); - } - - // ParametersType := - // RestParameterType - // | NonRestParametersType - // | NonRestParametersType ',' RestParameterType - // - // RestParameterType := - // '...' - // '...' Identifier - // - // NonRestParametersType := - // ParameterType ',' NonRestParametersType - // | ParameterType - // | OptionalParametersType - // - // OptionalParametersType := - // OptionalParameterType - // | OptionalParameterType, OptionalParametersType - // - // OptionalParameterType := ParameterType= - // - // ParameterType := TypeExpression | Identifier ':' TypeExpression - // - // Identifier is "new" or "this" - function parseParametersType() { - var params = [], normal = true, expr, rest = false; - - while (token !== Token.RPAREN) { - if (token === Token.REST) { - // RestParameterType - consume(Token.REST); - rest = true; - } - - expr = parseTypeExpression(); - if (expr.type === Syntax.NameExpression && token === Token.COLON) { - // Identifier ':' TypeExpression - consume(Token.COLON); - expr = { - type: Syntax.ParameterType, - name: expr.name, - expression: parseTypeExpression() - }; - } - if (token === Token.EQUAL) { - consume(Token.EQUAL); - expr = { - type: Syntax.OptionalType, - expression: expr - }; - normal = false; - } else { - if (!normal) { - throwError('unexpected token'); - } - } - if (rest) { - expr = { - type: Syntax.RestType, - expression: expr - }; - } - params.push(expr); - if (token !== Token.RPAREN) { - expect(Token.COMMA); - } - } - return params; - } - - // FunctionType := 'function' FunctionSignatureType - // - // FunctionSignatureType := - // | TypeParameters '(' ')' ResultType - // | TypeParameters '(' ParametersType ')' ResultType - // | TypeParameters '(' 'this' ':' TypeName ')' ResultType - // | TypeParameters '(' 'this' ':' TypeName ',' ParametersType ')' ResultType - function parseFunctionType() { - var isNew, thisBinding, params, result, fnType; - assert(token === Token.NAME && value === 'function', 'FunctionType should start with \'function\''); - consume(Token.NAME); - - // Google Closure Compiler is not implementing TypeParameters. - // So we do not. if we don't get '(', we see it as error. - expect(Token.LPAREN); - - isNew = false; - params = []; - thisBinding = null; - if (token !== Token.RPAREN) { - // ParametersType or 'this' - if (token === Token.NAME && - (value === 'this' || value === 'new')) { - // 'this' or 'new' - // 'new' is Closure Compiler extension - isNew = value === 'new'; - consume(Token.NAME); - expect(Token.COLON); - thisBinding = parseTypeName(); - if (token === Token.COMMA) { - consume(Token.COMMA); - params = parseParametersType(); - } - } else { - params = parseParametersType(); - } - } - - expect(Token.RPAREN); - - result = null; - if (token === Token.COLON) { - result = parseResultType(); - } - - fnType = { - type: Syntax.FunctionType, - params: params, - result: result - }; - if (thisBinding) { - // avoid adding null 'new' and 'this' properties - fnType['this'] = thisBinding; - if (isNew) { - fnType['new'] = true; - } - } - return fnType; - } - - // BasicTypeExpression := - // '*' - // | 'null' - // | 'undefined' - // | TypeName - // | FunctionType - // | UnionType - // | RecordType - // | ArrayType - function parseBasicTypeExpression() { - var context; - switch (token) { - case Token.STAR: - consume(Token.STAR); - return { - type: Syntax.AllLiteral - }; - - case Token.LPAREN: - return parseUnionType(); - - case Token.LBRACK: - return parseArrayType(); - - case Token.LBRACE: - return parseRecordType(); - - case Token.NAME: - if (value === 'null') { - consume(Token.NAME); - return { - type: Syntax.NullLiteral - }; - } - - if (value === 'undefined') { - consume(Token.NAME); - return { - type: Syntax.UndefinedLiteral - }; - } - - context = Context.save(); - if (value === 'function') { - try { - return parseFunctionType(); - } catch (e) { - context.restore(); - } - } - - return parseTypeName(); - - default: - throwError('unexpected token'); - } - } - - // TypeExpression := - // BasicTypeExpression - // | '?' BasicTypeExpression - // | '!' BasicTypeExpression - // | BasicTypeExpression '?' - // | BasicTypeExpression '!' - // | '?' - // | BasicTypeExpression '[]' - function parseTypeExpression() { - var expr; - - if (token === Token.QUESTION) { - consume(Token.QUESTION); - if (token === Token.COMMA || token === Token.EQUAL || token === Token.RBRACE || - token === Token.RPAREN || token === Token.PIPE || token === Token.EOF || - token === Token.RBRACK) { - return { - type: Syntax.NullableLiteral - }; - } - return { - type: Syntax.NullableType, - expression: parseBasicTypeExpression(), - prefix: true - }; - } - - if (token === Token.BANG) { - consume(Token.BANG); - return { - type: Syntax.NonNullableType, - expression: parseBasicTypeExpression(), - prefix: true - }; - } - - expr = parseBasicTypeExpression(); - if (token === Token.BANG) { - consume(Token.BANG); - return { - type: Syntax.NonNullableType, - expression: expr, - prefix: false - }; - } - - if (token === Token.QUESTION) { - consume(Token.QUESTION); - return { - type: Syntax.NullableType, - expression: expr, - prefix: false - }; - } - - if (token === Token.LBRACK) { - consume(Token.LBRACK); - consume(Token.RBRACK, 'expected an array-style type declaration (' + value + '[])'); - return { - type: Syntax.TypeApplication, - expression: { - type: Syntax.NameExpression, - name: 'Array' - }, - applications: [expr] - }; - } - - return expr; - } - - // TopLevelTypeExpression := - // TypeExpression - // | TypeUnionList - // - // This rule is Google Closure Compiler extension, not ES4 - // like, - // { number | string } - // If strict to ES4, we should write it as - // { (number|string) } - function parseTop() { - var expr, elements; - - expr = parseTypeExpression(); - if (token !== Token.PIPE) { - return expr; - } - - elements = [ expr ]; - consume(Token.PIPE); - while (true) { - elements.push(parseTypeExpression()); - if (token !== Token.PIPE) { - break; - } - consume(Token.PIPE); - } - - return { - type: Syntax.UnionType, - elements: elements - }; - } - - function parseTopParamType() { - var expr; - - if (token === Token.REST) { - consume(Token.REST); - return { - type: Syntax.RestType, - expression: parseTop() - }; - } - - expr = parseTop(); - if (token === Token.EQUAL) { - consume(Token.EQUAL); - return { - type: Syntax.OptionalType, - expression: expr - }; - } - - return expr; - } - - function parseType(src, opt) { - var expr; - - source = src; - length = source.length; - index = 0; - previous = 0; - - if (!CanAccessStringByIndex) { - source = source.split(''); - } - - next(); - expr = parseTop(); - - if (opt && opt.midstream) { - return { - expression: expr, - index: previous - }; - } - - if (token !== Token.EOF) { - throwError('not reach to EOF'); - } - - return expr; - } - - function parseParamType(src, opt) { - var expr; - - source = src; - length = source.length; - index = 0; - previous = 0; - - if (!CanAccessStringByIndex) { - source = source.split(''); - } - - next(); - expr = parseTopParamType(); - - if (opt && opt.midstream) { - return { - expression: expr, - index: previous - }; - } - - if (token !== Token.EOF) { - throwError('not reach to EOF'); - } - - return expr; - } - - function stringifyImpl(node, compact, topLevel) { - var result, i, iz; - - switch (node.type) { - case Syntax.NullableLiteral: - result = '?'; - break; - - case Syntax.AllLiteral: - result = '*'; - break; - - case Syntax.NullLiteral: - result = 'null'; - break; - - case Syntax.UndefinedLiteral: - result = 'undefined'; - break; - - case Syntax.VoidLiteral: - result = 'void'; - break; - - case Syntax.UnionType: - if (!topLevel) { - result = '('; - } else { - result = ''; - } - - for (i = 0, iz = node.elements.length; i < iz; ++i) { - result += stringifyImpl(node.elements[i], compact); - if ((i + 1) !== iz) { - result += '|'; - } - } - - if (!topLevel) { - result += ')'; - } - break; - - case Syntax.ArrayType: - result = '['; - for (i = 0, iz = node.elements.length; i < iz; ++i) { - result += stringifyImpl(node.elements[i], compact); - if ((i + 1) !== iz) { - result += compact ? ',' : ', '; - } - } - result += ']'; - break; - - case Syntax.RecordType: - result = '{'; - for (i = 0, iz = node.fields.length; i < iz; ++i) { - result += stringifyImpl(node.fields[i], compact); - if ((i + 1) !== iz) { - result += compact ? ',' : ', '; - } - } - result += '}'; - break; - - case Syntax.FieldType: - if (node.value) { - result = node.key + (compact ? ':' : ': ') + stringifyImpl(node.value, compact); - } else { - result = node.key; - } - break; - - case Syntax.FunctionType: - result = compact ? 'function(' : 'function ('; - - if (node['this']) { - if (node['new']) { - result += (compact ? 'new:' : 'new: '); - } else { - result += (compact ? 'this:' : 'this: '); - } - - result += stringifyImpl(node['this'], compact); - - if (node.params.length !== 0) { - result += compact ? ',' : ', '; - } - } - - for (i = 0, iz = node.params.length; i < iz; ++i) { - result += stringifyImpl(node.params[i], compact); - if ((i + 1) !== iz) { - result += compact ? ',' : ', '; - } - } - - result += ')'; - - if (node.result) { - result += (compact ? ':' : ': ') + stringifyImpl(node.result, compact); - } - break; - - case Syntax.ParameterType: - result = node.name + (compact ? ':' : ': ') + stringifyImpl(node.expression, compact); - break; - - case Syntax.RestType: - result = '...'; - if (node.expression) { - result += stringifyImpl(node.expression, compact); - } - break; - - case Syntax.NonNullableType: - if (node.prefix) { - result = '!' + stringifyImpl(node.expression, compact); - } else { - result = stringifyImpl(node.expression, compact) + '!'; - } - break; - - case Syntax.OptionalType: - result = stringifyImpl(node.expression, compact) + '='; - break; - - case Syntax.NullableType: - if (node.prefix) { - result = '?' + stringifyImpl(node.expression, compact); - } else { - result = stringifyImpl(node.expression, compact) + '?'; - } - break; - - case Syntax.NameExpression: - result = node.name; - break; - - case Syntax.TypeApplication: - result = stringifyImpl(node.expression, compact) + '.<'; - for (i = 0, iz = node.applications.length; i < iz; ++i) { - result += stringifyImpl(node.applications[i], compact); - if ((i + 1) !== iz) { - result += compact ? ',' : ', '; - } - } - result += '>'; - break; - - default: - throwError('Unknown type ' + node.type); - } - - return result; - } - - function stringify(node, options) { - if (options == null) { - options = {}; - } - return stringifyImpl(node, options.compact, options.topLevel); - } - - exports.parseType = parseType; - exports.parseParamType = parseParamType; - exports.stringify = stringify; - exports.Syntax = Syntax; - }(typed = {})); - - // JSDoc Tag Parser - - (function (exports) { - var Rules, - index, - lineNumber, - lineStart, - length, - source, - recoverable, - sloppy, - strict; - - function skipStars(index) { - while (index < length && isWhiteSpace(source[index]) && !isLineTerminator(source[index])) { - index += 1; - } - while (source[index] === '*') { - index += 1; - } - while (index < length && isWhiteSpace(source[index]) && !isLineTerminator(source[index])) { - index += 1; - } - return index; - } - - function advance() { - var ch = source[index]; - index += 1; - if (isLineTerminator(ch) && !(ch === '\r' && source[index] === '\n')) { - lineNumber += 1; - lineStart = index; - index = skipStars(index); - } - return ch; - } - - function scanTitle() { - var title = ''; - // waste '@' - advance(); - - while (index < length && isASCIIAlphanumeric(source[index])) { - title += advance(); - } - - return title; - } - - function seekContent() { - var ch, waiting, last = index; - - waiting = false; - while (last < length) { - ch = source[last]; - if (isLineTerminator(ch) && !(ch === '\r' && source[last + 1] === '\n')) { - lineNumber += 1; - lineStart = last + 1; - last = skipStars(last + 1) - 1; - waiting = true; - } else if (waiting) { - if (ch === '@') { - break; - } - if (!isWhiteSpace(ch)) { - waiting = false; - } - } - last += 1; - } - return last; - } - - // type expression may have nest brace, such as, - // { { ok: string } } - // - // therefore, scanning type expression with balancing braces. - function parseType(title, last) { - var ch, brace, type, direct = false; - - // search '{' - while (index < last) { - ch = source[index]; - if (isWhiteSpace(ch)) { - advance(); - } else if (ch === '{') { - advance(); - break; - } else { - // this is direct pattern - direct = true; - break; - } - } - - if (!direct) { - // type expression { is found - brace = 1; - type = ''; - while (index < last) { - ch = source[index]; - if (isLineTerminator(ch)) { - advance(); - } else { - if (ch === '}') { - brace -= 1; - if (brace === 0) { - advance(); - break; - } - } else if (ch === '{') { - brace += 1; - } - type += advance(); - } - } - - if (brace !== 0) { - // braces is not balanced - return throwError('Braces are not balanced'); - } - - try { - if (isParamTitle(title)) { - return typed.parseParamType(type); - } - return typed.parseType(type); - } catch (e1) { - // parse failed - return null; - } - } else { - return null; - } - } - - function scanIdentifier(last) { - var identifier; - if (!isIdentifierStart(source[index])) { - return null; - } - identifier = advance(); - while (index < last && isIdentifierPart(source[index])) { - identifier += advance(); - } - return identifier; - } - - function skipWhiteSpace(last) { - while (index < last && (isWhiteSpace(source[index]) || isLineTerminator(source[index]))) { - advance(); - } - } - - function parseName(last, allowBrackets, allowNestedParams) { - var name = '', useBrackets; - - skipWhiteSpace(last); - - if (index >= last) { - return null; - } - - if (allowBrackets && source[index] === '[') { - useBrackets = true; - name = advance(); - } - - if (!isIdentifierStart(source[index])) { - return null; - } - - name += scanIdentifier(last); - - if (allowNestedParams) { - while (source[index] === '.' || source[index] === '#' || source[index] === '~') { - name += source[index]; - index += 1; - name += scanIdentifier(last); - } - } - - if (useBrackets) { - // do we have a default value for this? - if (source[index] === '=') { - - // consume the '='' symbol - name += advance(); - // scan in the default value - while (index < last && source[index] !== ']') { - name += advance(); - } - } - - if (index >= last || source[index] !== ']') { - // we never found a closing ']' - return null; - } - - // collect the last ']' - name += advance(); - } - - return name; - } - - function skipToTag() { - while (index < length && source[index] !== '@') { - advance(); - } - if (index >= length) { - return false; - } - assert(source[index] === '@'); - return true; - } - - function TagParser(options, title) { - this._options = options; - this._title = title; - this._tag = { - title: title, - description: null - }; - if (this._options.lineNumbers) { - this._tag.lineNumber = lineNumber; - } - this._last = 0; - // space to save special information for title parsers. - this._extra = { }; - } - - // addError(err, ...) - TagParser.prototype.addError = function addError(errorText) { - var args = Array.prototype.slice.call(arguments, 1), - msg = errorText.replace( - /%(\d)/g, - function (whole, index) { - assert(index < args.length, 'Message reference must be in range'); - return args[index]; - } - ); - - if (!this._tag.errors) { - this._tag.errors = []; - } - if (strict) { - throwError(msg); - } - this._tag.errors.push(msg); - return recoverable; - }; - - TagParser.prototype.parseType = function () { - // type required titles - if (isTypeParameterRequired(this._title)) { - try { - this._tag.type = parseType(this._title, this._last); - if (!this._tag.type) { - if (!isParamTitle(this._title)) { - if (!this.addError('Missing or invalid tag type')) { - return false; - } - } - } - } catch (error) { - this._tag.type = null; - if (!this.addError(error.message)) { - return false; - } - } - } else if (isAllowedType(this._title)) { - // optional types - try { - this._tag.type = parseType(this._title, this._last); - } catch (e) { - //For optional types, lets drop the thrown error when we hit the end of the file - } - } - return true; - }; - - TagParser.prototype._parseNamePath = function (optional) { - var name; - name = parseName(this._last, sloppy && isParamTitle(this._title), true); - if (!name) { - if (!optional) { - if (!this.addError('Missing or invalid tag name')) { - return false; - } - } - } - this._tag.name = name; - return true; - }; - - TagParser.prototype.parseNamePath = function () { - return this._parseNamePath(false); - }; - - TagParser.prototype.parseNamePathOptional = function () { - return this._parseNamePath(true); - }; - - - TagParser.prototype.parseName = function () { - var assign, name; - - // param, property requires name - if (isAllowedName(this._title)) { - this._tag.name = parseName(this._last, sloppy && isParamTitle(this._title), isAllowedNested(this._title)); - if (!this._tag.name) { - if (!isNameParameterRequired(this._title)) { - return true; - } - - // it's possible the name has already been parsed but interpreted as a type - // it's also possible this is a sloppy declaration, in which case it will be - // fixed at the end - if (isParamTitle(this._title) && this._tag.type && this._tag.type.name) { - this._extra.name = this._tag.type; - this._tag.name = this._tag.type.name; - this._tag.type = null; - } else { - if (!this.addError('Missing or invalid tag name')) { - return false; - } - } - } else { - name = this._tag.name; - if (name.charAt(0) === '[' && name.charAt(name.length - 1) === ']') { - // extract the default value if there is one - // example: @param {string} [somebody=John Doe] description - assign = name.substring(1, name.length - 1).split('='); - if (assign[1]) { - this._tag['default'] = assign[1]; - } - this._tag.name = assign[0]; - - // convert to an optional type - if (this._tag.type && this._tag.type.type !== 'OptionalType') { - this._tag.type = { - type: 'OptionalType', - expression: this._tag.type - }; - } - } - } - } - - return true; - }; - - TagParser.prototype.parseDescription = function parseDescription() { - var description = trim(sliceSource(source, index, this._last)); - if (description) { - if ((/^-\s+/).test(description)) { - description = description.substring(2); - } - if (this._options.unwrap) { - description = description.replace(/^\s*\*+\s*/gm, ''); - } - this._tag.description = description; - } - return true; - }; - - TagParser.prototype.parseKind = function parseKind() { - var kind, kinds; - kinds = { - 'class': true, - 'constant': true, - 'event': true, - 'external': true, - 'file': true, - 'function': true, - 'member': true, - 'mixin': true, - 'module': true, - 'namespace': true, - 'typedef': true - }; - kind = trim(sliceSource(source, index, this._last)); - this._tag.kind = kind; - if (!hasOwnProperty(kinds, kind)) { - if (!this.addError('Invalid kind name \'%0\'', kind)) { - return false; - } - } - return true; - }; - - TagParser.prototype.parseAccess = function parseAccess() { - var access; - access = trim(sliceSource(source, index, this._last)); - this._tag.access = access; - if (access !== 'private' && access !== 'protected' && access !== 'public') { - if (!this.addError('Invalid access name \'%0\'', access)) { - return false; - } - } - return true; - }; - - TagParser.prototype.parseVariation = function parseVariation() { - var variation, text; - text = trim(sliceSource(source, index, this._last)); - variation = parseFloat(text, 10); - this._tag.variation = variation; - if (isNaN(variation)) { - if (!this.addError('Invalid variation \'%0\'', text)) { - return false; - } - } - return true; - }; - - TagParser.prototype.ensureEnd = function () { - var shouldBeEmpty = trim(sliceSource(source, index, this._last)); - if (!shouldBeEmpty.match(/^[\s*]*$/)) { - if (!this.addError('Unknown content \'%0\'', shouldBeEmpty)) { - return false; - } - } - return true; - }; - - TagParser.prototype.epilogue = function epilogue() { - var description; - - description = this._tag.description; - // un-fix potentially sloppy declaration - if (isParamTitle(this._title) && !this._tag.type && description && description.charAt(0) === '[') { - this._tag.type = this._extra.name; - this._tag.name = undefined; - - if (!sloppy) { - if (!this.addError('Missing or invalid tag name')) { - return false; - } - } - } - - return true; - }; - - Rules = { - // http://usejsdoc.org/tags-access.html - 'access': ['parseAccess'], - // http://usejsdoc.org/tags-alias.html - 'alias': ['parseNamePath', 'ensureEnd'], - // http://usejsdoc.org/tags-augments.html - 'augments': ['parseType', 'parseNamePathOptional', 'ensureEnd'], - // http://usejsdoc.org/tags-constructor.html - 'constructor': ['parseType', 'parseNamePathOptional', 'ensureEnd'], - // Synonym: http://usejsdoc.org/tags-constructor.html - 'class': ['parseType', 'parseNamePathOptional', 'ensureEnd'], - // Synonym: http://usejsdoc.org/tags-extends.html - 'extends': ['parseType', 'parseNamePathOptional', 'ensureEnd'], - // http://usejsdoc.org/tags-deprecated.html - 'deprecated': ['parseDescription'], - // http://usejsdoc.org/tags-global.html - 'global': ['ensureEnd'], - // http://usejsdoc.org/tags-inner.html - 'inner': ['ensureEnd'], - // http://usejsdoc.org/tags-instance.html - 'instance': ['ensureEnd'], - // http://usejsdoc.org/tags-kind.html - 'kind': ['parseKind'], - // http://usejsdoc.org/tags-mixes.html - 'mixes': ['parseNamePath', 'ensureEnd'], - // http://usejsdoc.org/tags-mixin.html - 'mixin': ['parseNamePathOptional', 'ensureEnd'], - // http://usejsdoc.org/tags-member.html - 'member': ['parseType', 'parseNamePathOptional', 'ensureEnd'], - // http://usejsdoc.org/tags-method.html - 'method': ['parseNamePathOptional', 'ensureEnd'], - // http://usejsdoc.org/tags-module.html - 'module': ['parseType', 'parseNamePathOptional', 'ensureEnd'], - // Synonym: http://usejsdoc.org/tags-method.html - 'func': ['parseNamePathOptional', 'ensureEnd'], - // Synonym: http://usejsdoc.org/tags-method.html - 'function': ['parseNamePathOptional', 'ensureEnd'], - // Synonym: http://usejsdoc.org/tags-member.html - 'var': ['parseType', 'parseNamePathOptional', 'ensureEnd'], - // http://usejsdoc.org/tags-name.html - 'name': ['parseNamePath', 'ensureEnd'], - // http://usejsdoc.org/tags-namespace.html - 'namespace': ['parseType', 'parseNamePathOptional', 'ensureEnd'], - // http://usejsdoc.org/tags-private.html - 'private': ['parseType', 'parseDescription'], - // http://usejsdoc.org/tags-protected.html - 'protected': ['parseType', 'parseDescription'], - // http://usejsdoc.org/tags-public.html - 'public': ['parseType', 'parseDescription'], - // http://usejsdoc.org/tags-readonly.html - 'readonly': ['ensureEnd'], - // http://usejsdoc.org/tags-requires.html - 'requires': ['parseNamePath', 'ensureEnd'], - // http://usejsdoc.org/tags-since.html - 'since': ['parseDescription'], - // http://usejsdoc.org/tags-static.html - 'static': ['ensureEnd'], - // http://usejsdoc.org/tags-summary.html - 'summary': ['parseDescription'], - // http://usejsdoc.org/tags-this.html - 'this': ['parseNamePath', 'ensureEnd'], - // http://usejsdoc.org/tags-todo.html - 'todo': ['parseDescription'], - // http://usejsdoc.org/tags-variation.html - 'variation': ['parseVariation'], - // http://usejsdoc.org/tags-version.html - 'version': ['parseDescription'] - }; - - TagParser.prototype.parse = function parse() { - var i, iz, sequences, method, - oldLineNumber, oldLineStart, - newLineNumber, newLineStart; - - // empty title - if (!this._title) { - if (!this.addError('Missing or invalid title')) { - return null; - } - } - - // Seek to content last index. - oldLineNumber = lineNumber; - oldLineStart = lineStart; - this._last = seekContent(this._title); - newLineNumber = lineNumber; - newLineStart = lineStart; - lineNumber = oldLineNumber; - lineStart = oldLineStart; - - if (hasOwnProperty(Rules, this._title)) { - sequences = Rules[this._title]; - } else { - // default sequences - sequences = ['parseType', 'parseName', 'parseDescription', 'epilogue']; - } - - for (i = 0, iz = sequences.length; i < iz; ++i) { - method = sequences[i]; - if (!this[method]()) { - return null; - } - } - - // Seek global index to end of this tag. - index = this._last; - lineNumber = newLineNumber; - lineStart = newLineStart; - return this._tag; - }; - - function parseTag(options) { - var title, parser, startLine, startColumn, res; - - // skip to tag - if (!skipToTag()) { - return null; - } - - if (options.lineNumbers) { - startLine = lineNumber; - startColumn = index - lineStart; - } - - // scan title - title = scanTitle(); - - // construct tag parser - parser = new TagParser(options, title); - res = parser.parse(); - - if (options.lineNumbers) { - res.startLine = startLine; - res.startColumn = startColumn; - } - - return res; - } - - // - // Parse JSDoc - // - - function scanJSDocDescription() { - var description = '', ch, atAllowed; - - atAllowed = true; - while (index < length) { - ch = source[index]; - - if (atAllowed && ch === '@') { - break; - } - - if (isLineTerminator(ch)) { - atAllowed = true; - } else if (atAllowed && !isWhiteSpace(ch)) { - atAllowed = false; - } - - description += advance(); - } - return trim(description); - } - - function parse(comment, options) { - var tags = [], tag, description, interestingTags, i, iz; - - if (options === undefined) { - options = {}; - } - - if (typeof options.unwrap === 'boolean' && options.unwrap) { - source = comment.replace(/^\/?\*+/, '').replace(/\*+\/?$/, ''); - } else { - source = comment; - } - - // array of relevant tags - if (options.tags) { - if (isArray(options.tags)) { - interestingTags = { }; - for (i = 0, iz = options.tags.length; i < iz; i++) { - if (typeof options.tags[i] === 'string') { - interestingTags[options.tags[i]] = true; - } else { - throwError('Invalid "tags" parameter: ' + options.tags); - } - } - } else { - throwError('Invalid "tags" parameter: ' + options.tags); - } - } - - if (!CanAccessStringByIndex) { - source = source.split(''); - } - - length = source.length; - index = 0; - lineNumber = 0; - lineStart = 0; - recoverable = options.recoverable; - sloppy = options.sloppy; - strict = options.strict; - - description = scanJSDocDescription(); - - while (true) { - tag = parseTag(options); - if (!tag) { - break; - } - if (!interestingTags || interestingTags.hasOwnProperty(tag.title)) { - tags.push(tag); - } - } - - return { - description: description, - tags: tags - }; - } - exports.parse = parse; - }(jsdoc = {})); - - exports.version = VERSION; - exports.parse = jsdoc.parse; - exports.parseType = typed.parseType; - exports.parseParamType = typed.parseParamType; - exports.unwrapComment = unwrapComment; - exports.Syntax = shallowCopy(typed.Syntax); - exports.Error = DoctrineError; - exports.type = { - Syntax: exports.Syntax, - parseType: typed.parseType, - parseParamType: typed.parseParamType, - stringify: typed.stringify - }; -}(typeof exports === 'undefined' ? (doctrine = {}) : exports)); -/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/javascript/extractor/lib/external/doctrine/eslint.json b/javascript/extractor/lib/external/doctrine/eslint.json deleted file mode 100644 index 330835b9bf7e..000000000000 --- a/javascript/extractor/lib/external/doctrine/eslint.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "env": { - "node": true - }, - "rules": { - "quotes": [2, "single"], - "valid-jsdoc": [2, true], - "brace-style": [2, true], - "semi": [2, true], - "no-bitwise": [2, true], - "camelcase": [2, true], - "curly": [2, true], - "eqeqeq": [2, "allow-null"], - "wrap-iife": [2, true], - "eqeqeq": [2, true], - "strict": [2, true], - "no-unused-vars": [2, true], - "no-underscore-dangle": [0, false], - "no-use-before-define": [0, false], - "no-constant-condition": [0, false] - } -} diff --git a/javascript/extractor/lib/external/doctrine/package.json b/javascript/extractor/lib/external/doctrine/package.json deleted file mode 100644 index a2e633f23221..000000000000 --- a/javascript/extractor/lib/external/doctrine/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "doctrine", - "description": "JSDoc parser", - "homepage": "http://github.com/Constellation/doctrine.html", - "main": "doctrine.js", - "version": "0.5.3-dev", - "engines": { - "node": ">=0.10.0" - }, - "maintainers": [{ - "name": "Yusuke Suzuki", - "email": "utatane.tea@gmail.com", - "web": "http://github.com/Constellation" - }], - "repository": { - "type": "git", - "url": "http://github.com/Constellation/doctrine.git" - }, - "devDependencies": { - "jslint": "~0.1.9", - "eslint": "~0.6.2", - "mocha": "*", - "should": "*" - }, - "licenses": [{ - "type": "BSD", - "url": "http://github.com/Constellation/doctrine/raw/master/LICENSE.BSD" - }], - "scripts": { - "test": "npm run-script lint && npm run-script eslint && ./node_modules/.bin/mocha", - "lint": "node_modules/jslint/bin/jslint.js doctrine.js", - "eslint": "node_modules/eslint/bin/eslint.js -c eslint.json doctrine.js" - } -} diff --git a/javascript/extractor/lib/external/doctrine/test/parse.js b/javascript/extractor/lib/external/doctrine/test/parse.js deleted file mode 100644 index f5e43823a71e..000000000000 --- a/javascript/extractor/lib/external/doctrine/test/parse.js +++ /dev/null @@ -1,1888 +0,0 @@ -/* - Copyright (C) 2013 Yusuke Suzuki - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/*global require describe it*/ -/*jslint node:true */ -'use strict'; - -var doctrine = require('../doctrine'); -require('should'); - -describe('parse', function () { - it('alias', function () { - var res = doctrine.parse('/** @alias */', { unwrap: true }); - res.tags.should.have.length(0); - }); - - it('alias with name', function () { - var res = doctrine.parse('/** @alias aliasName */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'alias'); - res.tags[0].should.have.property('name', 'aliasName'); - }); - - it('alias with namepath', function () { - var res = doctrine.parse('/** @alias aliasName.OK */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'alias'); - res.tags[0].should.have.property('name', 'aliasName.OK'); - }); - - it('const', function () { - var res = doctrine.parse('/** @const */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'const'); - }); - - it('const with name', function () { - var res = doctrine.parse('/** @const constname */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'const'); - res.tags[0].should.have.property('name', 'constname'); - }); - - it('constant with name', function () { - var res = doctrine.parse('/** @constant constname */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'constant'); - res.tags[0].should.have.property('name', 'constname'); - }); - - it('const with type and name', function () { - var res = doctrine.parse('/** @const {String} constname */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'const'); - res.tags[0].should.have.property('name', 'constname'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'String' - }); - }); - - it('constant with type and name', function () { - var res = doctrine.parse('/** @constant {String} constname */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'constant'); - res.tags[0].should.have.property('name', 'constname'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'String' - }); - }); - - it('const multiple', function () { - var res = doctrine.parse("/**@const\n @const*/", { unwrap: true }); - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', 'const'); - res.tags[1].should.have.property('title', 'const'); - }); - - it('const double', function () { - var res = doctrine.parse("/**@const\n @const*/", { unwrap: true }); - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', 'const'); - res.tags[1].should.have.property('title', 'const'); - }); - - it('const triple', function () { - var res = doctrine.parse( - [ - "/**", - " * @const @const", - " * @const @const", - " * @const @const", - " */" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(3); - res.tags[0].should.have.property('title', 'const'); - res.tags[1].should.have.property('title', 'const'); - res.tags[2].should.have.property('title', 'const'); - }); - - it('constructor', function () { - var res = doctrine.parse('/** @constructor */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'constructor'); - }); - - it('constructor with type', function () { - var res = doctrine.parse('/** @constructor {Object} */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'constructor'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'Object' - }); - }); - - it('constructor with type and name', function () { - var res = doctrine.parse('/** @constructor {Object} objName */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'constructor'); - res.tags[0].should.have.property('name', 'objName'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'Object' - }); - }); - - it('class', function () { - var res = doctrine.parse('/** @class */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'class'); - }); - - it('class with type', function () { - var res = doctrine.parse('/** @class {Object} */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'class'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'Object' - }); - }); - - it('class with type and name', function () { - var res = doctrine.parse('/** @class {Object} objName */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'class'); - res.tags[0].should.have.property('name', 'objName'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'Object' - }); - }); - - it('deprecated', function () { - var res = doctrine.parse('/** @deprecated */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'deprecated'); - }); - - it('deprecated', function () { - var res = doctrine.parse('/** @deprecated some text here describing why it is deprecated */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'deprecated'); - res.tags[0].should.have.property('description', 'some text here describing why it is deprecated'); - }); - - it('func', function () { - var res = doctrine.parse('/** @func */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'func'); - }); - - it('func with name', function () { - var res = doctrine.parse('/** @func thingName.func */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'func'); - res.tags[0].should.have.property('name', 'thingName.func'); - }); - - it('func with type', function () { - var res = doctrine.parse('/** @func {Object} thingName.func */', { unwrap: true }); - res.tags.should.have.length(0); - // func does not accept type - }); - - it('function', function () { - var res = doctrine.parse('/** @function */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'function'); - }); - - it('function with name', function () { - var res = doctrine.parse('/** @function thingName.function */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'function'); - res.tags[0].should.have.property('name', 'thingName.function'); - }); - - it('function with type', function () { - var res = doctrine.parse('/** @function {Object} thingName.function */', { unwrap: true }); - res.tags.should.have.length(0); - // function does not accept type - }); - - it('member', function () { - var res = doctrine.parse('/** @member */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'member'); - }); - - it('member with name', function () { - var res = doctrine.parse('/** @member thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'member'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('member with type', function () { - var res = doctrine.parse('/** @member {Object} thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'member'); - res.tags[0].should.have.property('name', 'thingName.name'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'Object' - }); - }); - - it('method', function () { - var res = doctrine.parse('/** @method */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'method'); - }); - - it('method with name', function () { - var res = doctrine.parse('/** @method thingName.function */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'method'); - res.tags[0].should.have.property('name', 'thingName.function'); - }); - - it('method with type', function () { - var res = doctrine.parse('/** @method {Object} thingName.function */', { unwrap: true }); - res.tags.should.have.length(0); - // method does not accept type - }); - - it('mixes', function () { - var res = doctrine.parse('/** @mixes */', { unwrap: true }); - res.tags.should.have.length(0); - }); - - it('mixes with name', function () { - var res = doctrine.parse('/** @mixes thingName */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'mixes'); - res.tags[0].should.have.property('name', 'thingName'); - }); - - it('mixes with namepath', function () { - var res = doctrine.parse('/** @mixes thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'mixes'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('mixin', function () { - var res = doctrine.parse('/** @mixin */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'mixin'); - }); - - it('mixin with name', function () { - var res = doctrine.parse('/** @mixin thingName */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'mixin'); - res.tags[0].should.have.property('name', 'thingName'); - }); - - it('mixin with namepath', function () { - var res = doctrine.parse('/** @mixin thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'mixin'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('module', function () { - var res = doctrine.parse('/** @module */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'module'); - }); - - it('module with name', function () { - var res = doctrine.parse('/** @module thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'module'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('module with type', function () { - var res = doctrine.parse('/** @module {Object} thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'module'); - res.tags[0].should.have.property('name', 'thingName.name'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'Object' - }); - }); - - it('name', function () { - var res = doctrine.parse('/** @name thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'name'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('name', function () { - var res = doctrine.parse('/** @name thingName#name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'name'); - res.tags[0].should.have.property('name', 'thingName#name'); - }); - - it('name', function () { - var res = doctrine.parse('/** @name thingName~name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'name'); - res.tags[0].should.have.property('name', 'thingName~name'); - }); - - it('name', function () { - var res = doctrine.parse('/** @name {thing} thingName.name */', { unwrap: true }); - // name does not accept type - res.tags.should.have.length(0); - }); - - it('namespace', function () { - var res = doctrine.parse('/** @namespace */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'namespace'); - }); - - it('namespace with name', function () { - var res = doctrine.parse('/** @namespace thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'namespace'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('namespace with type', function () { - var res = doctrine.parse('/** @namespace {Object} thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'namespace'); - res.tags[0].should.have.property('name', 'thingName.name'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'Object' - }); - }); - - it('param', function () { - var res = doctrine.parse( - [ - "/**", - " * @param {String} userName", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'userName'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'String' - }); - }); - - it('param with properties', function () { - var res = doctrine.parse( - [ - "/**", - " * @param {String} user.name", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'user.name'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'String' - }); - }); - - it('arg with properties', function () { - var res = doctrine.parse( - [ - "/**", - " * @arg {String} user.name", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'arg'); - res.tags[0].should.have.property('name', 'user.name'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'String' - }); - }); - - it('argument with properties', function () { - var res = doctrine.parse( - [ - "/**", - " * @argument {String} user.name", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'argument'); - res.tags[0].should.have.property('name', 'user.name'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'String' - }); - }); - - it('param typeless', function () { - var res = doctrine.parse( - [ - "/**", - " * @param userName", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.eql({ - title: 'param', - type: null, - name: 'userName', - description: null - }); - - var res = doctrine.parse( - [ - "/**", - " * @param userName Something descriptive", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.eql({ - title: 'param', - type: null, - name: 'userName', - description: 'Something descriptive' - }); - - var res = doctrine.parse( - [ - "/**", - " * @param user.name Something descriptive", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.eql({ - title: 'param', - type: null, - name: 'user.name', - description: 'Something descriptive' - }); - }); - - it('param broken', function () { - var res = doctrine.parse( - [ - "/**", - " * @param {String} userName", - " * @param {String userName", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'userName'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'String' - }); - }); - - it('param record', function () { - var res = doctrine.parse( - [ - "/**", - " * @param {{ok:String}} userName", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'userName'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'RecordType', - fields: [{ - type: 'FieldType', - key: 'ok', - value: { - type: 'NameExpression', - name: 'String' - } - }] - }); - }); - - it('param record broken', function () { - var res = doctrine.parse( - [ - "/**", - " * @param {{ok:String} userName", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.be.empty; - }); - - it('param multiple lines', function () { - var res = doctrine.parse( - [ - "/**", - " * @param {string|", - " * number} userName", - " * }}", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'userName'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'UnionType', - elements: [{ - type: 'NameExpression', - name: 'string' - }, { - type: 'NameExpression', - name: 'number' - }] - }); - }); - - it('param without braces', function () { - var res = doctrine.parse( - [ - "/**", - " * @param string name description", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'string'); - res.tags[0].should.have.property('type', null); - res.tags[0].should.have.property('description', 'name description'); - }); - - it('param w/ hyphen before description', function () { - var res = doctrine.parse( - [ - "/**", - " * @param {string} name - description", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.eql({ - title: 'param', - type: { - type: 'NameExpression', - name: 'string' - }, - name: 'name', - description: 'description' - }); - }); - - it('param w/ hyphen + leading space before description', function () { - var res = doctrine.parse( - [ - "/**", - " * @param {string} name - description", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.eql({ - title: 'param', - type: { - type: 'NameExpression', - name: 'string' - }, - name: 'name', - description: ' description' - }); - }); - - it('description and param separated by blank line', function () { - var res = doctrine.parse( - [ - "/**", - " * Description", - " * blah blah blah", - " *", - " * @param {string} name description", - "*/" - ].join('\n'), { unwrap: true }); - res.description.should.eql('Description\nblah blah blah'); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'name'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'string' - }); - res.tags[0].should.have.property('description', 'description'); - }); - - it('regular block comment instead of jsdoc-style block comment', function () { - var res = doctrine.parse( - [ - "/*", - " * Description", - " * blah blah blah", - "*/" - ].join('\n'), { unwrap: true }); - res.description.should.eql("Description\nblah blah blah"); - }); - - it('augments', function () { - var res = doctrine.parse('/** @augments */', { unwrap: true }); - res.tags.should.have.length(1); - }); - - it('augments with name', function () { - var res = doctrine.parse('/** @augments ClassName */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'augments'); - res.tags[0].should.have.property('name', 'ClassName'); - }); - - it('augments with type', function () { - var res = doctrine.parse('/** @augments {ClassName} */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'augments'); - res.tags[0].should.have.property('type', { - type: 'NameExpression', - name: 'ClassName' - }); - }); - - it('augments with name', function () { - var res = doctrine.parse('/** @augments ClassName.OK */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'augments'); - res.tags[0].should.have.property('name', 'ClassName.OK'); - }); - - it('extends', function () { - var res = doctrine.parse('/** @extends */', { unwrap: true }); - res.tags.should.have.length(1); - }); - - it('extends with name', function () { - var res = doctrine.parse('/** @extends ClassName */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'extends'); - res.tags[0].should.have.property('name', 'ClassName'); - }); - - it('extends with type', function () { - var res = doctrine.parse('/** @extends {ClassName} */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'extends'); - res.tags[0].should.have.property('type', { - type: 'NameExpression', - name: 'ClassName' - }); - }); - - it('extends with namepath', function () { - var res = doctrine.parse('/** @extends ClassName.OK */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'extends'); - res.tags[0].should.have.property('name', 'ClassName.OK'); - }); - - it('prop', function () { - var res = doctrine.parse( - [ - "/**", - " * @prop {string} thingName - does some stuff", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'prop'); - res.tags[0].should.have.property('description', 'does some stuff'); - res.tags[0].type.should.have.property('name', 'string'); - res.tags[0].should.have.property('name', 'thingName'); - }); - - it('prop without type', function () { - var res = doctrine.parse( - [ - "/**", - " * @prop thingName - does some stuff", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(0); - }); - - - it('property', function () { - var res = doctrine.parse( - [ - "/**", - " * @property {string} thingName - does some stuff", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'property'); - res.tags[0].should.have.property('description', 'does some stuff'); - res.tags[0].type.should.have.property('name', 'string'); - res.tags[0].should.have.property('name', 'thingName'); - }); - - it('property without type', function () { - var res = doctrine.parse( - [ - "/**", - " * @property thingName - does some stuff", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(0); - }); - - it('property with nested name', function () { - var res = doctrine.parse( - [ - "/**", - " * @property {string} thingName.name - does some stuff", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'property'); - res.tags[0].should.have.property('description', 'does some stuff'); - res.tags[0].type.should.have.property('name', 'string'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('throws', function () { - var res = doctrine.parse( - [ - "/**", - " * @throws {Error} if something goes wrong", - " */" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'throws'); - res.tags[0].should.have.property('description', 'if something goes wrong'); - res.tags[0].type.should.have.property('name', 'Error'); - }); - - it('throws without type', function () { - var res = doctrine.parse( - [ - "/**", - " * @throws if something goes wrong", - " */" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'throws'); - res.tags[0].should.have.property('description', 'if something goes wrong'); - }); - - it('kind', function () { - var res = doctrine.parse('/** @kind class */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'kind'); - res.tags[0].should.have.property('kind', 'class'); - }); - - it('kind error', function () { - var res = doctrine.parse('/** @kind ng */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Invalid kind name \'ng\''); - }); - - it('todo', function () { - var res = doctrine.parse('/** @todo Write the documentation */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'todo'); - res.tags[0].should.have.property('description', 'Write the documentation'); - }); - - it('summary', function () { - // japanese lang - var res = doctrine.parse('/** @summary ゆるゆり3期おめでとー */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'summary'); - res.tags[0].should.have.property('description', 'ゆるゆり3期おめでとー'); - }); - - it('variation', function () { - // japanese lang - var res = doctrine.parse('/** @variation 42 */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'variation'); - res.tags[0].should.have.property('variation', 42); - }); - - it('variation error', function () { - // japanese lang - var res = doctrine.parse('/** @variation Animation */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Invalid variation \'Animation\''); - }); - - it('access', function () { - var res = doctrine.parse('/** @access public */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'access'); - res.tags[0].should.have.property('access', 'public'); - }); - - it('access error', function () { - var res = doctrine.parse('/** @access ng */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Invalid access name \'ng\''); - }); - - it('public', function () { - var res = doctrine.parse('/** @public */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'public'); - }); - - it('public type and description', function () { - var res = doctrine.parse('/** @public {number} ok */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'public'); - res.tags[0].should.have.property('description', 'ok'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'number' - }); - }); - - it('protected', function () { - var res = doctrine.parse('/** @protected */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'protected'); - }); - - it('protected type and description', function () { - var res = doctrine.parse('/** @protected {number} ok */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'protected'); - res.tags[0].should.have.property('description', 'ok'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'number' - }); - }); - - it('private', function () { - var res = doctrine.parse('/** @private */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'private'); - }); - - it('private type and description', function () { - var res = doctrine.parse('/** @private {number} ok */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'private'); - res.tags[0].should.have.property('description', 'ok'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'number' - }); - }); - - it('readonly', function () { - var res = doctrine.parse('/** @readonly */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'readonly'); - }); - - it('readonly error', function () { - var res = doctrine.parse('/** @readonly ng */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Unknown content \'ng\''); - }); - - it('requires', function () { - var res = doctrine.parse('/** @requires */', { unwrap: true }); - res.tags.should.have.length(0); - }); - - it('requires with module name', function () { - var res = doctrine.parse('/** @requires name.path */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'requires'); - res.tags[0].should.have.property('name', 'name.path'); - }); - - it('global', function () { - var res = doctrine.parse('/** @global */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'global'); - }); - - it('global error', function () { - var res = doctrine.parse('/** @global ng */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Unknown content \'ng\''); - }); - - it('inner', function () { - var res = doctrine.parse('/** @inner */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'inner'); - }); - - it('inner error', function () { - var res = doctrine.parse('/** @inner ng */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Unknown content \'ng\''); - }); - - it('instance', function () { - var res = doctrine.parse('/** @instance */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'instance'); - }); - - it('instance error', function () { - var res = doctrine.parse('/** @instance ng */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Unknown content \'ng\''); - }); - - it('since', function () { - var res = doctrine.parse('/** @since 1.2.1 */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'since'); - res.tags[0].should.have.property('description', '1.2.1'); - }); - - it('static', function () { - var res = doctrine.parse('/** @static */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'static'); - }); - - it('static error', function () { - var res = doctrine.parse('/** @static ng */', { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Unknown content \'ng\''); - }); - - it('this', function () { - var res = doctrine.parse( - [ - "/**", - " * @this thingName", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'this'); - res.tags[0].should.have.property('name', 'thingName'); - }); - - it('this with namepath', function () { - var res = doctrine.parse( - [ - "/**", - " * @this thingName.name", - "*/" - ].join('\n'), { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'this'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('this error', function () { - var res = doctrine.parse( - [ - "/**", - " * @this", - "*/" - ].join('\n'), { unwrap: true, recoverable: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'this'); - res.tags[0].should.have.property('errors'); - res.tags[0].errors.should.have.length(1); - res.tags[0].errors[0].should.equal('Missing or invalid tag name'); - }); - - it('var', function () { - var res = doctrine.parse('/** @var */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'var'); - }); - - it('var with name', function () { - var res = doctrine.parse('/** @var thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'var'); - res.tags[0].should.have.property('name', 'thingName.name'); - }); - - it('var with type', function () { - var res = doctrine.parse('/** @var {Object} thingName.name */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'var'); - res.tags[0].should.have.property('name', 'thingName.name'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - type: 'NameExpression', - name: 'Object' - }); - }); - - it('version', function () { - var res = doctrine.parse('/** @version 1.2.1 */', { unwrap: true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'version'); - res.tags[0].should.have.property('description', '1.2.1'); - }); - -}); - -describe('parseType', function () { - it('union type closure-compiler extended', function () { - var type = doctrine.parseType("string|number"); - type.should.eql({ - type: 'UnionType', - elements: [{ - type: 'NameExpression', - name: 'string' - }, { - type: 'NameExpression', - name: 'number' - }] - }); - }); - - it('empty union type', function () { - var type = doctrine.parseType("()"); - type.should.eql({ - type: 'UnionType', - elements: [] - }); - }); - - it('comma last array type', function () { - var type = doctrine.parseType("[string,]"); - type.should.eql({ - type: 'ArrayType', - elements: [{ - type: 'NameExpression', - name: 'string' - }] - }); - }); - - it('array type of all literal', function () { - var type = doctrine.parseType("[*]"); - type.should.eql({ - type: 'ArrayType', - elements: [{ - type: 'AllLiteral' - }] - }); - }); - - it('array type of nullable literal', function () { - var type = doctrine.parseType("[?]"); - type.should.eql({ - type: 'ArrayType', - elements: [{ - type: 'NullableLiteral' - }] - }); - }); - - it('comma last record type', function () { - var type = doctrine.parseType("{,}"); - type.should.eql({ - type: 'RecordType', - fields: [] - }); - }); - - it('type application', function () { - var type = doctrine.parseType("Array."); - type.should.eql({ - type: 'TypeApplication', - expression: { - type: 'NameExpression', - name: 'Array' - }, - applications: [{ - type: 'NameExpression', - name: 'String' - }] - }); - }); - - it('type application with multiple patterns', function () { - var type = doctrine.parseType("Array."); - type.should.eql({ - type: 'TypeApplication', - expression: { - type: 'NameExpression', - name: 'Array' - }, - applications: [{ - type: 'NameExpression', - name: 'String' - }, { - type: 'NameExpression', - name: 'Number' - }] - }); - }); - - it('type application without dot', function () { - var type = doctrine.parseType("Array"); - type.should.eql({ - type: 'TypeApplication', - expression: { - type: 'NameExpression', - name: 'Array' - }, - applications: [{ - type: 'NameExpression', - name: 'String' - }] - }); - }); - - it('array-style type application', function () { - var type = doctrine.parseType("String[]"); - type.should.eql({ - type: 'TypeApplication', - expression: { - type: 'NameExpression', - name: 'Array' - }, - applications: [{ - type: 'NameExpression', - name: 'String' - }] - }); - }); - - it('function type simple', function () { - var type = doctrine.parseType("function()"); - type.should.eql({ - "type": "FunctionType", - "params": [], - "result": null - }); - }); - - it('function type with name', function () { - var type = doctrine.parseType("function(a)"); - type.should.eql({ - "type": "FunctionType", - "params": [ - { - "type": "NameExpression", - "name": "a" - } - ], - "result": null - }); - }); - it('function type with name and type', function () { - var type = doctrine.parseType("function(a:b)"); - type.should.eql({ - "type": "FunctionType", - "params": [ - { - "type": "ParameterType", - "name": "a", - "expression": { - "type": "NameExpression", - "name": "b" - } - } - ], - "result": null - }); - }); - it('function type with optional param', function () { - var type = doctrine.parseType("function(a=)"); - type.should.eql({ - "type": "FunctionType", - "params": [ - { - "type": "OptionalType", - "expression": { - "type": "NameExpression", - "name": "a" - } - } - ], - "result": null - }); - }); - it('function type with optional param name and type', function () { - var type = doctrine.parseType("function(a:b=)"); - type.should.eql({ - "type": "FunctionType", - "params": [ - { - "type": "OptionalType", - "expression": { - "type": "ParameterType", - "name": "a", - "expression": { - "type": "NameExpression", - "name": "b" - } - } - } - ], - "result": null - }); - }); - it('function type with rest param', function () { - var type = doctrine.parseType("function(...a)"); - type.should.eql({ - "type": "FunctionType", - "params": [ - { - "type": "RestType", - "expression": { - "type": "NameExpression", - "name": "a" - } - } - ], - "result": null - }); - }); - it('function type with rest param name and type', function () { - var type = doctrine.parseType("function(...a:b)"); - type.should.eql({ - "type": "FunctionType", - "params": [ - { - "type": "RestType", - "expression": { - "type": "ParameterType", - "name": "a", - "expression": { - "type": "NameExpression", - "name": "b" - } - } - } - ], - "result": null - }); - }); - - it('function type with optional rest param', function () { - var type = doctrine.parseType("function(...a=)"); - type.should.eql({ - "type": "FunctionType", - "params": [ - { - "type": "RestType", - "expression": { - "type": "OptionalType", - "expression": { - "type": "NameExpression", - "name": "a" - } - } - } - ], - "result": null - }); - }); - it('function type with optional rest param name and type', function () { - var type = doctrine.parseType("function(...a:b=)"); - type.should.eql({ - "type": "FunctionType", - "params": [ - { - "type": "RestType", - "expression": { - "type": "OptionalType", - "expression": { - "type": "ParameterType", - "name": "a", - "expression": { - "type": "NameExpression", - "name": "b" - } - } - } - }], - "result": null - }); - }); -}); - -describe('parseParamType', function () { - it('question', function () { - var type = doctrine.parseParamType("?"); - type.should.eql({ - type: 'NullableLiteral' - }); - }); - - it('question option', function () { - var type = doctrine.parseParamType("?="); - type.should.eql({ - type: 'OptionalType', - expression: { - type: 'NullableLiteral' - } - }); - }); - - it('function option parameters former', function () { - var type = doctrine.parseParamType("function(?, number)"); - type.should.eql({ - type: 'FunctionType', - params: [{ - type: 'NullableLiteral' - }, { - type: 'NameExpression', - name: 'number' - }], - result: null - }); - }); - - it('function option parameters latter', function () { - var type = doctrine.parseParamType("function(number, ?)"); - type.should.eql({ - type: 'FunctionType', - params: [{ - type: 'NameExpression', - name: 'number' - }, { - type: 'NullableLiteral' - }], - result: null - }); - }); - - it('function type union', function () { - var type = doctrine.parseParamType("function(): ?|number"); - type.should.eql({ - type: 'UnionType', - elements: [{ - type: 'FunctionType', - params: [], - result: { - type: 'NullableLiteral' - } - }, { - type: 'NameExpression', - name: 'number' - }] - }); - }); -}); - -describe('invalid', function () { - it('empty union pipe', function () { - doctrine.parseType.bind(doctrine, "(|)").should.throw(); - doctrine.parseType.bind(doctrine, "(string|)").should.throw(); - doctrine.parseType.bind(doctrine, "(string||)").should.throw(); - }); - - it('comma only array type', function () { - doctrine.parseType.bind(doctrine, "[,]").should.throw(); - }); - - it('comma only record type', function () { - doctrine.parseType.bind(doctrine, "{,,}").should.throw(); - }); -}); - -describe('tags option', function() { - it ('only param', function() { - var res = doctrine.parse( - [ - "/**", - " * @const @const", - " * @param {String} y", - " */" - ].join('\n'), { tags: ['param'], unwrap:true }); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'y'); - }); - - it ('param and type', function() { - var res = doctrine.parse( - [ - "/**", - " * @const x", - " * @param {String} y", - " * @type {String} ", - " */" - ].join('\n'), { tags: ['param', 'type'], unwrap:true }); - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('name', 'y'); - res.tags[1].should.have.property('title', 'type'); - res.tags[1].should.have.property('type'); - res.tags[1].type.should.have.property('name', 'String'); - }); - -}); - -describe('invalid tags', function() { - it ('bad tag 1', function() { - doctrine.parse.bind(doctrine, - [ - "/**", - " * @param {String} hucairz", - " */" - ].join('\n'), { tags: 1, unwrap:true }).should.throw(); - }); - - it ('bad tag 2', function() { - doctrine.parse.bind(doctrine, - [ - "/**", - " * @param {String} hucairz", - " */" - ].join('\n'), { tags: ['a', 1], unwrap:true }).should.throw(); - }); -}); - -describe('optional params', function() { - - // should fail since sloppy option not set - it('failure 0', function() { - doctrine.parse( - ["/**", " * @param {String} [val]", " */"].join('\n'), { - unwrap: true - }).should.eql({ - "description": "", - "tags": [] - }); - }); - it('success 1', function() { - doctrine.parse( - ["/**", " * @param {String} [val]", " */"].join('\n'), { - unwrap: true, sloppy: true - }).should.eql({ - "description": "", - "tags": [{ - "title": "param", - "description": null, - "type": { - "type": "OptionalType", - "expression": { - "type": "NameExpression", - "name": "String" - } - }, - "name": "val" - }] - }); - }); - it('success 2', function() { - doctrine.parse( - ["/**", " * @param {String=} val", " */"].join('\n'), { - unwrap: true, sloppy: true - }).should.eql({ - "description": "", - "tags": [{ - "title": "param", - "description": null, - "type": { - "type": "OptionalType", - "expression": { - "type": "NameExpression", - "name": "String" - } - }, - "name": "val" - }] - }); - }); - - it('success 3', function() { - doctrine.parse( - ["/**", " * @param {String=} [val=abc] some description", " */"].join('\n'), - { unwrap: true, sloppy: true} - ).should.eql({ - "description": "", - "tags": [{ - "title": "param", - "description": "some description", - "type": { - "type": "OptionalType", - "expression": { - "type": "NameExpression", - "name": "String" - } - }, - "name": "val", - "default": "abc" - }] - }); - }); - - it('line numbers', function() { - var res = doctrine.parse( - [ - "/**", - " * @param {string} foo", - " * @returns {string}", - " *", - " * @example", - " * f('blah'); // => undefined", - " */" - ].join('\n'), - { unwrap: true, lineNumbers: true } - ); - - res.tags[0].should.have.property('lineNumber', 1); - res.tags[1].should.have.property('lineNumber', 2); - res.tags[2].should.have.property('lineNumber', 4); - }); - - it('should handle \\r\\n line endings correctly', function() { - var res = doctrine.parse( - [ - "/**", - " * @param {string} foo", - " * @returns {string}", - " *", - " * @example", - " * f('blah'); // => undefined", - " */" - ].join('\r\n'), - { unwrap: true, lineNumbers: true } - ); - - res.tags[0].should.have.property('lineNumber', 1); - res.tags[1].should.have.property('lineNumber', 2); - res.tags[2].should.have.property('lineNumber', 4); - }); -}); - -describe('recovery tests', function() { - it ('params 2', function () { - var res = doctrine.parse( - [ - "@param f", - "@param {string} f2" - ].join('\n'), { recoverable: true }); - - // ensure both parameters are OK - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('type', null); - res.tags[0].should.have.property('name', 'f'); - - res.tags[1].should.have.property('title', 'param'); - res.tags[1].should.have.property('type'); - res.tags[1].type.should.have.property('name', 'string'); - res.tags[1].type.should.have.property('type', 'NameExpression'); - res.tags[1].should.have.property('name', 'f2'); - }); - - it ('params 2', function () { - var res = doctrine.parse( - [ - "@param string f", - "@param {string} f2" - ].join('\n'), { recoverable: true }); - - // ensure first parameter is OK even with invalid type name - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('type', null); - res.tags[0].should.have.property('name', 'string'); - res.tags[0].should.have.property('description', 'f'); - - res.tags[1].should.have.property('title', 'param'); - res.tags[1].should.have.property('type'); - res.tags[1].type.should.have.property('name', 'string'); - res.tags[1].type.should.have.property('type', 'NameExpression'); - res.tags[1].should.have.property('name', 'f2'); - }); - - it ('return 1', function() { - var res = doctrine.parse( - [ - "@returns" - ].join('\n'), { recoverable: true }); - - // return tag should exist - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'returns'); - // Since @returns requires type parameter, its type value becomes - // undefined. But property exists. - res.tags[0].should.have.property('type', undefined); - }); - it ('return 2', function() { - var res = doctrine.parse( - [ - "@returns", - "@param {string} f2" - ].join('\n'), { recoverable: true }); - - // return tag should exist as well as next tag - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', 'returns'); - // Since @returns requires type parameter, its type value becomes - // undefined. But property exists. - res.tags[0].should.have.property('type', undefined); - - res.tags[1].should.have.property('title', 'param'); - res.tags[1].should.have.property('type'); - res.tags[1].type.should.have.property('name', 'string'); - res.tags[1].type.should.have.property('type', 'NameExpression'); - res.tags[1].should.have.property('name', 'f2'); - }); - - it ('extra @ 1', function() { - var res = doctrine.parse( - [ - "@", - "@returns", - "@param {string} f2" - ].join('\n'), { recoverable: true }); - - // empty tag name shouldn't affect subsequent tags - res.tags.should.have.length(3); - res.tags[0].should.have.property('title', ''); - res.tags[0].should.not.have.property('type'); - - res.tags[1].should.have.property('title', 'returns'); - // Since @returns requires type parameter, its type value becomes - // undefined. But property exists. - res.tags[1].should.have.property('type', undefined); - - res.tags[2].should.have.property('title', 'param'); - res.tags[2].should.have.property('type'); - res.tags[2].type.should.have.property('name', 'string'); - res.tags[2].type.should.have.property('type', 'NameExpression'); - res.tags[2].should.have.property('name', 'f2'); - }); - - it ('extra @ 2', function() { - var res = doctrine.parse( - [ - "@ invalid name", - "@param {string} f2" - ].join('\n'), { recoverable: true }); - - // empty tag name shouldn't affect subsequent tags - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', ''); - res.tags[0].should.not.have.property('type'); - res.tags[0].should.not.have.property('name'); - res.tags[0].should.have.property('description', 'invalid name'); - - res.tags[1].should.have.property('title', 'param'); - res.tags[1].should.have.property('type'); - res.tags[1].type.should.have.property('name', 'string'); - res.tags[1].type.should.have.property('type', 'NameExpression'); - res.tags[1].should.have.property('name', 'f2'); - }); - - it ('invalid tag 1', function() { - var res = doctrine.parse( - [ - "@111 invalid name", - "@param {string} f2" - ].join('\n'), { recoverable: true }); - - // invalid tag name shouldn't affect subsequent tags - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', '111'); - res.tags[0].should.not.have.property('type'); - res.tags[0].should.not.have.property('name'); - res.tags[0].should.have.property('description', 'invalid name'); - - res.tags[1].should.have.property('title', 'param'); - res.tags[1].should.have.property('type'); - res.tags[1].type.should.have.property('name', 'string'); - res.tags[1].type.should.have.property('type', 'NameExpression'); - res.tags[1].should.have.property('name', 'f2'); - }); - - it ('invalid tag 1', function() { - var res = doctrine.parse( - [ - "@111", - "@param {string} f2" - ].join('\n'), { recoverable: true }); - - // invalid tag name shouldn't affect subsequent tags - res.tags.should.have.length(2); - res.tags[0].should.have.property('title', '111'); - res.tags[0].should.not.have.property('type'); - res.tags[0].should.not.have.property('name'); - res.tags[0].should.have.property('description', null); - - res.tags[1].should.have.property('title', 'param'); - res.tags[1].should.have.property('type'); - res.tags[1].type.should.have.property('name', 'string'); - res.tags[1].type.should.have.property('type', 'NameExpression'); - res.tags[1].should.have.property('name', 'f2'); - }); - - it ('should not crash on bad type in @param without name', function() { - var res = doctrine.parse("@param {Function(DOMNode)}", - { recoverable: true }); - }); - - it ('should not crash on bad type in @param in sloppy mode', function() { - var res = doctrine.parse("@param {int[} [x]", - { sloppy: true }); - }); -}); - -describe('exported Syntax', function() { - it ('members', function () { - doctrine.Syntax.should.eql({ - NullableLiteral: 'NullableLiteral', - AllLiteral: 'AllLiteral', - NullLiteral: 'NullLiteral', - UndefinedLiteral: 'UndefinedLiteral', - VoidLiteral: 'VoidLiteral', - UnionType: 'UnionType', - ArrayType: 'ArrayType', - RecordType: 'RecordType', - FieldType: 'FieldType', - FunctionType: 'FunctionType', - ParameterType: 'ParameterType', - RestType: 'RestType', - NonNullableType: 'NonNullableType', - OptionalType: 'OptionalType', - NullableType: 'NullableType', - NameExpression: 'NameExpression', - TypeApplication: 'TypeApplication' - }); - }); -}); - -describe('@ mark contained descriptions', function () { - it ('comment description #10', function () { - doctrine.parse( - [ - '/**', - ' * Prevents the default action. It is equivalent to', - ' * {@code e.preventDefault()}, but can be used as the callback argument of', - ' * {@link goog.events.listen} without declaring another function.', - ' * @param {!goog.events.Event} e An event.', - ' */' - ].join('\n'), - { unwrap: true, sloppy: true }).should.eql({ - 'description': 'Prevents the default action. It is equivalent to\n{@code e.preventDefault()}, but can be used as the callback argument of\n{@link goog.events.listen} without declaring another function.', - 'tags': [{ - 'title': 'param', - 'description': 'An event.', - 'type': { - 'type': 'NonNullableType', - 'expression': { - 'type': 'NameExpression', - 'name': 'goog.events.Event' - }, - 'prefix': true - }, - 'name': 'e' - }] - }); - }); - - it ('tag description', function () { - doctrine.parse( - [ - '/**', - ' * Prevents the default action. It is equivalent to', - ' * @param {!goog.events.Event} e An event.', - ' * {@code e.preventDefault()}, but can be used as the callback argument of', - ' * {@link goog.events.listen} without declaring another function.', - ' */' - ].join('\n'), - { unwrap: true, sloppy: true }).should.eql({ - 'description': 'Prevents the default action. It is equivalent to', - 'tags': [{ - 'title': 'param', - 'description': 'An event.\n{@code e.preventDefault()}, but can be used as the callback argument of\n{@link goog.events.listen} without declaring another function.', - 'type': { - 'type': 'NonNullableType', - 'expression': { - 'type': 'NameExpression', - 'name': 'goog.events.Event' - }, - 'prefix': true - }, - 'name': 'e' - }] - }); - }); -}); - -describe('function', function () { - it ('recognize "function" type', function () { - var res = doctrine.parse( - [ - "@param {function} foo description", - ].join('\n'), {}); - res.tags.should.have.length(1); - res.tags[0].should.have.property('title', 'param'); - res.tags[0].should.have.property('type'); - res.tags[0].type.should.eql({ - "name": "function", - "type": "NameExpression" - }); - res.tags[0].should.have.property('name', 'foo'); - res.tags[0].should.have.property('description', 'description'); - }); -}); - -/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/javascript/extractor/lib/external/doctrine/test/strict.js b/javascript/extractor/lib/external/doctrine/test/strict.js deleted file mode 100644 index b28a6d2025a5..000000000000 --- a/javascript/extractor/lib/external/doctrine/test/strict.js +++ /dev/null @@ -1,165 +0,0 @@ -/* - Copyright (C) 2014 Yusuke Suzuki - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/*global require describe it*/ -/*jslint node:true */ -'use strict'; - -var doctrine = require('../doctrine'); -require('should'); - -describe('strict parse', function () { - // https://github.com/Constellation/doctrine/issues/21 - it('unbalanced braces', function () { - (function () { - doctrine.parse( - [ - "/**", - " * @param {const", - " */" - ].join('\n'), { unwrap: true, strict: true }); - }).should.throw('Braces are not balanced'); - - (function () { - doctrine.parse( - [ - "/**", - " * @param {const", - " */" - ].join('\n'), { unwrap: true }); - }).should.not.throw(); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @param {string name Param description", - " * @param {int} foo Bar", - " */" - ].join('\n'), { unwrap: true, strict: true }); - }).should.throw('Braces are not balanced'); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @param {string name Param description", - " * @param {int} foo Bar", - " */" - ].join('\n'), { unwrap: true }); - }).should.not.throw(); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @returns {int", - " */" - ].join('\n'), { unwrap: true, strict: true }); - }).should.throw('Braces are not balanced'); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @returns {int", - " */" - ].join('\n'), { unwrap: true }); - }).should.not.throw(); - }); - - // https://github.com/Constellation/doctrine/issues/21 - it('incorrect tag starting with @@', function () { - (function () { - doctrine.parse( - [ - "/**", - " * @@version", - " */" - ].join('\n'), { unwrap: true, strict: true }); - }).should.throw('Missing or invalid title'); - - (function () { - doctrine.parse( - [ - "/**", - " * @@version", - " */" - ].join('\n'), { unwrap: true }); - }).should.not.throw(); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @@param {string} name Param description", - " */" - ].join('\n'), { unwrap: true, strict: true }); - }).should.throw('Missing or invalid title'); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @@param {string} name Param description", - " */" - ].join('\n'), { unwrap: true }); - }).should.not.throw(); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @kind ng", - " */" - ].join('\n'), { unwrap: true, strict: true }); - }).should.throw('Invalid kind name \'ng\''); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @variation Animation", - " */" - ].join('\n'), { unwrap: true, strict: true }); - }).should.throw('Invalid variation \'Animation\''); - - (function () { - doctrine.parse( - [ - "/**", - " * Description", - " * @access ng", - " */" - ].join('\n'), { unwrap: true, strict: true }); - }).should.throw('Invalid access name \'ng\''); - }); -}); diff --git a/javascript/extractor/lib/external/doctrine/test/stringify.js b/javascript/extractor/lib/external/doctrine/test/stringify.js deleted file mode 100644 index 4c37197e1a82..000000000000 --- a/javascript/extractor/lib/external/doctrine/test/stringify.js +++ /dev/null @@ -1,410 +0,0 @@ -/* - Copyright (C) 2013 Yusuke Suzuki - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/*global require describe it*/ -/*jslint node:true */ -'use strict'; - -var doctrine = require('../doctrine'); -var assert = require('assert'); -require('should'); - -// tests for the stringify function. -// ensure that we can parse and then stringify and the results are identical -describe('stringify', function () { - - function testStringify(text) { - it (text, function() { - var result = doctrine.parse("@param {" + text + "} name"); - // console.log("Parse Tree: " + JSON.stringify(result, null, " ")); - var stringed = doctrine.type.stringify(result.tags[0].type, {compact:true}); - stringed.should.equal(text); - }); - } - - // simple - testStringify("String"); - testStringify("*"); - testStringify("null"); - testStringify("undefined"); - testStringify("void"); - //testStringify("?="); // Failing - - // rest - testStringify("...string"); - testStringify("...[string]"); - testStringify("...[[string]]"); - - // optional, nullable, nonnullable - testStringify("string="); - testStringify("?string"); - testStringify("!string"); - testStringify("!string="); - - // type applications - testStringify("Array."); - testStringify("Array."); - - // union types - testStringify("()"); - testStringify("(String|Number)"); - - // Arrays - testStringify("[String]"); - testStringify("[String,Number]"); - testStringify("[(String|Number)]"); - - // Record types - testStringify("{a}"); - testStringify("{a:String}"); - testStringify("{a:String,b}"); - testStringify("{a:String,b:object}"); - testStringify("{a:String,b:foo.bar.baz}"); - testStringify("{a:(String|Number),b,c:Array.}"); - testStringify("...{a:(String|Number),b,c:Array.}"); - testStringify("{a:(String|Number),b,c:Array.}="); - - // fn types - testStringify("function(a)"); - testStringify("function(a):String"); - testStringify("function(a:number):String"); - testStringify("function(a:number,b:Array.<(String|Number|Object)>):String"); - testStringify("function(a:number,callback:function(a:Array.<(String|Number|Object)>):boolean):String"); - testStringify("function(a:(string|number),this:string,new:true):function():number"); - testStringify("function(a:(string|number),this:string,new:true):function(a:function(val):result):number"); -}); - -describe('literals', function() { - it('NullableLiteral', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.NullableLiteral - }).should.equal('?'); - }); - - it('AllLiteral', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.AllLiteral - }).should.equal('*'); - }); - - it('NullLiteral', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.NullLiteral - }).should.equal('null'); - }); - - it('UndefinedLiteral', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.UndefinedLiteral - }).should.equal('undefined'); - }); -}); - -describe('Expression', function () { - it('NameExpression', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.NameExpression, - name: 'this.is.valid' - }).should.equal('this.is.valid'); - - doctrine.type.stringify({ - type: doctrine.Syntax.NameExpression, - name: 'String' - }).should.equal('String'); - }); - - it('ArrayType', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.ArrayType, - elements: [{ - type: doctrine.Syntax.NameExpression, - name: 'String' - }] - }).should.equal('[String]'); - - doctrine.type.stringify({ - type: doctrine.Syntax.ArrayType, - elements: [{ - type: doctrine.Syntax.NameExpression, - name: 'String' - }, { - type: doctrine.Syntax.NameExpression, - name: 'Number' - }] - }).should.equal('[String, Number]'); - - doctrine.type.stringify({ - type: doctrine.Syntax.ArrayType, - elements: [] - }).should.equal('[]'); - }); - - it('RecordType', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.RecordType, - fields: [{ - type: doctrine.Syntax.FieldType, - key: 'name', - value: null - }] - }).should.equal('{name}'); - - doctrine.type.stringify({ - type: doctrine.Syntax.RecordType, - fields: [{ - type: doctrine.Syntax.FieldType, - key: 'name', - value: { - type: doctrine.Syntax.NameExpression, - name: 'String' - } - }] - }).should.equal('{name: String}'); - - doctrine.type.stringify({ - type: doctrine.Syntax.RecordType, - fields: [{ - type: doctrine.Syntax.FieldType, - key: 'string', - value: { - type: doctrine.Syntax.NameExpression, - name: 'String' - } - }, { - type: doctrine.Syntax.FieldType, - key: 'number', - value: { - type: doctrine.Syntax.NameExpression, - name: 'Number' - } - }] - }).should.equal('{string: String, number: Number}'); - - doctrine.type.stringify({ - type: doctrine.Syntax.RecordType, - fields: [] - }).should.equal('{}'); - }); - - it('UnionType', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.UnionType, - elements: [{ - type: doctrine.Syntax.NameExpression, - name: 'String' - }] - }).should.equal('(String)'); - - doctrine.type.stringify({ - type: doctrine.Syntax.UnionType, - elements: [{ - type: doctrine.Syntax.NameExpression, - name: 'String' - }, { - type: doctrine.Syntax.NameExpression, - name: 'Number' - }] - }).should.equal('(String|Number)'); - - doctrine.type.stringify({ - type: doctrine.Syntax.UnionType, - elements: [{ - type: doctrine.Syntax.NameExpression, - name: 'String' - }, { - type: doctrine.Syntax.NameExpression, - name: 'Number' - }] - }, { topLevel: true }).should.equal('String|Number'); - }); - - it('RestType', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.RestType, - expression: { - type: doctrine.Syntax.NameExpression, - name: 'String' - } - }).should.equal('...String'); - }); - - it('NonNullableType', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.NonNullableType, - expression: { - type: doctrine.Syntax.NameExpression, - name: 'String' - }, - prefix: true - }).should.equal('!String'); - - doctrine.type.stringify({ - type: doctrine.Syntax.NonNullableType, - expression: { - type: doctrine.Syntax.NameExpression, - name: 'String' - }, - prefix: false - }).should.equal('String!'); - }); - - it('OptionalType', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.OptionalType, - expression: { - type: doctrine.Syntax.NameExpression, - name: 'String' - } - }).should.equal('String='); - }); - - it('NullableType', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.NullableType, - expression: { - type: doctrine.Syntax.NameExpression, - name: 'String' - }, - prefix: true - }).should.equal('?String'); - - doctrine.type.stringify({ - type: doctrine.Syntax.NullableType, - expression: { - type: doctrine.Syntax.NameExpression, - name: 'String' - }, - prefix: false - }).should.equal('String?'); - }); - - it('TypeApplication', function () { - doctrine.type.stringify({ - type: doctrine.Syntax.TypeApplication, - expression: { - type: doctrine.Syntax.NameExpression, - name: 'Array' - }, - applications: [ - { - type: doctrine.Syntax.NameExpression, - name: 'String' - } - ] - }).should.equal('Array.'); - - doctrine.type.stringify({ - type: doctrine.Syntax.TypeApplication, - expression: { - type: doctrine.Syntax.NameExpression, - name: 'Array' - }, - applications: [ - { - type: doctrine.Syntax.NameExpression, - name: 'String' - }, - { - type: doctrine.Syntax.AllLiteral - } - ] - }).should.equal('Array.'); - }); -}); - -describe('Complex identity', function () { - it('Functions', function () { - var data01 = 'function (): void'; - doctrine.type.stringify( - doctrine.type.parseType(data01) - ).should.equal(data01); - - var data02 = 'function (): String'; - doctrine.type.stringify( - doctrine.type.parseType(data02) - ).should.equal(data02); - - var data03 = 'function (test: string): String'; - doctrine.type.stringify( - doctrine.type.parseType(data03) - ).should.equal(data03); - - var data04 = 'function (this: Date, test: String): String'; - doctrine.type.stringify( - doctrine.type.parseType(data04) - ).should.equal(data04); - - var data05 = 'function (this: Date, a: String, b: Number): String'; - doctrine.type.stringify( - doctrine.type.parseType(data05) - ).should.equal(data05); - - var data06 = 'function (this: Date, a: Array., b: Number): String'; - doctrine.type.stringify( - doctrine.type.parseType(data06) - ).should.equal(data06); - - var data07 = 'function (new: Date, a: Array., b: Number): HashMap.'; - doctrine.type.stringify( - doctrine.type.parseType(data07) - ).should.equal(data07); - - var data08 = 'function (new: Date, a: Array., b: (Number|String|Date)): HashMap.'; - doctrine.type.stringify( - doctrine.type.parseType(data08) - ).should.equal(data08); - - var data09 = 'function (new: Date)'; - doctrine.type.stringify( - doctrine.type.parseType(data09) - ).should.equal(data09); - - var data10 = 'function (this: Date)'; - doctrine.type.stringify( - doctrine.type.parseType(data10) - ).should.equal(data10); - - var data11 = 'function (this: Date, ...list)'; - doctrine.type.stringify( - doctrine.type.parseType(data11) - ).should.equal(data11); - - var data11a = 'function (this: Date, test: String=)'; - doctrine.type.stringify( - doctrine.type.parseType(data11a) - ).should.equal(data11a); - - // raw ... are not supported -// var data12 = 'function (this: Date, ...)'; -// doctrine.type.stringify( -// doctrine.type.parseType(data12) -// ).should.equal(data12); - - var data12a = 'function (this: Date, ?=)'; - doctrine.type.stringify( - doctrine.type.parseType(data12a) - ).should.equal(data12a); - }); -}); - -/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/javascript/extractor/lib/external/doctrine/test/test.html b/javascript/extractor/lib/external/doctrine/test/test.html deleted file mode 100644 index 3784c2e5e4e1..000000000000 --- a/javascript/extractor/lib/external/doctrine/test/test.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - -Doctrine trying - - - - - -
    -
    - -
    -
    -

    Parse Tree

    -
    
    -	

    Stringified

    -
    
    -
    -
    \ No newline at end of file
    diff --git a/javascript/extractor/lib/external/doctrine/test/unwrap.js b/javascript/extractor/lib/external/doctrine/test/unwrap.js
    deleted file mode 100644
    index 649577fef127..000000000000
    --- a/javascript/extractor/lib/external/doctrine/test/unwrap.js
    +++ /dev/null
    @@ -1,57 +0,0 @@
    -/*
    -  Copyright (C) 2012 Yusuke Suzuki 
    -
    -  Redistribution and use in source and binary forms, with or without
    -  modification, are permitted provided that the following conditions are met:
    -
    -    * Redistributions of source code must retain the above copyright
    -      notice, this list of conditions and the following disclaimer.
    -    * Redistributions in binary form must reproduce the above copyright
    -      notice, this list of conditions and the following disclaimer in the
    -      documentation and/or other materials provided with the distribution.
    -
    -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    -  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    -  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    -  ARE DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
    -  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    -  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    -  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    -  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    -  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    -  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    -*/
    -
    -/*jslint node:true */
    -'use strict';
    -
    -var doctrine = require('../doctrine');
    -require('should');
    -
    -describe('unwrapComment', function () {
    -  it('normal', function () {
    -    doctrine.unwrapComment('/**\n * @const\n * @const\n */').should.equal('\n@const\n@const\n');
    -  });
    -
    -  it('single', function () {
    -    doctrine.unwrapComment('/**x*/').should.equal('x');
    -  });
    -
    -  it('more stars', function () {
    -    doctrine.unwrapComment('/***x*/').should.equal('x');
    -    doctrine.unwrapComment('/****x*/').should.equal('*x');
    -  });
    -
    -  it('2 lines', function () {
    -    doctrine.unwrapComment('/**x\n * y\n*/').should.equal('x\ny\n');
    -  });
    -
    -  it('2 lines with space', function () {
    -    doctrine.unwrapComment('/**x\n *    y\n*/').should.equal('x\n   y\n');
    -  });
    -
    -  it('3 lines with blank line', function () {
    -    doctrine.unwrapComment('/**x\n *\n \* y\n*/').should.equal('x\n\ny\n');
    -  });
    -});
    -/* vim: set sw=4 ts=4 et tw=80 : */
    
    From 585347fb5dafd6f78acafbc1320140560d3ee80e Mon Sep 17 00:00:00 2001
    From: Max Schaefer 
    Date: Fri, 9 Nov 2018 09:03:19 +0000
    Subject: [PATCH 47/68] JavaScript: Remove obsolete Rhino interface classes.
    
    ---
     .../com/semmle/js/parser/JSObjectDecoder.java | 196 ------------------
     .../com/semmle/js/parser/ScriptLoader.java    | 152 --------------
     2 files changed, 348 deletions(-)
     delete mode 100644 javascript/extractor/src/com/semmle/js/parser/JSObjectDecoder.java
     delete mode 100644 javascript/extractor/src/com/semmle/js/parser/ScriptLoader.java
    
    diff --git a/javascript/extractor/src/com/semmle/js/parser/JSObjectDecoder.java b/javascript/extractor/src/com/semmle/js/parser/JSObjectDecoder.java
    deleted file mode 100644
    index 269127e363ee..000000000000
    --- a/javascript/extractor/src/com/semmle/js/parser/JSObjectDecoder.java
    +++ /dev/null
    @@ -1,196 +0,0 @@
    -package com.semmle.js.parser;
    -
    -import java.lang.reflect.InvocationTargetException;
    -import java.util.ArrayList;
    -import java.util.List;
    -import java.util.Map;
    -
    -import org.mozilla.javascript.NativeArray;
    -import org.mozilla.javascript.NativeObject;
    -import org.mozilla.javascript.UniqueTag;
    -
    -import com.semmle.js.ast.Position;
    -import com.semmle.js.ast.SourceElement;
    -import com.semmle.js.ast.SourceLocation;
    -import com.semmle.util.exception.CatastrophicError;
    -
    -/**
    - * Decode SpiderMonkey AST objects into their Java equivalents.
    - *
    - * We assume that every AST node has a type property uniquely identifying its
    - * type, which is also the name of the corresponding Java class.
    - *
    - * For each Java class, a list of properties to read from the SpiderMonkey AST object has to be provided.
    - * It is assumed that the Java class has a single constructor which takes exactly those
    - * properties as arguments.
    - */
    -public class JSObjectDecoder {
    -	private final ScriptLoader loader;
    -	private final String source;
    -	private final String pkg;
    -	private final Map, List> spec;
    -
    -	/**
    -	 * Construct a new object decoder.
    -	 *
    -	 * @param source the source code from which the AST was parsed
    -	 * @param loader the Rhino instance to use
    -	 * @param pkg the package in which to look for Java classes
    -	 * @param spec a mapping from Java classes to properties
    -	 */
    -	public JSObjectDecoder(String source, ScriptLoader loader, String pkg, Map, List> spec) {
    -		this.source = source;
    -		this.loader = loader;
    -		this.pkg = pkg;
    -		this.spec = spec;
    -	}
    -
    -	/**
    -	 * Decode a given SpiderMonkey AST object.
    -	 *
    -	 * Any exceptions that occur during conversion are caught and re-thrown as {@link CatastrophicError},
    -	 * except for {@link ClassNotFoundException}s resulting from unsupported AST node types, which are
    -	 * re-thrown as {@link ParseError}s.
    -	 */
    -	@SuppressWarnings("unchecked")
    -	public T decodeObject(NativeObject object) throws ParseError {
    -		String type = (String) loader.readProperty(object, "type");
    -		try {
    -			Class clazz = (Class)Class.forName(pkg + "." + type);
    -			return decodeObject(object, clazz);
    -		} catch (ClassNotFoundException e) {
    -			throw new ParseError("Unexpected node type " + e, decodeLocation(object).getStart());
    -		}
    -	}
    -
    -	/**
    -	 * Decode a given SpiderMonkey AST object as an instance of a given class.
    -	 *
    -	 * Any exceptions that occur during conversion are caught and re-thrown as {@link CatastrophicError},
    -	 * except for {@link ClassNotFoundException}s resulting from unsupported AST node types, which are
    -	 * re-thrown as {@link ParseError}s.
    -	 */
    -	@SuppressWarnings("unchecked")
    -	public  V decodeObject(NativeObject object, Class clazz) throws ParseError {
    -		SourceLocation loc = decodeLocation(object);
    -		Object[] ctorArgs = null;
    -		try {
    -			List props = spec.get(clazz);
    -			if (props == null)
    -				throw new CatastrophicError("Unsupported node type " + clazz.getName());
    -			ctorArgs = new Object[props.size()+1];
    -			ctorArgs[0] = loc;
    -			for (int i=1; i decodeObjects(NativeArray objects) throws ParseError {
    -		List result = new ArrayList(objects.size());
    -		for (Object object : objects) {
    -			if (object == null)
    -				result.add(null);
    -			else
    -				result.add(decodeObject((NativeObject)object));
    -		}
    -		return result;
    -	}
    -
    -	/**
    -	 * Decode an array of SpiderMonkey AST objects as instances of a given class.
    -	 */
    -	public  List decodeObjects(Class clazz, NativeArray objects) throws ParseError {
    -		List result = new ArrayList(objects.size());
    -		for (Object object : objects) {
    -			if (object == null)
    -				result.add(null);
    -			else
    -				result.add(decodeObject((NativeObject)object, clazz));
    -		}
    -		return result;
    -	}
    -
    -	/**
    -	 * Bound x between lo and hi, inclusive.
    -	 */
    -	private int bound(int x, int lo, int hi) {
    -		if (x < lo)
    -			return lo;
    -		if (x > hi)
    -			return hi;
    -		return x;
    -	}
    -
    -	/**
    -	 * Decode a SpiderMonkey location object into a {@link SourceLocation}.
    -	 */
    -	public SourceLocation decodeLocation(NativeObject object) {
    -		Integer startOffset, endOffset;
    -		Position start, end;
    -		Object loc = loader.readProperty(object, "loc");
    -
    -		if (loc == null) {
    -			// no 'loc' property; check whether we have 'range'
    -			Object range = loader.readProperty(object, "range");
    -			if (range instanceof NativeArray) {
    -				// good; make up a source location on line 0
    -				startOffset = loader.readIntProperty(range, 0);
    -				endOffset = loader.readIntProperty(range, 1);
    -				start = new Position(1, startOffset, startOffset);
    -				end = new Position(1, endOffset, endOffset);
    -				return new SourceLocation(getSource(startOffset, endOffset), start, end);
    -			}
    -			return null;
    -		}
    -
    -		startOffset = loader.readIntProperty(object, "start");
    -		endOffset = loader.readIntProperty(object, "end");
    -		start = decodePosition((NativeObject)loader.readProperty(loc, "start"), startOffset);
    -		end = decodePosition((NativeObject)loader.readProperty(loc, "end"), endOffset);
    -		return new SourceLocation(getSource(startOffset, endOffset), start, end);
    -	}
    -
    -	/**
    -	 * Extract the source code between a given start and end offset.
    -	 */
    -	public String getSource(Integer startOffset, Integer endOffset) {
    -		if (startOffset == null || endOffset == null || startOffset > endOffset)
    -			return "";
    -		return source.substring(bound(startOffset, 0, source.length()), bound(endOffset, 0, source.length()));
    -	}
    -
    -	/**
    -	 * Decode a SpiderMonkey position object into a {@link SourceLocation}.
    -	 */
    -	private Position decodePosition(NativeObject object, int offset) {
    -		return new Position(loader.readIntProperty(object, "line"), loader.readIntProperty(object, "column"), offset);
    -	}
    -}
    diff --git a/javascript/extractor/src/com/semmle/js/parser/ScriptLoader.java b/javascript/extractor/src/com/semmle/js/parser/ScriptLoader.java
    deleted file mode 100644
    index f7ae305f21c9..000000000000
    --- a/javascript/extractor/src/com/semmle/js/parser/ScriptLoader.java
    +++ /dev/null
    @@ -1,152 +0,0 @@
    -package com.semmle.js.parser;
    -
    -import java.io.IOException;
    -import java.io.InputStream;
    -import java.io.InputStreamReader;
    -import java.net.URL;
    -
    -import org.mozilla.javascript.Context;
    -import org.mozilla.javascript.Function;
    -import org.mozilla.javascript.NativeArray;
    -import org.mozilla.javascript.NativeJSON;
    -import org.mozilla.javascript.NativeObject;
    -import org.mozilla.javascript.ScriptableObject;
    -import org.mozilla.javascript.Undefined;
    -import org.mozilla.javascript.UniqueTag;
    -
    -import com.semmle.util.exception.CatastrophicError;
    -import com.semmle.util.files.FileUtil;
    -
    -/**
    - * Helper class for executing JavaScript programs through Rhino and reading out values from the
    - * resulting environment.
    - */
    -public class ScriptLoader {
    -	private final Context cx;
    -	private final ScriptableObject scope;
    -	
    -	public ScriptLoader(String scriptPath) {
    -		InputStreamReader inputStreamReader = null;
    -
    -		this.cx = Context.enter();
    -		this.scope = cx.initStandardObjects();
    -		try {
    -			URL script = ScriptLoader.class.getResource(scriptPath);
    -			if (script == null)
    -				throw new IOException();
    -			InputStream scriptStream = script.openStream();
    -			inputStreamReader = new InputStreamReader(scriptStream, FileUtil.UTF8);
    -			cx.evaluateReader(scope, inputStreamReader, scriptPath, 1, null);
    -		} catch (IOException e) {
    -			throw new CatastrophicError("Could not load script " + scriptPath + ".", e);
    -		} finally {
    -			if (inputStreamReader != null)
    -				FileUtil.close(inputStreamReader);
    -		}
    -	}
    -
    -	/**
    -	 * Read a global variable.
    -	 */
    -	public Object readGlobal(String name) {
    -		return scope.get(name, scope);
    -	}
    -
    -	/**
    -	 * Read an object property; the property name may be a path of several individual
    -	 * names separated by dots.
    -	 *
    -	 * @return The value of the property, or {@literal null} if it could not be found.
    -	 */
    -	public Object readProperty(Object obj, String prop) {
    -		Object res = obj;
    -		for (String p : prop.split("\\."))
    -			res = ScriptableObject.getProperty((ScriptableObject)res, p);
    -		if (res == UniqueTag.NOT_FOUND)
    -			return null;
    -		return res;
    -	}
    -
    -	/**
    -	 * Read an array element.
    -	 *
    -	 * @return The value of the element, or {@literal null} if it could not be found.
    -	 */
    -	public Object readProperty(Object obj, int idx) {
    -		Object res = ((ScriptableObject)obj).get(idx, scope);
    -		if (res == UniqueTag.NOT_FOUND)
    -			return null;
    -		return res;
    -	}
    -
    -	/**
    -	 * Read an object property and return its value cast to an integer.
    -	 */
    -	public Integer readIntProperty(Object obj, String prop) {
    -		Object res = readProperty(obj, prop);
    -		if (res == null || res == Undefined.instance)
    -			return null;
    -		return ((Number)res).intValue();
    -	}
    -
    -	/**
    -	 * Read an array element and return its value cast to an integer.
    -	 */
    -	public Integer readIntProperty(Object obj, int idx) {
    -		Object res = readProperty(obj, idx);
    -		if (res == null || res == Undefined.instance)
    -			return null;
    -		return ((Number)res).intValue();
    -	}
    -
    -	/**
    -	 * Read an object property and return its value cast to a string.
    -	 */
    -	public String readStringProperty(Object obj, String prop) {
    -		Object val = readProperty(obj, prop);
    -		if (val == null || val == Undefined.instance)
    -			return null;
    -		return String.valueOf(val);
    -	}
    -
    -	/**
    -	 * Create an empty JavaScript array.
    -	 */
    -	public NativeArray mkArray() {
    -		return (NativeArray)cx.newArray(scope, 0);
    -	}
    -
    -	/**
    -	 * Create a JavaScript object.
    -	 *
    -	 * @param properties a list of alternating keys and values to populate the object with
    -	 */
    -	public NativeObject mkObject(Object... properties) {
    -		NativeObject obj = new NativeObject();
    -		for (int i=0; i+1
    Date: Fri, 9 Nov 2018 09:01:23 +0000
    Subject: [PATCH 48/68] JavaScript: Update `.classpath`.
    
    ---
     javascript/extractor/.classpath | 2 --
     1 file changed, 2 deletions(-)
    
    diff --git a/javascript/extractor/.classpath b/javascript/extractor/.classpath
    index e4c64231cf4b..56b8d2597587 100644
    --- a/javascript/extractor/.classpath
    +++ b/javascript/extractor/.classpath
    @@ -1,8 +1,6 @@
     
     
     	
    -	
    -	
     	
     	
     	
    
    From 6312f31f59cc45e07d5502612b9b146ba5dab6a4 Mon Sep 17 00:00:00 2001
    From: Felicity Chapman 
    Date: Wed, 14 Nov 2018 22:08:53 +0000
    Subject: [PATCH 49/68] Remove the duplicate overview tag
    
    ---
     cpp/ql/src/Critical/OverflowCalculated.qhelp | 3 +--
     1 file changed, 1 insertion(+), 2 deletions(-)
    
    diff --git a/cpp/ql/src/Critical/OverflowCalculated.qhelp b/cpp/ql/src/Critical/OverflowCalculated.qhelp
    index a26d28b5dce9..bc5421e6e69c 100644
    --- a/cpp/ql/src/Critical/OverflowCalculated.qhelp
    +++ b/cpp/ql/src/Critical/OverflowCalculated.qhelp
    @@ -13,7 +13,6 @@ zero terminator into consideration.
     
  • strcat or strncat that use buffers that are too small to contain the new string.
  • -

    The highlighted expression will cause a buffer overflow because the buffer is too small to contain @@ -22,8 +21,8 @@ if the array is on stack-allocated memory).

    - +

    Increase the size of the buffer being allocated. From fbf5a052ed68015f052798f088bbffe4c9682ff4 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Thu, 15 Nov 2018 07:09:11 +0000 Subject: [PATCH 50/68] Remove stray

    tag --- cpp/ql/src/Critical/OverflowCalculated.qhelp | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/ql/src/Critical/OverflowCalculated.qhelp b/cpp/ql/src/Critical/OverflowCalculated.qhelp index bc5421e6e69c..dca9d6daeb69 100644 --- a/cpp/ql/src/Critical/OverflowCalculated.qhelp +++ b/cpp/ql/src/Critical/OverflowCalculated.qhelp @@ -12,7 +12,6 @@ This query finds calls to:

    zero terminator into consideration.
  • strcat or strncat that use buffers that are too small to contain the new string.
  • -

    The highlighted expression will cause a buffer overflow because the buffer is too small to contain From 1776ebd991fc7346c311366154528ba5d6dc9c29 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Thu, 15 Nov 2018 08:14:08 +0000 Subject: [PATCH 51/68] Fix typo in code tag --- cpp/ql/src/Critical/OverflowCalculated.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Critical/OverflowCalculated.qhelp b/cpp/ql/src/Critical/OverflowCalculated.qhelp index dca9d6daeb69..50ad526503bf 100644 --- a/cpp/ql/src/Critical/OverflowCalculated.qhelp +++ b/cpp/ql/src/Critical/OverflowCalculated.qhelp @@ -32,7 +32,7 @@ Increase the size of the buffer being allocated.

    This example includes three annotated calls that copy a string into a buffer. The first call to malloc creates a buffer that's the same size as the string, leaving no space for the zero terminator -and causing an overflow. The second call to malloc +and causing an overflow. The second call to malloc correctly calculates the required buffer size. The call to strcat appends an additional string to the same buffer causing a second overflow.

    From 03b8ed6597a2dcf002f6a1e05aae1f3d2a1c59f0 Mon Sep 17 00:00:00 2001 From: calum Date: Thu, 15 Nov 2018 10:49:16 +0000 Subject: [PATCH 52/68] C#: Fix indentation in change notes. --- change-notes/1.19/analysis-csharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.19/analysis-csharp.md b/change-notes/1.19/analysis-csharp.md index 86dc2d786fab..7f0767b7f4e9 100644 --- a/change-notes/1.19/analysis-csharp.md +++ b/change-notes/1.19/analysis-csharp.md @@ -3,7 +3,7 @@ ## General improvements * Control flow graph improvements: -* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead. + * The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead. * Code that is only reachable from a constant failing assertion, such as `Debug.Assert(false)`, is considered to be unreachable. ## New queries From bb49fe170ba8dc7df03467d2055955fc5b52813b Mon Sep 17 00:00:00 2001 From: calum Date: Wed, 31 Oct 2018 13:42:46 +0000 Subject: [PATCH 53/68] C# extractor: Handle the type name of `dynamic`. --- .../Entities/Expressions/Name.cs | 1 + .../ql/test/library-tests/regressions/Program.cs | 15 +++++++++++++++ .../regressions/TypeMentions.expected | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs index c76753789adf..6225a29351ba 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs @@ -43,6 +43,7 @@ public static Expression Create(ExpressionNodeInfo info) { case SymbolKind.TypeParameter: case SymbolKind.NamedType: + case SymbolKind.DynamicType: return TypeAccess.Create(info); case SymbolKind.Property: diff --git a/csharp/ql/test/library-tests/regressions/Program.cs b/csharp/ql/test/library-tests/regressions/Program.cs index 5723fb7593d7..a9d440852c3e 100644 --- a/csharp/ql/test/library-tests/regressions/Program.cs +++ b/csharp/ql/test/library-tests/regressions/Program.cs @@ -119,3 +119,18 @@ void F() new Point { x=1, y=2 }; } } + +class DynamicType +{ + void F() + { + dynamic t = (dynamic)null; + } +} + +class LocalVariableTags +{ + Func F = x => { int y=x; return y; }; +} + +// semmle-extractor-options: /r:System.Dynamic.Runtime.dll diff --git a/csharp/ql/test/library-tests/regressions/TypeMentions.expected b/csharp/ql/test/library-tests/regressions/TypeMentions.expected index 353c9156fdb5..59911eae3f2e 100644 --- a/csharp/ql/test/library-tests/regressions/TypeMentions.expected +++ b/csharp/ql/test/library-tests/regressions/TypeMentions.expected @@ -52,3 +52,10 @@ | Program.cs:114:16:114:19 | Nullable | | Program.cs:117:5:117:8 | Void | | Program.cs:119:13:119:17 | Point | +| Program.cs:125:5:125:8 | Void | +| Program.cs:127:9:127:15 | dynamic | +| Program.cs:127:22:127:28 | dynamic | +| Program.cs:133:5:133:8 | Func | +| Program.cs:133:10:133:12 | Int32 | +| Program.cs:133:15:133:17 | Int32 | +| Program.cs:133:31:133:33 | Int32 | From 090e896ff582ff1acb6d359fc3a6a0e4401b3da9 Mon Sep 17 00:00:00 2001 From: calum Date: Thu, 15 Nov 2018 18:25:48 +0000 Subject: [PATCH 54/68] C#: Change Property TagStackBehaviour to push a tag, to give the expression body a tag stack. --- .../extractor/Semmle.Extraction.CSharp/Entities/Property.cs | 2 +- csharp/ql/test/library-tests/regressions/Program.cs | 6 ++++++ .../ql/test/library-tests/regressions/TypeMentions.expected | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index 7b26e21be457..a75fc809d727 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -114,6 +114,6 @@ class PropertyFactory : ICachedEntityFactory public Property Create(Context cx, IPropertySymbol init) => new Property(cx, init); } - public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.PushesLabel; } } diff --git a/csharp/ql/test/library-tests/regressions/Program.cs b/csharp/ql/test/library-tests/regressions/Program.cs index a9d440852c3e..576910ac8f27 100644 --- a/csharp/ql/test/library-tests/regressions/Program.cs +++ b/csharp/ql/test/library-tests/regressions/Program.cs @@ -131,6 +131,12 @@ void F() class LocalVariableTags { Func F = x => { int y=x; return y; }; + + private static Func _getter => (o, n) => + { + object x = o; + return x; + }; } // semmle-extractor-options: /r:System.Dynamic.Runtime.dll diff --git a/csharp/ql/test/library-tests/regressions/TypeMentions.expected b/csharp/ql/test/library-tests/regressions/TypeMentions.expected index 59911eae3f2e..b3c3f6b4b6fd 100644 --- a/csharp/ql/test/library-tests/regressions/TypeMentions.expected +++ b/csharp/ql/test/library-tests/regressions/TypeMentions.expected @@ -59,3 +59,8 @@ | Program.cs:133:10:133:12 | Int32 | | Program.cs:133:15:133:17 | Int32 | | Program.cs:133:31:133:33 | Int32 | +| Program.cs:135:20:135:23 | Func | +| Program.cs:135:25:135:30 | Object | +| Program.cs:135:33:135:38 | String | +| Program.cs:135:41:135:46 | Object | +| Program.cs:137:10:137:15 | Object | From 9eed758642ea14f464cff5c3691e623881995c68 Mon Sep 17 00:00:00 2001 From: calum Date: Wed, 31 Oct 2018 14:07:41 +0000 Subject: [PATCH 55/68] C#: Update change notes. --- change-notes/1.19/analysis-csharp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.19/analysis-csharp.md b/change-notes/1.19/analysis-csharp.md index 86dc2d786fab..ee30e5c8b370 100644 --- a/change-notes/1.19/analysis-csharp.md +++ b/change-notes/1.19/analysis-csharp.md @@ -23,6 +23,7 @@ ## Changes to code extraction * Arguments passed using `in` are now extracted. +* Fix a bug where the `dynamic` type name was not extracted correctly in certain circumstances. ## Changes to QL libraries From b5d3dd5e22e20ccf9d114fa67da9a70533c114c6 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Nov 2018 14:59:37 +0000 Subject: [PATCH 56/68] TS: do more work in parallel --- .../extractor/lib/typescript/src/main.ts | 62 +++++++++++++++++-- .../com/semmle/js/extractor/AutoBuild.java | 30 +++++++-- .../src/com/semmle/js/extractor/Main.java | 35 ++++++++--- .../semmle/js/parser/TypeScriptParser.java | 19 ++++++ 4 files changed, 129 insertions(+), 17 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index c9eaf632635f..2c03ab58670b 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -67,13 +67,24 @@ interface ResetCommand { interface QuitCommand { command: "quit"; } +interface PrepareFilesCommand { + command: "prepare-files"; + filenames: string[]; +} type Command = ParseCommand | OpenProjectCommand | CloseProjectCommand - | GetTypeTableCommand | ResetCommand | QuitCommand; + | GetTypeTableCommand | ResetCommand | QuitCommand | PrepareFilesCommand; /** The state to be shared between commands. */ class State { public project: Project = null; public typeTable = new TypeTable(); + + /** List of files that have been requested. */ + public pendingFiles: string[] = []; + public pendingFileIndex = 0; + + /** Next response to be delivered. */ + public pendingResponse: string = null; } let state = new State(); @@ -154,16 +165,43 @@ function getSourceCode(filename: string): string { return code; } -function handleParseCommand(command: ParseCommand) { - let filename = String(command.filename); +function extractFile(filename: string): string { let {ast, code} = getAstForFile(filename); // Get the AST and augment it. ast_extractor.augmentAst(ast, code, state.project); - console.log(stringifyAST( - { type: "ast", ast, nodeFlags: ts.NodeFlags, syntaxKinds: ts.SyntaxKind }, - )); + return stringifyAST({ + type: "ast", + ast, + nodeFlags: ts.NodeFlags, + syntaxKinds: ts.SyntaxKind + }); +} + +function prepareNextFile() { + if (state.pendingResponse != null) return; + if (state.pendingFileIndex < state.pendingFiles.length) { + let nextFilename = state.pendingFiles[state.pendingFileIndex]; + state.pendingResponse = extractFile(nextFilename); + } +} + +function handleParseCommand(command: ParseCommand) { + let filename = command.filename; + let expectedFilename = state.pendingFiles[state.pendingFileIndex]; + if (expectedFilename !== filename) { + throw new Error("File requested out of order. Expected '" + expectedFilename + "' but got '" + filename + "'"); + } + ++state.pendingFileIndex; + let response = state.pendingResponse || extractFile(command.filename); + state.pendingResponse = null; + process.stdout.write(response + "\n", () => { + // Start working on the next file as soon as the old one is flushed. + // Note that if we didn't wait for flushing, this would block the I/O + // loop and delay flushing. + prepareNextFile(); + }); } /** @@ -360,6 +398,15 @@ function handleResetCommand(command: ResetCommand) { })); } +function handlePrepareFilesCommand(command: PrepareFilesCommand) { + state.pendingFiles = command.filenames; + state.pendingFileIndex = 0; + state.pendingResponse = null; + process.stdout.write('{"type":"ok"}\n', () => { + prepareNextFile(); + }); +} + function reset() { state = new State(); state.typeTable.restrictedExpansion = getEnvironmentVariable("SEMMLE_TYPESCRIPT_NO_EXPANSION", Boolean, false); @@ -400,6 +447,9 @@ function runReadLineInterface() { case "get-type-table": handleGetTypeTableCommand(req); break; + case "prepare-files": + handlePrepareFilesCommand(req); + break; case "reset": handleResetCommand(req); break; diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 6d72d7fab0a5..cebf15021fe8 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -494,14 +494,19 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th logEndProcess(); // Extract all files belonging to this project which are also matched // by our include/exclude filters. + List typeScriptFiles = new ArrayList(); for (File sourceFile : project.getSourceFiles()) { Path sourcePath = sourceFile.toPath(); if (!filesToExtract.contains(normalizePath(sourcePath))) continue; if (extractedFiles.add(sourcePath)) { - extract(extractor, sourcePath); + typeScriptFiles.add(sourcePath.toFile()); } } + tsParser.prepareFiles(typeScriptFiles); + for (File file : typeScriptFiles) { + extract(extractor, file.toPath()); + } tsParser.closeProject(projectFile); } @@ -509,12 +514,29 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th // Extract all the types discovered when extracting the ASTs. TypeTable typeTable = tsParser.getTypeTable(); extractTypeTable(tsconfigFiles.iterator().next(), typeTable); + } - // The TypeScript compiler instance is no longer needed. - tsParser.killProcess(); + // Extract remaining TypeScript files. + List remainingTypeScriptFiles = new ArrayList(); + for (Path f : filesToExtract) { + if (!extractedFiles.contains(f) && FileType.forFileExtension(f.toFile()) == FileType.TYPESCRIPT) { + remainingTypeScriptFiles.add(f.toFile()); + } } + if (!remainingTypeScriptFiles.isEmpty()) { + tsParser.prepareFiles(remainingTypeScriptFiles); + for (File f : remainingTypeScriptFiles) { + Path path = f.toPath(); + if (extractedFiles.add(path)) { + extract(extractor, path); + } + } + } + + // The TypeScript compiler instance is no longer needed. + tsParser.killProcess(); - // Extract files that were not part of a project. + // Extract non-TypeScript files for (Path f : filesToExtract) { if (extractedFiles.add(f)) { extract(extractor, f); diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index bca6014f66cb..892fc270353e 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -2,7 +2,9 @@ import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import java.util.regex.Pattern; @@ -140,16 +142,22 @@ public void run(String[] args) { tsParser.verifyInstallation(!ap.has(P_QUIET)); } for (File projectFile : projectFiles) { + long start = verboseLogStartTimer(ap, "Opening project " + projectFile); ParsedProject project = tsParser.openProject(projectFile); verboseLogEndTimer(ap, start); // Extract all files belonging to this project which are also matched // by our include/exclude filters. + List filesToExtract = new ArrayList<>(); for (File sourceFile : project.getSourceFiles()) { - if (files.contains(normalizeFile(sourceFile))) { - ensureFileIsExtracted(sourceFile, ap); + if (files.contains(normalizeFile(sourceFile)) && !extractedFiles.contains(sourceFile.getAbsoluteFile())) { + filesToExtract.add(sourceFile); } } + tsParser.prepareFiles(filesToExtract); + for (int i = 0; i < filesToExtract.size(); ++i) { + ensureFileIsExtracted(filesToExtract.get(i), ap); + } // Close the project to free memory. This does not need to be in a `finally` as // the project is not a system resource. tsParser.closeProject(projectFile); @@ -159,14 +167,27 @@ public void run(String[] args) { // Extract all the types discovered when extracting the ASTs. TypeTable typeTable = tsParser.getTypeTable(); extractTypeTable(projectFiles.iterator().next(), typeTable); + } - // The TypeScript compiler instance is no longer needed - free up some memory. - if (hasSharedExtractorState) { - tsParser.reset(); // This is called from a test runner, so keep the process alive. - } else { - tsParser.killProcess(); + List remainingTypescriptFiles = new ArrayList<>(); + for (File f : files) { + if (!extractedFiles.contains(f.getAbsoluteFile()) && FileType.forFileExtension(f) == FileType.TYPESCRIPT) { + remainingTypescriptFiles.add(f); } } + if (!remainingTypescriptFiles.isEmpty()) { + tsParser.prepareFiles(remainingTypescriptFiles); + for (File f : remainingTypescriptFiles) { + ensureFileIsExtracted(f, ap); + } + } + + // The TypeScript compiler instance is no longer needed - free up some memory. + if (hasSharedExtractorState) { + tsParser.reset(); // This is called from a test runner, so keep the process alive. + } else { + tsParser.killProcess(); + } // Extract files that were not part of a project. for (File f : files) { diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index 186b1804d4e5..bc956b34def6 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -292,6 +292,25 @@ public Result parse(File sourceFile, String source) { } } + /** + * Informs the parser process that the following files are going to be + * requested, in that order. + *

    + * The parser process uses this list to start work on the next file before it is + * requested. + */ + public void prepareFiles(List files) { + JsonObject request = new JsonObject(); + request.add("command", new JsonPrimitive("prepare-files")); + JsonArray filenames = new JsonArray(); + for (File file : files) { + filenames.add(new JsonPrimitive(file.getAbsolutePath())); + } + request.add("filenames", filenames); + JsonObject response = talkToParserWrapper(request); + checkResponseType(response, "ok"); + } + /** * Opens a new project based on a tsconfig.json file. The compiler will analyze * all files in the project. From 6ec13feab4f68cf8f25eb54f3ec295d5c819a9cc Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 8 Nov 2018 11:02:46 +0000 Subject: [PATCH 57/68] JS: recognize sanitizing slashes in URL redirection queries --- .../dataflow/ServerSideUrlRedirect.qll | 42 +------------------ .../security/dataflow/UrlConcatenation.qll | 20 ++++++--- .../ServerSideUrlRedirect.expected | 40 +++++++++++------- .../CWE-601/ServerSideUrlRedirect/express.js | 12 ++++++ 4 files changed, 52 insertions(+), 62 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll index dcf3f0a81ca0..ceed93bcfaf9 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll @@ -16,46 +16,8 @@ module ServerSideUrlRedirect { /** * A data flow sink for unvalidated URL redirect vulnerabilities. */ - abstract class Sink extends DataFlow::Node { - /** - * Holds if this sink may redirect to a non-local URL. - */ - predicate maybeNonLocal() { - exists (DataFlow::Node prefix | prefix = getAPrefix(this) | - not exists(prefix.asExpr().getStringValue()) - or - exists (string prefixVal | prefixVal = prefix.asExpr().getStringValue() | - // local URLs (i.e., URLs that start with `/` not followed by `\` or `/`, - // or that start with `~/`) are unproblematic - not prefixVal.regexpMatch("/[^\\\\/].*|~/.*") and - // so are localhost URLs - not prefixVal.regexpMatch("(\\w+:)?//localhost[:/].*") - ) - ) - } - } + abstract class Sink extends DataFlow::Node { } - /** - * Gets a node that is transitively reachable from `nd` along prefix predecessor edges. - */ - private DataFlow::Node prefixCandidate(Sink sink) { - result = sink or - result = prefixCandidate(sink).getAPredecessor() or - result = StringConcatenation::getFirstOperand(prefixCandidate(sink)) - } - - /** - * Gets an expression that may end up being a prefix of the string concatenation `nd`. - */ - private DataFlow::Node getAPrefix(Sink sink) { - exists (DataFlow::Node prefix | - prefix = prefixCandidate(sink) and - not exists(StringConcatenation::getFirstOperand(prefix)) and - not exists(prefix.getAPredecessor()) and - result = prefix - ) - } - /** * A sanitizer for unvalidated URL redirect vulnerabilities. */ @@ -72,7 +34,7 @@ module ServerSideUrlRedirect { } override predicate isSink(DataFlow::Node sink) { - sink.(Sink).maybeNonLocal() + sink instanceof Sink } override predicate isSanitizer(DataFlow::Node node) { diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll index 5d12531128ab..eadb60b37639 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll @@ -7,11 +7,19 @@ import javascript /** - * Holds if a string value containing `?` or `#` may flow into - * `nd` or one of its operands, assuming that it is a concatenation. + * Holds if the string value of `nd` prevents anything appended after it + * from affecting the hostname of a URL. + * + * Specifically, this holds if the string contains any of the following: + * - `?` (any suffix becomes part of query) + * - `#` (any suffix becomes part of fragment) + * - `/` or `\`, immediately prefixed by a character other than `:`, `/`, or `\` (any suffix becomes part of the path) + * + * In the latter case, the additional prefix check is necessary to avoid a `/` that could be interpreted as + * the `//` separating the (optional) scheme from the hostname. */ -private predicate hasSanitizingSubstring(DataFlow::Node nd) { - nd.asExpr().getStringValue().regexpMatch(".*[?#].*") +predicate hasSanitizingSubstring(DataFlow::Node nd) { + nd.asExpr().getStringValue().regexpMatch(".*([?#]|[^?#:/\\\\][/\\\\]).*") or hasSanitizingSubstring(StringConcatenation::getAnOperand(nd)) or @@ -21,8 +29,8 @@ private predicate hasSanitizingSubstring(DataFlow::Node nd) { } /** - * Holds if data that flows from `source` to `sink` may have a string - * containing the character `?` or `#` prepended to it. + * Holds if data that flows from `source` to `sink` cannot affect the + * hostname of the resulting string when interpreted as a URL. * * This is considered as a sanitizing edge for the URL redirection queries. */ diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected index 2d57e091ba27..a2711a2cdf04 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected @@ -7,14 +7,6 @@ nodes | express.js:35:16:35:21 | target | | express.js:40:16:40:108 | (req.pa ... ntacts" | | express.js:40:69:40:87 | req.param('action') | -| express.js:44:7:44:28 | handle | -| express.js:44:16:44:28 | req.params[0] | -| express.js:45:7:45:33 | url | -| express.js:45:13:45:27 | "/Me/" + handle | -| express.js:45:13:45:33 | "/Me/" ... e + "/" | -| express.js:45:22:45:27 | handle | -| express.js:49:3:49:3 | url | -| express.js:49:26:49:28 | url | | express.js:74:16:74:43 | `${req. ... )}/foo` | | express.js:74:19:74:37 | req.param("target") | | express.js:83:7:83:34 | target | @@ -24,6 +16,18 @@ nodes | express.js:118:16:118:63 | [req.qu ... ection] | | express.js:118:16:118:72 | [req.qu ... oin('') | | express.js:118:17:118:30 | req.query.page | +| express.js:134:16:134:36 | '/' + r ... ms.user | +| express.js:134:22:134:36 | req.params.user | +| express.js:135:16:135:37 | '//' + ... ms.user | +| express.js:135:23:135:37 | req.params.user | +| express.js:136:16:136:36 | 'u' + r ... ms.user | +| express.js:136:22:136:36 | req.params.user | +| express.js:138:16:138:45 | '/' + ( ... s.user) | +| express.js:138:22:138:45 | ('/u' + ... s.user) | +| express.js:138:23:138:44 | '/u' + ... ms.user | +| express.js:138:30:138:44 | req.params.user | +| express.js:139:16:139:37 | '/u' + ... ms.user | +| express.js:139:23:139:37 | req.params.user | | node.js:6:7:6:52 | target | | node.js:6:16:6:39 | url.par ... , true) | | node.js:6:16:6:45 | url.par ... ).query | @@ -54,19 +58,19 @@ edges | express.js:27:7:27:34 | target | express.js:35:16:35:21 | target | | express.js:27:16:27:34 | req.param("target") | express.js:27:7:27:34 | target | | express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | -| express.js:44:7:44:28 | handle | express.js:45:22:45:27 | handle | -| express.js:44:16:44:28 | req.params[0] | express.js:44:7:44:28 | handle | -| express.js:45:7:45:33 | url | express.js:49:3:49:3 | url | -| express.js:45:13:45:27 | "/Me/" + handle | express.js:45:13:45:33 | "/Me/" ... e + "/" | -| express.js:45:13:45:33 | "/Me/" ... e + "/" | express.js:45:7:45:33 | url | -| express.js:45:22:45:27 | handle | express.js:45:13:45:27 | "/Me/" + handle | -| express.js:49:3:49:3 | url | express.js:49:26:49:28 | url | | express.js:74:19:74:37 | req.param("target") | express.js:74:16:74:43 | `${req. ... )}/foo` | | express.js:83:7:83:34 | target | express.js:90:18:90:23 | target | | express.js:83:7:83:34 | target | express.js:97:16:97:21 | target | | express.js:83:16:83:34 | req.param("target") | express.js:83:7:83:34 | target | | express.js:118:16:118:63 | [req.qu ... ection] | express.js:118:16:118:72 | [req.qu ... oin('') | | express.js:118:17:118:30 | req.query.page | express.js:118:16:118:63 | [req.qu ... ection] | +| express.js:134:22:134:36 | req.params.user | express.js:134:16:134:36 | '/' + r ... ms.user | +| express.js:135:23:135:37 | req.params.user | express.js:135:16:135:37 | '//' + ... ms.user | +| express.js:136:22:136:36 | req.params.user | express.js:136:16:136:36 | 'u' + r ... ms.user | +| express.js:138:22:138:45 | ('/u' + ... s.user) | express.js:138:16:138:45 | '/' + ( ... s.user) | +| express.js:138:23:138:44 | '/u' + ... ms.user | express.js:138:22:138:45 | ('/u' + ... s.user) | +| express.js:138:30:138:44 | req.params.user | express.js:138:23:138:44 | '/u' + ... ms.user | +| express.js:139:23:139:37 | req.params.user | express.js:139:16:139:37 | '/u' + ... ms.user | | node.js:6:7:6:52 | target | node.js:7:34:7:39 | target | | node.js:6:16:6:39 | url.par ... , true) | node.js:6:16:6:45 | url.par ... ).query | | node.js:6:16:6:45 | url.par ... ).query | node.js:6:16:6:52 | url.par ... .target | @@ -94,11 +98,15 @@ edges | express.js:33:18:33:23 | target | express.js:27:16:27:34 | req.param("target") | express.js:33:18:33:23 | target | Untrusted URL redirection due to $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | | express.js:35:16:35:21 | target | express.js:27:16:27:34 | req.param("target") | express.js:35:16:35:21 | target | Untrusted URL redirection due to $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | | express.js:40:16:40:108 | (req.pa ... ntacts" | express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | Untrusted URL redirection due to $@. | express.js:40:69:40:87 | req.param('action') | user-provided value | -| express.js:49:26:49:28 | url | express.js:44:16:44:28 | req.params[0] | express.js:49:26:49:28 | url | Untrusted URL redirection due to $@. | express.js:44:16:44:28 | req.params[0] | user-provided value | | express.js:74:16:74:43 | `${req. ... )}/foo` | express.js:74:19:74:37 | req.param("target") | express.js:74:16:74:43 | `${req. ... )}/foo` | Untrusted URL redirection due to $@. | express.js:74:19:74:37 | req.param("target") | user-provided value | | express.js:90:18:90:23 | target | express.js:83:16:83:34 | req.param("target") | express.js:90:18:90:23 | target | Untrusted URL redirection due to $@. | express.js:83:16:83:34 | req.param("target") | user-provided value | | express.js:97:16:97:21 | target | express.js:83:16:83:34 | req.param("target") | express.js:97:16:97:21 | target | Untrusted URL redirection due to $@. | express.js:83:16:83:34 | req.param("target") | user-provided value | | express.js:118:16:118:72 | [req.qu ... oin('') | express.js:118:17:118:30 | req.query.page | express.js:118:16:118:72 | [req.qu ... oin('') | Untrusted URL redirection due to $@. | express.js:118:17:118:30 | req.query.page | user-provided value | +| express.js:134:16:134:36 | '/' + r ... ms.user | express.js:134:22:134:36 | req.params.user | express.js:134:16:134:36 | '/' + r ... ms.user | Untrusted URL redirection due to $@. | express.js:134:22:134:36 | req.params.user | user-provided value | +| express.js:135:16:135:37 | '//' + ... ms.user | express.js:135:23:135:37 | req.params.user | express.js:135:16:135:37 | '//' + ... ms.user | Untrusted URL redirection due to $@. | express.js:135:23:135:37 | req.params.user | user-provided value | +| express.js:136:16:136:36 | 'u' + r ... ms.user | express.js:136:22:136:36 | req.params.user | express.js:136:16:136:36 | 'u' + r ... ms.user | Untrusted URL redirection due to $@. | express.js:136:22:136:36 | req.params.user | user-provided value | +| express.js:138:16:138:45 | '/' + ( ... s.user) | express.js:138:30:138:44 | req.params.user | express.js:138:16:138:45 | '/' + ( ... s.user) | Untrusted URL redirection due to $@. | express.js:138:30:138:44 | req.params.user | user-provided value | +| express.js:139:16:139:37 | '/u' + ... ms.user | express.js:139:23:139:37 | req.params.user | express.js:139:16:139:37 | '/u' + ... ms.user | Untrusted URL redirection due to $@. | express.js:139:23:139:37 | req.params.user | user-provided value | | node.js:7:34:7:39 | target | node.js:6:26:6:32 | req.url | node.js:7:34:7:39 | target | Untrusted URL redirection due to $@. | node.js:6:26:6:32 | req.url | user-provided value | | node.js:15:34:15:45 | '/' + target | node.js:11:26:11:32 | req.url | node.js:15:34:15:45 | '/' + target | Untrusted URL redirection due to $@. | node.js:11:26:11:32 | req.url | user-provided value | | node.js:32:34:32:55 | target ... =" + me | node.js:29:26:29:32 | req.url | node.js:32:34:32:55 | target ... =" + me | Untrusted URL redirection due to $@. | node.js:29:26:29:32 | req.url | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js index 37a1370698ce..36276d65c73b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js +++ b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js @@ -126,3 +126,15 @@ function sendUserToUrl(res, nextUrl) { app.get('/call', function(req, res) { sendUserToUrl(res, req.query.nextUrl); }); + +app.get('/redirect/:user', function(req, res) { + res.redirect('/users/' + req.params.user); // GOOD + res.redirect('users/' + req.params.user); // GOOD + + res.redirect('/' + req.params.user); // BAD - could go to //evil.com + res.redirect('//' + req.params.user); // BAD - could go to //evil.com + res.redirect('u' + req.params.user); // BAD - could go to u.evil.com + + res.redirect('/' + ('/u' + req.params.user)); // BAD - could go to //u.evil.com + res.redirect('/u' + req.params.user); // GOOD - but flagged anyway +}); From 0153a4794e1bd55436c2bca54842bc8edabdfc91 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 8 Nov 2018 11:06:40 +0000 Subject: [PATCH 58/68] JS: add change note --- change-notes/1.19/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.19/analysis-javascript.md b/change-notes/1.19/analysis-javascript.md index ee3d05e7bb1b..63679cb0174c 100644 --- a/change-notes/1.19/analysis-javascript.md +++ b/change-notes/1.19/analysis-javascript.md @@ -49,6 +49,8 @@ | Unused variable, import, function or class | Fewer results | This rule now flags import statements with multiple unused imports once. | | Useless assignment to local variable | Fewer false-positive results | This rule now recognizes additional ways default values can be set. | | Whitespace contradicts operator precedence | Fewer false-positive results | This rule no longer flags operators with asymmetric whitespace. | +| Client-side URL redirect | Fewer false-positive results | This rule now recognizes safe redirects in more cases. | +| Server-side URL redirect | Fewer false-positive results | This rule now recognizes safe redirects in more cases. | ## Changes to QL libraries From dd5f485fffbe74d8df6641cd817f5e9e66d0232b Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 9 Nov 2018 09:47:05 +0000 Subject: [PATCH 59/68] JS: use original sanitizer for SSRF query --- .../dataflow/ClientSideUrlRedirect.qll | 2 +- .../dataflow/ServerSideUrlRedirect.qll | 2 +- .../security/dataflow/UrlConcatenation.qll | 40 ++++++++++++++++--- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll index dc331b7d2a82..8cdc442edaea 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll @@ -58,7 +58,7 @@ module ClientSideUrlRedirect { } override predicate isSanitizer(DataFlow::Node source, DataFlow::Node sink) { - sanitizingPrefixEdge(source, sink) + hostnameSanitizingPrefixEdge(source, sink) } override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel f, DataFlow::FlowLabel g) { diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll index ceed93bcfaf9..c2c4f21ad9e0 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll @@ -43,7 +43,7 @@ module ServerSideUrlRedirect { } override predicate isSanitizer(DataFlow::Node source, DataFlow::Node sink) { - sanitizingPrefixEdge(source, sink) + hostnameSanitizingPrefixEdge(source, sink) } override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll index eadb60b37639..77bf16a43b45 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll @@ -6,6 +6,34 @@ import javascript +/** + * Holds if the string value of `nd` prevents anything appended after it + * from affecting the hostname or path of a URL. + * + * Specifically, this holds if the string contains `?` or `#`. + */ +private predicate hasSanitizingSubstring(DataFlow::Node nd) { + nd.asExpr().getStringValue().regexpMatch(".*[?#].*") + or + hasSanitizingSubstring(StringConcatenation::getAnOperand(nd)) + or + hasSanitizingSubstring(nd.getAPredecessor()) + or + nd.isIncomplete(_) +} + +/** + * Holds if data that flows from `source` to `sink` cannot affect the + * path or earlier part of the resulting string when interpreted as a URL. + * + * This is considered as a sanitizing edge for the URL redirection queries. + */ +predicate sanitizingPrefixEdge(DataFlow::Node source, DataFlow::Node sink) { + exists (DataFlow::Node operator, int n | + StringConcatenation::taintStep(source, sink, operator, n) and + hasSanitizingSubstring(StringConcatenation::getOperand(operator, [0..n-1]))) +} + /** * Holds if the string value of `nd` prevents anything appended after it * from affecting the hostname of a URL. @@ -18,24 +46,24 @@ import javascript * In the latter case, the additional prefix check is necessary to avoid a `/` that could be interpreted as * the `//` separating the (optional) scheme from the hostname. */ -predicate hasSanitizingSubstring(DataFlow::Node nd) { +private predicate hasHostnameSanitizingSubstring(DataFlow::Node nd) { nd.asExpr().getStringValue().regexpMatch(".*([?#]|[^?#:/\\\\][/\\\\]).*") or - hasSanitizingSubstring(StringConcatenation::getAnOperand(nd)) + hasHostnameSanitizingSubstring(StringConcatenation::getAnOperand(nd)) or - hasSanitizingSubstring(nd.getAPredecessor()) + hasHostnameSanitizingSubstring(nd.getAPredecessor()) or nd.isIncomplete(_) } /** * Holds if data that flows from `source` to `sink` cannot affect the - * hostname of the resulting string when interpreted as a URL. + * hostname or scheme of the resulting string when interpreted as a URL. * * This is considered as a sanitizing edge for the URL redirection queries. */ -predicate sanitizingPrefixEdge(DataFlow::Node source, DataFlow::Node sink) { +predicate hostnameSanitizingPrefixEdge(DataFlow::Node source, DataFlow::Node sink) { exists (DataFlow::Node operator, int n | StringConcatenation::taintStep(source, sink, operator, n) and hasSanitizingSubstring(StringConcatenation::getOperand(operator, [0..n-1]))) -} +} \ No newline at end of file From c06c9a02f7969ba96a3d691dc287ae0b29802f0d Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Nov 2018 13:03:13 +0000 Subject: [PATCH 60/68] JS: fix copy pasta and test output --- .../semmle/javascript/security/dataflow/UrlConcatenation.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll index 77bf16a43b45..970e2ee22300 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll @@ -65,5 +65,5 @@ private predicate hasHostnameSanitizingSubstring(DataFlow::Node nd) { predicate hostnameSanitizingPrefixEdge(DataFlow::Node source, DataFlow::Node sink) { exists (DataFlow::Node operator, int n | StringConcatenation::taintStep(source, sink, operator, n) and - hasSanitizingSubstring(StringConcatenation::getOperand(operator, [0..n-1]))) + hasHostnameSanitizingSubstring(StringConcatenation::getOperand(operator, [0..n-1]))) } \ No newline at end of file From 437b2c15033db925f2a3022c0b44e44512334928 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 14 Nov 2018 13:18:54 +0100 Subject: [PATCH 61/68] Java: Cosmetic changes and missing overrides. --- .../src/Security/CWE/CWE-129/ArraySizing.qll | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-129/ArraySizing.qll b/java/ql/src/Security/CWE/CWE-129/ArraySizing.qll index f6c519c32d4a..59db7d4f87f5 100644 --- a/java/ql/src/Security/CWE/CWE-129/ArraySizing.qll +++ b/java/ql/src/Security/CWE/CWE-129/ArraySizing.qll @@ -7,32 +7,25 @@ private import BoundingChecks * If the `Array` accessed by the `ArrayAccess` is a fixed size, return the array size. */ int fixedArraySize(ArrayAccess arrayAccess) { - result = arrayAccess - .getArray() - .(VarAccess) - .getVariable() - .getAnAssignedValue() - .(ArrayCreationExpr) - .getFirstDimensionSize() + exists(Variable v | + v.getAnAccess() = arrayAccess.getArray() and + result = v.getAnAssignedValue().(ArrayCreationExpr).getFirstDimensionSize() + ) } /** * Holds if an `ArrayIndexOutOfBoundsException` is ever caught. */ private predicate arrayIndexOutOfBoundExceptionCaught(ArrayAccess arrayAccess) { - exists(TryStmt ts, CatchClause cc | + exists(TryStmt ts, CatchClause cc, RefType exc | ( ts.getBlock().getAChild*() = arrayAccess.getEnclosingStmt() or ts.getAResourceDecl().getAChild*() = arrayAccess.getEnclosingStmt() or ts.getAResourceExpr().getAChildExpr*() = arrayAccess ) and - cc = ts.getACatchClause() - | - cc - .getVariable() - .getType() - .(RefType) - .hasQualifiedName("java.lang", "ArrayIndexOutOfBoundsException") + cc = ts.getACatchClause() and + exc = cc.getVariable().getType() and + exc.hasQualifiedName("java.lang", "ArrayIndexOutOfBoundsException") ) } @@ -144,14 +137,14 @@ class RandomValueFlowSource extends BoundedFlowSource { ) } - int lowerBound() { + override int lowerBound() { // If this call is to `nextInt()`, the lower bound is zero. this.asExpr().(MethodAccess).getCallee().hasName("nextInt") and this.asExpr().(MethodAccess).getNumArgument() = 1 and result = 0 } - int upperBound() { + override int upperBound() { // If this call specified an argument to `nextInt()`, and that argument is a compile time constant, // it forms the upper bound. this.asExpr().(MethodAccess).getCallee().hasName("nextInt") and @@ -159,7 +152,7 @@ class RandomValueFlowSource extends BoundedFlowSource { result = this.asExpr().(MethodAccess).getArgument(0).(CompileTimeConstantExpr).getIntValue() } - string getDescription() { result = "Random value" } + override string getDescription() { result = "Random value" } } /** @@ -168,11 +161,11 @@ class RandomValueFlowSource extends BoundedFlowSource { class NumericLiteralFlowSource extends BoundedFlowSource { NumericLiteralFlowSource() { exists(this.asExpr().(CompileTimeConstantExpr).getIntValue()) } - int lowerBound() { result = this.asExpr().(CompileTimeConstantExpr).getIntValue() } + override int lowerBound() { result = this.asExpr().(CompileTimeConstantExpr).getIntValue() } - int upperBound() { result = this.asExpr().(CompileTimeConstantExpr).getIntValue() } + override int upperBound() { result = this.asExpr().(CompileTimeConstantExpr).getIntValue() } - string getDescription() { + override string getDescription() { result = "Literal value " + this.asExpr().(CompileTimeConstantExpr).getIntValue() } } From 5e03b6f681b778d7ace79e0175c7ee4fbdc15f2b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 14 Nov 2018 13:11:47 +0100 Subject: [PATCH 62/68] Java: Convert security queries to path-problems. --- .../src/Security/CWE/CWE-022/TaintedPath.ql | 12 ++++--- .../Security/CWE/CWE-022/TaintedPathLocal.ql | 13 +++++--- java/ql/src/Security/CWE/CWE-022/ZipSlip.ql | 10 +++--- .../src/Security/CWE/CWE-078/ExecCommon.qll | 4 +-- .../src/Security/CWE/CWE-078/ExecTainted.ql | 10 +++--- .../Security/CWE/CWE-078/ExecTaintedLocal.ql | 11 ++++--- .../src/Security/CWE/CWE-078/ExecUnescaped.ql | 2 +- java/ql/src/Security/CWE/CWE-079/XSS.ql | 10 +++--- java/ql/src/Security/CWE/CWE-079/XSSLocal.ql | 10 +++--- .../Security/CWE/CWE-089/SqlInjectionLib.qll | 6 ++-- .../ql/src/Security/CWE/CWE-089/SqlTainted.ql | 9 +++--- .../Security/CWE/CWE-089/SqlTaintedLocal.ql | 11 ++++--- .../src/Security/CWE/CWE-089/SqlUnescaped.ql | 2 +- .../Security/CWE/CWE-113/ResponseSplitting.ql | 10 +++--- .../CWE/CWE-113/ResponseSplittingLocal.ql | 10 +++--- .../ImproperValidationOfArrayConstruction.ql | 14 +++++---- ...idationOfArrayConstructionCodeSpecified.ql | 15 +++++---- ...roperValidationOfArrayConstructionLocal.ql | 14 +++++---- .../CWE-129/ImproperValidationOfArrayIndex.ql | 15 ++++----- ...operValidationOfArrayIndexCodeSpecified.ql | 31 ++++++++++--------- .../ImproperValidationOfArrayIndexLocal.ql | 15 ++++----- .../ExternallyControlledFormatString.ql | 13 +++++--- .../Security/CWE/CWE-190/ArithmeticTainted.ql | 14 +++++---- .../CWE/CWE-190/ArithmeticTaintedLocal.ql | 14 +++++---- .../CWE/CWE-190/ArithmeticUncontrolled.ql | 14 +++++---- .../CWE-190/ArithmeticWithExtremeValues.ql | 18 ++++++----- java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql | 13 +++++--- .../CWE/CWE-327/BrokenCryptoAlgorithm.ql | 15 ++++++--- .../CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql | 15 ++++++--- .../CWE/CWE-502/UnsafeDeserialization.ql | 10 +++--- .../src/Security/CWE/CWE-601/UrlRedirect.ql | 10 +++--- .../Security/CWE/CWE-601/UrlRedirectLocal.ql | 10 +++--- java/ql/src/Security/CWE/CWE-611/XXE.ql | 10 +++--- .../CWE/CWE-681/NumericCastTainted.ql | 15 +++++---- .../CWE/CWE-681/NumericCastTaintedLocal.ql | 14 ++++++--- .../CWE-798/HardcodedCredentialsApiCall.ql | 11 ++++--- .../CWE-798/HardcodedCredentialsSourceCall.ql | 10 +++--- .../Security/CWE/CWE-807/ConditionalBypass.ql | 15 ++++++--- .../CWE/CWE-807/TaintedPermissionsCheck.ql | 11 ++++--- 39 files changed, 279 insertions(+), 187 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql index fef3fa65e853..0aef239d264c 100644 --- a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -1,7 +1,7 @@ /** * @name Uncontrolled data used in path expression * @description Accessing paths influenced by users can allow an attacker to access unexpected resources. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/path-injection @@ -15,6 +15,7 @@ import java import semmle.code.java.dataflow.FlowSources import PathsCommon +import DataFlow::PathGraph class TaintedPathConfig extends TaintTracking::Configuration { TaintedPathConfig() { this = "TaintedPathConfig" } @@ -30,8 +31,9 @@ class TaintedPathConfig extends TaintTracking::Configuration { } } -from RemoteUserInput u, PathCreation p, Expr e, TaintedPathConfig conf +from DataFlow::PathNode source, DataFlow::PathNode sink, PathCreation p, TaintedPathConfig conf where - e = p.getInput() and - conf.hasFlow(u, DataFlow::exprNode(e)) -select p, "$@ flows to here and is used in a path.", u, "User-provided value" + sink.getNode().asExpr() = p.getInput() and + conf.hasFlowPath(source, sink) +select p, source, sink, "$@ flows to here and is used in a path.", source.getNode(), + "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql b/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql index e1e6b3e53fc8..4d1c20f923e4 100644 --- a/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql +++ b/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql @@ -1,7 +1,7 @@ /** * @name Local-user-controlled data in path expression * @description Accessing paths influenced by users can allow an attacker to access unexpected resources. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/path-injection-local @@ -15,6 +15,7 @@ import java import semmle.code.java.dataflow.FlowSources import PathsCommon +import DataFlow::PathGraph class TaintedPathLocalConfig extends TaintTracking::Configuration { TaintedPathLocalConfig() { this = "TaintedPathLocalConfig" } @@ -24,9 +25,13 @@ class TaintedPathLocalConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(PathCreation p).getInput() } } -from LocalUserInput u, PathCreation p, Expr e, TaintedPathLocalConfig conf +from + DataFlow::PathNode source, DataFlow::PathNode sink, PathCreation p, Expr e, + TaintedPathLocalConfig conf where + e = sink.getNode().asExpr() and e = p.getInput() and - conf.hasFlow(u, DataFlow::exprNode(e)) and + conf.hasFlowPath(source, sink) and not guarded(e) -select p, "$@ flows to here and is used in a path.", u, "User-provided value" +select p, source, sink, "$@ flows to here and is used in a path.", source.getNode(), + "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql b/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql index ff4a39af80ad..f23167eed24e 100644 --- a/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql +++ b/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql @@ -3,7 +3,7 @@ * @description Extracting files from a malicious archive without validating that the * destination file path is within the destination directory can cause files outside * the destination directory to be overwritten. - * @kind problem + * @kind path-problem * @id java/zipslip * @problem.severity error * @precision high @@ -16,6 +16,7 @@ import semmle.code.java.controlflow.Guards import semmle.code.java.dataflow.SSA import semmle.code.java.dataflow.TaintTracking import DataFlow +import PathGraph /** * A method that returns the name of an archive entry. @@ -170,7 +171,8 @@ class ZipSlipConfiguration extends TaintTracking::Configuration { } } -from Node source, Node sink -where any(ZipSlipConfiguration c).hasFlow(source, sink) -select source, "Unsanitized archive entry, which may contain '..', is used in a $@.", sink, +from PathNode source, PathNode sink +where any(ZipSlipConfiguration c).hasFlowPath(source, sink) +select source.getNode(), source, sink, + "Unsanitized archive entry, which may contain '..', is used in a $@.", sink.getNode(), "file system operation" diff --git a/java/ql/src/Security/CWE/CWE-078/ExecCommon.qll b/java/ql/src/Security/CWE/CWE-078/ExecCommon.qll index 1900b081dfd7..00c7fea3e02b 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecCommon.qll +++ b/java/ql/src/Security/CWE/CWE-078/ExecCommon.qll @@ -20,8 +20,8 @@ private class RemoteUserInputToArgumentToExecFlowConfig extends TaintTracking::C * so that it can be excluded from `ExecUnescaped.ql` to avoid * reporting overlapping results. */ -predicate execTainted(RemoteUserInput source, ArgumentToExec execArg) { +predicate execTainted(DataFlow::PathNode source, DataFlow::PathNode sink, ArgumentToExec execArg) { exists(RemoteUserInputToArgumentToExecFlowConfig conf | - conf.hasFlow(source, DataFlow::exprNode(execArg)) + conf.hasFlowPath(source, sink) and sink.getNode() = DataFlow::exprNode(execArg) ) } diff --git a/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql b/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql index f86c6ca917f9..8774de339b6c 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql @@ -2,7 +2,7 @@ * @name Uncontrolled command line * @description Using externally controlled strings in a command line is vulnerable to malicious * changes in the strings. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/command-line-injection @@ -15,7 +15,9 @@ import semmle.code.java.Expr import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.ExternalProcess import ExecCommon +import DataFlow::PathGraph -from StringArgumentToExec execArg, RemoteUserInput origin -where execTainted(origin, execArg) -select execArg, "$@ flows to here and is used in a command.", origin, "User-provided value" +from DataFlow::PathNode source, DataFlow::PathNode sink, StringArgumentToExec execArg +where execTainted(source, sink, execArg) +select execArg, source, sink, "$@ flows to here and is used in a command.", source.getNode(), + "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql index bff0956b9da0..d809f1bb5dd0 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql @@ -2,7 +2,7 @@ * @name Local-user-controlled command line * @description Using externally controlled strings in a command line is vulnerable to malicious * changes in the strings. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/command-line-injection-local @@ -14,6 +14,7 @@ import semmle.code.java.Expr import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.ExternalProcess +import DataFlow::PathGraph class LocalUserInputToArgumentToExecFlowConfig extends TaintTracking::Configuration { LocalUserInputToArgumentToExecFlowConfig() { this = "LocalUserInputToArgumentToExecFlowConfig" } @@ -28,6 +29,8 @@ class LocalUserInputToArgumentToExecFlowConfig extends TaintTracking::Configurat } from - StringArgumentToExec execArg, LocalUserInput origin, LocalUserInputToArgumentToExecFlowConfig conf -where conf.hasFlow(origin, DataFlow::exprNode(execArg)) -select execArg, "$@ flows to here and is used in a command.", origin, "User-provided value" + DataFlow::PathNode source, DataFlow::PathNode sink, StringArgumentToExec execArg, + LocalUserInputToArgumentToExecFlowConfig conf +where conf.hasFlowPath(source, sink) and sink.getNode().asExpr() = execArg +select execArg, source, sink, "$@ flows to here and is used in a command.", source.getNode(), + "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql index afc4fafe4dca..e80afa7f6ebd 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql @@ -47,5 +47,5 @@ predicate builtFromUncontrolledConcat(Expr expr) { from StringArgumentToExec argument where builtFromUncontrolledConcat(argument) and - not execTainted(_, argument) + not execTainted(_, _, argument) select argument, "Command line is built with string concatenation." diff --git a/java/ql/src/Security/CWE/CWE-079/XSS.ql b/java/ql/src/Security/CWE/CWE-079/XSS.ql index 75eaa38cb327..dc4c7f606bca 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSS.ql +++ b/java/ql/src/Security/CWE/CWE-079/XSS.ql @@ -2,7 +2,7 @@ * @name Cross-site scripting * @description Writing user input directly to a web page * allows for a cross-site scripting vulnerability. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/xss @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.XSS +import DataFlow2::PathGraph class XSSConfig extends TaintTracking::Configuration2 { XSSConfig() { this = "XSSConfig" } @@ -26,6 +27,7 @@ class XSSConfig extends TaintTracking::Configuration2 { } } -from XssSink sink, RemoteUserInput source, XSSConfig conf -where conf.hasFlow(source, sink) -select sink, "Cross-site scripting vulnerability due to $@.", source, "user-provided value" +from DataFlow2::PathNode source, DataFlow2::PathNode sink, XSSConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", + source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql b/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql index 58ac779bea84..d0e2a04b681c 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql +++ b/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql @@ -2,7 +2,7 @@ * @name Cross-site scripting from local source * @description Writing user input directly to a web page * allows for a cross-site scripting vulnerability. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/xss-local @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.XSS +import DataFlow2::PathGraph class XSSLocalConfig extends TaintTracking::Configuration2 { XSSLocalConfig() { this = "XSSLocalConfig" } @@ -22,6 +23,7 @@ class XSSLocalConfig extends TaintTracking::Configuration2 { override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } } -from XssSink sink, LocalUserInput source, XSSLocalConfig conf -where conf.hasFlow(source, sink) -select sink, "Cross-site scripting vulnerability due to $@.", source, "user-provided value" +from DataFlow2::PathNode source, DataFlow2::PathNode sink, XSSLocalConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", + source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll index 74288aec5e5f..09da2e6de2a6 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll @@ -62,6 +62,8 @@ private class QueryInjectionFlowConfig extends TaintTracking::Configuration { * Implementation of `SqlTainted.ql`. This is extracted to a QLL so that it * can be excluded from `SqlUnescaped.ql` to avoid overlapping results. */ -predicate queryTaintedBy(QueryInjectionSink query, RemoteUserInput source) { - exists(QueryInjectionFlowConfig conf | conf.hasFlow(source, query)) +predicate queryTaintedBy( + QueryInjectionSink query, DataFlow::PathNode source, DataFlow::PathNode sink +) { + exists(QueryInjectionFlowConfig conf | conf.hasFlowPath(source, sink) and sink.getNode() = query) } diff --git a/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql index 8ae4b466db89..5b79c56a83c9 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql +++ b/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql @@ -2,7 +2,7 @@ * @name Query built from user-controlled sources * @description Building a SQL or Java Persistence query from user-controlled sources is vulnerable to insertion of * malicious code by the user. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/sql-injection @@ -13,7 +13,8 @@ import semmle.code.java.Expr import semmle.code.java.dataflow.FlowSources import SqlInjectionLib +import DataFlow::PathGraph -from QueryInjectionSink query, RemoteUserInput source -where queryTaintedBy(query, source) -select query, "Query might include code from $@.", source, "this user input" +from QueryInjectionSink query, DataFlow::PathNode source, DataFlow::PathNode sink +where queryTaintedBy(query, source, sink) +select query, source, sink, "Query might include code from $@.", source.getNode(), "this user input" diff --git a/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql index 5a69e48d9a90..f5cb9ca4aae2 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql +++ b/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql @@ -2,7 +2,7 @@ * @name Query built from local-user-controlled sources * @description Building a SQL or Java Persistence query from user-controlled sources is vulnerable to insertion of * malicious code by the user. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/sql-injection-local @@ -13,6 +13,7 @@ import semmle.code.java.Expr import semmle.code.java.dataflow.FlowSources import SqlInjectionLib +import DataFlow::PathGraph class LocalUserInputToQueryInjectionFlowConfig extends TaintTracking::Configuration { LocalUserInputToQueryInjectionFlowConfig() { this = "LocalUserInputToQueryInjectionFlowConfig" } @@ -26,6 +27,8 @@ class LocalUserInputToQueryInjectionFlowConfig extends TaintTracking::Configurat } } -from QueryInjectionSink query, LocalUserInput source, LocalUserInputToQueryInjectionFlowConfig conf -where conf.hasFlow(source, query) -select query, "Query might include code from $@.", source, "this user input" +from + DataFlow::PathNode source, DataFlow::PathNode sink, LocalUserInputToQueryInjectionFlowConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Query might include code from $@.", source.getNode(), + "this user input" diff --git a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql index a974725a2fb0..83eaa50ea2c0 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql @@ -46,6 +46,6 @@ where conf.hasFlow(DataFlow::exprNode(sbv.getToStringCall()), query) ) ) and - not queryTaintedBy(query, _) + not queryTaintedBy(query, _, _) select query, "Query might not neutralize special characters in $@.", uncontrolled, "this expression" diff --git a/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql b/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql index d6a6f74dcbf3..c2a6e0363a0f 100644 --- a/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql +++ b/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql @@ -2,7 +2,7 @@ * @name HTTP response splitting * @description Writing user input directly to an HTTP header * makes code vulnerable to attack by header splitting. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/http-response-splitting @@ -12,6 +12,7 @@ import java import ResponseSplitting +import DataFlow::PathGraph class ResponseSplittingConfig extends TaintTracking::Configuration { ResponseSplittingConfig() { this = "ResponseSplittingConfig" } @@ -24,6 +25,7 @@ class ResponseSplittingConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink } } -from HeaderSplittingSink sink, RemoteUserInput source, ResponseSplittingConfig conf -where conf.hasFlow(source, sink) -select sink, "Response-splitting vulnerability due to this $@.", source, "user-provided value" +from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Response-splitting vulnerability due to this $@.", + source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql b/java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql index a3205298190a..fb17d709b928 100644 --- a/java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql +++ b/java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql @@ -2,7 +2,7 @@ * @name HTTP response splitting from local source * @description Writing user input directly to an HTTP header * makes code vulnerable to attack by header splitting. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/http-response-splitting-local @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.FlowSources import ResponseSplitting +import DataFlow::PathGraph class ResponseSplittingLocalConfig extends TaintTracking::Configuration { ResponseSplittingLocalConfig() { this = "ResponseSplittingLocalConfig" } @@ -22,6 +23,7 @@ class ResponseSplittingLocalConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink } } -from HeaderSplittingSink sink, LocalUserInput source, ResponseSplittingLocalConfig conf -where conf.hasFlow(source, sink) -select sink, "Response-splitting vulnerability due to this $@.", source, "user-provided value" +from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingLocalConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Response-splitting vulnerability due to this $@.", + source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql index 6589d4e60db0..3d9c6b0e4830 100644 --- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql +++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql @@ -1,7 +1,7 @@ /** * @name Improper validation of user-provided size used for array construction * @description Using unvalidated external input as the argument to a construction of an array can lead to index out of bound exceptions. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id java/improper-validation-of-array-construction @@ -12,6 +12,7 @@ import java import ArraySizing import semmle.code.java.dataflow.FlowSources +import DataFlow::PathGraph class Conf extends TaintTracking::Configuration { Conf() { this = "RemoteUserInputTocanThrowOutOfBoundsDueToEmptyArrayConfig" } @@ -24,11 +25,12 @@ class Conf extends TaintTracking::Configuration { } from - RemoteUserInput source, Expr sizeExpr, ArrayCreationExpr arrayCreation, - CheckableArrayAccess arrayAccess + DataFlow::PathNode source, DataFlow::PathNode sink, Expr sizeExpr, + ArrayCreationExpr arrayCreation, CheckableArrayAccess arrayAccess where arrayAccess.canThrowOutOfBoundsDueToEmptyArray(sizeExpr, arrayCreation) and - any(Conf conf).hasFlow(source, DataFlow::exprNode(sizeExpr)) -select arrayAccess.getIndexExpr(), + sizeExpr = sink.getNode().asExpr() and + any(Conf conf).hasFlowPath(source, sink) +select arrayAccess.getIndexExpr(), source, sink, "The $@ is accessed here, but the array is initialized using $@ which may be zero.", - arrayCreation, "array", source, "User-provided value" + arrayCreation, "array", source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql index 8eee3e41c3b5..16519955c6dd 100644 --- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql +++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql @@ -2,7 +2,7 @@ * @name Improper validation of code-specified size used for array construction * @description Using a code-specified value that may be zero as the argument to * a construction of an array can lead to index out of bound exceptions. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/improper-validation-of-array-construction-code-specified @@ -12,6 +12,7 @@ import java import ArraySizing +import DataFlow::PathGraph class BoundedFlowSourceConf extends DataFlow::Configuration { BoundedFlowSourceConf() { this = "BoundedFlowSource" } @@ -28,11 +29,13 @@ class BoundedFlowSourceConf extends DataFlow::Configuration { } from - BoundedFlowSource source, Expr sizeExpr, ArrayCreationExpr arrayCreation, - CheckableArrayAccess arrayAccess + DataFlow::PathNode source, DataFlow::PathNode sink, BoundedFlowSource boundedsource, + Expr sizeExpr, ArrayCreationExpr arrayCreation, CheckableArrayAccess arrayAccess where arrayAccess.canThrowOutOfBoundsDueToEmptyArray(sizeExpr, arrayCreation) and - any(BoundedFlowSourceConf conf).hasFlow(source, DataFlow::exprNode(sizeExpr)) -select arrayAccess.getIndexExpr(), + sizeExpr = sink.getNode().asExpr() and + boundedsource = source.getNode() and + any(BoundedFlowSourceConf conf).hasFlowPath(source, sink) +select arrayAccess.getIndexExpr(), source, sink, "The $@ is accessed here, but the array is initialized using $@ which may be zero.", - arrayCreation, "array", source, source.getDescription().toLowerCase() + arrayCreation, "array", boundedsource, boundedsource.getDescription().toLowerCase() diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionLocal.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionLocal.ql index c182ca0eeeba..6938946ce0cd 100644 --- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionLocal.ql +++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionLocal.ql @@ -2,7 +2,7 @@ * @name Improper validation of local user-provided size used for array construction * @description Using unvalidated local input as the argument to * a construction of an array can lead to index out of bound exceptions. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/improper-validation-of-array-construction-local @@ -13,6 +13,7 @@ import java import ArraySizing import semmle.code.java.dataflow.FlowSources +import DataFlow::PathGraph class Conf extends TaintTracking::Configuration { Conf() { this = "LocalUserInputTocanThrowOutOfBoundsDueToEmptyArrayConfig" } @@ -25,11 +26,12 @@ class Conf extends TaintTracking::Configuration { } from - LocalUserInput source, Expr sizeExpr, ArrayCreationExpr arrayCreation, - CheckableArrayAccess arrayAccess + DataFlow::PathNode source, DataFlow::PathNode sink, Expr sizeExpr, + ArrayCreationExpr arrayCreation, CheckableArrayAccess arrayAccess where arrayAccess.canThrowOutOfBoundsDueToEmptyArray(sizeExpr, arrayCreation) and - any(Conf conf).hasFlow(source, DataFlow::exprNode(sizeExpr)) -select arrayAccess.getIndexExpr(), + sizeExpr = sink.getNode().asExpr() and + any(Conf conf).hasFlowPath(source, sink) +select arrayAccess.getIndexExpr(), source, sink, "The $@ is accessed here, but the array is initialized using $@ which may be zero.", - arrayCreation, "array", source, "User-provided value" + arrayCreation, "array", source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql index e81181d8c4f3..32571c7f5408 100644 --- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql +++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql @@ -1,7 +1,7 @@ /** * @name Improper validation of user-provided array index * @description Using external input as an index to an array, without proper validation, can lead to index out of bound exceptions. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id java/improper-validation-of-array-index @@ -12,6 +12,7 @@ import java import ArraySizing import semmle.code.java.dataflow.FlowSources +import DataFlow::PathGraph class Conf extends TaintTracking::Configuration { Conf() { this = "RemoteUserInputTocanThrowOutOfBoundsDueToEmptyArrayConfig" } @@ -25,10 +26,10 @@ class Conf extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node.getType() instanceof BooleanType } } -from RemoteUserInput source, Expr index, CheckableArrayAccess arrayAccess +from DataFlow::PathNode source, DataFlow::PathNode sink, CheckableArrayAccess arrayAccess where - arrayAccess.canThrowOutOfBounds(index) and - any(Conf conf).hasFlow(source, DataFlow::exprNode(index)) -select arrayAccess.getIndexExpr(), - "$@ flows to here and is used as an index causing an ArrayIndexOutOfBoundsException.", source, - "User-provided value" + arrayAccess.canThrowOutOfBounds(sink.getNode().asExpr()) and + any(Conf conf).hasFlowPath(source, sink) +select arrayAccess.getIndexExpr(), source, sink, + "$@ flows to here and is used as an index causing an ArrayIndexOutOfBoundsException.", + source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql index 02099fafae04..9d0098cab637 100644 --- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql +++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql @@ -2,7 +2,7 @@ * @name Improper validation of code-specified array index * @description Using a code-specified value as an index to an array, without * proper validation, can lead to index out of bound exceptions. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/improper-validation-of-array-index-code-specified @@ -13,6 +13,7 @@ import java import ArraySizing import BoundingChecks +import DataFlow::PathGraph class BoundedFlowSourceConf extends DataFlow::Configuration { BoundedFlowSourceConf() { this = "BoundedFlowSource" } @@ -24,34 +25,34 @@ class BoundedFlowSourceConf extends DataFlow::Configuration { } } -from BoundedFlowSource source, Expr index, CheckableArrayAccess arrayAccess +from + DataFlow::PathNode source, DataFlow::PathNode sink, BoundedFlowSource boundedsource, + CheckableArrayAccess arrayAccess where - arrayAccess.canThrowOutOfBounds(index) and - any(BoundedFlowSourceConf conf).hasFlow(source, DataFlow::exprNode(index)) and - source != DataFlow::exprNode(index) and + arrayAccess.canThrowOutOfBounds(sink.getNode().asExpr()) and + boundedsource = source.getNode() and + any(BoundedFlowSourceConf conf).hasFlowPath(source, sink) and + boundedsource != sink.getNode() and not ( ( // The input has a lower bound. - source.lowerBound() >= 0 + boundedsource.lowerBound() >= 0 or // There is a condition dominating this expression ensuring that the index is >= 0. lowerBound(arrayAccess.getIndexExpr()) >= 0 ) and ( // The input has an upper bound, and the array has a fixed size, and that fixed size is less. - source.upperBound() < fixedArraySize(arrayAccess) + boundedsource.upperBound() < fixedArraySize(arrayAccess) or // There is a condition dominating this expression that ensures the index is less than the length. lessthanLength(arrayAccess) ) ) and - /* - * Exclude cases where the array is assigned multiple times. The checks for bounded flow sources - * can use fixed sizes for arrays, but this doesn't work well when the array is initialized to zero - * and subsequently reassigned or grown. - */ - + // Exclude cases where the array is assigned multiple times. The checks for bounded flow sources + // can use fixed sizes for arrays, but this doesn't work well when the array is initialized to zero + // and subsequently reassigned or grown. count(arrayAccess.getArray().(VarAccess).getVariable().getAnAssignedValue()) = 1 -select arrayAccess.getIndexExpr(), +select arrayAccess.getIndexExpr(), source, sink, "$@ flows to the index used in this array access, and may cause the operation to throw an ArrayIndexOutOfBoundsException.", - source, source.getDescription() + boundedsource, boundedsource.getDescription() diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexLocal.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexLocal.ql index df5977031915..37e68292f66a 100644 --- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexLocal.ql +++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexLocal.ql @@ -2,7 +2,7 @@ * @name Improper validation of local user-provided array index * @description Using local user input as an index to an array, without * proper validation, can lead to index out of bound exceptions. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/improper-validation-of-array-index-local @@ -13,6 +13,7 @@ import java import ArraySizing import semmle.code.java.dataflow.FlowSources +import DataFlow::PathGraph class Conf extends TaintTracking::Configuration { Conf() { this = "LocalUserInputTocanThrowOutOfBoundsDueToEmptyArrayConfig" } @@ -24,10 +25,10 @@ class Conf extends TaintTracking::Configuration { } } -from LocalUserInput source, Expr index, CheckableArrayAccess arrayAccess +from DataFlow::PathNode source, DataFlow::PathNode sink, CheckableArrayAccess arrayAccess where - arrayAccess.canThrowOutOfBounds(index) and - any(Conf conf).hasFlow(source, DataFlow::exprNode(index)) -select arrayAccess.getIndexExpr(), - "$@ flows to here and is used as an index causing an ArrayIndexOutOfBoundsException.", source, - "User-provided value" + arrayAccess.canThrowOutOfBounds(sink.getNode().asExpr()) and + any(Conf conf).hasFlowPath(source, sink) +select arrayAccess.getIndexExpr(), source, sink, + "$@ flows to here and is used as an index causing an ArrayIndexOutOfBoundsException.", + source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql b/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql index 06d680854af1..4251e275e0d4 100644 --- a/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql +++ b/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql @@ -1,7 +1,7 @@ /** * @name Use of externally-controlled format string * @description Using external input in format strings can lead to exceptions or information leaks. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/tainted-format-string @@ -12,6 +12,7 @@ import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.StringFormat +import DataFlow::PathGraph class ExternallyControlledFormatStringConfig extends TaintTracking::Configuration { ExternallyControlledFormatStringConfig() { this = "ExternallyControlledFormatStringConfig" } @@ -27,7 +28,9 @@ class ExternallyControlledFormatStringConfig extends TaintTracking::Configuratio } } -from RemoteUserInput source, StringFormat formatCall, ExternallyControlledFormatStringConfig conf -where conf.hasFlow(source, DataFlow::exprNode(formatCall.getFormatArgument())) -select formatCall.getFormatArgument(), "$@ flows to here and is used in a format string.", source, - "User-provided value" +from + DataFlow::PathNode source, DataFlow::PathNode sink, StringFormat formatCall, + ExternallyControlledFormatStringConfig conf +where conf.hasFlowPath(source, sink) and sink.getNode().asExpr() = formatCall.getFormatArgument() +select formatCall.getFormatArgument(), source, sink, + "$@ flows to here and is used in a format string.", source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql index 4fa8cc9e6b02..b607b0fcad59 100644 --- a/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql +++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql @@ -2,7 +2,7 @@ * @name User-controlled data in arithmetic expression * @description Arithmetic operations on user-controlled data that is not validated can cause * overflows. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id java/tainted-arithmetic @@ -14,6 +14,7 @@ import java import semmle.code.java.dataflow.FlowSources import ArithmeticCommon +import DataFlow::PathGraph predicate sink(ArithExpr exp, VarAccess tainted, string effect) { exp.getAnOperand() = tainted and @@ -39,10 +40,11 @@ class RemoteUserInputConfig extends TaintTracking::Configuration { } from - ArithExpr exp, VarAccess tainted, RemoteUserInput origin, string effect, + DataFlow::PathNode source, DataFlow::PathNode sink, ArithExpr exp, string effect, RemoteUserInputConfig conf where - conf.hasFlow(origin, DataFlow::exprNode(tainted)) and - sink(exp, tainted, effect) -select exp, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", - origin, "User-provided value" + conf.hasFlowPath(source, sink) and + sink(exp, sink.getNode().asExpr(), effect) +select exp, source, sink, + "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", + source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticTaintedLocal.ql index f4658b9ed140..dfd79c1abb4b 100644 --- a/java/ql/src/Security/CWE/CWE-190/ArithmeticTaintedLocal.ql +++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticTaintedLocal.ql @@ -2,7 +2,7 @@ * @name Local-user-controlled data in arithmetic expression * @description Arithmetic operations on user-controlled data that is not validated can cause * overflows. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/tainted-arithmetic-local @@ -14,6 +14,7 @@ import java import semmle.code.java.dataflow.FlowSources import ArithmeticCommon +import DataFlow::PathGraph predicate sink(ArithExpr exp, VarAccess tainted, string effect) { exp.getAnOperand() = tainted and @@ -38,9 +39,10 @@ class ArithmeticTaintedLocalFlowConfig extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node n) { n.getType() instanceof BooleanType } } -from ArithExpr exp, VarAccess tainted, LocalUserInput origin, string effect +from DataFlow::PathNode source, DataFlow::PathNode sink, ArithExpr exp, string effect where - any(ArithmeticTaintedLocalFlowConfig conf).hasFlow(origin, DataFlow::exprNode(tainted)) and - sink(exp, tainted, effect) -select exp, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", - origin, "User-provided value" + any(ArithmeticTaintedLocalFlowConfig conf).hasFlowPath(source, sink) and + sink(exp, sink.getNode().asExpr(), effect) +select exp, source, sink, + "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", + source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql index b91bc8921343..41ea9b6faf34 100644 --- a/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql +++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql @@ -2,7 +2,7 @@ * @name Uncontrolled data in arithmetic expression * @description Arithmetic operations on uncontrolled data that is not validated can cause * overflows. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id java/uncontrolled-arithmetic @@ -15,6 +15,7 @@ import java import semmle.code.java.dataflow.TaintTracking import semmle.code.java.security.SecurityTests import ArithmeticCommon +import DataFlow::PathGraph class TaintSource extends DataFlow::ExprNode { TaintSource() { @@ -68,10 +69,11 @@ class ArithmeticUncontrolledFlowConfig extends TaintTracking::Configuration { } from - ArithExpr exp, VarAccess tainted, TaintSource origin, string effect, + DataFlow::PathNode source, DataFlow::PathNode sink, ArithExpr exp, string effect, ArithmeticUncontrolledFlowConfig conf where - conf.hasFlow(origin, DataFlow::exprNode(tainted)) and - sink(exp, tainted, effect) -select exp, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", - origin, "Uncontrolled value" + conf.hasFlowPath(source, sink) and + sink(exp, sink.getNode().asExpr(), effect) +select exp, source, sink, + "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", + source.getNode(), "Uncontrolled value" diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql index e418b107918d..b32c04f0078e 100644 --- a/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql +++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql @@ -2,7 +2,7 @@ * @name Use of extreme values in arithmetic expression * @description If a variable is assigned the maximum or minimum value for that variable's type and * is then used in an arithmetic expression, this may result in an overflow. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/extreme-value-arithmetic @@ -15,6 +15,7 @@ import java import semmle.code.java.dataflow.DataFlow import ArithmeticCommon +import DataFlow::PathGraph abstract class ExtremeValueField extends Field { ExtremeValueField() { getType() instanceof IntegralType } @@ -53,24 +54,27 @@ predicate sink(ArithExpr exp, VarAccess use) { } predicate query( - ArithExpr exp, Variable v, ExtremeValueField f, VarAccess use, ExtremeSource s, Type t + DataFlow::PathNode source, DataFlow::PathNode sink, ArithExpr exp, Variable v, + ExtremeValueField f, VarAccess use, ExtremeSource s, Type t ) { // `use` is the use of `v` in `exp`. use = exp.getAnOperand() and use = v.getAnAccess() and // An extreme field flows to `use`. f = s.getVariable() and - any(ExtremeSourceFlowConfig conf).hasFlow(DataFlow::exprNode(s), DataFlow::exprNode(use)) and + any(ExtremeSourceFlowConfig conf).hasFlowPath(source, sink) and + s = source.getNode().asExpr() and + use = sink.getNode().asExpr() and t = s.getType() and // Division isn't a problem in this case. not exp instanceof DivExpr } from - ArithExpr exp, Variable v, ExtremeValueField f, VarAccess use, ExtremeSource s, string effect, - Type t + DataFlow::PathNode source, DataFlow::PathNode sink, ArithExpr exp, Variable v, + ExtremeValueField f, VarAccess use, ExtremeSource s, string effect, Type t where - query(exp, v, f, use, s, t) and + query(source, sink, exp, v, f, use, s, t) and // We're not guarded against the appropriate kind of flow error. ( f instanceof MinValueField and not guardedAgainstUnderflow(exp, use) and effect = "underflow" @@ -81,6 +85,6 @@ where // unless there is an enclosing cast down to a narrower type. narrowerThanOrEqualTo(exp, t) and not overflowIrrelevant(exp) -select exp, +select exp, source, sink, "Variable " + v.getName() + " is assigned an extreme value $@, and may cause an " + effect + ".", s, f.getName() diff --git a/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql b/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql index 3dbfd6081971..799ebdbe1593 100644 --- a/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql +++ b/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql @@ -1,7 +1,7 @@ /** * @name Failure to use HTTPS URLs * @description Non-HTTPS connections can be intercepted by third parties. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/non-https-url @@ -11,6 +11,7 @@ import java import semmle.code.java.dataflow.TaintTracking +import DataFlow::PathGraph class HTTPString extends StringLiteral { HTTPString() { @@ -73,8 +74,10 @@ class HTTPStringToURLOpenMethodFlowConfig extends TaintTracking::Configuration { } } -from MethodAccess m, HTTPString s +from DataFlow::PathNode source, DataFlow::PathNode sink, MethodAccess m, HTTPString s where - any(HTTPStringToURLOpenMethodFlowConfig c) - .hasFlow(DataFlow::exprNode(s), DataFlow::exprNode(m.getQualifier())) -select m, "URL may have been constructed with HTTP protocol, using $@.", s, "this source" + source.getNode().asExpr() = s and + sink.getNode().asExpr() = m.getQualifier() and + any(HTTPStringToURLOpenMethodFlowConfig c).hasFlowPath(source, sink) +select m, source, sink, "URL may have been constructed with HTTP protocol, using $@.", s, + "this source" diff --git a/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql index 53767eb8115f..384c24752cc7 100644 --- a/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql +++ b/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql @@ -1,7 +1,7 @@ /** * @name Use of a broken or risky cryptographic algorithm * @description Using broken or weak cryptographic algorithms can allow an attacker to compromise security. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id java/weak-cryptographic-algorithm @@ -13,6 +13,7 @@ import java import semmle.code.java.security.Encryption import semmle.code.java.dataflow.TaintTracking import DataFlow +import PathGraph private class ShortStringLiteral extends StringLiteral { ShortStringLiteral() { getLiteral().length() < 100 } @@ -38,8 +39,12 @@ class InsecureCryptoConfiguration extends TaintTracking::Configuration { } } -from CryptoAlgoSpec c, Expr a, BrokenAlgoLiteral s, InsecureCryptoConfiguration conf +from + PathNode source, PathNode sink, CryptoAlgoSpec c, BrokenAlgoLiteral s, + InsecureCryptoConfiguration conf where - a = c.getAlgoSpec() and - conf.hasFlow(exprNode(s), exprNode(a)) -select c, "Cryptographic algorithm $@ is weak and should not be used.", s, s.getLiteral() + sink.getNode().asExpr() = c.getAlgoSpec() and + source.getNode().asExpr() = s and + conf.hasFlowPath(source, sink) +select c, source, sink, "Cryptographic algorithm $@ is weak and should not be used.", s, + s.getLiteral() diff --git a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql index 26289e801c22..d8d4d7e36509 100644 --- a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql +++ b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql @@ -1,7 +1,7 @@ /** * @name Use of a potentially broken or risky cryptographic algorithm * @description Using broken or weak cryptographic algorithms can allow an attacker to compromise security. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id java/potentially-weak-cryptographic-algorithm @@ -14,6 +14,7 @@ import semmle.code.java.security.Encryption import semmle.code.java.dataflow.TaintTracking import DataFlow import semmle.code.java.dispatch.VirtualDispatch +import PathGraph private class ShortStringLiteral extends StringLiteral { ShortStringLiteral() { getLiteral().length() < 100 } @@ -63,9 +64,13 @@ class InsecureCryptoConfiguration extends TaintTracking::Configuration { } } -from CryptoAlgoSpec c, Expr a, InsecureAlgoLiteral s, InsecureCryptoConfiguration conf +from + PathNode source, PathNode sink, CryptoAlgoSpec c, InsecureAlgoLiteral s, + InsecureCryptoConfiguration conf where - a = c.getAlgoSpec() and - conf.hasFlow(exprNode(s), exprNode(a)) -select c, "Cryptographic algorithm $@ may not be secure, consider using a different algorithm.", s, + sink.getNode().asExpr() = c.getAlgoSpec() and + source.getNode().asExpr() = s and + conf.hasFlowPath(source, sink) +select c, source, sink, + "Cryptographic algorithm $@ may not be secure, consider using a different algorithm.", s, s.getLiteral() diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql index 551bde36711f..9d857203538b 100644 --- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql +++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql @@ -2,7 +2,7 @@ * @name Deserialization of user-controlled data * @description Deserializing user-controlled data may allow attackers to * execute arbitrary code. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/unsafe-deserialization @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.FlowSources import UnsafeDeserialization +import DataFlow::PathGraph class UnsafeDeserializationConfig extends TaintTracking::Configuration { UnsafeDeserializationConfig() { this = "UnsafeDeserializationConfig" } @@ -22,6 +23,7 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink } } -from UnsafeDeserializationSink sink, RemoteUserInput source, UnsafeDeserializationConfig conf -where conf.hasFlow(source, sink) -select sink.getMethodAccess(), "Unsafe deserialization of $@.", source, "user input" +from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeDeserializationConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode().(UnsafeDeserializationSink).getMethodAccess(), source, sink, + "Unsafe deserialization of $@.", source.getNode(), "user input" diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql index b7c96e929ea0..b343ae1e8a83 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql +++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql @@ -2,7 +2,7 @@ * @name URL redirection from remote source * @description URL redirection based on unvalidated user-input * may cause redirection to malicious web sites. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/unvalidated-url-redirection @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.FlowSources import UrlRedirect +import DataFlow::PathGraph class UrlRedirectConfig extends TaintTracking::Configuration { UrlRedirectConfig() { this = "UrlRedirectConfig" } @@ -22,6 +23,7 @@ class UrlRedirectConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof UrlRedirectSink } } -from UrlRedirectSink sink, RemoteUserInput source, UrlRedirectConfig conf -where conf.hasFlow(source, sink) -select sink, "Potentially untrusted URL redirection due to $@.", source, "user-provided value" +from DataFlow::PathNode source, DataFlow::PathNode sink, UrlRedirectConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Potentially untrusted URL redirection due to $@.", + source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql index 8a8c78039660..5f6421145307 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql +++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql @@ -2,7 +2,7 @@ * @name URL redirection from local source * @description URL redirection based on unvalidated user-input * may cause redirection to malicious web sites. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/unvalidated-url-redirection-local @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.FlowSources import UrlRedirect +import DataFlow::PathGraph class UrlRedirectLocalConfig extends TaintTracking::Configuration { UrlRedirectLocalConfig() { this = "UrlRedirectLocalConfig" } @@ -22,6 +23,7 @@ class UrlRedirectLocalConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof UrlRedirectSink } } -from UrlRedirectSink sink, LocalUserInput source, UrlRedirectLocalConfig conf -where conf.hasFlow(source, sink) -select sink, "Potentially untrusted URL redirection due to $@.", source, "user-provided value" +from DataFlow::PathNode source, DataFlow::PathNode sink, UrlRedirectLocalConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Potentially untrusted URL redirection due to $@.", + source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-611/XXE.ql b/java/ql/src/Security/CWE/CWE-611/XXE.ql index deb0c5108047..fba77e0640a3 100644 --- a/java/ql/src/Security/CWE/CWE-611/XXE.ql +++ b/java/ql/src/Security/CWE/CWE-611/XXE.ql @@ -2,7 +2,7 @@ * @name Resolving XML external entity in user-controlled data * @description Parsing user-controlled XML documents and allowing expansion of external entity * references may lead to disclosure of confidential data or denial of service. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/xxe @@ -13,6 +13,7 @@ import java import XmlParsers import semmle.code.java.dataflow.FlowSources +import DataFlow::PathGraph class SafeSAXSourceFlowConfig extends TaintTracking::Configuration2 { SafeSAXSourceFlowConfig() { this = "XmlParsers::SafeSAXSourceFlowConfig" } @@ -44,6 +45,7 @@ class XxeConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeXxeSink } } -from UnsafeXxeSink sink, RemoteUserInput source, XxeConfig conf -where conf.hasFlow(source, sink) -select sink, "Unsafe parsing of XML file from $@.", source, "user input" +from DataFlow::PathNode source, DataFlow::PathNode sink, XxeConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Unsafe parsing of XML file from $@.", source.getNode(), + "user input" diff --git a/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql b/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql index d22b8f6bfa76..840d11730703 100644 --- a/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql +++ b/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql @@ -2,7 +2,7 @@ * @name User-controlled data in numeric cast * @description Casting user-controlled numeric data to a narrower type without validation * can cause unexpected truncation. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/tainted-numeric-cast @@ -14,6 +14,7 @@ import java import semmle.code.java.dataflow.FlowSources import NumericCastCommon +import DataFlow::PathGraph private class NumericCastFlowConfig extends TaintTracking::Configuration { NumericCastFlowConfig() { this = "NumericCastTainted::RemoteUserInputToNumericNarrowingCastExpr" } @@ -34,11 +35,13 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration { } from - NumericNarrowingCastExpr exp, VarAccess tainted, RemoteUserInput origin, - NumericCastFlowConfig conf + DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp, + VarAccess tainted, NumericCastFlowConfig conf where exp.getExpr() = tainted and - conf.hasFlow(origin, DataFlow::exprNode(tainted)) and + sink.getNode().asExpr() = tainted and + conf.hasFlowPath(source, sink) and not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable()) -select exp, "$@ flows to here and is cast to a narrower type, potentially causing truncation.", - origin, "User-provided value" +select exp, source, sink, + "$@ flows to here and is cast to a narrower type, potentially causing truncation.", + source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-681/NumericCastTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-681/NumericCastTaintedLocal.ql index 23ac0cb11844..9dadb0ae4432 100644 --- a/java/ql/src/Security/CWE/CWE-681/NumericCastTaintedLocal.ql +++ b/java/ql/src/Security/CWE/CWE-681/NumericCastTaintedLocal.ql @@ -2,7 +2,7 @@ * @name Local-user-controlled data in numeric cast * @description Casting user-controlled numeric data to a narrower type without validation * can cause unexpected truncation. - * @kind problem + * @kind path-problem * @problem.severity recommendation * @precision medium * @id java/tainted-numeric-cast-local @@ -14,6 +14,7 @@ import java import semmle.code.java.dataflow.FlowSources import NumericCastCommon +import DataFlow::PathGraph private class NumericCastFlowConfig extends TaintTracking::Configuration { NumericCastFlowConfig() { @@ -36,10 +37,13 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration { } from - NumericNarrowingCastExpr exp, VarAccess tainted, LocalUserInput origin, NumericCastFlowConfig conf + DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp, + VarAccess tainted, NumericCastFlowConfig conf where exp.getExpr() = tainted and - conf.hasFlow(origin, DataFlow::exprNode(tainted)) and + sink.getNode().asExpr() = tainted and + conf.hasFlowPath(source, sink) and not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable()) -select exp, "$@ flows to here and is cast to a narrower type, potentially causing truncation.", - origin, "User-provided value" +select exp, source, sink, + "$@ flows to here and is cast to a narrower type, potentially causing truncation.", + source.getNode(), "User-provided value" diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql index 478ee9375764..86b303750192 100644 --- a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql +++ b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql @@ -1,7 +1,7 @@ /** * @name Hard-coded credential in API call * @description Using a hard-coded credential in a call to a sensitive Java API may compromise security. - * @kind problem + * @kind path-problem * @problem.severity error * @precision medium * @id java/hardcoded-credential-api-call @@ -12,6 +12,7 @@ import java import semmle.code.java.dataflow.DataFlow import HardcodedCredentials +import DataFlow::PathGraph class HardcodedCredentialApiCallConfiguration extends DataFlow::Configuration { HardcodedCredentialApiCallConfiguration() { this = "HardcodedCredentialApiCallConfiguration" } @@ -32,6 +33,8 @@ class HardcodedCredentialApiCallConfiguration extends DataFlow::Configuration { } } -from CredentialsApiSink sink, HardcodedExpr source, HardcodedCredentialApiCallConfiguration conf -where conf.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink)) -select source, "Hard-coded value flows to $@.", sink, "sensitive API call" +from + DataFlow::PathNode source, DataFlow::PathNode sink, HardcodedCredentialApiCallConfiguration conf +where conf.hasFlowPath(source, sink) +select source.getNode(), source, sink, "Hard-coded value flows to $@.", sink.getNode(), + "sensitive API call" diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql index c2ec2a54dde8..93d0dde665a4 100644 --- a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql +++ b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql @@ -1,7 +1,7 @@ /** * @name Hard-coded credential in sensitive call * @description Using a hard-coded credential in a sensitive call may compromise security. - * @kind problem + * @kind path-problem * @problem.severity error * @precision low * @id java/hardcoded-credential-sensitive-call @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.DataFlow2 import HardcodedCredentials +import DataFlow::PathGraph class HardcodedCredentialSourceCallConfiguration extends DataFlow::Configuration { HardcodedCredentialSourceCallConfiguration() { @@ -45,7 +46,8 @@ class FinalCredentialsSourceSink extends CredentialsSourceSink { } from - FinalCredentialsSourceSink sink, HardcodedExpr source, + DataFlow::PathNode source, DataFlow::PathNode sink, HardcodedCredentialSourceCallConfiguration conf -where conf.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink)) -select source, "Hard-coded value flows to $@.", sink, "sensitive call" +where conf.hasFlowPath(source, sink) +select source.getNode(), source, sink, "Hard-coded value flows to $@.", sink.getNode(), + "sensitive call" diff --git a/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql b/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql index 5259bcc6bd83..beb40d86d718 100644 --- a/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql +++ b/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql @@ -2,7 +2,7 @@ * @name User-controlled bypass of sensitive method * @description User-controlled bypassing of sensitive methods may allow attackers to avoid * passing through authentication systems. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/user-controlled-bypass @@ -16,6 +16,7 @@ import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.SensitiveActions import semmle.code.java.controlflow.Dominance import semmle.code.java.controlflow.Guards +import DataFlow::PathGraph /** * Calls to a sensitive method that are controlled by a condition @@ -38,9 +39,13 @@ class ConditionalBypassFlowConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { conditionControlsMethod(_, sink.asExpr()) } } -from UserInput u, MethodAccess m, Expr e, ConditionalBypassFlowConfig conf +from + DataFlow::PathNode source, DataFlow::PathNode sink, MethodAccess m, Expr e, + ConditionalBypassFlowConfig conf where conditionControlsMethod(m, e) and - conf.hasFlow(u, DataFlow::exprNode(e)) -select m, "Sensitive method may not be executed depending on $@, which flows from $@.", e, - "this condition", u, "user input" + sink.getNode().asExpr() = e and + conf.hasFlowPath(source, sink) +select m, source, sink, + "Sensitive method may not be executed depending on $@, which flows from $@.", e, "this condition", + source.getNode(), "user input" diff --git a/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql b/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql index aac0f1cc4146..60dfbd6fc8c3 100644 --- a/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql +++ b/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql @@ -2,7 +2,7 @@ * @name User-controlled data used in permissions check * @description Using user-controlled data in a permissions check may result in inappropriate * permissions being granted. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id java/tainted-permissions-check @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.FlowSources +import DataFlow::PathGraph class TypeShiroSubject extends RefType { TypeShiroSubject() { this.getQualifiedName() = "org.apache.shiro.subject.Subject" } @@ -58,6 +59,8 @@ class TaintedPermissionsCheckFlowConfig extends TaintTracking::Configuration { } } -from UserInput u, PermissionsConstruction p, TaintedPermissionsCheckFlowConfig conf -where conf.hasFlow(u, DataFlow::exprNode(p.getInput())) -select p, "Permissions check uses user-controlled $@.", u, "data" +from + DataFlow::PathNode source, DataFlow::PathNode sink, PermissionsConstruction p, + TaintedPermissionsCheckFlowConfig conf +where sink.getNode().asExpr() = p.getInput() and conf.hasFlowPath(source, sink) +select p, source, sink, "Permissions check uses user-controlled $@.", source.getNode(), "data" From deb61d6f296a6834531bf822118577d59df8d5a0 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 15 Nov 2018 14:39:46 +0100 Subject: [PATCH 63/68] Java: Update test output. --- .../CWE-022/semmle/tests/TaintedPath.expected | 11 +- .../CWE-022/semmle/tests/ZipSlip.expected | 11 +- .../CWE-079/semmle/tests/XSS.expected | 14 +- .../semmle/examples/SqlTaintedLocal.expected | 18 +- .../semmle/tests/ResponseSplitting.expected | 11 +- ...nOfArrayConstructionCodeSpecified.expected | 5 +- ...alidationOfArrayConstructionLocal.expected | 8 +- ...lidationOfArrayIndexCodeSpecified.expected | 13 +- ...properValidationOfArrayIndexLocal.expected | 5 +- .../ExternallyControlledFormatString.expected | 7 +- .../tests/ArithmeticTaintedLocal.expected | 41 ++- .../tests/ArithmeticUncontrolled.expected | 8 +- .../ArithmeticWithExtremeValues.expected | 30 +- .../tests/BrokenCryptoAlgorithm.expected | 8 +- .../tests/MaybeBrokenCryptoAlgorithm.expected | 5 +- .../CWE-502/UnsafeDeserialization.expected | 56 ++-- .../CWE-601/semmle/tests/UrlRedirect.expected | 14 +- .../query-tests/security/CWE-611/XXE.expected | 284 ++++++++++++------ .../tests/NumericCastTaintedLocal.expected | 5 +- .../HardcodedCredentialsApiCall.expected | 66 ++-- .../HardcodedCredentialsSourceCall.expected | 8 +- .../semmle/tests/ConditionalBypass.expected | 19 +- .../tests/TaintedPermissionsCheck.expected | 5 +- 23 files changed, 463 insertions(+), 189 deletions(-) diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.expected b/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.expected index bcab22f08f0c..fa1c155857b5 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.expected +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.expected @@ -1,3 +1,8 @@ -| Test.java:24:11:24:24 | new File(...) | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | -| Test.java:27:11:27:25 | get(...) | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | -| Test.java:30:11:30:48 | getPath(...) | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | +edges +| Test.java:19:18:19:38 | getHostName(...) [String] | Test.java:24:20:24:23 | temp | +| Test.java:19:18:19:38 | getHostName(...) [String] | Test.java:27:21:27:24 | temp | +| Test.java:19:18:19:38 | getHostName(...) [String] | Test.java:30:44:30:47 | temp | +#select +| Test.java:24:11:24:24 | new File(...) | Test.java:19:18:19:38 | getHostName(...) [String] | Test.java:24:20:24:23 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | +| Test.java:27:11:27:25 | get(...) | Test.java:19:18:19:38 | getHostName(...) [String] | Test.java:27:21:27:24 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | +| Test.java:30:11:30:48 | getPath(...) | Test.java:19:18:19:38 | getHostName(...) [String] | Test.java:30:44:30:47 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.expected b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.expected index 3bfa3aaebe82..8d6b9bc86084 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.expected +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.expected @@ -1,3 +1,8 @@ -| ZipTest.java:7:19:7:33 | getName(...) | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:9:48:9:51 | file | file system operation | -| ZipTest.java:7:19:7:33 | getName(...) | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:10:49:10:52 | file | file system operation | -| ZipTest.java:7:19:7:33 | getName(...) | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:11:36:11:39 | file | file system operation | +edges +| ZipTest.java:7:19:7:33 | getName(...) [String] | ZipTest.java:9:48:9:51 | file | +| ZipTest.java:7:19:7:33 | getName(...) [String] | ZipTest.java:10:49:10:52 | file | +| ZipTest.java:7:19:7:33 | getName(...) [String] | ZipTest.java:11:36:11:39 | file | +#select +| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) [String] | ZipTest.java:9:48:9:51 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:9:48:9:51 | file | file system operation | +| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) [String] | ZipTest.java:10:49:10:52 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:10:49:10:52 | file | file system operation | +| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) [String] | ZipTest.java:11:36:11:39 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:11:36:11:39 | file | file system operation | diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected b/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected index 293e81c6cd13..783b599c312e 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected @@ -1,4 +1,10 @@ -| XSS.java:23:5:23:70 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:23:21:23:48 | getParameter(...) | user-provided value | -| XSS.java:27:5:27:70 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:27:21:27:48 | getParameter(...) | user-provided value | -| XSS.java:38:30:38:87 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:38:67:38:87 | getPathInfo(...) | user-provided value | -| XSS.java:41:36:41:67 | getBytes(...) | Cross-site scripting vulnerability due to $@. | XSS.java:41:36:41:56 | getPathInfo(...) | user-provided value | +edges +| XSS.java:23:21:23:48 | getParameter(...) [String] | XSS.java:23:5:23:70 | ... + ... | +| XSS.java:27:21:27:48 | getParameter(...) [String] | XSS.java:27:5:27:70 | ... + ... | +| XSS.java:38:67:38:87 | getPathInfo(...) [String] | XSS.java:38:30:38:87 | ... + ... | +| XSS.java:41:36:41:56 | getPathInfo(...) [String] | XSS.java:41:36:41:67 | getBytes(...) | +#select +| XSS.java:23:5:23:70 | ... + ... | XSS.java:23:21:23:48 | getParameter(...) [String] | XSS.java:23:5:23:70 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:23:21:23:48 | getParameter(...) | user-provided value | +| XSS.java:27:5:27:70 | ... + ... | XSS.java:27:21:27:48 | getParameter(...) [String] | XSS.java:27:5:27:70 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:27:21:27:48 | getParameter(...) | user-provided value | +| XSS.java:38:30:38:87 | ... + ... | XSS.java:38:67:38:87 | getPathInfo(...) [String] | XSS.java:38:30:38:87 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:38:67:38:87 | getPathInfo(...) | user-provided value | +| XSS.java:41:36:41:67 | getBytes(...) | XSS.java:41:36:41:56 | getPathInfo(...) [String] | XSS.java:41:36:41:67 | getBytes(...) | Cross-site scripting vulnerability due to $@. | XSS.java:41:36:41:56 | getPathInfo(...) | user-provided value | diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected index 0e14f76fbec7..7fc66dfe5417 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected @@ -1,4 +1,14 @@ -| Test.java:36:47:36:52 | query1 | Query might include code from $@. | Test.java:190:26:190:38 | args | this user input | -| Test.java:44:62:44:67 | query3 | Query might include code from $@. | Test.java:190:26:190:38 | args | this user input | -| Test.java:56:47:56:61 | querySbToString | Query might include code from $@. | Test.java:190:26:190:38 | args | this user input | -| Test.java:186:47:186:68 | queryWithUserTableName | Query might include code from $@. | Test.java:190:26:190:38 | args | this user input | +edges +| Test.java:29:30:29:42 | args [String[]] | Test.java:36:47:36:52 | query1 | +| Test.java:29:30:29:42 | args [String[]] | Test.java:44:62:44:67 | query3 | +| Test.java:29:30:29:42 | args [String[]] | Test.java:56:47:56:61 | querySbToString | +| Test.java:160:33:160:45 | args [String[]] | Test.java:186:47:186:68 | queryWithUserTableName | +| Test.java:190:26:190:38 | args [String[]] | Test.java:191:11:191:14 | args [String[]] | +| Test.java:190:26:190:38 | args [String[]] | Test.java:195:14:195:17 | args [String[]] | +| Test.java:191:11:191:14 | args [String[]] | Test.java:29:30:29:42 | args [String[]] | +| Test.java:195:14:195:17 | args [String[]] | Test.java:160:33:160:45 | args [String[]] | +#select +| Test.java:36:47:36:52 | query1 | Test.java:190:26:190:38 | args [String[]] | Test.java:36:47:36:52 | query1 | Query might include code from $@. | Test.java:190:26:190:38 | args | this user input | +| Test.java:44:62:44:67 | query3 | Test.java:190:26:190:38 | args [String[]] | Test.java:44:62:44:67 | query3 | Query might include code from $@. | Test.java:190:26:190:38 | args | this user input | +| Test.java:56:47:56:61 | querySbToString | Test.java:190:26:190:38 | args [String[]] | Test.java:56:47:56:61 | querySbToString | Query might include code from $@. | Test.java:190:26:190:38 | args | this user input | +| Test.java:186:47:186:68 | queryWithUserTableName | Test.java:190:26:190:38 | args [String[]] | Test.java:186:47:186:68 | queryWithUserTableName | Query might include code from $@. | Test.java:190:26:190:38 | args | this user input | diff --git a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.expected b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.expected index bde977b5f2ed..08860eb220a5 100644 --- a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.expected +++ b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.expected @@ -1,3 +1,8 @@ -| ResponseSplitting.java:23:23:23:28 | cookie | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:22:39:22:66 | getParameter(...) | user-provided value | -| ResponseSplitting.java:28:38:28:72 | getParameter(...) | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:28:38:28:72 | getParameter(...) | user-provided value | -| ResponseSplitting.java:29:38:29:72 | getParameter(...) | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:29:38:29:72 | getParameter(...) | user-provided value | +edges +| ResponseSplitting.java:22:39:22:66 | getParameter(...) [String] | ResponseSplitting.java:23:23:23:28 | cookie | +| ResponseSplitting.java:28:38:28:72 | getParameter(...) [String] | ResponseSplitting.java:28:38:28:72 | getParameter(...) | +| ResponseSplitting.java:29:38:29:72 | getParameter(...) [String] | ResponseSplitting.java:29:38:29:72 | getParameter(...) | +#select +| ResponseSplitting.java:23:23:23:28 | cookie | ResponseSplitting.java:22:39:22:66 | getParameter(...) [String] | ResponseSplitting.java:23:23:23:28 | cookie | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:22:39:22:66 | getParameter(...) | user-provided value | +| ResponseSplitting.java:28:38:28:72 | getParameter(...) | ResponseSplitting.java:28:38:28:72 | getParameter(...) [String] | ResponseSplitting.java:28:38:28:72 | getParameter(...) | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:28:38:28:72 | getParameter(...) | user-provided value | +| ResponseSplitting.java:29:38:29:72 | getParameter(...) | ResponseSplitting.java:29:38:29:72 | getParameter(...) [String] | ResponseSplitting.java:29:38:29:72 | getParameter(...) | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:29:38:29:72 | getParameter(...) | user-provided value | diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.expected index 5bd722ef5cbc..e97efe4d4d3c 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.expected +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.expected @@ -1 +1,4 @@ -| Test.java:91:30:91:30 | 0 | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:88:19:88:31 | new int[] | array | Test.java:86:16:86:16 | 0 | literal value 0 | +edges +| Test.java:86:16:86:16 | 0 [Number] | Test.java:88:27:88:30 | size | +#select +| Test.java:91:30:91:30 | 0 | Test.java:86:16:86:16 | 0 [Number] | Test.java:88:27:88:30 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:88:19:88:31 | new int[] | array | Test.java:86:16:86:16 | 0 | literal value 0 | diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected index 9f9272ac515f..250c1eeb76ed 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected @@ -1,2 +1,6 @@ -| Test.java:64:34:64:34 | 0 | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:61:23:61:35 | new int[] | array | Test.java:57:27:57:60 | getProperty(...) | User-provided value | -| Test.java:70:37:70:37 | 0 | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:67:26:67:38 | new int[] | array | Test.java:57:27:57:60 | getProperty(...) | User-provided value | +edges +| Test.java:57:27:57:60 | getProperty(...) [String] | Test.java:61:31:61:34 | size | +| Test.java:57:27:57:60 | getProperty(...) [String] | Test.java:67:34:67:37 | size | +#select +| Test.java:64:34:64:34 | 0 | Test.java:57:27:57:60 | getProperty(...) [String] | Test.java:61:31:61:34 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:61:23:61:35 | new int[] | array | Test.java:57:27:57:60 | getProperty(...) | User-provided value | +| Test.java:70:37:70:37 | 0 | Test.java:57:27:57:60 | getProperty(...) [String] | Test.java:67:34:67:37 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:67:26:67:38 | new int[] | array | Test.java:57:27:57:60 | getProperty(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.expected index e1f31a5f8dc7..ab7e75ea1b61 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.expected +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.expected @@ -1 +1,12 @@ -| Test.java:43:30:43:34 | index | $@ flows to the index used in this array access, and may cause the operation to throw an ArrayIndexOutOfBoundsException. | Test.java:40:17:40:48 | nextInt(...) | Random value | +edges +| Test.java:40:17:40:48 | nextInt(...) [Number] | Test.java:43:30:43:34 | index | +| Test.java:40:17:40:48 | nextInt(...) [Number] | Test.java:47:32:47:36 | index | +| Test.java:40:17:40:48 | nextInt(...) [Number] | Test.java:51:39:51:43 | index | +| Test.java:64:34:64:34 | 0 [Number] | Test.java:64:34:64:34 | 0 | +| Test.java:70:37:70:37 | 0 [Number] | Test.java:70:37:70:37 | 0 | +| Test.java:77:39:77:39 | 0 [Number] | Test.java:77:39:77:39 | 0 | +| Test.java:91:30:91:30 | 0 [Number] | Test.java:91:30:91:30 | 0 | +| Test.java:93:17:93:17 | 0 [Number] | Test.java:96:32:96:36 | index | +| Test.java:102:30:102:30 | 0 [Number] | Test.java:102:30:102:30 | 0 | +#select +| Test.java:43:30:43:34 | index | Test.java:40:17:40:48 | nextInt(...) [Number] | Test.java:43:30:43:34 | index | $@ flows to the index used in this array access, and may cause the operation to throw an ArrayIndexOutOfBoundsException. | Test.java:40:17:40:48 | nextInt(...) | Random value | diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected index 20223404d614..0ea9b6f7d3d5 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected @@ -1 +1,4 @@ -| Test.java:18:34:18:38 | index | $@ flows to here and is used as an index causing an ArrayIndexOutOfBoundsException. | Test.java:13:27:13:60 | getProperty(...) | User-provided value | +edges +| Test.java:13:27:13:60 | getProperty(...) [String] | Test.java:18:34:18:38 | index | +#select +| Test.java:18:34:18:38 | index | Test.java:13:27:13:60 | getProperty(...) [String] | Test.java:18:34:18:38 | index | $@ flows to here and is used as an index causing an ArrayIndexOutOfBoundsException. | Test.java:13:27:13:60 | getProperty(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.expected b/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.expected index 35b460ae9b9e..a843797fcc17 100644 --- a/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.expected +++ b/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.expected @@ -1 +1,6 @@ -| Test.java:39:25:39:30 | format | $@ flows to here and is used in a format string. | Test.java:33:30:33:74 | getParameter(...) | User-provided value | +edges +| Test.java:33:30:33:74 | getParameter(...) [String] | Test.java:34:20:34:32 | userParameter [String] | +| Test.java:34:20:34:32 | userParameter [String] | Test.java:37:31:37:43 | format [String] | +| Test.java:37:31:37:43 | format [String] | Test.java:39:25:39:30 | format | +#select +| Test.java:39:25:39:30 | format | Test.java:33:30:33:74 | getParameter(...) [String] | Test.java:39:25:39:30 | format | $@ flows to here and is used in a format string. | Test.java:33:30:33:74 | getParameter(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected index 64a964a8882e..a292ffe24745 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected @@ -1,9 +1,32 @@ -| ArithmeticTainted.java:32:17:32:25 | ... + ... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:40:17:40:25 | ... - ... | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:50:17:50:24 | ... + ... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:71:17:71:27 | ... + ... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:95:37:95:46 | ... + ... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:127:3:127:8 | ...++ | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:131:3:131:8 | ++... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:135:3:135:8 | ...-- | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:139:3:139:8 | --... | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +edges +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:32:17:32:20 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:40:17:40:20 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:50:17:50:20 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:64:20:64:23 | data [Number] | +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:95:37:95:40 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:118:9:118:12 | data [Number] | +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:119:10:119:13 | data [Number] | +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:120:10:120:13 | data [Number] | +| ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:121:10:121:13 | data [Number] | +| ArithmeticTainted.java:64:4:64:10 | tainted [post update] [dat, ... (1)] | ArithmeticTainted.java:66:18:66:24 | tainted [dat, ... (1)] | +| ArithmeticTainted.java:64:20:64:23 | data [Number] | ArithmeticTainted.java:64:4:64:10 | tainted [post update] [dat, ... (1)] | +| ArithmeticTainted.java:66:18:66:24 | tainted [dat, ... (1)] | ArithmeticTainted.java:66:18:66:34 | getData(...) [Number] | +| ArithmeticTainted.java:66:18:66:34 | getData(...) [Number] | ArithmeticTainted.java:71:17:71:23 | herring | +| ArithmeticTainted.java:118:9:118:12 | data [Number] | ArithmeticTainted.java:125:26:125:33 | data [Number] | +| ArithmeticTainted.java:119:10:119:13 | data [Number] | ArithmeticTainted.java:129:27:129:34 | data [Number] | +| ArithmeticTainted.java:120:10:120:13 | data [Number] | ArithmeticTainted.java:133:27:133:34 | data [Number] | +| ArithmeticTainted.java:121:10:121:13 | data [Number] | ArithmeticTainted.java:137:27:137:34 | data [Number] | +| ArithmeticTainted.java:125:26:125:33 | data [Number] | ArithmeticTainted.java:127:3:127:6 | data | +| ArithmeticTainted.java:129:27:129:34 | data [Number] | ArithmeticTainted.java:131:5:131:8 | data | +| ArithmeticTainted.java:133:27:133:34 | data [Number] | ArithmeticTainted.java:135:3:135:6 | data | +| ArithmeticTainted.java:137:27:137:34 | data [Number] | ArithmeticTainted.java:139:5:139:8 | data | +#select +| ArithmeticTainted.java:32:17:32:25 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:32:17:32:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:40:17:40:25 | ... - ... | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:40:17:40:20 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:50:17:50:24 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:50:17:50:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:71:17:71:27 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:71:17:71:23 | herring | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:95:37:95:46 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:95:37:95:40 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:127:3:127:8 | ...++ | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:127:3:127:6 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:131:3:131:8 | ++... | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:131:5:131:8 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:135:3:135:8 | ...-- | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:135:3:135:6 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:139:3:139:8 | --... | ArithmeticTainted.java:17:46:17:54 | System.in [InputStream] | ArithmeticTainted.java:139:5:139:8 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.expected b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.expected index d43c9445d1f3..a94a48a3707a 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.expected +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.expected @@ -1,2 +1,6 @@ -| Test.java:209:17:209:24 | ... + ... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | Test.java:205:14:205:57 | nextInt(...) | Uncontrolled value | -| Test.java:240:37:240:46 | ... + ... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | Test.java:205:14:205:57 | nextInt(...) | Uncontrolled value | +edges +| Test.java:205:14:205:57 | nextInt(...) [Number] | Test.java:209:17:209:20 | data | +| Test.java:205:14:205:57 | nextInt(...) [Number] | Test.java:240:37:240:40 | data | +#select +| Test.java:209:17:209:24 | ... + ... | Test.java:205:14:205:57 | nextInt(...) [Number] | Test.java:209:17:209:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | Test.java:205:14:205:57 | nextInt(...) | Uncontrolled value | +| Test.java:240:37:240:46 | ... + ... | Test.java:205:14:205:57 | nextInt(...) [Number] | Test.java:240:37:240:40 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | Test.java:205:14:205:57 | nextInt(...) | Uncontrolled value | diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.expected b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.expected index d55dbcaaf0e4..e0a8192ee294 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.expected +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.expected @@ -1,8 +1,22 @@ -| Test.java:95:8:95:12 | ... + ... | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:92:8:92:24 | Integer.MAX_VALUE | MAX_VALUE | -| Test.java:110:13:110:17 | ... - ... | Variable i is assigned an extreme value $@, and may cause an underflow. | Test.java:108:13:108:26 | Long.MIN_VALUE | MIN_VALUE | -| Test.java:138:14:138:18 | ... + ... | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:137:9:137:25 | Integer.MAX_VALUE | MAX_VALUE | -| Test.java:146:14:146:18 | ... + ... | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:143:12:143:28 | Integer.MAX_VALUE | MAX_VALUE | -| Test.java:155:14:155:18 | ... + ... | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:151:12:151:28 | Integer.MAX_VALUE | MAX_VALUE | -| Test.java:187:39:187:43 | ... + ... | Variable b is assigned an extreme value $@, and may cause an overflow. | Test.java:184:13:184:26 | Byte.MAX_VALUE | MAX_VALUE | -| Test.java:194:41:194:45 | ... + ... | Variable s is assigned an extreme value $@, and may cause an overflow. | Test.java:191:14:191:28 | Short.MAX_VALUE | MAX_VALUE | -| Test.java:201:37:201:42 | ... + ... | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:198:12:198:28 | Integer.MAX_VALUE | MAX_VALUE | +edges +| Test.java:92:8:92:24 | Integer.MAX_VALUE [Number] | Test.java:95:8:95:8 | i | +| Test.java:108:13:108:26 | Long.MIN_VALUE [Number] | Test.java:110:13:110:13 | i | +| Test.java:114:13:114:26 | Long.MAX_VALUE [Number] | Test.java:116:13:116:13 | i | +| Test.java:137:9:137:25 | Integer.MAX_VALUE [Number] | Test.java:138:14:138:14 | i | +| Test.java:143:12:143:28 | Integer.MAX_VALUE [Number] | Test.java:146:14:146:14 | i | +| Test.java:151:12:151:28 | Integer.MAX_VALUE [Number] | Test.java:155:14:155:14 | i | +| Test.java:160:13:160:26 | Byte.MAX_VALUE [Number] | Test.java:164:12:164:12 | b | +| Test.java:168:14:168:28 | Short.MAX_VALUE [Number] | Test.java:172:12:172:12 | s | +| Test.java:176:12:176:28 | Integer.MAX_VALUE [Number] | Test.java:180:13:180:13 | i | +| Test.java:184:13:184:26 | Byte.MAX_VALUE [Number] | Test.java:187:39:187:39 | b | +| Test.java:191:14:191:28 | Short.MAX_VALUE [Number] | Test.java:194:41:194:41 | s | +| Test.java:198:12:198:28 | Integer.MAX_VALUE [Number] | Test.java:201:37:201:37 | i | +#select +| Test.java:95:8:95:12 | ... + ... | Test.java:92:8:92:24 | Integer.MAX_VALUE [Number] | Test.java:95:8:95:8 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:92:8:92:24 | Integer.MAX_VALUE | MAX_VALUE | +| Test.java:110:13:110:17 | ... - ... | Test.java:108:13:108:26 | Long.MIN_VALUE [Number] | Test.java:110:13:110:13 | i | Variable i is assigned an extreme value $@, and may cause an underflow. | Test.java:108:13:108:26 | Long.MIN_VALUE | MIN_VALUE | +| Test.java:138:14:138:18 | ... + ... | Test.java:137:9:137:25 | Integer.MAX_VALUE [Number] | Test.java:138:14:138:14 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:137:9:137:25 | Integer.MAX_VALUE | MAX_VALUE | +| Test.java:146:14:146:18 | ... + ... | Test.java:143:12:143:28 | Integer.MAX_VALUE [Number] | Test.java:146:14:146:14 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:143:12:143:28 | Integer.MAX_VALUE | MAX_VALUE | +| Test.java:155:14:155:18 | ... + ... | Test.java:151:12:151:28 | Integer.MAX_VALUE [Number] | Test.java:155:14:155:14 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:151:12:151:28 | Integer.MAX_VALUE | MAX_VALUE | +| Test.java:187:39:187:43 | ... + ... | Test.java:184:13:184:26 | Byte.MAX_VALUE [Number] | Test.java:187:39:187:39 | b | Variable b is assigned an extreme value $@, and may cause an overflow. | Test.java:184:13:184:26 | Byte.MAX_VALUE | MAX_VALUE | +| Test.java:194:41:194:45 | ... + ... | Test.java:191:14:191:28 | Short.MAX_VALUE [Number] | Test.java:194:41:194:41 | s | Variable s is assigned an extreme value $@, and may cause an overflow. | Test.java:191:14:191:28 | Short.MAX_VALUE | MAX_VALUE | +| Test.java:201:37:201:42 | ... + ... | Test.java:198:12:198:28 | Integer.MAX_VALUE [Number] | Test.java:201:37:201:37 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:198:12:198:28 | Integer.MAX_VALUE | MAX_VALUE | diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected index 42492272df0f..29dfbb3bee1b 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected @@ -1,2 +1,6 @@ -| Test.java:19:20:19:50 | getInstance(...) | Cryptographic algorithm $@ is weak and should not be used. | Test.java:19:45:19:49 | "DES" | "DES" | -| Test.java:42:14:42:38 | getInstance(...) | Cryptographic algorithm $@ is weak and should not be used. | Test.java:42:33:42:37 | "RC2" | "RC2" | +edges +| Test.java:19:45:19:49 | "DES" [String] | Test.java:19:45:19:49 | "DES" | +| Test.java:42:33:42:37 | "RC2" [String] | Test.java:42:33:42:37 | "RC2" | +#select +| Test.java:19:20:19:50 | getInstance(...) | Test.java:19:45:19:49 | "DES" [String] | Test.java:19:45:19:49 | "DES" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:19:45:19:49 | "DES" | "DES" | +| Test.java:42:14:42:38 | getInstance(...) | Test.java:42:33:42:37 | "RC2" [String] | Test.java:42:33:42:37 | "RC2" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:42:33:42:37 | "RC2" | "RC2" | diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.expected b/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.expected index 13acd5a22bb1..b0f956155c4b 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.expected +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.expected @@ -1 +1,4 @@ -| Test.java:34:21:34:53 | new SecretKeySpec(...) | Cryptographic algorithm $@ may not be secure, consider using a different algorithm. | Test.java:34:48:34:52 | "foo" | "foo" | +edges +| Test.java:34:48:34:52 | "foo" [String] | Test.java:34:48:34:52 | "foo" | +#select +| Test.java:34:21:34:53 | new SecretKeySpec(...) | Test.java:34:48:34:52 | "foo" [String] | Test.java:34:48:34:52 | "foo" | Cryptographic algorithm $@ may not be secure, consider using a different algorithm. | Test.java:34:48:34:52 | "foo" | "foo" | diff --git a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected index b0dde770e099..545a8644ee81 100644 --- a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected +++ b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected @@ -1,18 +1,38 @@ -| A.java:15:12:15:26 | readObject(...) | Unsafe deserialization of $@. | A.java:13:31:13:51 | getInputStream(...) | user input | -| A.java:21:12:21:28 | readUnshared(...) | Unsafe deserialization of $@. | A.java:19:31:19:51 | getInputStream(...) | user input | -| A.java:27:12:27:25 | readObject(...) | Unsafe deserialization of $@. | A.java:25:31:25:51 | getInputStream(...) | user input | -| A.java:34:12:34:29 | fromXML(...) | Unsafe deserialization of $@. | A.java:32:31:32:51 | getInputStream(...) | user input | -| A.java:40:12:40:42 | readObject(...) | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | -| A.java:41:12:41:48 | readObjectOrNull(...) | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | -| A.java:42:16:42:45 | readClassAndObject(...) | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | -| A.java:61:16:61:31 | load(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:62:17:62:35 | loadAll(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:63:17:63:56 | parse(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:64:12:64:38 | loadAs(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:65:12:65:61 | loadAs(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:71:16:71:31 | load(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| A.java:72:17:72:35 | loadAll(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| A.java:73:17:73:56 | parse(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| A.java:74:12:74:38 | loadAs(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| A.java:75:12:75:61 | loadAs(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input | +edges +| A.java:13:31:13:51 | getInputStream(...) [InputStream] | A.java:15:12:15:13 | in | +| A.java:19:31:19:51 | getInputStream(...) [InputStream] | A.java:21:12:21:13 | in | +| A.java:25:31:25:51 | getInputStream(...) [InputStream] | A.java:27:12:27:12 | d | +| A.java:32:31:32:51 | getInputStream(...) [InputStream] | A.java:34:23:34:28 | reader | +| A.java:39:29:39:49 | getInputStream(...) [InputStream] | A.java:40:28:40:32 | input | +| A.java:39:29:39:49 | getInputStream(...) [InputStream] | A.java:41:34:41:38 | input | +| A.java:39:29:39:49 | getInputStream(...) [InputStream] | A.java:42:40:42:44 | input | +| A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:61:26:61:30 | input | +| A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:62:30:62:34 | input | +| A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:63:28:63:55 | new InputStreamReader(...) | +| A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:64:24:64:28 | input | +| A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:65:24:65:51 | new InputStreamReader(...) | +| A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:71:26:71:30 | input | +| A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:72:30:72:34 | input | +| A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:73:28:73:55 | new InputStreamReader(...) | +| A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:74:24:74:28 | input | +| A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:75:24:75:51 | new InputStreamReader(...) | +| TestMessageBodyReader.java:20:55:20:78 | entityStream [InputStream] | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | +#select +| A.java:15:12:15:26 | readObject(...) | A.java:13:31:13:51 | getInputStream(...) [InputStream] | A.java:15:12:15:13 | in | Unsafe deserialization of $@. | A.java:13:31:13:51 | getInputStream(...) | user input | +| A.java:21:12:21:28 | readUnshared(...) | A.java:19:31:19:51 | getInputStream(...) [InputStream] | A.java:21:12:21:13 | in | Unsafe deserialization of $@. | A.java:19:31:19:51 | getInputStream(...) | user input | +| A.java:27:12:27:25 | readObject(...) | A.java:25:31:25:51 | getInputStream(...) [InputStream] | A.java:27:12:27:12 | d | Unsafe deserialization of $@. | A.java:25:31:25:51 | getInputStream(...) | user input | +| A.java:34:12:34:29 | fromXML(...) | A.java:32:31:32:51 | getInputStream(...) [InputStream] | A.java:34:23:34:28 | reader | Unsafe deserialization of $@. | A.java:32:31:32:51 | getInputStream(...) | user input | +| A.java:40:12:40:42 | readObject(...) | A.java:39:29:39:49 | getInputStream(...) [InputStream] | A.java:40:28:40:32 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | +| A.java:41:12:41:48 | readObjectOrNull(...) | A.java:39:29:39:49 | getInputStream(...) [InputStream] | A.java:41:34:41:38 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | +| A.java:42:16:42:45 | readClassAndObject(...) | A.java:39:29:39:49 | getInputStream(...) [InputStream] | A.java:42:40:42:44 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | +| A.java:61:16:61:31 | load(...) | A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:61:26:61:30 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:62:17:62:35 | loadAll(...) | A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:62:30:62:34 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:63:17:63:56 | parse(...) | A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:63:28:63:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:64:12:64:38 | loadAs(...) | A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:64:24:64:28 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:65:12:65:61 | loadAs(...) | A.java:60:25:60:45 | getInputStream(...) [InputStream] | A.java:65:24:65:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:71:16:71:31 | load(...) | A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:71:26:71:30 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:72:17:72:35 | loadAll(...) | A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:72:30:72:34 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:73:17:73:56 | parse(...) | A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:73:28:73:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:74:12:74:38 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:74:24:74:28 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:75:12:75:61 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) [InputStream] | A.java:75:24:75:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream [InputStream] | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input | diff --git a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.expected b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.expected index 43b1301170a4..479d7172c307 100644 --- a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.expected +++ b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.expected @@ -1,4 +1,10 @@ -| UrlRedirect.java:23:25:23:54 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:23:25:23:54 | getParameter(...) | user-provided value | -| UrlRedirect.java:36:25:36:89 | ... + ... | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:36:58:36:89 | getParameter(...) | user-provided value | -| UrlRedirect.java:39:34:39:63 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:39:34:39:63 | getParameter(...) | user-provided value | -| UrlRedirect.java:42:43:42:72 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:42:43:42:72 | getParameter(...) | user-provided value | \ No newline at end of file +edges +| UrlRedirect.java:23:25:23:54 | getParameter(...) [String] | UrlRedirect.java:23:25:23:54 | getParameter(...) | +| UrlRedirect.java:36:58:36:89 | getParameter(...) [String] | UrlRedirect.java:36:25:36:89 | ... + ... | +| UrlRedirect.java:39:34:39:63 | getParameter(...) [String] | UrlRedirect.java:39:34:39:63 | getParameter(...) | +| UrlRedirect.java:42:43:42:72 | getParameter(...) [String] | UrlRedirect.java:42:43:42:72 | getParameter(...) | +#select +| UrlRedirect.java:23:25:23:54 | getParameter(...) | UrlRedirect.java:23:25:23:54 | getParameter(...) [String] | UrlRedirect.java:23:25:23:54 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:23:25:23:54 | getParameter(...) | user-provided value | +| UrlRedirect.java:36:25:36:89 | ... + ... | UrlRedirect.java:36:58:36:89 | getParameter(...) [String] | UrlRedirect.java:36:25:36:89 | ... + ... | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:36:58:36:89 | getParameter(...) | user-provided value | +| UrlRedirect.java:39:34:39:63 | getParameter(...) | UrlRedirect.java:39:34:39:63 | getParameter(...) [String] | UrlRedirect.java:39:34:39:63 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:39:34:39:63 | getParameter(...) | user-provided value | +| UrlRedirect.java:42:43:42:72 | getParameter(...) | UrlRedirect.java:42:43:42:72 | getParameter(...) [String] | UrlRedirect.java:42:43:42:72 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:42:43:42:72 | getParameter(...) | user-provided value | diff --git a/java/ql/test/query-tests/security/CWE-611/XXE.expected b/java/ql/test/query-tests/security/CWE-611/XXE.expected index 2f754473bc40..1677c9449724 100644 --- a/java/ql/test/query-tests/security/CWE-611/XXE.expected +++ b/java/ql/test/query-tests/security/CWE-611/XXE.expected @@ -1,94 +1,190 @@ -| DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | user input | -| DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | user input | -| DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | user input | -| DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | user input | -| DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | user input | -| DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | user input | -| DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | user input | -| DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) | user input | -| DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input | -| DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input | -| SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | user input | -| SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | user input | -| SAXParserTests.java:13:18:13:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:13:18:13:38 | getInputStream(...) | user input | -| SAXParserTests.java:30:18:30:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:30:18:30:38 | getInputStream(...) | user input | -| SAXParserTests.java:38:18:38:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:38:18:38:38 | getInputStream(...) | user input | -| SAXParserTests.java:46:18:46:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:46:18:46:38 | getInputStream(...) | user input | -| SAXParserTests.java:55:18:55:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:55:18:55:38 | getInputStream(...) | user input | -| SAXParserTests.java:64:18:64:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:64:18:64:38 | getInputStream(...) | user input | -| SAXParserTests.java:73:18:73:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:73:18:73:38 | getInputStream(...) | user input | -| SAXReaderTests.java:8:17:8:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | user input | -| SAXReaderTests.java:23:17:23:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | user input | -| SAXReaderTests.java:30:17:30:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | user input | -| SAXReaderTests.java:37:17:37:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | user input | -| SAXReaderTests.java:45:17:45:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | user input | -| SAXReaderTests.java:53:17:53:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | user input | -| SAXReaderTests.java:61:17:61:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | user input | -| SchemaTests.java:12:39:12:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:12:56:12:76 | getInputStream(...) | user input | -| SchemaTests.java:25:39:25:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:25:56:25:76 | getInputStream(...) | user input | -| SchemaTests.java:31:39:31:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:31:56:31:76 | getInputStream(...) | user input | -| SchemaTests.java:38:39:38:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:38:56:38:76 | getInputStream(...) | user input | -| SchemaTests.java:45:39:45:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:45:56:45:76 | getInputStream(...) | user input | -| SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | user input | -| SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | user input | -| SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) | user input | -| SimpleXMLTests.java:31:41:31:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:38:41:38:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) | user input | -| SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | user input | -| SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | user input | -| SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | user input | -| SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | user input | -| SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) | user input | -| SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) | user input | -| SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) | user input | -| SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) | user input | -| SimpleXMLTests.java:90:37:90:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:97:37:97:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:104:26:104:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:111:26:111:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | user input | -| SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) | user input | -| SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | user input | -| SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) | user input | -| SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | user input | -| SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) | user input | -| SimpleXMLTests.java:146:22:146:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:153:22:153:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) | user input | -| TransformerTests.java:20:27:20:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:20:44:20:64 | getInputStream(...) | user input | -| TransformerTests.java:21:23:21:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:21:40:21:60 | getInputStream(...) | user input | -| TransformerTests.java:71:27:71:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:71:44:71:64 | getInputStream(...) | user input | -| TransformerTests.java:72:23:72:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:72:40:72:60 | getInputStream(...) | user input | -| TransformerTests.java:79:27:79:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:79:44:79:64 | getInputStream(...) | user input | -| TransformerTests.java:80:23:80:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:80:40:80:60 | getInputStream(...) | user input | -| TransformerTests.java:88:27:88:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:88:44:88:64 | getInputStream(...) | user input | -| TransformerTests.java:89:23:89:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:89:40:89:60 | getInputStream(...) | user input | -| TransformerTests.java:97:27:97:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:97:44:97:64 | getInputStream(...) | user input | -| TransformerTests.java:98:23:98:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:98:40:98:60 | getInputStream(...) | user input | -| TransformerTests.java:103:21:103:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:103:38:103:58 | getInputStream(...) | user input | -| TransformerTests.java:116:21:116:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:116:38:116:58 | getInputStream(...) | user input | -| TransformerTests.java:122:21:122:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:122:38:122:58 | getInputStream(...) | user input | -| TransformerTests.java:129:21:129:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:129:38:129:58 | getInputStream(...) | user input | -| TransformerTests.java:136:21:136:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:136:38:136:58 | getInputStream(...) | user input | -| TransformerTests.java:141:18:141:70 | new SAXSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:141:48:141:68 | getInputStream(...) | user input | -| XMLReaderTests.java:16:18:16:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:16:34:16:54 | getInputStream(...) | user input | -| XMLReaderTests.java:56:18:56:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:56:34:56:54 | getInputStream(...) | user input | -| XMLReaderTests.java:63:18:63:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:63:34:63:54 | getInputStream(...) | user input | -| XMLReaderTests.java:70:18:70:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:70:34:70:54 | getInputStream(...) | user input | -| XMLReaderTests.java:78:18:78:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:78:34:78:54 | getInputStream(...) | user input | -| XMLReaderTests.java:86:18:86:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:86:34:86:54 | getInputStream(...) | user input | -| XMLReaderTests.java:94:18:94:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:94:34:94:54 | getInputStream(...) | user input | -| XMLReaderTests.java:100:18:100:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:100:34:100:54 | getInputStream(...) | user input | -| XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | Unsafe parsing of XML file from $@. | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | user input | -| XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | user input | +edges +| DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | +| DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | +| DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | +| DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | +| DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | +| DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | +| DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | +| DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | +| DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | +| DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | +| SAXBuilderTests.java:8:19:8:39 | getInputStream(...) [InputStream] | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | +| SAXBuilderTests.java:20:19:20:39 | getInputStream(...) [InputStream] | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | +| SAXParserTests.java:13:18:13:38 | getInputStream(...) [InputStream] | SAXParserTests.java:13:18:13:38 | getInputStream(...) | +| SAXParserTests.java:30:18:30:38 | getInputStream(...) [InputStream] | SAXParserTests.java:30:18:30:38 | getInputStream(...) | +| SAXParserTests.java:38:18:38:38 | getInputStream(...) [InputStream] | SAXParserTests.java:38:18:38:38 | getInputStream(...) | +| SAXParserTests.java:46:18:46:38 | getInputStream(...) [InputStream] | SAXParserTests.java:46:18:46:38 | getInputStream(...) | +| SAXParserTests.java:55:18:55:38 | getInputStream(...) [InputStream] | SAXParserTests.java:55:18:55:38 | getInputStream(...) | +| SAXParserTests.java:64:18:64:38 | getInputStream(...) [InputStream] | SAXParserTests.java:64:18:64:38 | getInputStream(...) | +| SAXParserTests.java:73:18:73:38 | getInputStream(...) [InputStream] | SAXParserTests.java:73:18:73:38 | getInputStream(...) | +| SAXReaderTests.java:8:17:8:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | +| SAXReaderTests.java:23:17:23:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | +| SAXReaderTests.java:30:17:30:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | +| SAXReaderTests.java:37:17:37:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | +| SAXReaderTests.java:45:17:45:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | +| SAXReaderTests.java:53:17:53:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | +| SAXReaderTests.java:61:17:61:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | +| SchemaTests.java:12:56:12:76 | getInputStream(...) [InputStream] | SchemaTests.java:12:39:12:77 | new StreamSource(...) | +| SchemaTests.java:25:56:25:76 | getInputStream(...) [InputStream] | SchemaTests.java:25:39:25:77 | new StreamSource(...) | +| SchemaTests.java:31:56:31:76 | getInputStream(...) [InputStream] | SchemaTests.java:31:39:31:77 | new StreamSource(...) | +| SchemaTests.java:38:56:38:76 | getInputStream(...) [InputStream] | SchemaTests.java:38:39:38:77 | new StreamSource(...) | +| SchemaTests.java:45:56:45:76 | getInputStream(...) [InputStream] | SchemaTests.java:45:39:45:77 | new StreamSource(...) | +| SimpleXMLTests.java:14:41:14:61 | getInputStream(...) [InputStream] | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | +| SimpleXMLTests.java:19:41:19:61 | getInputStream(...) [InputStream] | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | +| SimpleXMLTests.java:24:63:24:83 | getInputStream(...) [InputStream] | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | +| SimpleXMLTests.java:30:5:30:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:31:41:31:53 | new String(...) | +| SimpleXMLTests.java:37:5:37:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:38:41:38:53 | new String(...) | +| SimpleXMLTests.java:43:63:43:83 | getInputStream(...) [InputStream] | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | +| SimpleXMLTests.java:48:37:48:57 | getInputStream(...) [InputStream] | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | +| SimpleXMLTests.java:53:37:53:57 | getInputStream(...) [InputStream] | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | +| SimpleXMLTests.java:58:26:58:46 | getInputStream(...) [InputStream] | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | +| SimpleXMLTests.java:63:26:63:46 | getInputStream(...) [InputStream] | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | +| SimpleXMLTests.java:68:59:68:79 | getInputStream(...) [InputStream] | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | +| SimpleXMLTests.java:73:59:73:79 | getInputStream(...) [InputStream] | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | +| SimpleXMLTests.java:78:48:78:68 | getInputStream(...) [InputStream] | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | +| SimpleXMLTests.java:83:48:83:68 | getInputStream(...) [InputStream] | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | +| SimpleXMLTests.java:89:5:89:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:90:37:90:49 | new String(...) | +| SimpleXMLTests.java:96:5:96:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:97:37:97:49 | new String(...) | +| SimpleXMLTests.java:103:5:103:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:104:26:104:38 | new String(...) | +| SimpleXMLTests.java:110:5:110:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:111:26:111:38 | new String(...) | +| SimpleXMLTests.java:115:22:115:42 | getInputStream(...) [InputStream] | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | +| SimpleXMLTests.java:119:44:119:64 | getInputStream(...) [InputStream] | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | +| SimpleXMLTests.java:124:22:124:42 | getInputStream(...) [InputStream] | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | +| SimpleXMLTests.java:129:44:129:64 | getInputStream(...) [InputStream] | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | +| SimpleXMLTests.java:134:22:134:42 | getInputStream(...) [InputStream] | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | +| SimpleXMLTests.java:139:44:139:64 | getInputStream(...) [InputStream] | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | +| SimpleXMLTests.java:145:5:145:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:146:22:146:34 | new String(...) | +| SimpleXMLTests.java:152:5:152:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:153:22:153:34 | new String(...) | +| TransformerTests.java:20:44:20:64 | getInputStream(...) [InputStream] | TransformerTests.java:20:27:20:65 | new StreamSource(...) | +| TransformerTests.java:21:40:21:60 | getInputStream(...) [InputStream] | TransformerTests.java:21:23:21:61 | new StreamSource(...) | +| TransformerTests.java:71:44:71:64 | getInputStream(...) [InputStream] | TransformerTests.java:71:27:71:65 | new StreamSource(...) | +| TransformerTests.java:72:40:72:60 | getInputStream(...) [InputStream] | TransformerTests.java:72:23:72:61 | new StreamSource(...) | +| TransformerTests.java:79:44:79:64 | getInputStream(...) [InputStream] | TransformerTests.java:79:27:79:65 | new StreamSource(...) | +| TransformerTests.java:80:40:80:60 | getInputStream(...) [InputStream] | TransformerTests.java:80:23:80:61 | new StreamSource(...) | +| TransformerTests.java:88:44:88:64 | getInputStream(...) [InputStream] | TransformerTests.java:88:27:88:65 | new StreamSource(...) | +| TransformerTests.java:89:40:89:60 | getInputStream(...) [InputStream] | TransformerTests.java:89:23:89:61 | new StreamSource(...) | +| TransformerTests.java:97:44:97:64 | getInputStream(...) [InputStream] | TransformerTests.java:97:27:97:65 | new StreamSource(...) | +| TransformerTests.java:98:40:98:60 | getInputStream(...) [InputStream] | TransformerTests.java:98:23:98:61 | new StreamSource(...) | +| TransformerTests.java:103:38:103:58 | getInputStream(...) [InputStream] | TransformerTests.java:103:21:103:59 | new StreamSource(...) | +| TransformerTests.java:116:38:116:58 | getInputStream(...) [InputStream] | TransformerTests.java:116:21:116:59 | new StreamSource(...) | +| TransformerTests.java:122:38:122:58 | getInputStream(...) [InputStream] | TransformerTests.java:122:21:122:59 | new StreamSource(...) | +| TransformerTests.java:129:38:129:58 | getInputStream(...) [InputStream] | TransformerTests.java:129:21:129:59 | new StreamSource(...) | +| TransformerTests.java:136:38:136:58 | getInputStream(...) [InputStream] | TransformerTests.java:136:21:136:59 | new StreamSource(...) | +| TransformerTests.java:141:48:141:68 | getInputStream(...) [InputStream] | TransformerTests.java:141:18:141:70 | new SAXSource(...) | +| XMLReaderTests.java:16:34:16:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | +| XMLReaderTests.java:56:34:56:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | +| XMLReaderTests.java:63:34:63:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | +| XMLReaderTests.java:70:34:70:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | +| XMLReaderTests.java:78:34:78:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | +| XMLReaderTests.java:86:34:86:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | +| XMLReaderTests.java:94:34:94:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | +| XMLReaderTests.java:100:34:100:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | +| XPathExpressionTests.java:27:37:27:57 | getInputStream(...) [InputStream] | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | +| XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | +| XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | +| XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | +| XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | +| XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | +| XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | +| XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | +| XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | +| XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | +| XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | +| XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | +| XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | +#select +| DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | user input | +| DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | user input | +| DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | user input | +| DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | user input | +| DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | user input | +| DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | user input | +| DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | user input | +| DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) | user input | +| DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input | +| DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [InputStream] | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input | +| SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) [InputStream] | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | user input | +| SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) [InputStream] | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | user input | +| SAXParserTests.java:13:18:13:38 | getInputStream(...) | SAXParserTests.java:13:18:13:38 | getInputStream(...) [InputStream] | SAXParserTests.java:13:18:13:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:13:18:13:38 | getInputStream(...) | user input | +| SAXParserTests.java:30:18:30:38 | getInputStream(...) | SAXParserTests.java:30:18:30:38 | getInputStream(...) [InputStream] | SAXParserTests.java:30:18:30:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:30:18:30:38 | getInputStream(...) | user input | +| SAXParserTests.java:38:18:38:38 | getInputStream(...) | SAXParserTests.java:38:18:38:38 | getInputStream(...) [InputStream] | SAXParserTests.java:38:18:38:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:38:18:38:38 | getInputStream(...) | user input | +| SAXParserTests.java:46:18:46:38 | getInputStream(...) | SAXParserTests.java:46:18:46:38 | getInputStream(...) [InputStream] | SAXParserTests.java:46:18:46:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:46:18:46:38 | getInputStream(...) | user input | +| SAXParserTests.java:55:18:55:38 | getInputStream(...) | SAXParserTests.java:55:18:55:38 | getInputStream(...) [InputStream] | SAXParserTests.java:55:18:55:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:55:18:55:38 | getInputStream(...) | user input | +| SAXParserTests.java:64:18:64:38 | getInputStream(...) | SAXParserTests.java:64:18:64:38 | getInputStream(...) [InputStream] | SAXParserTests.java:64:18:64:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:64:18:64:38 | getInputStream(...) | user input | +| SAXParserTests.java:73:18:73:38 | getInputStream(...) | SAXParserTests.java:73:18:73:38 | getInputStream(...) [InputStream] | SAXParserTests.java:73:18:73:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:73:18:73:38 | getInputStream(...) | user input | +| SAXReaderTests.java:8:17:8:37 | getInputStream(...) | SAXReaderTests.java:8:17:8:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | user input | +| SAXReaderTests.java:23:17:23:37 | getInputStream(...) | SAXReaderTests.java:23:17:23:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | user input | +| SAXReaderTests.java:30:17:30:37 | getInputStream(...) | SAXReaderTests.java:30:17:30:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | user input | +| SAXReaderTests.java:37:17:37:37 | getInputStream(...) | SAXReaderTests.java:37:17:37:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | user input | +| SAXReaderTests.java:45:17:45:37 | getInputStream(...) | SAXReaderTests.java:45:17:45:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | user input | +| SAXReaderTests.java:53:17:53:37 | getInputStream(...) | SAXReaderTests.java:53:17:53:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | user input | +| SAXReaderTests.java:61:17:61:37 | getInputStream(...) | SAXReaderTests.java:61:17:61:37 | getInputStream(...) [InputStream] | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | user input | +| SchemaTests.java:12:39:12:77 | new StreamSource(...) | SchemaTests.java:12:56:12:76 | getInputStream(...) [InputStream] | SchemaTests.java:12:39:12:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:12:56:12:76 | getInputStream(...) | user input | +| SchemaTests.java:25:39:25:77 | new StreamSource(...) | SchemaTests.java:25:56:25:76 | getInputStream(...) [InputStream] | SchemaTests.java:25:39:25:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:25:56:25:76 | getInputStream(...) | user input | +| SchemaTests.java:31:39:31:77 | new StreamSource(...) | SchemaTests.java:31:56:31:76 | getInputStream(...) [InputStream] | SchemaTests.java:31:39:31:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:31:56:31:76 | getInputStream(...) | user input | +| SchemaTests.java:38:39:38:77 | new StreamSource(...) | SchemaTests.java:38:56:38:76 | getInputStream(...) [InputStream] | SchemaTests.java:38:39:38:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:38:56:38:76 | getInputStream(...) | user input | +| SchemaTests.java:45:39:45:77 | new StreamSource(...) | SchemaTests.java:45:56:45:76 | getInputStream(...) [InputStream] | SchemaTests.java:45:39:45:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:45:56:45:76 | getInputStream(...) | user input | +| SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) [InputStream] | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | user input | +| SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) [InputStream] | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | user input | +| SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) [InputStream] | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) | user input | +| SimpleXMLTests.java:31:41:31:53 | new String(...) | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:31:41:31:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:38:41:38:53 | new String(...) | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:38:41:38:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) [InputStream] | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) | user input | +| SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) [InputStream] | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | user input | +| SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) [InputStream] | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | user input | +| SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) [InputStream] | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | user input | +| SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) [InputStream] | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | user input | +| SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) [InputStream] | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) | user input | +| SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) [InputStream] | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) | user input | +| SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) [InputStream] | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) | user input | +| SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) [InputStream] | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) | user input | +| SimpleXMLTests.java:90:37:90:49 | new String(...) | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:90:37:90:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:97:37:97:49 | new String(...) | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:97:37:97:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:104:26:104:38 | new String(...) | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:104:26:104:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:111:26:111:38 | new String(...) | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:111:26:111:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) [InputStream] | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | user input | +| SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) [InputStream] | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) | user input | +| SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) [InputStream] | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | user input | +| SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) [InputStream] | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) | user input | +| SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) [InputStream] | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | user input | +| SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) [InputStream] | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) | user input | +| SimpleXMLTests.java:146:22:146:34 | new String(...) | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:146:22:146:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:153:22:153:34 | new String(...) | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) [InputStream] | SimpleXMLTests.java:153:22:153:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) | user input | +| TransformerTests.java:20:27:20:65 | new StreamSource(...) | TransformerTests.java:20:44:20:64 | getInputStream(...) [InputStream] | TransformerTests.java:20:27:20:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:20:44:20:64 | getInputStream(...) | user input | +| TransformerTests.java:21:23:21:61 | new StreamSource(...) | TransformerTests.java:21:40:21:60 | getInputStream(...) [InputStream] | TransformerTests.java:21:23:21:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:21:40:21:60 | getInputStream(...) | user input | +| TransformerTests.java:71:27:71:65 | new StreamSource(...) | TransformerTests.java:71:44:71:64 | getInputStream(...) [InputStream] | TransformerTests.java:71:27:71:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:71:44:71:64 | getInputStream(...) | user input | +| TransformerTests.java:72:23:72:61 | new StreamSource(...) | TransformerTests.java:72:40:72:60 | getInputStream(...) [InputStream] | TransformerTests.java:72:23:72:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:72:40:72:60 | getInputStream(...) | user input | +| TransformerTests.java:79:27:79:65 | new StreamSource(...) | TransformerTests.java:79:44:79:64 | getInputStream(...) [InputStream] | TransformerTests.java:79:27:79:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:79:44:79:64 | getInputStream(...) | user input | +| TransformerTests.java:80:23:80:61 | new StreamSource(...) | TransformerTests.java:80:40:80:60 | getInputStream(...) [InputStream] | TransformerTests.java:80:23:80:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:80:40:80:60 | getInputStream(...) | user input | +| TransformerTests.java:88:27:88:65 | new StreamSource(...) | TransformerTests.java:88:44:88:64 | getInputStream(...) [InputStream] | TransformerTests.java:88:27:88:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:88:44:88:64 | getInputStream(...) | user input | +| TransformerTests.java:89:23:89:61 | new StreamSource(...) | TransformerTests.java:89:40:89:60 | getInputStream(...) [InputStream] | TransformerTests.java:89:23:89:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:89:40:89:60 | getInputStream(...) | user input | +| TransformerTests.java:97:27:97:65 | new StreamSource(...) | TransformerTests.java:97:44:97:64 | getInputStream(...) [InputStream] | TransformerTests.java:97:27:97:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:97:44:97:64 | getInputStream(...) | user input | +| TransformerTests.java:98:23:98:61 | new StreamSource(...) | TransformerTests.java:98:40:98:60 | getInputStream(...) [InputStream] | TransformerTests.java:98:23:98:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:98:40:98:60 | getInputStream(...) | user input | +| TransformerTests.java:103:21:103:59 | new StreamSource(...) | TransformerTests.java:103:38:103:58 | getInputStream(...) [InputStream] | TransformerTests.java:103:21:103:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:103:38:103:58 | getInputStream(...) | user input | +| TransformerTests.java:116:21:116:59 | new StreamSource(...) | TransformerTests.java:116:38:116:58 | getInputStream(...) [InputStream] | TransformerTests.java:116:21:116:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:116:38:116:58 | getInputStream(...) | user input | +| TransformerTests.java:122:21:122:59 | new StreamSource(...) | TransformerTests.java:122:38:122:58 | getInputStream(...) [InputStream] | TransformerTests.java:122:21:122:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:122:38:122:58 | getInputStream(...) | user input | +| TransformerTests.java:129:21:129:59 | new StreamSource(...) | TransformerTests.java:129:38:129:58 | getInputStream(...) [InputStream] | TransformerTests.java:129:21:129:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:129:38:129:58 | getInputStream(...) | user input | +| TransformerTests.java:136:21:136:59 | new StreamSource(...) | TransformerTests.java:136:38:136:58 | getInputStream(...) [InputStream] | TransformerTests.java:136:21:136:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:136:38:136:58 | getInputStream(...) | user input | +| TransformerTests.java:141:18:141:70 | new SAXSource(...) | TransformerTests.java:141:48:141:68 | getInputStream(...) [InputStream] | TransformerTests.java:141:18:141:70 | new SAXSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:141:48:141:68 | getInputStream(...) | user input | +| XMLReaderTests.java:16:18:16:55 | new InputSource(...) | XMLReaderTests.java:16:34:16:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:16:34:16:54 | getInputStream(...) | user input | +| XMLReaderTests.java:56:18:56:55 | new InputSource(...) | XMLReaderTests.java:56:34:56:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:56:34:56:54 | getInputStream(...) | user input | +| XMLReaderTests.java:63:18:63:55 | new InputSource(...) | XMLReaderTests.java:63:34:63:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:63:34:63:54 | getInputStream(...) | user input | +| XMLReaderTests.java:70:18:70:55 | new InputSource(...) | XMLReaderTests.java:70:34:70:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:70:34:70:54 | getInputStream(...) | user input | +| XMLReaderTests.java:78:18:78:55 | new InputSource(...) | XMLReaderTests.java:78:34:78:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:78:34:78:54 | getInputStream(...) | user input | +| XMLReaderTests.java:86:18:86:55 | new InputSource(...) | XMLReaderTests.java:86:34:86:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:86:34:86:54 | getInputStream(...) | user input | +| XMLReaderTests.java:94:18:94:55 | new InputSource(...) | XMLReaderTests.java:94:34:94:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:94:34:94:54 | getInputStream(...) | user input | +| XMLReaderTests.java:100:18:100:55 | new InputSource(...) | XMLReaderTests.java:100:34:100:54 | getInputStream(...) [InputStream] | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:100:34:100:54 | getInputStream(...) | user input | +| XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) [InputStream] | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | Unsafe parsing of XML file from $@. | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | user input | +| XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) [InputStream] | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | user input | diff --git a/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected index 95ba9d0eb7b2..a7e41c43c578 100644 --- a/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected @@ -1 +1,4 @@ -| Test.java:21:17:21:25 | (...)... | $@ flows to here and is cast to a narrower type, potentially causing truncation. | Test.java:11:28:11:36 | System.in | User-provided value | +edges +| Test.java:11:28:11:36 | System.in [InputStream] | Test.java:21:22:21:25 | data | +#select +| Test.java:21:17:21:25 | (...)... | Test.java:11:28:11:36 | System.in [InputStream] | Test.java:21:22:21:25 | data | $@ flows to here and is cast to a narrower type, potentially causing truncation. | Test.java:11:28:11:36 | System.in | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected index e11047d8dc0e..0ec980529f07 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected @@ -1,18 +1,48 @@ -| CredentialsTest.java:7:34:7:41 | "123456" | Hard-coded value flows to $@. | CredentialsTest.java:13:39:13:39 | p | sensitive API call | -| CredentialsTest.java:7:34:7:41 | "123456" | Hard-coded value flows to $@. | CredentialsTest.java:18:39:18:39 | q | sensitive API call | -| CredentialsTest.java:11:14:11:20 | "admin" | Hard-coded value flows to $@. | CredentialsTest.java:13:36:13:36 | u | sensitive API call | -| CredentialsTest.java:11:14:11:20 | "admin" | Hard-coded value flows to $@. | CredentialsTest.java:18:36:18:36 | v | sensitive API call | -| FileCredentialTest.java:13:14:13:20 | "admin" | Hard-coded value flows to $@. | FileCredentialTest.java:23:36:23:36 | v | sensitive API call | -| FileCredentialTest.java:18:35:18:41 | "admin" | Hard-coded value flows to $@. | FileCredentialTest.java:18:35:18:41 | "admin" | sensitive API call | -| Test.java:9:16:9:22 | "admin" | Hard-coded value flows to $@. | Test.java:15:36:15:38 | usr | sensitive API call | -| Test.java:9:16:9:22 | "admin" | Hard-coded value flows to $@. | Test.java:17:39:17:41 | usr | sensitive API call | -| Test.java:9:16:9:22 | "admin" | Hard-coded value flows to $@. | Test.java:18:39:18:41 | usr | sensitive API call | -| Test.java:9:16:9:22 | "admin" | Hard-coded value flows to $@. | Test.java:30:36:30:39 | user | sensitive API call | -| Test.java:10:17:10:24 | "123456" | Hard-coded value flows to $@. | Test.java:15:41:15:44 | pass | sensitive API call | -| Test.java:10:17:10:24 | "123456" | Hard-coded value flows to $@. | Test.java:18:44:18:61 | toCharArray(...) | sensitive API call | -| Test.java:10:17:10:24 | "123456" | Hard-coded value flows to $@. | Test.java:30:42:30:49 | password | sensitive API call | -| Test.java:14:36:14:42 | "admin" | Hard-coded value flows to $@. | Test.java:14:36:14:42 | "admin" | sensitive API call | -| Test.java:14:45:14:52 | "123456" | Hard-coded value flows to $@. | Test.java:14:45:14:52 | "123456" | sensitive API call | -| Test.java:17:44:17:51 | "123456" | Hard-coded value flows to $@. | Test.java:17:44:17:65 | toCharArray(...) | sensitive API call | -| Test.java:20:16:20:39 | new byte[] | Hard-coded value flows to $@. | Test.java:21:78:21:80 | key | sensitive API call | -| Test.java:23:17:23:26 | "abcdefgh" | Hard-coded value flows to $@. | Test.java:24:79:24:82 | key2 | sensitive API call | +edges +| CredentialsTest.java:7:34:7:41 | "123456" [String] | CredentialsTest.java:13:39:13:39 | p | +| CredentialsTest.java:7:34:7:41 | "123456" [String] | CredentialsTest.java:14:16:14:16 | p [String] | +| CredentialsTest.java:11:14:11:20 | "admin" [String] | CredentialsTest.java:13:36:13:36 | u | +| CredentialsTest.java:11:14:11:20 | "admin" [String] | CredentialsTest.java:14:13:14:13 | u [String] | +| CredentialsTest.java:14:13:14:13 | u [String] | CredentialsTest.java:17:38:17:45 | v [String] | +| CredentialsTest.java:14:16:14:16 | p [String] | CredentialsTest.java:17:48:17:55 | q [String] | +| CredentialsTest.java:17:38:17:45 | v [String] | CredentialsTest.java:18:36:18:36 | v | +| CredentialsTest.java:17:48:17:55 | q [String] | CredentialsTest.java:18:39:18:39 | q | +| FileCredentialTest.java:13:14:13:20 | "admin" [String] | FileCredentialTest.java:19:13:19:13 | u [String] | +| FileCredentialTest.java:18:35:18:41 | "admin" [String] | FileCredentialTest.java:18:35:18:41 | "admin" | +| FileCredentialTest.java:19:13:19:13 | u [String] | FileCredentialTest.java:22:38:22:45 | v [String] | +| FileCredentialTest.java:22:38:22:45 | v [String] | FileCredentialTest.java:23:36:23:36 | v | +| Test.java:9:16:9:22 | "admin" [String] | Test.java:12:13:12:15 | usr [String] | +| Test.java:9:16:9:22 | "admin" [String] | Test.java:15:36:15:38 | usr | +| Test.java:9:16:9:22 | "admin" [String] | Test.java:17:39:17:41 | usr | +| Test.java:9:16:9:22 | "admin" [String] | Test.java:18:39:18:41 | usr | +| Test.java:10:17:10:24 | "123456" [String] | Test.java:12:18:12:21 | pass [String] | +| Test.java:10:17:10:24 | "123456" [String] | Test.java:15:41:15:44 | pass | +| Test.java:10:17:10:24 | "123456" [String] | Test.java:18:44:18:61 | toCharArray(...) | +| Test.java:12:13:12:15 | usr [String] | Test.java:29:38:29:48 | user [String] | +| Test.java:12:18:12:21 | pass [String] | Test.java:29:51:29:65 | password [String] | +| Test.java:14:36:14:42 | "admin" [String] | Test.java:14:36:14:42 | "admin" | +| Test.java:14:45:14:52 | "123456" [String] | Test.java:14:45:14:52 | "123456" | +| Test.java:17:44:17:51 | "123456" [String] | Test.java:17:44:17:65 | toCharArray(...) | +| Test.java:20:16:20:39 | new byte[] [byte[]] | Test.java:21:78:21:80 | key | +| Test.java:23:17:23:26 | "abcdefgh" [String] | Test.java:24:79:24:82 | key2 | +| Test.java:29:38:29:48 | user [String] | Test.java:30:36:30:39 | user | +| Test.java:29:51:29:65 | password [String] | Test.java:30:42:30:49 | password | +#select +| CredentialsTest.java:7:34:7:41 | "123456" | CredentialsTest.java:7:34:7:41 | "123456" [String] | CredentialsTest.java:13:39:13:39 | p | Hard-coded value flows to $@. | CredentialsTest.java:13:39:13:39 | p | sensitive API call | +| CredentialsTest.java:7:34:7:41 | "123456" | CredentialsTest.java:7:34:7:41 | "123456" [String] | CredentialsTest.java:18:39:18:39 | q | Hard-coded value flows to $@. | CredentialsTest.java:18:39:18:39 | q | sensitive API call | +| CredentialsTest.java:11:14:11:20 | "admin" | CredentialsTest.java:11:14:11:20 | "admin" [String] | CredentialsTest.java:13:36:13:36 | u | Hard-coded value flows to $@. | CredentialsTest.java:13:36:13:36 | u | sensitive API call | +| CredentialsTest.java:11:14:11:20 | "admin" | CredentialsTest.java:11:14:11:20 | "admin" [String] | CredentialsTest.java:18:36:18:36 | v | Hard-coded value flows to $@. | CredentialsTest.java:18:36:18:36 | v | sensitive API call | +| FileCredentialTest.java:13:14:13:20 | "admin" | FileCredentialTest.java:13:14:13:20 | "admin" [String] | FileCredentialTest.java:23:36:23:36 | v | Hard-coded value flows to $@. | FileCredentialTest.java:23:36:23:36 | v | sensitive API call | +| FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" [String] | FileCredentialTest.java:18:35:18:41 | "admin" | Hard-coded value flows to $@. | FileCredentialTest.java:18:35:18:41 | "admin" | sensitive API call | +| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" [String] | Test.java:15:36:15:38 | usr | Hard-coded value flows to $@. | Test.java:15:36:15:38 | usr | sensitive API call | +| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" [String] | Test.java:17:39:17:41 | usr | Hard-coded value flows to $@. | Test.java:17:39:17:41 | usr | sensitive API call | +| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" [String] | Test.java:18:39:18:41 | usr | Hard-coded value flows to $@. | Test.java:18:39:18:41 | usr | sensitive API call | +| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" [String] | Test.java:30:36:30:39 | user | Hard-coded value flows to $@. | Test.java:30:36:30:39 | user | sensitive API call | +| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" [String] | Test.java:15:41:15:44 | pass | Hard-coded value flows to $@. | Test.java:15:41:15:44 | pass | sensitive API call | +| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" [String] | Test.java:18:44:18:61 | toCharArray(...) | Hard-coded value flows to $@. | Test.java:18:44:18:61 | toCharArray(...) | sensitive API call | +| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" [String] | Test.java:30:42:30:49 | password | Hard-coded value flows to $@. | Test.java:30:42:30:49 | password | sensitive API call | +| Test.java:14:36:14:42 | "admin" | Test.java:14:36:14:42 | "admin" [String] | Test.java:14:36:14:42 | "admin" | Hard-coded value flows to $@. | Test.java:14:36:14:42 | "admin" | sensitive API call | +| Test.java:14:45:14:52 | "123456" | Test.java:14:45:14:52 | "123456" [String] | Test.java:14:45:14:52 | "123456" | Hard-coded value flows to $@. | Test.java:14:45:14:52 | "123456" | sensitive API call | +| Test.java:17:44:17:51 | "123456" | Test.java:17:44:17:51 | "123456" [String] | Test.java:17:44:17:65 | toCharArray(...) | Hard-coded value flows to $@. | Test.java:17:44:17:65 | toCharArray(...) | sensitive API call | +| Test.java:20:16:20:39 | new byte[] | Test.java:20:16:20:39 | new byte[] [byte[]] | Test.java:21:78:21:80 | key | Hard-coded value flows to $@. | Test.java:21:78:21:80 | key | sensitive API call | +| Test.java:23:17:23:26 | "abcdefgh" | Test.java:23:17:23:26 | "abcdefgh" [String] | Test.java:24:79:24:82 | key2 | Hard-coded value flows to $@. | Test.java:24:79:24:82 | key2 | sensitive API call | diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected index 3b8925425d4e..0919a5ec1fd4 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected @@ -1,2 +1,6 @@ -| Test.java:10:17:10:24 | "123456" | Hard-coded value flows to $@. | Test.java:26:17:26:20 | pass | sensitive call | -| User.java:2:43:2:50 | "123456" | Hard-coded value flows to $@. | User.java:5:15:5:24 | DEFAULT_PW | sensitive call | +edges +| Test.java:10:17:10:24 | "123456" [String] | Test.java:26:17:26:20 | pass | +| User.java:2:43:2:50 | "123456" [String] | User.java:5:15:5:24 | DEFAULT_PW | +#select +| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" [String] | Test.java:26:17:26:20 | pass | Hard-coded value flows to $@. | Test.java:26:17:26:20 | pass | sensitive call | +| User.java:2:43:2:50 | "123456" | User.java:2:43:2:50 | "123456" [String] | User.java:5:15:5:24 | DEFAULT_PW | Hard-coded value flows to $@. | User.java:5:15:5:24 | DEFAULT_PW | sensitive call | diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected index 652ba02dbeea..eacb210ef47d 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected @@ -1,6 +1,13 @@ -| Test.java:26:4:26:24 | login(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:25:6:25:21 | ... == ... | this condition | Test.java:17:26:17:38 | args | user input | -| Test.java:32:4:32:24 | login(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:31:6:31:43 | equals(...) | this condition | Test.java:31:6:31:27 | getValue(...) | user input | -| Test.java:37:4:37:24 | login(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | -| Test.java:39:4:39:30 | reCheckAuth(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | -| Test.java:82:4:82:24 | login(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:81:6:81:36 | ... == ... | this condition | Test.java:81:6:81:27 | getValue(...) | user input | -| Test.java:92:4:92:24 | login(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:91:6:91:36 | ... == ... | this condition | Test.java:91:6:91:27 | getValue(...) | user input | +edges +| Test.java:17:26:17:38 | args [String[]] | Test.java:25:6:25:21 | ... == ... | +| Test.java:31:6:31:27 | getValue(...) [String] | Test.java:31:6:31:43 | equals(...) | +| Test.java:36:6:36:27 | getValue(...) [String] | Test.java:36:6:36:36 | ... == ... | +| Test.java:81:6:81:27 | getValue(...) [String] | Test.java:81:6:81:36 | ... == ... | +| Test.java:91:6:91:27 | getValue(...) [String] | Test.java:91:6:91:36 | ... == ... | +#select +| Test.java:26:4:26:24 | login(...) | Test.java:17:26:17:38 | args [String[]] | Test.java:25:6:25:21 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:25:6:25:21 | ... == ... | this condition | Test.java:17:26:17:38 | args | user input | +| Test.java:32:4:32:24 | login(...) | Test.java:31:6:31:27 | getValue(...) [String] | Test.java:31:6:31:43 | equals(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:31:6:31:43 | equals(...) | this condition | Test.java:31:6:31:27 | getValue(...) | user input | +| Test.java:37:4:37:24 | login(...) | Test.java:36:6:36:27 | getValue(...) [String] | Test.java:36:6:36:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | +| Test.java:39:4:39:30 | reCheckAuth(...) | Test.java:36:6:36:27 | getValue(...) [String] | Test.java:36:6:36:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | +| Test.java:82:4:82:24 | login(...) | Test.java:81:6:81:27 | getValue(...) [String] | Test.java:81:6:81:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:81:6:81:36 | ... == ... | this condition | Test.java:81:6:81:27 | getValue(...) | user input | +| Test.java:92:4:92:24 | login(...) | Test.java:91:6:91:27 | getValue(...) [String] | Test.java:91:6:91:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:91:6:91:36 | ... == ... | this condition | Test.java:91:6:91:27 | getValue(...) | user input | diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected index 39e42826996d..2a5c2b961b1f 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected @@ -1 +1,4 @@ -| Test.java:50:6:50:65 | isPermitted(...) | Permissions check uses user-controlled $@. | Test.java:17:26:17:38 | args | data | +edges +| Test.java:17:26:17:38 | args [String[]] | Test.java:50:26:50:64 | ... + ... | +#select +| Test.java:50:6:50:65 | isPermitted(...) | Test.java:17:26:17:38 | args [String[]] | Test.java:50:26:50:64 | ... + ... | Permissions check uses user-controlled $@. | Test.java:17:26:17:38 | args | data | From 918fc90515ef8371217defb7b33930666b43a902 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 16 Nov 2018 13:38:48 +0100 Subject: [PATCH 64/68] Java: Add change note. --- change-notes/1.19/analysis-java.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.19/analysis-java.md b/change-notes/1.19/analysis-java.md index d5a6d6a61b81..6458ff1d0101 100644 --- a/change-notes/1.19/analysis-java.md +++ b/change-notes/1.19/analysis-java.md @@ -2,6 +2,8 @@ ## General improvements +* Where applicable, path explanations have been added to the security queries. + ## New queries | **Query** | **Tags** | **Purpose** | From d839fcdafc0ca92c0073b115ecb60a948da9f29b Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 16 Nov 2018 12:52:26 +0000 Subject: [PATCH 65/68] TS: refactor to fix AutoBuildTest --- .../com/semmle/js/extractor/AutoBuild.java | 23 ++++++++++--------- .../js/extractor/test/AutoBuildTests.java | 8 +++++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index cebf15021fe8..7f4147c02c03 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -503,10 +503,7 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th typeScriptFiles.add(sourcePath.toFile()); } } - tsParser.prepareFiles(typeScriptFiles); - for (File file : typeScriptFiles) { - extract(extractor, file.toPath()); - } + extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractor); tsParser.closeProject(projectFile); } @@ -524,13 +521,7 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th } } if (!remainingTypeScriptFiles.isEmpty()) { - tsParser.prepareFiles(remainingTypeScriptFiles); - for (File f : remainingTypeScriptFiles) { - Path path = f.toPath(); - if (extractedFiles.add(path)) { - extract(extractor, path); - } - } + extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractor); } // The TypeScript compiler instance is no longer needed. @@ -552,6 +543,16 @@ public void verifyTypeScriptInstallation() { extractorState.getTypeScriptParser().verifyInstallation(true); } + public void extractTypeScriptFiles(List files, Set extractedFiles, FileExtractor extractor) throws IOException { + extractorState.getTypeScriptParser().prepareFiles(files); + for (File f : files) { + Path path = f.toPath(); + if (extractedFiles.add(path)) { + extract(extractor, f.toPath()); + } + } + } + private Path normalizePath(Path path) { return path.toAbsolutePath().normalize(); } diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java index 89d9494b4049..7969c093f4e6 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java @@ -1,5 +1,6 @@ package com.semmle.js.extractor.test; +import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -100,6 +101,13 @@ protected void extract(FileExtractor extractor, Path file) { @Override public void verifyTypeScriptInstallation() { } + + @Override + public void extractTypeScriptFiles(List files, Set extractedFiles, FileExtractor extractor) throws IOException { + for (File f : files) { + actual.add(f.toString()); + } + } }.run(); String expectedString = StringUtil.glue("\n", expected.stream().sorted().toArray()); String actualString = StringUtil.glue("\n", actual.stream().sorted().toArray()); From a35061ee79ad3f3a141a2eb511f73d349e8437fb Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 14 Nov 2018 17:33:48 +0000 Subject: [PATCH 66/68] TS: dont create JSON nodes in convertJsxSelfClosingElement --- .../js/parser/TypeScriptASTConverter.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 59fcb87a75ca..8cb4f2b25947 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -1385,7 +1385,7 @@ private Node convertJsxClosingFragment(JsonObject node, SourceLocation loc) { return new JSXClosingElement(loc, null); } - private Node convertJsxOpeningElement(JsonObject node, SourceLocation loc) throws ParseError { + private List convertJsxAttributes(JsonObject node) throws ParseError { JsonElement attributes = node.get("attributes"); List convertedAttributes; if (attributes.isJsonArray()) { @@ -1393,15 +1393,18 @@ private Node convertJsxOpeningElement(JsonObject node, SourceLocation loc) throw } else { convertedAttributes = convertChildren(attributes.getAsJsonObject(), "properties"); } + return convertedAttributes; + } + + private Node convertJsxOpeningElement(JsonObject node, SourceLocation loc) throws ParseError { + List convertedAttributes = convertJsxAttributes(node); return new JSXOpeningElement(loc, convertJSXName(convertChild(node, "tagName")), convertedAttributes, hasChild(node, "selfClosing")); } - private Node convertJsxSelfClosingElement(JsonObject node, - SourceLocation loc) throws ParseError { - node.remove("kind"); - node.add("kind", syntaxKinds.get("JsxOpeningElement")); - node.add("selfClosing", new JsonPrimitive(true)); - return new JSXElement(loc, (JSXOpeningElement) convertNode(node), new ArrayList<>(), null); + private Node convertJsxSelfClosingElement(JsonObject node, SourceLocation loc) throws ParseError { + List convertedAttributes = convertJsxAttributes(node); + JSXOpeningElement opening = new JSXOpeningElement(loc, convertJSXName(convertChild(node, "tagName")), convertedAttributes, true); + return new JSXElement(loc, opening, new ArrayList<>(), null); } private Node convertJsxSpreadAttribute(JsonObject node, From 84c1ba0b31ab786785dfd3a3f40d2db15b9f9f0f Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 16 Nov 2018 14:39:43 +0000 Subject: [PATCH 67/68] TS: fix the fix --- .../extractor/src/com/semmle/js/extractor/AutoBuild.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 7f4147c02c03..c04db341407a 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -499,7 +499,7 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th Path sourcePath = sourceFile.toPath(); if (!filesToExtract.contains(normalizePath(sourcePath))) continue; - if (extractedFiles.add(sourcePath)) { + if (!extractedFiles.contains(sourcePath)) { typeScriptFiles.add(sourcePath.toFile()); } } @@ -547,9 +547,8 @@ public void extractTypeScriptFiles(List files, Set extractedFiles, F extractorState.getTypeScriptParser().prepareFiles(files); for (File f : files) { Path path = f.toPath(); - if (extractedFiles.add(path)) { - extract(extractor, f.toPath()); - } + extractedFiles.add(path); + extract(extractor, f.toPath()); } } From 1aa5e24108e35fbc39347f5352f3e28b44d0af48 Mon Sep 17 00:00:00 2001 From: calum Date: Fri, 16 Nov 2018 16:50:35 +0000 Subject: [PATCH 68/68] C#: Remove duplicate results from cs/use-of-vulnerable-package --- .../CWE-937/Vulnerability.qll | 28 ++++++++++++------- .../CWE-937/VulnerablePackage.expected | 7 +++-- .../Security Features/CWE-937/packages.config | 5 +++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll b/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll index 2c8063e1b668..685789ebfac0 100644 --- a/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll +++ b/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll @@ -41,22 +41,22 @@ class Package extends XMLElement { abstract class Vulnerability extends string { bindingset[this] Vulnerability() { any() } - + /** * Holds if a package with name `name` is vulnerable from version `affected` * until version `fixed`. */ predicate matchesRange(string name, Version affected, Version fixed) { none() } - + /** * Holds if a package with name `name` is vulnerable in version `affected`, and * is fixed by version `fixed`. */ predicate matchesVersion(string name, Version affected, Version fixed) { none() } - + /** Gets the URL describing the vulnerability. */ abstract string getUrl(); - + /** * Holds if a package with name `name` and version `version` * has this vulnerability. The fixed version is given by `fixed`. @@ -75,20 +75,28 @@ abstract class Vulnerability extends string { } } +bindingset[name, version] +private Version getUltimateFix(string name, Version version) { + result = max(Version fix | any(Vulnerability v).isVulnerable(name, version, fix)) +} + /** * A package with a vulnerability. */ class VulnerablePackage extends Package { Vulnerability vuln; - Version fixed; - + VulnerablePackage() { - vuln.isVulnerable(this.getPackageName(), this.getVersion(), fixed) + vuln.isVulnerable(this.getPackageName(), this.getVersion(), _) } - + /** Gets the vulnerability of this package. */ Vulnerability getVulnerability() { result = vuln } - + /** Gets the version of this package where the vulnerability is fixed. */ - Version getFixedVersion() { result = fixed } + Version getFixedVersion() { + // This is needed because sometimes the "fixed" version of some + // vulnerabilities are themselves vulnerable to other vulnerabilities. + result = getUltimateFix(this.getPackageName(), this.getVersion()) + } } diff --git a/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.expected b/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.expected index bd39de4e295a..b930dbe6886d 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.expected @@ -2,5 +2,8 @@ | csproj.config:11:5:11:75 | system.text.encodings.web 4.3 | Package 'system.text.encodings.web 4.3' has vulnerability $@, and should be upgraded to version 4.3.1. | https://github.com/dotnet/corefx/issues/19535 | Microsoft Security Advisory 4021279 | | csproj.config:12:5:12:67 | System.Net.Http 4.1.1 | Package 'System.Net.Http 4.1.1' has vulnerability $@, and should be upgraded to version 4.1.2. | https://github.com/dotnet/corefx/issues/19535 | Microsoft Security Advisory 4021279 | | csproj.config:13:5:13:67 | System.Net.Http 4.1.2 | Package 'System.Net.Http 4.1.2' has vulnerability $@, and should be upgraded to version 4.3.4. | https://github.com/dotnet/announcements/issues/88 | CVE-2018-8292 | -| packages.config:8:3:8:79 | System.IO.Pipelines 4.5.0 | Package 'System.IO.Pipelines 4.5.0' has vulnerability $@, and should be upgraded to version 4.5.1. | https://github.com/aspnet/Announcements/issues/316 | CVE-2018-8409 | -| packages.config:9:3:9:81 | System.IO.Pipelines 4.5.0.0 | Package 'System.IO.Pipelines 4.5.0.0' has vulnerability $@, and should be upgraded to version 4.5.1. | https://github.com/aspnet/Announcements/issues/316 | CVE-2018-8409 | +| packages.config:9:3:9:79 | System.IO.Pipelines 4.5.0 | Package 'System.IO.Pipelines 4.5.0' has vulnerability $@, and should be upgraded to version 4.5.1. | https://github.com/aspnet/Announcements/issues/316 | CVE-2018-8409 | +| packages.config:10:3:10:81 | System.IO.Pipelines 4.5.0.0 | Package 'System.IO.Pipelines 4.5.0.0' has vulnerability $@, and should be upgraded to version 4.5.1. | https://github.com/aspnet/Announcements/issues/316 | CVE-2018-8409 | +| packages.config:11:3:11:84 | microsoft.aspnetcore.all 2.0.0 | Package 'microsoft.aspnetcore.all 2.0.0' has vulnerability $@, and should be upgraded to version 2.0.9. | https://github.com/aspnet/Announcements/issues/300 | ASPNETCore-Mar18 | +| packages.config:11:3:11:84 | microsoft.aspnetcore.all 2.0.0 | Package 'microsoft.aspnetcore.all 2.0.0' has vulnerability $@, and should be upgraded to version 2.0.9. | https://github.com/aspnet/Announcements/issues/311 | ASPNETCore-July18 | +| packages.config:12:3:12:84 | Microsoft.AspNetCore.All 2.0.8 | Package 'Microsoft.AspNetCore.All 2.0.8' has vulnerability $@, and should be upgraded to version 2.0.9. | https://github.com/aspnet/Announcements/issues/311 | ASPNETCore-July18 | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-937/packages.config b/csharp/ql/test/query-tests/Security Features/CWE-937/packages.config index 06e5ea78fd00..40e82a77df33 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-937/packages.config +++ b/csharp/ql/test/query-tests/Security Features/CWE-937/packages.config @@ -3,8 +3,11 @@ - + + + +