mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
Merge pull request #323 from esben-semmle/js/always-return-type-inference
JS: additional return type inference
This commit is contained in:
@@ -756,7 +756,7 @@ module DataFlow {
|
||||
/**
|
||||
* A data flow node representing an explicit (that is, non-reflective) function call.
|
||||
*/
|
||||
private class ExplicitCallNode extends CallNodeDef, ExplicitInvokeNode {
|
||||
class ExplicitCallNode extends CallNodeDef, ExplicitInvokeNode {
|
||||
override CallExpr astNode;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,17 +91,19 @@ class AnalyzedNode extends DataFlow::Node {
|
||||
|
||||
/** Gets a type inferred for this node. */
|
||||
pragma[nomagic] InferredType getAType() {
|
||||
result = getALocalValue().getType()
|
||||
result = getAValue().getType()
|
||||
}
|
||||
|
||||
/** Gets a primitive type to which the value of this node can be coerced. */
|
||||
/**
|
||||
* Gets a primitive type to which the value of this node can be coerced.
|
||||
*/
|
||||
PrimitiveType getAPrimitiveType() {
|
||||
result = getALocalValue().toPrimitive().getType()
|
||||
result = getAValue().toPrimitive().getType()
|
||||
}
|
||||
|
||||
/** Gets a Boolean value that this node evaluates to. */
|
||||
boolean getABooleanValue() {
|
||||
result = getALocalValue().getBooleanValue()
|
||||
result = getAValue().getBooleanValue()
|
||||
}
|
||||
|
||||
/** Gets the unique Boolean value that this node evaluates to, if any. */
|
||||
@@ -166,7 +168,7 @@ class AnalyzedNode extends DataFlow::Node {
|
||||
|
||||
/** Holds if the flow analysis can infer at least one abstract value for this node. */
|
||||
predicate hasFlow() {
|
||||
exists(getALocalValue())
|
||||
exists(getAValue())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -242,18 +242,25 @@ private class AnalyzedBinaryExpr extends DataFlow::AnalyzedValueNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a primitive type to which the local value of `e` can be coerced.
|
||||
*/
|
||||
private PrimitiveType getALocalPrimitiveType(Expr e) {
|
||||
result = e.analyze().getALocalValue().toPrimitive().getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` may hold a string value.
|
||||
*/
|
||||
private predicate maybeString(Expr e) {
|
||||
e.analyze().getAPrimitiveType() = TTString()
|
||||
getALocalPrimitiveType(e) = TTString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` may hold a non-string value.
|
||||
*/
|
||||
private predicate maybeNonString(Expr e) {
|
||||
e.analyze().getAPrimitiveType() != TTString()
|
||||
getALocalPrimitiveType(e) != TTString()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,8 +14,7 @@ import semmle.javascript.dataflow.Configuration
|
||||
*/
|
||||
predicate shouldTrackProperties(AbstractValue obj) {
|
||||
obj instanceof AbstractExportsObject or
|
||||
obj instanceof AbstractModuleObject or
|
||||
obj instanceof AbstractObjectLiteral
|
||||
obj instanceof AbstractModuleObject
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -143,6 +143,23 @@ abstract class CallWithAnalyzedReturnFlow extends DataFlow::AnalyzedValueNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call with inter-procedural type inference for the return value.
|
||||
*
|
||||
* Unlike `CallWithAnalyzedReturnFlow`, this only contributes to `getAValue()`, not `getALocalValue()`.
|
||||
*/
|
||||
abstract class CallWithNonLocalAnalyzedReturnFlow extends DataFlow::AnalyzedValueNode {
|
||||
|
||||
/**
|
||||
* Gets a called function.
|
||||
*/
|
||||
abstract AnalyzedFunction getACallee();
|
||||
|
||||
override AbstractValue getAValue() {
|
||||
result = getACallee().getAReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow analysis for the return value of IIFEs.
|
||||
*/
|
||||
@@ -210,4 +227,30 @@ private class LocalFunctionCallWithAnalyzedReturnFlow extends CallWithAnalyzedRe
|
||||
result = f.analyze()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasExplicitDefiniteCallee(DataFlow::Impl::ExplicitCallNode call, DataFlow::AnalyzedNode callee) {
|
||||
callee = call.getCalleeNode() and
|
||||
not callee.getALocalValue().isIndefinite(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables inter-procedural type inference for the return value of a call to a type-inferred callee.
|
||||
*/
|
||||
private class TypeInferredCalleeWithAnalyzedReturnFlow extends CallWithNonLocalAnalyzedReturnFlow {
|
||||
|
||||
DataFlow::FunctionNode fun;
|
||||
|
||||
TypeInferredCalleeWithAnalyzedReturnFlow() {
|
||||
exists (DataFlow::AnalyzedNode calleeNode |
|
||||
hasExplicitDefiniteCallee(this, calleeNode) and
|
||||
calleeNode.getALocalValue().(AbstractFunction).getFunction().flow() = fun
|
||||
)
|
||||
}
|
||||
|
||||
override AnalyzedFunction getACallee() {
|
||||
result = fun
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
| advanced-callgraph.js:2:13:2:20 | source() | advanced-callgraph.js:6:22:6:22 | v |
|
||||
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:17:14:17:14 | x |
|
||||
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:20:14:20:14 | y |
|
||||
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:30:14:30:20 | x.value |
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
(function(){
|
||||
let x = source();
|
||||
function nest1() {
|
||||
function nest2(){
|
||||
function nest3(v){
|
||||
sink(v);
|
||||
}
|
||||
return nest3;
|
||||
}
|
||||
return nest2;
|
||||
}
|
||||
nest1()()(x);
|
||||
});
|
||||
@@ -1,6 +1,23 @@
|
||||
| tst.js:1:1:1:16 | (function(){})() | tst.js:1:2:1:13 | function(){} | file://:0:0:0:0 | undefined |
|
||||
| tst.js:2:1:2:25 | (functi ... n; })() | tst.js:2:2:2:22 | functio ... turn; } | file://:0:0:0:0 | undefined |
|
||||
| tst.js:3:1:3:30 | (functi ... e; })() | tst.js:3:2:3:27 | functio ... true; } | file://:0:0:0:0 | true |
|
||||
| tst.js:4:1:4:51 | (functi ... e; })() | tst.js:4:2:4:48 | functio ... alse; } | file://:0:0:0:0 | false |
|
||||
| tst.js:4:1:4:51 | (functi ... e; })() | tst.js:4:2:4:48 | functio ... alse; } | file://:0:0:0:0 | true |
|
||||
| tst.js:5:1:5:27 | (functi ... x; })() | tst.js:5:2:5:24 | functio ... rn x; } | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:4:1:4:16 | (function(){})() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:5:1:5:25 | (functi ... n; })() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:6:1:6:30 | (functi ... e; })() | file://:0:0:0:0 | true |
|
||||
| tst.js:7:1:7:57 | (functi ... e; })() | file://:0:0:0:0 | false |
|
||||
| tst.js:7:1:7:57 | (functi ... e; })() | file://:0:0:0:0 | true |
|
||||
| tst.js:8:1:8:33 | (functi ... n; })() | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:11:5:11:8 | f1() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:14:5:14:8 | f2() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:15:5:15:8 | f2() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:23:5:23:8 | f4() | tst.js:21:16:21:30 | function f5 |
|
||||
| tst.js:23:5:23:10 | f4()() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:30:5:30:8 | f6() | tst.js:26:16:28:9 | function f7 |
|
||||
| tst.js:30:5:30:10 | f6()() | tst.js:27:20:27:34 | function f8 |
|
||||
| tst.js:36:5:36:9 | f10() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:39:5:39:9 | f11() | file://:0:0:0:0 | non-empty, non-numeric string |
|
||||
| tst.js:39:5:39:9 | f11() | file://:0:0:0:0 | non-zero value |
|
||||
| tst.js:45:5:45:9 | f13() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:48:5:48:9 | f14() | file://:0:0:0:0 | non-empty, non-numeric string |
|
||||
| tst.js:48:5:48:9 | f14() | file://:0:0:0:0 | non-zero value |
|
||||
| tst.js:61:5:61:9 | f15() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:64:5:64:9 | f16() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:84:17:84:22 | getF() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:89:17:89:22 | getG() | file://:0:0:0:0 | undefined |
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import javascript
|
||||
|
||||
from CallWithAnalyzedReturnFlow call
|
||||
select call, call.getACallee(), call.getACallee().getAReturnValue()
|
||||
from DataFlow::AnalyzedValueNode call
|
||||
where call instanceof CallWithAnalyzedReturnFlow or
|
||||
call instanceof CallWithNonLocalAnalyzedReturnFlow
|
||||
select call, call.getAValue()
|
||||
@@ -0,0 +1,64 @@
|
||||
| tst.js:1:18:1:24 | require | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:2:16:2:22 | require | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:4:1:4:14 | (function(){}) | tst.js:4:2:4:13 | anonymous function |
|
||||
| tst.js:5:1:5:23 | (functi ... urn; }) | tst.js:5:2:5:22 | anonymous function |
|
||||
| tst.js:6:1:6:28 | (functi ... rue; }) | tst.js:6:2:6:27 | anonymous function |
|
||||
| tst.js:7:1:7:55 | (functi ... lse; }) | tst.js:7:2:7:54 | anonymous function |
|
||||
| tst.js:8:1:8:31 | (functi ... own; }) | tst.js:8:2:8:30 | anonymous function |
|
||||
| tst.js:11:5:11:6 | f1 | tst.js:10:5:10:19 | function f1 |
|
||||
| tst.js:14:5:14:6 | f2 | tst.js:13:5:13:19 | function f2 |
|
||||
| tst.js:15:5:15:6 | f2 | tst.js:13:5:13:19 | function f2 |
|
||||
| tst.js:18:5:18:9 | o1.f3 | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:18:5:18:9 | o1.f3 | tst.js:17:20:17:34 | function f3 |
|
||||
| tst.js:23:5:23:6 | f4 | tst.js:20:5:22:5 | function f4 |
|
||||
| tst.js:23:5:23:8 | f4() | tst.js:21:16:21:30 | function f5 |
|
||||
| tst.js:30:5:30:6 | f6 | tst.js:25:5:29:5 | function f6 |
|
||||
| tst.js:30:5:30:8 | f6() | tst.js:26:16:28:9 | function f7 |
|
||||
| tst.js:30:5:30:10 | f6()() | tst.js:27:20:27:34 | function f8 |
|
||||
| tst.js:32:14:32:20 | unknown | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:33:5:33:6 | f9 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:36:5:36:7 | f10 | tst.js:35:24:35:36 | anonymous function |
|
||||
| tst.js:36:5:36:7 | f10 | tst.js:35:39:35:51 | anonymous function |
|
||||
| tst.js:39:5:39:7 | f11 | tst.js:38:24:38:48 | anonymous function |
|
||||
| tst.js:39:5:39:7 | f11 | tst.js:38:51:38:78 | anonymous function |
|
||||
| tst.js:41:39:41:45 | unknown | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:42:5:42:7 | f12 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:42:5:42:7 | f12 | tst.js:41:24:41:36 | anonymous function |
|
||||
| tst.js:45:5:45:7 | f13 | file://:0:0:0:0 | non-zero value |
|
||||
| tst.js:45:5:45:7 | f13 | tst.js:44:24:44:36 | anonymous function |
|
||||
| tst.js:48:5:48:7 | f14 | file://:0:0:0:0 | non-zero value |
|
||||
| tst.js:48:5:48:7 | f14 | tst.js:47:34:47:56 | anonymous function |
|
||||
| tst.js:48:5:48:7 | f14 | tst.js:47:59:47:86 | anonymous function |
|
||||
| tst.js:50:5:50:16 | someFunction | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:51:5:51:25 | someObj ... eMethod | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:51:5:51:25 | someObj ... eMethod | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:53:5:53:14 | someModule | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:53:5:53:14 | someModule | file://:0:0:0:0 | undefined |
|
||||
| tst.js:54:5:54:25 | someMod ... eMethod | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:54:5:54:25 | someMod ... eMethod | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:56:5:56:12 | myModule | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:56:5:56:12 | myModule | file://:0:0:0:0 | undefined |
|
||||
| tst.js:56:5:56:12 | myModule | myModule.js:1:1:4:0 | exports object of module myModule |
|
||||
| tst.js:56:5:56:12 | myModule | myModule.js:1:18:1:30 | anonymous function |
|
||||
| tst.js:57:5:57:22 | myModule.myMethod1 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:57:5:57:22 | myModule.myMethod1 | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:58:5:58:22 | myModule.myMethod2 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:58:5:58:22 | myModule.myMethod2 | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:58:5:58:34 | myModul ... Method3 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:58:5:58:34 | myModul ... Method3 | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:61:5:61:7 | f15 | file://:0:0:0:0 | undefined |
|
||||
| tst.js:61:5:61:7 | f15 | tst.js:60:24:60:36 | anonymous function |
|
||||
| tst.js:64:5:64:7 | f16 | tst.js:63:24:63:36 | anonymous function |
|
||||
| tst.js:64:5:64:7 | f16 | tst.js:63:39:63:40 | object literal |
|
||||
| tst.js:68:9:68:11 | f17 | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:68:9:68:11 | f17 | tst.js:67:31:67:42 | anonymous function |
|
||||
| tst.js:73:9:73:11 | f18 | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| tst.js:73:9:73:11 | f18 | tst.js:72:31:72:42 | anonymous function |
|
||||
| tst.js:77:5:77:7 | f19 | file://:0:0:0:0 | undefined |
|
||||
| tst.js:80:5:80:7 | f20 | file://:0:0:0:0 | undefined |
|
||||
| tst.js:80:5:80:7 | f20 | tst.js:79:24:79:25 | object literal |
|
||||
| tst.js:84:17:84:20 | getF | tst.js:83:20:83:31 | function getF |
|
||||
| tst.js:86:13:86:13 | f | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:86:13:86:13 | f | file://:0:0:0:0 | undefined |
|
||||
| tst.js:89:17:89:20 | getG | tst.js:88:9:88:25 | function getG |
|
||||
| tst.js:91:13:91:13 | g | file://:0:0:0:0 | undefined |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode call
|
||||
select call.getCalleeNode(), call.getCalleeNode().analyze().getAValue()
|
||||
@@ -0,0 +1,47 @@
|
||||
| tst.js:1:18:1:38 | require ... odule') | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:2:16:2:36 | require ... odule') | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:2:16:2:36 | require ... odule') | myModule.js:1:1:4:0 | exports object of module myModule |
|
||||
| tst.js:2:16:2:36 | require ... odule') | myModule.js:1:18:1:30 | anonymous function |
|
||||
| tst.js:4:1:4:16 | (function(){})() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:5:1:5:25 | (functi ... n; })() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:6:1:6:30 | (functi ... e; })() | file://:0:0:0:0 | true |
|
||||
| tst.js:7:1:7:57 | (functi ... e; })() | file://:0:0:0:0 | false |
|
||||
| tst.js:7:1:7:57 | (functi ... e; })() | file://:0:0:0:0 | true |
|
||||
| tst.js:8:1:8:33 | (functi ... n; })() | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:11:5:11:8 | f1() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:14:5:14:8 | f2() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:15:5:15:8 | f2() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:18:5:18:11 | o1.f3() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:23:5:23:8 | f4() | tst.js:21:16:21:30 | function f5 |
|
||||
| tst.js:23:5:23:10 | f4()() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:30:5:30:8 | f6() | tst.js:26:16:28:9 | function f7 |
|
||||
| tst.js:30:5:30:10 | f6()() | tst.js:27:20:27:34 | function f8 |
|
||||
| tst.js:30:5:30:12 | f6()()() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:32:14:32:22 | unknown() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:33:5:33:8 | f9() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:36:5:36:9 | f10() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:39:5:39:9 | f11() | file://:0:0:0:0 | non-empty, non-numeric string |
|
||||
| tst.js:39:5:39:9 | f11() | file://:0:0:0:0 | non-zero value |
|
||||
| tst.js:41:39:41:47 | unknown() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:42:5:42:9 | f12() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:45:5:45:9 | f13() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:48:5:48:9 | f14() | file://:0:0:0:0 | non-empty, non-numeric string |
|
||||
| tst.js:48:5:48:9 | f14() | file://:0:0:0:0 | non-zero value |
|
||||
| tst.js:50:5:50:18 | someFunction() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:51:5:51:27 | someObj ... ethod() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:53:5:53:16 | someModule() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:54:5:54:27 | someMod ... ethod() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:56:5:56:14 | myModule() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:57:5:57:24 | myModule.myMethod1() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:58:5:58:24 | myModule.myMethod2() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:58:5:58:36 | myModul ... thod3() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:61:5:61:9 | f15() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:64:5:64:9 | f16() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:68:9:68:13 | f17() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:73:9:73:13 | f18() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:77:5:77:9 | f19() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:80:5:80:9 | f20() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:84:17:84:22 | getF() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:86:13:86:15 | f() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:89:17:89:22 | getG() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:91:13:91:15 | g() | file://:0:0:0:0 | indefinite value (call) |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode call
|
||||
select call, call.analyze().getAValue()
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = function() {}
|
||||
module.exports.myMyMethod1 = function(){}
|
||||
module.exports.myMyMethod2 = function(){ return function(){} }
|
||||
@@ -1,5 +1,95 @@
|
||||
var someModule = require('someModule'),
|
||||
myModule = require('./myModule');
|
||||
|
||||
(function(){})();
|
||||
(function(){ return; })();
|
||||
(function(){ return true; })();
|
||||
(function(){ if (x) return true; return false; })();
|
||||
(function(){ return x; })();
|
||||
(function(){ if (unknown) return true; return false; })();
|
||||
(function(){ return unknown; })();
|
||||
(function(){
|
||||
function f1(){}
|
||||
f1();
|
||||
|
||||
function f2(){}
|
||||
f2();
|
||||
f2();
|
||||
|
||||
var o1 = { f3: function f3(){} };
|
||||
o1.f3();
|
||||
|
||||
function f4(){
|
||||
return function f5(){}
|
||||
}
|
||||
f4()();
|
||||
|
||||
function f6(){
|
||||
return function f7(){
|
||||
return function f8(){}
|
||||
}
|
||||
}
|
||||
f6()()();
|
||||
|
||||
var f9 = unknown();
|
||||
f9();
|
||||
|
||||
var f10 = unknown? function (){}: function (){};
|
||||
f10();
|
||||
|
||||
var f11 = unknown? function (){ return 42; }: function (){ return "foo"; };
|
||||
f11();
|
||||
|
||||
var f12 = unknown? function (){}: unknown();
|
||||
f12();
|
||||
|
||||
var f13 = unknown? function (){}: 42;
|
||||
f13(); // the call may crash, but the eventual return value is known!
|
||||
|
||||
var f14 = unknown? (unknown? function (){ return 42}: function (){ return "foo"; }): 42;
|
||||
f14(); // the call may crash, but the eventual return value is known!
|
||||
|
||||
someFunction();
|
||||
someObject.someMethod();
|
||||
|
||||
someModule();
|
||||
someModule.someMethod();
|
||||
|
||||
myModule();
|
||||
myModule.myMethod1();
|
||||
myModule.myMethod2().myMethod3();
|
||||
|
||||
var f15 = unknown? function (){}: undefined;
|
||||
f15(); // the call may crash, but the eventual return value is known!
|
||||
|
||||
var f16 = unknown? function (){}: {};
|
||||
f16(); // the call may crash, but the eventual return value is known!
|
||||
|
||||
for (var f of { f: function(){} }) {
|
||||
var f17 = unknown? f: function(){}
|
||||
f17();
|
||||
}
|
||||
|
||||
for (var f of unknown) {
|
||||
var f18 = unknown? f: function(){};
|
||||
f18();
|
||||
}
|
||||
|
||||
var f19 = undefined;
|
||||
f19();
|
||||
|
||||
var f20 = unknown? {}: undefined;
|
||||
f20();
|
||||
|
||||
(function () {
|
||||
var getF = function(){}
|
||||
var f = getF();
|
||||
(function () {
|
||||
f();
|
||||
});
|
||||
function getG(){}
|
||||
var g = getG();
|
||||
(function () {
|
||||
g();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
| tst.js:6:7:6:10 | true | 0 | file://:0:0:0:0 | true |
|
||||
| tst.js:6:13:6:19 | UNKNOWN | 1 | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:6:22:6:31 | getKnown() | 2 | file://:0:0:0:0 | true |
|
||||
| tst.js:6:34:6:45 | getUnknown() | 3 | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:6:48:6:55 | getKnown | 4 | tst.js:2:5:2:40 | function getKnown |
|
||||
| tst.js:6:58:6:67 | getUnknown | 5 | tst.js:4:5:4:45 | function getUnknown |
|
||||
| tst.js:9:14:9:23 | getKnown() | 0 | file://:0:0:0:0 | true |
|
||||
| tst.js:9:26:9:37 | getUnknown() | 1 | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:10:14:10:30 | getKnown_indirect | 0 | tst.js:2:5:2:40 | function getKnown |
|
||||
| tst.js:10:33:10:51 | getUnknown_indirect | 1 | tst.js:4:5:4:45 | function getUnknown |
|
||||
| tst.js:11:14:11:18 | known | 0 | file://:0:0:0:0 | true |
|
||||
| tst.js:11:21:11:27 | unknown | 1 | file://:0:0:0:0 | indefinite value (global) |
|
||||
| tst.js:11:30:11:37 | gotKnown | 2 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:11:40:11:49 | gotUnknown | 3 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:11:52:11:70 | getKnown_indirect() | 4 | file://:0:0:0:0 | true |
|
||||
| tst.js:11:73:11:93 | getUnkn ... irect() | 5 | file://:0:0:0:0 | indefinite value (global) |
|
||||
@@ -0,0 +1,5 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::CallNode c, int i, DataFlow::Node arg
|
||||
where arg = c.getArgument(i)
|
||||
select arg, i, arg.analyze().getAValue()
|
||||
@@ -0,0 +1,13 @@
|
||||
(function(){
|
||||
function getKnown() { return true; }
|
||||
|
||||
function getUnknown() { return UNKNOWN; }
|
||||
|
||||
f(true, UNKNOWN, getKnown(), getUnknown(), getKnown, getUnknown);
|
||||
|
||||
function f(known, unknown, gotKnown, gotUnknown, getKnown_indirect, getUnknown_indirect) {
|
||||
DUMP(getKnown(), getUnknown());
|
||||
DUMP(getKnown_indirect, getUnknown_indirect);
|
||||
DUMP(known, unknown, gotKnown, gotUnknown, getKnown_indirect(), getUnknown_indirect())
|
||||
}
|
||||
});
|
||||
@@ -18,6 +18,7 @@
|
||||
| src/iterated-handlers.js:4:2:4:22 | functio ... res){} |
|
||||
| src/middleware-attacher-getter.js:4:17:4:36 | function(req, res){} |
|
||||
| src/middleware-attacher-getter.js:19:19:19:38 | function(req, res){} |
|
||||
| src/middleware-attacher-getter.js:29:32:29:51 | function(req, res){} |
|
||||
| src/middleware-attacher.js:3:13:3:32 | function(req, res){} |
|
||||
| src/nodejs.js:3:19:3:38 | function(req, res){} |
|
||||
| src/nodejs.js:5:22:5:41 | function(req, res){} |
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
| src/handler-in-property.js:5:14:5:33 | function(req, res){} |
|
||||
| src/handler-in-property.js:12:18:12:37 | function(req, res){} |
|
||||
| src/middleware-attacher-getter.js:4:17:4:36 | function(req, res){} |
|
||||
| src/middleware-attacher-getter.js:19:19:19:38 | function(req, res){} |
|
||||
| src/middleware-attacher.js:3:13:3:32 | function(req, res){} |
|
||||
| src/nodejs.js:3:19:3:38 | function(req, res){} |
|
||||
| src/nodejs.js:8:14:8:33 | function(req, res){} |
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
| src/iterated-handlers.js:4:2:4:22 | functio ... res){} |
|
||||
| src/middleware-attacher-getter.js:4:17:4:36 | function(req, res){} |
|
||||
| src/middleware-attacher-getter.js:19:19:19:38 | function(req, res){} |
|
||||
| src/middleware-attacher-getter.js:29:32:29:51 | function(req, res){} |
|
||||
| src/middleware-attacher.js:3:13:3:32 | function(req, res){} |
|
||||
| src/nodejs.js:3:19:3:38 | function(req, res){} |
|
||||
| src/nodejs.js:5:22:5:41 | function(req, res){} |
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
| src/iterated-handlers.js:5:5:5:14 | app.use(h) |
|
||||
| src/middleware-attacher-getter.js:4:9:4:37 | app.use ... res){}) |
|
||||
| src/middleware-attacher-getter.js:14:9:14:18 | app.use(h) |
|
||||
| src/middleware-attacher-getter.js:24:9:24:18 | app.use(h) |
|
||||
| src/middleware-attacher.js:3:5:3:33 | app.use ... res){}) |
|
||||
| src/nodejs.js:3:1:3:39 | http.cr ... res){}) |
|
||||
| src/nodejs.js:8:1:8:34 | createS ... res){}) |
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
| src/iterated-handlers.js:5:5:5:14 | app.use(h) |
|
||||
| src/middleware-attacher-getter.js:4:9:4:37 | app.use ... res){}) |
|
||||
| src/middleware-attacher-getter.js:14:9:14:18 | app.use(h) |
|
||||
| src/middleware-attacher-getter.js:24:9:24:18 | app.use(h) |
|
||||
| src/middleware-attacher.js:3:5:3:33 | app.use ... res){}) |
|
||||
| src/nodejs.js:3:1:3:39 | http.cr ... res){}) |
|
||||
| src/nodejs.js:5:1:5:42 | unknown ... res){}) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| src/bound-handler.js:4:1:4:28 | functio ... res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. |
|
||||
| src/bound-handler.js:9:12:9:31 | function(req, res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. |
|
||||
| src/iterated-handlers.js:4:2:4:22 | functio ... res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. |
|
||||
| src/middleware-attacher-getter.js:19:19:19:38 | function(req, res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. |
|
||||
| src/middleware-attacher-getter.js:29:32:29:51 | function(req, res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. |
|
||||
| src/route-objects.js:7:19:7:38 | function(req, res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. |
|
||||
| src/route-objects.js:8:12:10:5 | (req, res) {\\n\\n } | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. |
|
||||
| src/route-objects.js:20:16:22:9 | (req, r ... } | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. |
|
||||
|
||||
@@ -7,7 +7,7 @@ function getAttacher1 (app) {
|
||||
|
||||
var app = express();
|
||||
getAttacher1(app);
|
||||
confuse(getAttacher2); // disable the type inference
|
||||
confuse(getAttacher2); // attempt to disable the type inference
|
||||
|
||||
function getAttacher2 (app) {
|
||||
return function(h) {
|
||||
@@ -17,4 +17,13 @@ function getAttacher2 (app) {
|
||||
|
||||
var app = express();
|
||||
getAttacher2(app)(function(req, res){});
|
||||
confuse(getAttacher2); // disable the type inference
|
||||
confuse(getAttacher2); // attempt to disable the type inference
|
||||
|
||||
function getAttacher3 (app) {
|
||||
return function(h) {
|
||||
app.use(h);
|
||||
};
|
||||
}
|
||||
|
||||
var app = express();
|
||||
(unknown || getAttacher3)(app)(function(req, res){}); // confuse the type inference
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
| interprocedural.js:11:9:11:13 | known | Variable 'known' is of type string, but it is compared to $@ of type number. | interprocedural.js:11:19:11:20 | 42 | an expression |
|
||||
| interprocedural.js:15:9:15:18 | getKnown() | This expression is of type string, but it is compared to $@ of type number. | interprocedural.js:15:24:15:25 | 42 | an expression |
|
||||
| interprocedural.js:17:9:17:27 | getKnown_indirect() | This expression is of type string, but it is compared to $@ of type number. | interprocedural.js:17:33:17:34 | 42 | an expression |
|
||||
| tst.js:2:5:2:17 | typeof window | This expression is of type string, but it is compared to $@ of type undefined. | tst.js:2:23:2:31 | undefined | 'undefined' |
|
||||
| tst.js:10:28:10:34 | "Hello" | This expression is of type string, but it is compared to $@ of type number. | tst.js:10:39:10:39 | 0 | an expression |
|
||||
| tst.js:20:1:20:4 | null | This expression is of type null, but it is compared to $@ of type number. | tst.js:20:9:20:9 | 0 | an expression |
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
(function(){
|
||||
|
||||
function getUnknown() { return UNKNOWN; }
|
||||
|
||||
function getKnown() { return "foo"; }
|
||||
|
||||
function f(known, unknown, gotKnown, gotUnknown, getKnown_indirect, getUnknown_indirect) {
|
||||
// disable the whitelist
|
||||
known = known; unknown = unknown; gotKnown = gotKnown; gotUnknown = gotUnknown;
|
||||
|
||||
known === 42;
|
||||
known == 42;
|
||||
gotKnown === 42;
|
||||
gotKnown == 42;
|
||||
getKnown() === 42;
|
||||
getKnown() == 42;
|
||||
getKnown_indirect() === 42;
|
||||
getKnown_indirect() == 42;
|
||||
|
||||
unknown === 42;
|
||||
unknown == 42;
|
||||
gotUnknown === 42;
|
||||
gotUnknown == 42;
|
||||
getUnknown() === 42;
|
||||
getUnknown() == 42;
|
||||
getUnknown_indirect() === 42;
|
||||
getUnknown_indirect() == 42;
|
||||
}
|
||||
|
||||
f("foo", UNKNOWN, getKnown(), getUnknown(), getKnown, getUnknown);
|
||||
|
||||
});
|
||||
@@ -9,3 +9,5 @@
|
||||
| tst.js:73:5:73:5 | x | This expression will be implicitly converted from undefined to number. |
|
||||
| tst.js:79:19:79:22 | name | This expression will be implicitly converted from undefined to string. |
|
||||
| tst.js:85:3:85:3 | x | This expression will be implicitly converted from undefined to number. |
|
||||
| tst.js:100:5:100:7 | f() | This expression will be implicitly converted from undefined to number. |
|
||||
| tst.js:106:5:106:7 | g() | This expression will be implicitly converted from undefined to number. |
|
||||
|
||||
@@ -94,4 +94,17 @@ function l() {
|
||||
}
|
||||
});
|
||||
|
||||
(function(){
|
||||
function f() {
|
||||
}
|
||||
f()|0;
|
||||
|
||||
unknown()|0;
|
||||
|
||||
function g() {
|
||||
}
|
||||
g()|0;
|
||||
g();
|
||||
});
|
||||
|
||||
// semmle-extractor-options: --experimental
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
(function () {
|
||||
var getF = function(){}
|
||||
var f = getF();
|
||||
(function () {
|
||||
f();
|
||||
});
|
||||
});
|
||||
|
||||
(function () {
|
||||
var getF = unknown
|
||||
if (false) {
|
||||
var f = getF();
|
||||
(function () {
|
||||
f();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
| SuspiciousPropAccess.js:4:10:4:21 | result.value | The base expression of this property access is always undefined. |
|
||||
| tst.js:32:32:32:38 | a(1)[0] | The base expression of this property access is always null. |
|
||||
| tst.ts:19:3:19:5 | x.p | The base expression of this property access is always undefined. |
|
||||
| typeassertion.ts:14:3:14:9 | z.field | The base expression of this property access is always null. |
|
||||
|
||||
@@ -27,3 +27,7 @@
|
||||
v1.p;
|
||||
}
|
||||
});
|
||||
|
||||
(function(){
|
||||
function a(){return null;} a(1)[0];
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user