Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7670a2b

Browse files
authored
Merge pull request #20375 from asgerf/js/promise-try
JS: Support Promise.try and Array.prototype.with
2 parents eac8a79 + edf79a3 commit 7670a2b

File tree

6 files changed

+110
-0
lines changed

6 files changed

+110
-0
lines changed

javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,25 @@ class ToSpliced extends SummarizedCallable {
544544
}
545545
}
546546

547+
class With extends SummarizedCallable {
548+
With() { this = "Array#with" }
549+
550+
override InstanceCall getACallSimple() { result.getMethodName() = "with" }
551+
552+
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
553+
preservesValue = true and
554+
(
555+
// Copy all elements from the original array to the new array
556+
input = "Argument[this].WithArrayElement" and
557+
output = "ReturnValue"
558+
or
559+
// Replace the value at the specified index
560+
input = "Argument[1]" and
561+
output = "ReturnValue.ArrayElement"
562+
)
563+
}
564+
}
565+
547566
class ArrayCoercionPackage extends FunctionalPackageSummary {
548567
ArrayCoercionPackage() { this = "ArrayCoercionPackage" }
549568

javascript/ql/lib/semmle/javascript/internal/flow_summaries/FlowSummaryUtil.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,10 @@ string getAnArrayContent() {
4949
// Values stored at an unknown index
5050
result = "ArrayElement[?]"
5151
}
52+
53+
/**
54+
* Gets an argument position up to a certain limit.
55+
*
56+
* This can be used to generate flow summaries that should preserve such positions.
57+
*/
58+
int getAnArgumentPosition() { result = [0 .. 10] }

javascript/ql/lib/semmle/javascript/internal/flow_summaries/Promises.qll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,29 @@ private class PromiseWithResolversLike extends SummarizedCallable {
368368
)
369369
}
370370
}
371+
372+
class PromiseTry extends DataFlow::SummarizedCallable {
373+
PromiseTry() { this = "Promise.try()" }
374+
375+
override DataFlow::CallNode getACallSimple() {
376+
result = promiseConstructorRef().getAMemberCall(["try", "attempt"])
377+
or
378+
result = DataFlow::moduleImport(["p-try", "es6-promise-try"]).getACall()
379+
}
380+
381+
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
382+
preservesValue = true and
383+
(
384+
exists(int i | i = getAnArgumentPosition() |
385+
input = "Argument[" + (i + 1) + "]" and
386+
output = "Argument[0].Parameter[" + i + "]"
387+
)
388+
or
389+
input = "Argument[0].ReturnValue" and
390+
output = "ReturnValue.Awaited"
391+
or
392+
input = "Argument[0].ReturnValue[exception]" and
393+
output = "ReturnValue.Awaited[error]"
394+
)
395+
}
396+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Data flow is now tracked through the `Promise.try` and `Array.prototype.with` functions.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
function t1() {
2+
const arr = [1, 2, 3];
3+
const newArr = arr.with(1, source('with.1'));
4+
sink(newArr[1]); // $ hasValueFlow=with.1
5+
}
6+
7+
function t2() {
8+
const arr = [source('with.2.1'), 2, source('with.2.3')];
9+
const newArr = arr.with(1, 'replaced');
10+
sink(newArr[0]); // $ hasValueFlow=with.2.1
11+
sink(newArr[2]); // $ hasValueFlow=with.2.3
12+
}
13+
14+
function t3() {
15+
const arr = [1, 2, 3];
16+
const index = source('with.3.index');
17+
const newArr = arr.with(index, 'new value');
18+
// No assertions here as the index is tainted, not the value
19+
}
20+
21+
function t4() {
22+
const arr = [1, 2, 3];
23+
const newArr = arr.with(1, source('with.4'));
24+
sink(arr[1]); // This should NOT have value flow as with() returns a new array
25+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
async function t1() {
2+
const promise = Promise.try(() => {
3+
return source('try.1');
4+
});
5+
sink(await promise); // $ hasValueFlow=try.1
6+
}
7+
8+
async function t2() {
9+
const promise = Promise.try((x) => {
10+
return x
11+
}, source('try.2'));
12+
sink(await promise); // $ hasValueFlow=try.2
13+
}
14+
15+
async function t3() {
16+
const promise = Promise.try((x) => {
17+
throw x;
18+
}, source('try.3'));
19+
promise.catch(err => {
20+
sink(err); // $ hasValueFlow=try.3
21+
});
22+
}
23+
24+
async function t4() {
25+
const promise = Promise.try((x, y) => {
26+
return y;
27+
}, source('try.4.1'), source('try.4.2'));
28+
sink(await promise); // $ hasValueFlow=try.4.2
29+
}

0 commit comments

Comments
 (0)