From 87d4e13584297992d169cf7fc6816f94fb5543cf Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 17 Sep 2020 12:42:37 +0200 Subject: [PATCH 1/6] added support for ES2021 assignment operators --- .../src/com/semmle/jcorn/Parser.java | 20 +- .../extractor/tests/es2021/input/assign.js | 9 + .../extractor/tests/es2021/options.json | 3 + .../tests/es2021/output/trap/assign.js.trap | 633 ++++++++++++++++++ 4 files changed, 659 insertions(+), 6 deletions(-) create mode 100644 javascript/extractor/tests/es2021/input/assign.js create mode 100644 javascript/extractor/tests/es2021/options.json create mode 100644 javascript/extractor/tests/es2021/output/trap/assign.js.trap diff --git a/javascript/extractor/src/com/semmle/jcorn/Parser.java b/javascript/extractor/src/com/semmle/jcorn/Parser.java index a8348c3c307..7c018b6a456 100644 --- a/javascript/extractor/src/com/semmle/jcorn/Parser.java +++ b/javascript/extractor/src/com/semmle/jcorn/Parser.java @@ -531,9 +531,14 @@ public class Parser { int next2 = charAt(this.pos + 2); if (this.options.esnext()) { if (next == '.' && !('0' <= next2 && next2 <= '9')) // '?.', but not '?.X' where X is a digit - return this.finishOp(TokenType.questiondot, 2); - if (next == '?') // '??' - return this.finishOp(TokenType.questionquestion, 2); + return this.finishOp(TokenType.questiondot, 2); + if (next == '?') { // '??' + if (next2 == '=') { // ??= + return this.finishOp(TokenType.assign, 3); + } + return this.finishOp(TokenType.questionquestion, 2); + } + } return this.finishOp(TokenType.question, 1); } @@ -566,8 +571,11 @@ public class Parser { private Token readToken_pipe_amp(int code) { // '|&' int next = charAt(this.pos + 1); - if (next == code) + int next2 = charAt(this.pos + 2); + if (next == code) { // && || + if (next2 == 61) return this.finishOp(TokenType.assign, 3); // &&= ||= return this.finishOp(code == 124 ? TokenType.logicalOR : TokenType.logicalAND, 2); + } if (next == 61) return this.finishOp(TokenType.assign, 2); return this.finishOp(code == 124 ? TokenType.bitwiseOR : TokenType.bitwiseAND, 1); } @@ -709,8 +717,8 @@ public class Parser { case 42: // '%*' return this.readToken_mult_modulo_exp(code); - case 124: - case 38: // '|&' + case 124: // '|' + case 38: // '&' return this.readToken_pipe_amp(code); case 94: // '^' diff --git a/javascript/extractor/tests/es2021/input/assign.js b/javascript/extractor/tests/es2021/input/assign.js new file mode 100644 index 00000000000..7075534fe3b --- /dev/null +++ b/javascript/extractor/tests/es2021/input/assign.js @@ -0,0 +1,9 @@ +var x = 1; +var y = 2; +var foo = x && y; +var bar = x &&= y; +console.log(x); // 2 + +x &&= y; +x ||= y; +x ??= y; diff --git a/javascript/extractor/tests/es2021/options.json b/javascript/extractor/tests/es2021/options.json new file mode 100644 index 00000000000..075583ca1f6 --- /dev/null +++ b/javascript/extractor/tests/es2021/options.json @@ -0,0 +1,3 @@ +{ + "experimental": true +} diff --git a/javascript/extractor/tests/es2021/output/trap/assign.js.trap b/javascript/extractor/tests/es2021/output/trap/assign.js.trap new file mode 100644 index 00000000000..1fb2b771f15 --- /dev/null +++ b/javascript/extractor/tests/es2021/output/trap/assign.js.trap @@ -0,0 +1,633 @@ +#10000=@"/assign.js;sourcefile" +files(#10000,"/assign.js","assign","js",0) +#10001=@"/;folder" +folders(#10001,"/","") +containerparent(#10001,#10000) +#10002=@"loc,{#10000},0,0,0,0" +locations_default(#10002,#10000,0,0,0,0) +hasLocation(#10000,#10002) +#20000=@"global_scope" +scopes(#20000,0) +#20001=@"script;{#10000},1,1" +#20002=* +comments(#20002,0,#20001," 2","// 2") +#20003=@"loc,{#10000},5,17,5,20" +locations_default(#20003,#10000,5,17,5,20) +hasLocation(#20002,#20003) +#20004=* +lines(#20004,#20001,"var x = 1;"," +") +#20005=@"loc,{#10000},1,1,1,10" +locations_default(#20005,#10000,1,1,1,10) +hasLocation(#20004,#20005) +#20006=* +lines(#20006,#20001,"var y = 2;"," +") +#20007=@"loc,{#10000},2,1,2,10" +locations_default(#20007,#10000,2,1,2,10) +hasLocation(#20006,#20007) +#20008=* +lines(#20008,#20001,"var foo = x && y;"," +") +#20009=@"loc,{#10000},3,1,3,17" +locations_default(#20009,#10000,3,1,3,17) +hasLocation(#20008,#20009) +#20010=* +lines(#20010,#20001,"var bar = x &&= y;"," +") +#20011=@"loc,{#10000},4,1,4,18" +locations_default(#20011,#10000,4,1,4,18) +hasLocation(#20010,#20011) +#20012=* +lines(#20012,#20001,"console.log(x); // 2"," +") +#20013=@"loc,{#10000},5,1,5,20" +locations_default(#20013,#10000,5,1,5,20) +hasLocation(#20012,#20013) +#20014=* +lines(#20014,#20001,""," +") +#20015=@"loc,{#10000},6,1,6,0" +locations_default(#20015,#10000,6,1,6,0) +hasLocation(#20014,#20015) +#20016=* +lines(#20016,#20001,"x &&= y;"," +") +#20017=@"loc,{#10000},7,1,7,8" +locations_default(#20017,#10000,7,1,7,8) +hasLocation(#20016,#20017) +#20018=* +lines(#20018,#20001,"x ||= y;"," +") +#20019=@"loc,{#10000},8,1,8,8" +locations_default(#20019,#10000,8,1,8,8) +hasLocation(#20018,#20019) +#20020=* +lines(#20020,#20001,"x ??= y;"," +") +#20021=@"loc,{#10000},9,1,9,8" +locations_default(#20021,#10000,9,1,9,8) +hasLocation(#20020,#20021) +numlines(#20001,9,8,1) +#20022=* +tokeninfo(#20022,7,#20001,0,"var") +#20023=@"loc,{#10000},1,1,1,3" +locations_default(#20023,#10000,1,1,1,3) +hasLocation(#20022,#20023) +#20024=* +tokeninfo(#20024,6,#20001,1,"x") +#20025=@"loc,{#10000},1,5,1,5" +locations_default(#20025,#10000,1,5,1,5) +hasLocation(#20024,#20025) +#20026=* +tokeninfo(#20026,8,#20001,2,"=") +#20027=@"loc,{#10000},1,7,1,7" +locations_default(#20027,#10000,1,7,1,7) +hasLocation(#20026,#20027) +#20028=* +tokeninfo(#20028,3,#20001,3,"1") +#20029=@"loc,{#10000},1,9,1,9" +locations_default(#20029,#10000,1,9,1,9) +hasLocation(#20028,#20029) +#20030=* +tokeninfo(#20030,8,#20001,4,";") +#20031=@"loc,{#10000},1,10,1,10" +locations_default(#20031,#10000,1,10,1,10) +hasLocation(#20030,#20031) +#20032=* +tokeninfo(#20032,7,#20001,5,"var") +#20033=@"loc,{#10000},2,1,2,3" +locations_default(#20033,#10000,2,1,2,3) +hasLocation(#20032,#20033) +#20034=* +tokeninfo(#20034,6,#20001,6,"y") +#20035=@"loc,{#10000},2,5,2,5" +locations_default(#20035,#10000,2,5,2,5) +hasLocation(#20034,#20035) +#20036=* +tokeninfo(#20036,8,#20001,7,"=") +#20037=@"loc,{#10000},2,7,2,7" +locations_default(#20037,#10000,2,7,2,7) +hasLocation(#20036,#20037) +#20038=* +tokeninfo(#20038,3,#20001,8,"2") +#20039=@"loc,{#10000},2,9,2,9" +locations_default(#20039,#10000,2,9,2,9) +hasLocation(#20038,#20039) +#20040=* +tokeninfo(#20040,8,#20001,9,";") +#20041=@"loc,{#10000},2,10,2,10" +locations_default(#20041,#10000,2,10,2,10) +hasLocation(#20040,#20041) +#20042=* +tokeninfo(#20042,7,#20001,10,"var") +#20043=@"loc,{#10000},3,1,3,3" +locations_default(#20043,#10000,3,1,3,3) +hasLocation(#20042,#20043) +#20044=* +tokeninfo(#20044,6,#20001,11,"foo") +#20045=@"loc,{#10000},3,5,3,7" +locations_default(#20045,#10000,3,5,3,7) +hasLocation(#20044,#20045) +#20046=* +tokeninfo(#20046,8,#20001,12,"=") +#20047=@"loc,{#10000},3,9,3,9" +locations_default(#20047,#10000,3,9,3,9) +hasLocation(#20046,#20047) +#20048=* +tokeninfo(#20048,6,#20001,13,"x") +#20049=@"loc,{#10000},3,11,3,11" +locations_default(#20049,#10000,3,11,3,11) +hasLocation(#20048,#20049) +#20050=* +tokeninfo(#20050,8,#20001,14,"&&") +#20051=@"loc,{#10000},3,13,3,14" +locations_default(#20051,#10000,3,13,3,14) +hasLocation(#20050,#20051) +#20052=* +tokeninfo(#20052,6,#20001,15,"y") +#20053=@"loc,{#10000},3,16,3,16" +locations_default(#20053,#10000,3,16,3,16) +hasLocation(#20052,#20053) +#20054=* +tokeninfo(#20054,8,#20001,16,";") +#20055=@"loc,{#10000},3,17,3,17" +locations_default(#20055,#10000,3,17,3,17) +hasLocation(#20054,#20055) +#20056=* +tokeninfo(#20056,7,#20001,17,"var") +#20057=@"loc,{#10000},4,1,4,3" +locations_default(#20057,#10000,4,1,4,3) +hasLocation(#20056,#20057) +#20058=* +tokeninfo(#20058,6,#20001,18,"bar") +#20059=@"loc,{#10000},4,5,4,7" +locations_default(#20059,#10000,4,5,4,7) +hasLocation(#20058,#20059) +#20060=* +tokeninfo(#20060,8,#20001,19,"=") +#20061=@"loc,{#10000},4,9,4,9" +locations_default(#20061,#10000,4,9,4,9) +hasLocation(#20060,#20061) +#20062=* +tokeninfo(#20062,6,#20001,20,"x") +#20063=@"loc,{#10000},4,11,4,11" +locations_default(#20063,#10000,4,11,4,11) +hasLocation(#20062,#20063) +#20064=* +tokeninfo(#20064,8,#20001,21,"&&=") +#20065=@"loc,{#10000},4,13,4,15" +locations_default(#20065,#10000,4,13,4,15) +hasLocation(#20064,#20065) +#20066=* +tokeninfo(#20066,6,#20001,22,"y") +#20067=@"loc,{#10000},4,17,4,17" +locations_default(#20067,#10000,4,17,4,17) +hasLocation(#20066,#20067) +#20068=* +tokeninfo(#20068,8,#20001,23,";") +#20069=@"loc,{#10000},4,18,4,18" +locations_default(#20069,#10000,4,18,4,18) +hasLocation(#20068,#20069) +#20070=* +tokeninfo(#20070,6,#20001,24,"console") +#20071=@"loc,{#10000},5,1,5,7" +locations_default(#20071,#10000,5,1,5,7) +hasLocation(#20070,#20071) +#20072=* +tokeninfo(#20072,8,#20001,25,".") +#20073=@"loc,{#10000},5,8,5,8" +locations_default(#20073,#10000,5,8,5,8) +hasLocation(#20072,#20073) +#20074=* +tokeninfo(#20074,6,#20001,26,"log") +#20075=@"loc,{#10000},5,9,5,11" +locations_default(#20075,#10000,5,9,5,11) +hasLocation(#20074,#20075) +#20076=* +tokeninfo(#20076,8,#20001,27,"(") +#20077=@"loc,{#10000},5,12,5,12" +locations_default(#20077,#10000,5,12,5,12) +hasLocation(#20076,#20077) +#20078=* +tokeninfo(#20078,6,#20001,28,"x") +#20079=@"loc,{#10000},5,13,5,13" +locations_default(#20079,#10000,5,13,5,13) +hasLocation(#20078,#20079) +#20080=* +tokeninfo(#20080,8,#20001,29,")") +#20081=@"loc,{#10000},5,14,5,14" +locations_default(#20081,#10000,5,14,5,14) +hasLocation(#20080,#20081) +#20082=* +tokeninfo(#20082,8,#20001,30,";") +#20083=@"loc,{#10000},5,15,5,15" +locations_default(#20083,#10000,5,15,5,15) +hasLocation(#20082,#20083) +#20084=* +tokeninfo(#20084,6,#20001,31,"x") +#20085=@"loc,{#10000},7,1,7,1" +locations_default(#20085,#10000,7,1,7,1) +hasLocation(#20084,#20085) +next_token(#20002,#20084) +#20086=* +tokeninfo(#20086,8,#20001,32,"&&=") +#20087=@"loc,{#10000},7,3,7,5" +locations_default(#20087,#10000,7,3,7,5) +hasLocation(#20086,#20087) +#20088=* +tokeninfo(#20088,6,#20001,33,"y") +#20089=@"loc,{#10000},7,7,7,7" +locations_default(#20089,#10000,7,7,7,7) +hasLocation(#20088,#20089) +#20090=* +tokeninfo(#20090,8,#20001,34,";") +#20091=@"loc,{#10000},7,8,7,8" +locations_default(#20091,#10000,7,8,7,8) +hasLocation(#20090,#20091) +#20092=* +tokeninfo(#20092,6,#20001,35,"x") +#20093=@"loc,{#10000},8,1,8,1" +locations_default(#20093,#10000,8,1,8,1) +hasLocation(#20092,#20093) +#20094=* +tokeninfo(#20094,8,#20001,36,"||=") +#20095=@"loc,{#10000},8,3,8,5" +locations_default(#20095,#10000,8,3,8,5) +hasLocation(#20094,#20095) +#20096=* +tokeninfo(#20096,6,#20001,37,"y") +#20097=@"loc,{#10000},8,7,8,7" +locations_default(#20097,#10000,8,7,8,7) +hasLocation(#20096,#20097) +#20098=* +tokeninfo(#20098,8,#20001,38,";") +#20099=@"loc,{#10000},8,8,8,8" +locations_default(#20099,#10000,8,8,8,8) +hasLocation(#20098,#20099) +#20100=* +tokeninfo(#20100,6,#20001,39,"x") +#20101=@"loc,{#10000},9,1,9,1" +locations_default(#20101,#10000,9,1,9,1) +hasLocation(#20100,#20101) +#20102=* +tokeninfo(#20102,8,#20001,40,"??=") +#20103=@"loc,{#10000},9,3,9,5" +locations_default(#20103,#10000,9,3,9,5) +hasLocation(#20102,#20103) +#20104=* +tokeninfo(#20104,6,#20001,41,"y") +#20105=@"loc,{#10000},9,7,9,7" +locations_default(#20105,#10000,9,7,9,7) +hasLocation(#20104,#20105) +#20106=* +tokeninfo(#20106,8,#20001,42,";") +#20107=@"loc,{#10000},9,8,9,8" +locations_default(#20107,#10000,9,8,9,8) +hasLocation(#20106,#20107) +#20108=* +tokeninfo(#20108,0,#20001,43,"") +#20109=@"loc,{#10000},10,1,10,0" +locations_default(#20109,#10000,10,1,10,0) +hasLocation(#20108,#20109) +toplevels(#20001,0) +#20110=@"loc,{#10000},1,1,10,0" +locations_default(#20110,#10000,1,1,10,0) +hasLocation(#20001,#20110) +#20111=@"var;{x};{#20000}" +variables(#20111,"x",#20000) +#20112=@"var;{y};{#20000}" +variables(#20112,"y",#20000) +#20113=@"var;{foo};{#20000}" +variables(#20113,"foo",#20000) +#20114=@"var;{bar};{#20000}" +variables(#20114,"bar",#20000) +#20115=* +stmts(#20115,18,#20001,0,"var x = 1;") +hasLocation(#20115,#20005) +stmt_containers(#20115,#20001) +#20116=* +exprs(#20116,64,#20115,0,"x = 1") +#20117=@"loc,{#10000},1,5,1,9" +locations_default(#20117,#10000,1,5,1,9) +hasLocation(#20116,#20117) +enclosing_stmt(#20116,#20115) +expr_containers(#20116,#20001) +#20118=* +exprs(#20118,78,#20116,0,"x") +hasLocation(#20118,#20025) +enclosing_stmt(#20118,#20115) +expr_containers(#20118,#20001) +literals("x","x",#20118) +decl(#20118,#20111) +#20119=* +exprs(#20119,3,#20116,1,"1") +hasLocation(#20119,#20029) +enclosing_stmt(#20119,#20115) +expr_containers(#20119,#20001) +literals("1","1",#20119) +#20120=* +stmts(#20120,18,#20001,1,"var y = 2;") +hasLocation(#20120,#20007) +stmt_containers(#20120,#20001) +#20121=* +exprs(#20121,64,#20120,0,"y = 2") +#20122=@"loc,{#10000},2,5,2,9" +locations_default(#20122,#10000,2,5,2,9) +hasLocation(#20121,#20122) +enclosing_stmt(#20121,#20120) +expr_containers(#20121,#20001) +#20123=* +exprs(#20123,78,#20121,0,"y") +hasLocation(#20123,#20035) +enclosing_stmt(#20123,#20120) +expr_containers(#20123,#20001) +literals("y","y",#20123) +decl(#20123,#20112) +#20124=* +exprs(#20124,3,#20121,1,"2") +hasLocation(#20124,#20039) +enclosing_stmt(#20124,#20120) +expr_containers(#20124,#20001) +literals("2","2",#20124) +#20125=* +stmts(#20125,18,#20001,2,"var foo = x && y;") +hasLocation(#20125,#20009) +stmt_containers(#20125,#20001) +#20126=* +exprs(#20126,64,#20125,0,"foo = x && y") +#20127=@"loc,{#10000},3,5,3,16" +locations_default(#20127,#10000,3,5,3,16) +hasLocation(#20126,#20127) +enclosing_stmt(#20126,#20125) +expr_containers(#20126,#20001) +#20128=* +exprs(#20128,78,#20126,0,"foo") +hasLocation(#20128,#20045) +enclosing_stmt(#20128,#20125) +expr_containers(#20128,#20001) +literals("foo","foo",#20128) +decl(#20128,#20113) +#20129=* +exprs(#20129,44,#20126,1,"x && y") +#20130=@"loc,{#10000},3,11,3,16" +locations_default(#20130,#10000,3,11,3,16) +hasLocation(#20129,#20130) +enclosing_stmt(#20129,#20125) +expr_containers(#20129,#20001) +#20131=* +exprs(#20131,79,#20129,0,"x") +hasLocation(#20131,#20049) +enclosing_stmt(#20131,#20125) +expr_containers(#20131,#20001) +literals("x","x",#20131) +bind(#20131,#20111) +#20132=* +exprs(#20132,79,#20129,1,"y") +hasLocation(#20132,#20053) +enclosing_stmt(#20132,#20125) +expr_containers(#20132,#20001) +literals("y","y",#20132) +bind(#20132,#20112) +#20133=* +stmts(#20133,18,#20001,3,"var bar = x &&= y;") +hasLocation(#20133,#20011) +stmt_containers(#20133,#20001) +#20134=* +exprs(#20134,64,#20133,0,"bar = x &&= y") +#20135=@"loc,{#10000},4,5,4,17" +locations_default(#20135,#10000,4,5,4,17) +hasLocation(#20134,#20135) +enclosing_stmt(#20134,#20133) +expr_containers(#20134,#20001) +#20136=* +exprs(#20136,78,#20134,0,"bar") +hasLocation(#20136,#20059) +enclosing_stmt(#20136,#20133) +expr_containers(#20136,#20001) +literals("bar","bar",#20136) +decl(#20136,#20114) +#20137=* +exprs(#20137,116,#20134,1,"x &&= y") +#20138=@"loc,{#10000},4,11,4,17" +locations_default(#20138,#10000,4,11,4,17) +hasLocation(#20137,#20138) +enclosing_stmt(#20137,#20133) +expr_containers(#20137,#20001) +#20139=* +exprs(#20139,79,#20137,0,"x") +hasLocation(#20139,#20063) +enclosing_stmt(#20139,#20133) +expr_containers(#20139,#20001) +literals("x","x",#20139) +bind(#20139,#20111) +#20140=* +exprs(#20140,79,#20137,1,"y") +hasLocation(#20140,#20067) +enclosing_stmt(#20140,#20133) +expr_containers(#20140,#20001) +literals("y","y",#20140) +bind(#20140,#20112) +#20141=* +stmts(#20141,2,#20001,4,"console.log(x);") +#20142=@"loc,{#10000},5,1,5,15" +locations_default(#20142,#10000,5,1,5,15) +hasLocation(#20141,#20142) +stmt_containers(#20141,#20001) +#20143=* +exprs(#20143,13,#20141,0,"console.log(x)") +#20144=@"loc,{#10000},5,1,5,14" +locations_default(#20144,#10000,5,1,5,14) +hasLocation(#20143,#20144) +enclosing_stmt(#20143,#20141) +expr_containers(#20143,#20001) +#20145=* +exprs(#20145,14,#20143,-1,"console.log") +#20146=@"loc,{#10000},5,1,5,11" +locations_default(#20146,#10000,5,1,5,11) +hasLocation(#20145,#20146) +enclosing_stmt(#20145,#20141) +expr_containers(#20145,#20001) +#20147=* +exprs(#20147,79,#20145,0,"console") +hasLocation(#20147,#20071) +enclosing_stmt(#20147,#20141) +expr_containers(#20147,#20001) +literals("console","console",#20147) +#20148=@"var;{console};{#20000}" +variables(#20148,"console",#20000) +bind(#20147,#20148) +#20149=* +exprs(#20149,0,#20145,1,"log") +hasLocation(#20149,#20075) +enclosing_stmt(#20149,#20141) +expr_containers(#20149,#20001) +literals("log","log",#20149) +#20150=* +exprs(#20150,79,#20143,0,"x") +hasLocation(#20150,#20079) +enclosing_stmt(#20150,#20141) +expr_containers(#20150,#20001) +literals("x","x",#20150) +bind(#20150,#20111) +#20151=* +stmts(#20151,2,#20001,5,"x &&= y;") +hasLocation(#20151,#20017) +stmt_containers(#20151,#20001) +#20152=* +exprs(#20152,116,#20151,0,"x &&= y") +#20153=@"loc,{#10000},7,1,7,7" +locations_default(#20153,#10000,7,1,7,7) +hasLocation(#20152,#20153) +enclosing_stmt(#20152,#20151) +expr_containers(#20152,#20001) +#20154=* +exprs(#20154,79,#20152,0,"x") +hasLocation(#20154,#20085) +enclosing_stmt(#20154,#20151) +expr_containers(#20154,#20001) +literals("x","x",#20154) +bind(#20154,#20111) +#20155=* +exprs(#20155,79,#20152,1,"y") +hasLocation(#20155,#20089) +enclosing_stmt(#20155,#20151) +expr_containers(#20155,#20001) +literals("y","y",#20155) +bind(#20155,#20112) +#20156=* +stmts(#20156,2,#20001,6,"x ||= y;") +hasLocation(#20156,#20019) +stmt_containers(#20156,#20001) +#20157=* +exprs(#20157,117,#20156,0,"x ||= y") +#20158=@"loc,{#10000},8,1,8,7" +locations_default(#20158,#10000,8,1,8,7) +hasLocation(#20157,#20158) +enclosing_stmt(#20157,#20156) +expr_containers(#20157,#20001) +#20159=* +exprs(#20159,79,#20157,0,"x") +hasLocation(#20159,#20093) +enclosing_stmt(#20159,#20156) +expr_containers(#20159,#20001) +literals("x","x",#20159) +bind(#20159,#20111) +#20160=* +exprs(#20160,79,#20157,1,"y") +hasLocation(#20160,#20097) +enclosing_stmt(#20160,#20156) +expr_containers(#20160,#20001) +literals("y","y",#20160) +bind(#20160,#20112) +#20161=* +stmts(#20161,2,#20001,7,"x ??= y;") +hasLocation(#20161,#20021) +stmt_containers(#20161,#20001) +#20162=* +exprs(#20162,118,#20161,0,"x ??= y") +#20163=@"loc,{#10000},9,1,9,7" +locations_default(#20163,#10000,9,1,9,7) +hasLocation(#20162,#20163) +enclosing_stmt(#20162,#20161) +expr_containers(#20162,#20001) +#20164=* +exprs(#20164,79,#20162,0,"x") +hasLocation(#20164,#20101) +enclosing_stmt(#20164,#20161) +expr_containers(#20164,#20001) +literals("x","x",#20164) +bind(#20164,#20111) +#20165=* +exprs(#20165,79,#20162,1,"y") +hasLocation(#20165,#20105) +enclosing_stmt(#20165,#20161) +expr_containers(#20165,#20001) +literals("y","y",#20165) +bind(#20165,#20112) +#20166=* +entry_cfg_node(#20166,#20001) +#20167=@"loc,{#10000},1,1,1,0" +locations_default(#20167,#10000,1,1,1,0) +hasLocation(#20166,#20167) +#20168=* +exit_cfg_node(#20168,#20001) +hasLocation(#20168,#20109) +successor(#20161,#20164) +successor(#20164,#20165) +successor(#20164,#20168) +successor(#20165,#20164) +successor(#20162,#20168) +successor(#20156,#20159) +#20169=* +guard_node(#20169,1,#20159) +hasLocation(#20169,#20093) +successor(#20169,#20161) +#20170=* +guard_node(#20170,0,#20159) +hasLocation(#20170,#20093) +successor(#20170,#20160) +successor(#20159,#20169) +successor(#20159,#20170) +successor(#20160,#20159) +successor(#20157,#20161) +successor(#20151,#20154) +#20171=* +guard_node(#20171,1,#20154) +hasLocation(#20171,#20085) +successor(#20171,#20155) +#20172=* +guard_node(#20172,0,#20154) +hasLocation(#20172,#20085) +successor(#20172,#20156) +successor(#20154,#20171) +successor(#20154,#20172) +successor(#20155,#20154) +successor(#20152,#20156) +successor(#20141,#20147) +successor(#20150,#20143) +successor(#20149,#20145) +successor(#20147,#20149) +successor(#20145,#20150) +successor(#20143,#20151) +successor(#20133,#20136) +#20173=* +guard_node(#20173,1,#20139) +hasLocation(#20173,#20063) +successor(#20173,#20140) +#20174=* +guard_node(#20174,0,#20139) +hasLocation(#20174,#20063) +successor(#20174,#20134) +successor(#20139,#20173) +successor(#20139,#20174) +successor(#20140,#20139) +successor(#20137,#20134) +successor(#20136,#20139) +successor(#20134,#20141) +successor(#20125,#20128) +successor(#20129,#20131) +#20175=* +guard_node(#20175,1,#20131) +hasLocation(#20175,#20049) +successor(#20175,#20132) +#20176=* +guard_node(#20176,0,#20131) +hasLocation(#20176,#20049) +successor(#20176,#20126) +successor(#20131,#20175) +successor(#20131,#20176) +successor(#20132,#20126) +successor(#20128,#20129) +successor(#20126,#20133) +successor(#20120,#20123) +successor(#20124,#20121) +successor(#20123,#20124) +successor(#20121,#20125) +successor(#20115,#20118) +successor(#20119,#20116) +successor(#20118,#20119) +successor(#20116,#20120) +successor(#20166,#20115) +numlines(#10000,9,8,1) +filetype(#10000,"javascript") From 0dbdbfa6596a026c4403635b8ad0dac98a80e73e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 17 Sep 2020 13:13:55 +0200 Subject: [PATCH 2/6] bump extractor version --- 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 359e07d3194..a7b209bc7ce 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -43,7 +43,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2020-09-12"; + public static final String EXTRACTOR_VERSION = "2020-09-17"; public static final Pattern NEWLINE = Pattern.compile("\n"); From b09015380ac778d9376bf54a5f253af064bb1813 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 17 Sep 2020 14:00:44 +0200 Subject: [PATCH 3/6] add support for String.prototype.replaceAll --- .../ql/src/Expressions/StringInsteadOfRegex.ql | 2 +- .../ql/src/RegExp/IdentityReplacement.ql | 2 +- .../CWE-020/IncompleteUrlSchemeCheck.ql | 2 +- .../Security/CWE-116/IncompleteSanitization.ql | 1 + .../src/semmle/javascript/StandardLibrary.qll | 6 +++--- .../javascript/dataflow/TaintTracking.qll | 6 ++++-- .../heuristics/AdditionalTaintSteps.qll | 4 +--- .../CleartextLoggingCustomizations.qll | 12 ++++-------- .../dataflow/TaintedPathCustomizations.qll | 18 ++++++++---------- .../security/dataflow/UnsafeJQueryPlugin.qll | 5 ++--- .../javascript/security/dataflow/Xss.qll | 5 ++--- .../PolynomialReDoSCustomizations.qll | 1 + .../InterProceduralFlow/TaintTracking.expected | 2 ++ .../library-tests/InterProceduralFlow/tst.js | 3 +++ .../ReDoS/PolynomialBackTracking.expected | 1 + .../Performance/ReDoS/PolynomialReDoS.expected | 5 +++++ .../Performance/ReDoS/polynomial-redos.js | 2 +- 17 files changed, 41 insertions(+), 36 deletions(-) diff --git a/javascript/ql/src/Expressions/StringInsteadOfRegex.ql b/javascript/ql/src/Expressions/StringInsteadOfRegex.ql index f81b8b1a5ae..f1efb37e330 100644 --- a/javascript/ql/src/Expressions/StringInsteadOfRegex.ql +++ b/javascript/ql/src/Expressions/StringInsteadOfRegex.ql @@ -31,7 +31,7 @@ predicate isStringSplitOrReplace(MethodCallExpr mce) { mce.getMethodName() = name and mce.getNumArgument() = arity | - name = "replace" and arity = 2 + name = ["replace", "replaceAll"] and arity = 2 or name = "split" and (arity = 1 or arity = 2) diff --git a/javascript/ql/src/RegExp/IdentityReplacement.ql b/javascript/ql/src/RegExp/IdentityReplacement.ql index f8c62a1ab3a..2a6e354cc9c 100644 --- a/javascript/ql/src/RegExp/IdentityReplacement.ql +++ b/javascript/ql/src/RegExp/IdentityReplacement.ql @@ -70,7 +70,7 @@ predicate regExpMatchesString(RegExpTerm t, string s) { from MethodCallExpr repl, string s, string friendly where - repl.getMethodName() = "replace" and + repl.getMethodName() = ["replace", "replaceAll"] and matchesString(repl.getArgument(0), s) and repl.getArgument(1).getStringValue() = s and (if s = "" then friendly = "the empty string" else friendly = "'" + s + "'") diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql index 617692f3adb..0675b189cd1 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql @@ -75,7 +75,7 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) { exists(DataFlow::MethodCallNode stringop | stringop.getMethodName().matches("trim%") or stringop.getMethodName().matches("to%Case") or - stringop.getMethodName() = "replace" + stringop.getMethodName() = ["replace", "replaceAll"] | result = schemeCheck(stringop, scheme) and nd = stringop.getReceiver() diff --git a/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql b/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql index a1b466cab9f..9494dcde0e5 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql +++ b/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql @@ -79,6 +79,7 @@ predicate allBackslashesEscaped(DataFlow::Node nd) { // flow through string methods exists(DataFlow::MethodCallNode mc, string m | m = "replace" or + m = "replaceAll" or m = "slice" or m = "substr" or m = "substring" or diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index b28d1f27439..6a57bda6461 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -102,7 +102,7 @@ private class IteratorExceptionStep extends DataFlow::MethodCallNode, DataFlow:: */ class StringReplaceCall extends DataFlow::MethodCallNode { StringReplaceCall() { - getMethodName() = "replace" and + getMethodName() = ["replace", "replaceAll"] and (getNumArgument() = 2 or getReceiver().mayHaveStringValue(_)) } @@ -128,9 +128,9 @@ class StringReplaceCall extends DataFlow::MethodCallNode { /** * Holds if this is a global replacement, that is, the first argument is a regular expression - * with the `g` flag. + * with the `g` flag, or this is a call to `.replaceAll()`. */ - predicate isGlobal() { getRegExp().isGlobal() } + predicate isGlobal() { getRegExp().isGlobal() or getMethodName() = "replaceAll" } /** * Holds if this call to `replace` replaces `old` with `new`. diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index f0763c0893f..6698800918c 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -427,6 +427,7 @@ module TaintTracking { name = "padStart" or name = "repeat" or name = "replace" or + name = "replaceAll" or name = "slice" or name = "small" or name = "split" or @@ -452,7 +453,7 @@ module TaintTracking { exists(int i | pred.asExpr() = succ.getAstNode().(MethodCallExpr).getArgument(i) | name = "concat" or - name = "replace" and i = 1 + name = ["replace", "replaceAll"] and i = 1 ) ) or @@ -707,7 +708,8 @@ module TaintTracking { */ private ControlFlowNode getACaptureSetter(DataFlow::Node input) { exists(DataFlow::MethodCallNode call | result = call.asExpr() | - call.getMethodName() = ["search", "replace", "match"] and input = call.getReceiver() + call.getMethodName() = ["search", "replace", "replaceAll", "match"] and + input = call.getReceiver() or call.getMethodName() = ["test", "exec"] and input = call.getArgument(0) ) diff --git a/javascript/ql/src/semmle/javascript/heuristics/AdditionalTaintSteps.qll b/javascript/ql/src/semmle/javascript/heuristics/AdditionalTaintSteps.qll index e920fb10613..5cda6f0d867 100644 --- a/javascript/ql/src/semmle/javascript/heuristics/AdditionalTaintSteps.qll +++ b/javascript/ql/src/semmle/javascript/heuristics/AdditionalTaintSteps.qll @@ -15,9 +15,7 @@ abstract class HeuristicAdditionalTaintStep extends DataFlow::ValueNode { } * A call to `tainted.replace(x, y)` that preserves taint. */ private class HeuristicStringManipulationTaintStep extends HeuristicAdditionalTaintStep, - TaintTracking::AdditionalTaintStep, DataFlow::MethodCallNode { - HeuristicStringManipulationTaintStep() { getMethodName() = "replace" } - + TaintTracking::AdditionalTaintStep, StringReplaceCall { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = getReceiver() and succ = this } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll index 6fc13631ef2..eea099a7a79 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll @@ -34,15 +34,11 @@ module CleartextLogging { /** * A call to `.replace()` that seems to mask sensitive information. */ - class MaskingReplacer extends Barrier, DataFlow::MethodCallNode { + class MaskingReplacer extends Barrier, StringReplaceCall { MaskingReplacer() { - this.getCalleeName() = "replace" and - exists(RegExpLiteral reg | - reg = this.getArgument(0).getALocalSource().asExpr() and - reg.isGlobal() and - any(RegExpDot term).getLiteral() = reg - ) and - exists(this.getArgument(1).getStringValue()) + this.isGlobal() and + exists(this.getRawReplacement().getStringValue()) and + any(RegExpDot term).getLiteral() = getRegExp().asExpr() } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index daf0e9324ee..76b9e350427 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -218,12 +218,12 @@ module TaintedPath { output = this or // non-global replace or replace of something other than /\.\./g, /[/]/g, or /[\.]/g. - this.getCalleeName() = "replace" and + this instanceof StringReplaceCall and input = getReceiver() and output = this and not exists(RegExpLiteral literal, RegExpTerm term | - getArgument(0).getALocalSource().asExpr() = literal and - literal.isGlobal() and + this.(StringReplaceCall).getRegExp().asExpr() = literal and + this.(StringReplaceCall).isGlobal() and literal.getRoot() = term | term.getAMatchedString() = "/" or @@ -247,16 +247,15 @@ module TaintedPath { /** * A call that removes all instances of "../" in the prefix of the string. */ - class DotDotSlashPrefixRemovingReplace extends DataFlow::CallNode { + class DotDotSlashPrefixRemovingReplace extends StringReplaceCall { DataFlow::Node input; DataFlow::Node output; DotDotSlashPrefixRemovingReplace() { - this.getCalleeName() = "replace" and input = getReceiver() and output = this and exists(RegExpLiteral literal, RegExpTerm term | - getArgument(0).getALocalSource().asExpr() = literal and + getRegExp().asExpr() = literal and (term instanceof RegExpStar or term instanceof RegExpPlus) and term.getChild(0) = getADotDotSlashMatcher() | @@ -298,17 +297,16 @@ module TaintedPath { /** * A call that removes all "." or ".." from a path, without also removing all forward slashes. */ - class DotRemovingReplaceCall extends DataFlow::CallNode { + class DotRemovingReplaceCall extends StringReplaceCall { DataFlow::Node input; DataFlow::Node output; DotRemovingReplaceCall() { - this.getCalleeName() = "replace" and input = getReceiver() and output = this and + isGlobal() and exists(RegExpLiteral literal, RegExpTerm term | - getArgument(0).getALocalSource().asExpr() = literal and - literal.isGlobal() and + getRegExp().asExpr() = literal and literal.getRoot() = term and not term.getAMatchedString() = "/" | diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeJQueryPlugin.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeJQueryPlugin.qll index a2a7246b4a7..05c33b71330 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeJQueryPlugin.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeJQueryPlugin.qll @@ -39,10 +39,9 @@ module UnsafeJQueryPlugin { StringConcatenation::taintStep(pred, succ, _, any(int i | i >= 1)) or // prefixing through a poor-mans templating system: - exists(DataFlow::MethodCallNode replace | + exists(StringReplaceCall replace | replace = succ and - pred = replace.getArgument(1) and - replace.getMethodName() = "replace" + pred = replace.getRawReplacement() ) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 54e7b7de47d..346ff52c862 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -33,11 +33,10 @@ module Shared { * The XSS queries do not attempt to reason about correctness or completeness of sanitizers, * so any such replacement stops taint propagation. */ - class MetacharEscapeSanitizer extends Sanitizer, DataFlow::MethodCallNode { + class MetacharEscapeSanitizer extends Sanitizer, StringReplaceCall { MetacharEscapeSanitizer() { - getMethodName() = "replace" and exists(RegExpConstant c | - c.getLiteral() = getArgument(0).getALocalSource().asExpr() and + c.getLiteral() = getRegExp().asExpr() and c.getValue().regexpMatch("['\"&<>]") ) } diff --git a/javascript/ql/src/semmle/javascript/security/performance/PolynomialReDoSCustomizations.qll b/javascript/ql/src/semmle/javascript/security/performance/PolynomialReDoSCustomizations.qll index 5507f9e6981..ea3d9db3ada 100644 --- a/javascript/ql/src/semmle/javascript/security/performance/PolynomialReDoSCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/performance/PolynomialReDoSCustomizations.qll @@ -51,6 +51,7 @@ module PolynomialReDoS { name = "split" or name = "matchAll" or name = "replace" or + name = "replaceAll" or name = "search" ) or diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/TaintTracking.expected b/javascript/ql/test/library-tests/InterProceduralFlow/TaintTracking.expected index c3ea1cdb5f2..823db35f84d 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/TaintTracking.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/TaintTracking.expected @@ -86,6 +86,8 @@ | tst.js:2:17:2:22 | "src1" | tst.js:61:16:61:18 | o.r | | tst.js:2:17:2:22 | "src1" | tst.js:68:16:68:22 | inner() | | tst.js:2:17:2:22 | "src1" | tst.js:80:16:80:22 | outer() | +| tst.js:2:17:2:22 | "src1" | tst.js:87:16:87:43 | source1 ... /g, "") | +| tst.js:2:17:2:22 | "src1" | tst.js:88:16:88:46 | "foo".r ... ource1) | | underscore.js:2:17:2:22 | "src1" | underscore.js:3:15:3:28 | _.max(source1) | | underscore.js:5:17:5:22 | "src2" | underscore.js:6:15:6:34 | _.union([], source2) | | underscore.js:5:17:5:22 | "src2" | underscore.js:7:15:7:32 | _.zip(source2, []) | diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/tst.js b/javascript/ql/test/library-tests/InterProceduralFlow/tst.js index a557538bd11..a8fc56e3d52 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/tst.js +++ b/javascript/ql/test/library-tests/InterProceduralFlow/tst.js @@ -83,4 +83,7 @@ o.notTracked = source1; var sink22 = o.notTracked; + + var sink23 = source1.replaceAll(/f/g, ""); + var sink24 = "foo".replaceAll(/f/g, source1); })(); diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected index 98f5cb00ed4..1d78b51e8bf 100644 --- a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected +++ b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected @@ -17,6 +17,7 @@ | polynomial-redos.js:31:42:31:43 | -+ | it can start matching anywhere | | polynomial-redos.js:32:45:32:47 | \\n* | it can start matching anywhere | | polynomial-redos.js:33:17:33:20 | (.)* | it can start matching anywhere | +| polynomial-redos.js:48:22:48:24 | \\s* | it can start matching anywhere | | regexplib/address.js:18:26:18:31 | [ \\w]* | it can start matching anywhere after the start of the preceeding '[ \\w]{3,}' | | regexplib/address.js:20:144:20:147 | [ ]+ | it can start matching anywhere after the start of the preceeding '[a-zA-Z0-9 \\-.]{6,}' | | regexplib/address.js:24:26:24:31 | [ \\w]* | it can start matching anywhere after the start of the preceeding '[ \\w]{3,}' | diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialReDoS.expected b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialReDoS.expected index 4d3a9a12da6..e8ba1a56d67 100644 --- a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialReDoS.expected +++ b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialReDoS.expected @@ -28,6 +28,8 @@ nodes | polynomial-redos.js:30:2:30:8 | tainted | | polynomial-redos.js:33:2:33:8 | tainted | | polynomial-redos.js:33:2:33:8 | tainted | +| polynomial-redos.js:48:2:48:8 | tainted | +| polynomial-redos.js:48:2:48:8 | tainted | edges | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:7:2:7:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:7:2:7:8 | tainted | @@ -55,6 +57,8 @@ edges | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:30:2:30:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:33:2:33:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:33:2:33:8 | tainted | +| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:48:2:48:8 | tainted | +| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:48:2:48:8 | tainted | | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:5:6:5:32 | tainted | | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:5:6:5:32 | tainted | #select @@ -72,3 +76,4 @@ edges | polynomial-redos.js:27:77:27:83 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:27:77:27:83 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:27:14:27:22 | [A-Z]{2,} | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:30:2:30:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:30:2:30:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:30:19:30:22 | [?]+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:33:2:33:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:33:2:33:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:33:17:33:20 | (.)* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | +| polynomial-redos.js:48:2:48:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:48:2:48:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:48:22:48:24 | \\s* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/polynomial-redos.js b/javascript/ql/test/query-tests/Performance/ReDoS/polynomial-redos.js index 4175bd48a50..1dcce05f3c7 100644 --- a/javascript/ql/test/query-tests/Performance/ReDoS/polynomial-redos.js +++ b/javascript/ql/test/query-tests/Performance/ReDoS/polynomial-redos.js @@ -45,5 +45,5 @@ app.use(function(req, res) { tainted.match(/^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/); // NOT OK - but not flagged tainted.match(/^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/); // OK - + tainted.replaceAll(/\s*\n\s*/g, ' '); // NOT OK }); From 9f1b3d61b9fa6a87969cfedf4bdf38e3388a19a6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 17 Sep 2020 14:04:07 +0200 Subject: [PATCH 4/6] add test for numeric separators --- .../extractor/tests/es2021/input/numeric.js | 8 + .../tests/es2021/output/trap/numeric.js.trap | 435 ++++++++++++++++++ 2 files changed, 443 insertions(+) create mode 100644 javascript/extractor/tests/es2021/input/numeric.js create mode 100644 javascript/extractor/tests/es2021/output/trap/numeric.js.trap diff --git a/javascript/extractor/tests/es2021/input/numeric.js b/javascript/extractor/tests/es2021/input/numeric.js new file mode 100644 index 00000000000..e7e9d031f50 --- /dev/null +++ b/javascript/extractor/tests/es2021/input/numeric.js @@ -0,0 +1,8 @@ +1_000_000_000 // Ah, so a billion +101_475_938.38 // And this is hundreds of millions + +let fee = 123_00; // $123 (12300 cents, apparently) +let fee = 12_300; // $12,300 (woah, that fee!) +let amount = 12345_00; // 12,345 (1234500 cents, apparently) +let amount = 123_4500; // 123.45 (4-fixed financial) +let amount = 1_234_500; // 1,234,500 diff --git a/javascript/extractor/tests/es2021/output/trap/numeric.js.trap b/javascript/extractor/tests/es2021/output/trap/numeric.js.trap new file mode 100644 index 00000000000..afcf1627f2d --- /dev/null +++ b/javascript/extractor/tests/es2021/output/trap/numeric.js.trap @@ -0,0 +1,435 @@ +#10000=@"/numeric.js;sourcefile" +files(#10000,"/numeric.js","numeric","js",0) +#10001=@"/;folder" +folders(#10001,"/","") +containerparent(#10001,#10000) +#10002=@"loc,{#10000},0,0,0,0" +locations_default(#10002,#10000,0,0,0,0) +hasLocation(#10000,#10002) +#20000=@"global_scope" +scopes(#20000,0) +#20001=@"script;{#10000},1,1" +#20002=* +comments(#20002,0,#20001," Ah, so a billion","// Ah, so a billion") +#20003=@"loc,{#10000},1,25,1,43" +locations_default(#20003,#10000,1,25,1,43) +hasLocation(#20002,#20003) +#20004=* +comments(#20004,0,#20001," And this is hundreds of millions","// And ... illions") +#20005=@"loc,{#10000},2,25,2,59" +locations_default(#20005,#10000,2,25,2,59) +hasLocation(#20004,#20005) +#20006=* +comments(#20006,0,#20001," $123 (12300 cents, apparently)","// $123 ... rently)") +#20007=@"loc,{#10000},4,25,4,57" +locations_default(#20007,#10000,4,25,4,57) +hasLocation(#20006,#20007) +#20008=* +comments(#20008,0,#20001," $12,300 (woah, that fee!)","// $12, ... t fee!)") +#20009=@"loc,{#10000},5,25,5,52" +locations_default(#20009,#10000,5,25,5,52) +hasLocation(#20008,#20009) +#20010=* +comments(#20010,0,#20001," 12,345 (1234500 cents, apparently)","// 12,3 ... rently)") +#20011=@"loc,{#10000},6,25,6,61" +locations_default(#20011,#10000,6,25,6,61) +hasLocation(#20010,#20011) +#20012=* +comments(#20012,0,#20001," 123.45 (4-fixed financial)","// 123. ... ancial)") +#20013=@"loc,{#10000},7,25,7,53" +locations_default(#20013,#10000,7,25,7,53) +hasLocation(#20012,#20013) +#20014=* +comments(#20014,0,#20001," 1,234,500","// 1,234,500") +#20015=@"loc,{#10000},8,25,8,36" +locations_default(#20015,#10000,8,25,8,36) +hasLocation(#20014,#20015) +#20016=* +lines(#20016,#20001,"1_000_000_000 // Ah, so a billion"," +") +#20017=@"loc,{#10000},1,1,1,43" +locations_default(#20017,#10000,1,1,1,43) +hasLocation(#20016,#20017) +#20018=* +lines(#20018,#20001,"101_475_938.38 // And this is hundreds of millions"," +") +#20019=@"loc,{#10000},2,1,2,59" +locations_default(#20019,#10000,2,1,2,59) +hasLocation(#20018,#20019) +#20020=* +lines(#20020,#20001,""," +") +#20021=@"loc,{#10000},3,1,3,0" +locations_default(#20021,#10000,3,1,3,0) +hasLocation(#20020,#20021) +#20022=* +lines(#20022,#20001,"let fee = 123_00; // $123 (12300 cents, apparently)"," +") +#20023=@"loc,{#10000},4,1,4,57" +locations_default(#20023,#10000,4,1,4,57) +hasLocation(#20022,#20023) +#20024=* +lines(#20024,#20001,"let fee = 12_300; // $12,300 (woah, that fee!)"," +") +#20025=@"loc,{#10000},5,1,5,52" +locations_default(#20025,#10000,5,1,5,52) +hasLocation(#20024,#20025) +#20026=* +lines(#20026,#20001,"let amount = 12345_00; // 12,345 (1234500 cents, apparently)"," +") +#20027=@"loc,{#10000},6,1,6,61" +locations_default(#20027,#10000,6,1,6,61) +hasLocation(#20026,#20027) +#20028=* +lines(#20028,#20001,"let amount = 123_4500; // 123.45 (4-fixed financial)"," +") +#20029=@"loc,{#10000},7,1,7,53" +locations_default(#20029,#10000,7,1,7,53) +hasLocation(#20028,#20029) +#20030=* +lines(#20030,#20001,"let amount = 1_234_500; // 1,234,500"," +") +#20031=@"loc,{#10000},8,1,8,36" +locations_default(#20031,#10000,8,1,8,36) +hasLocation(#20030,#20031) +numlines(#20001,8,7,7) +#20032=* +tokeninfo(#20032,3,#20001,0,"1_000_000_000") +#20033=@"loc,{#10000},1,1,1,13" +locations_default(#20033,#10000,1,1,1,13) +hasLocation(#20032,#20033) +#20034=* +tokeninfo(#20034,3,#20001,1,"101_475_938.38") +#20035=@"loc,{#10000},2,1,2,14" +locations_default(#20035,#10000,2,1,2,14) +hasLocation(#20034,#20035) +next_token(#20002,#20034) +#20036=* +tokeninfo(#20036,7,#20001,2,"let") +#20037=@"loc,{#10000},4,1,4,3" +locations_default(#20037,#10000,4,1,4,3) +hasLocation(#20036,#20037) +next_token(#20004,#20036) +#20038=* +tokeninfo(#20038,6,#20001,3,"fee") +#20039=@"loc,{#10000},4,5,4,7" +locations_default(#20039,#10000,4,5,4,7) +hasLocation(#20038,#20039) +#20040=* +tokeninfo(#20040,8,#20001,4,"=") +#20041=@"loc,{#10000},4,9,4,9" +locations_default(#20041,#10000,4,9,4,9) +hasLocation(#20040,#20041) +#20042=* +tokeninfo(#20042,3,#20001,5,"123_00") +#20043=@"loc,{#10000},4,11,4,16" +locations_default(#20043,#10000,4,11,4,16) +hasLocation(#20042,#20043) +#20044=* +tokeninfo(#20044,8,#20001,6,";") +#20045=@"loc,{#10000},4,17,4,17" +locations_default(#20045,#10000,4,17,4,17) +hasLocation(#20044,#20045) +#20046=* +tokeninfo(#20046,7,#20001,7,"let") +#20047=@"loc,{#10000},5,1,5,3" +locations_default(#20047,#10000,5,1,5,3) +hasLocation(#20046,#20047) +next_token(#20006,#20046) +#20048=* +tokeninfo(#20048,6,#20001,8,"fee") +#20049=@"loc,{#10000},5,5,5,7" +locations_default(#20049,#10000,5,5,5,7) +hasLocation(#20048,#20049) +#20050=* +tokeninfo(#20050,8,#20001,9,"=") +#20051=@"loc,{#10000},5,9,5,9" +locations_default(#20051,#10000,5,9,5,9) +hasLocation(#20050,#20051) +#20052=* +tokeninfo(#20052,3,#20001,10,"12_300") +#20053=@"loc,{#10000},5,11,5,16" +locations_default(#20053,#10000,5,11,5,16) +hasLocation(#20052,#20053) +#20054=* +tokeninfo(#20054,8,#20001,11,";") +#20055=@"loc,{#10000},5,17,5,17" +locations_default(#20055,#10000,5,17,5,17) +hasLocation(#20054,#20055) +#20056=* +tokeninfo(#20056,7,#20001,12,"let") +#20057=@"loc,{#10000},6,1,6,3" +locations_default(#20057,#10000,6,1,6,3) +hasLocation(#20056,#20057) +next_token(#20008,#20056) +#20058=* +tokeninfo(#20058,6,#20001,13,"amount") +#20059=@"loc,{#10000},6,5,6,10" +locations_default(#20059,#10000,6,5,6,10) +hasLocation(#20058,#20059) +#20060=* +tokeninfo(#20060,8,#20001,14,"=") +#20061=@"loc,{#10000},6,12,6,12" +locations_default(#20061,#10000,6,12,6,12) +hasLocation(#20060,#20061) +#20062=* +tokeninfo(#20062,3,#20001,15,"12345_00") +#20063=@"loc,{#10000},6,14,6,21" +locations_default(#20063,#10000,6,14,6,21) +hasLocation(#20062,#20063) +#20064=* +tokeninfo(#20064,8,#20001,16,";") +#20065=@"loc,{#10000},6,22,6,22" +locations_default(#20065,#10000,6,22,6,22) +hasLocation(#20064,#20065) +#20066=* +tokeninfo(#20066,7,#20001,17,"let") +#20067=@"loc,{#10000},7,1,7,3" +locations_default(#20067,#10000,7,1,7,3) +hasLocation(#20066,#20067) +next_token(#20010,#20066) +#20068=* +tokeninfo(#20068,6,#20001,18,"amount") +#20069=@"loc,{#10000},7,5,7,10" +locations_default(#20069,#10000,7,5,7,10) +hasLocation(#20068,#20069) +#20070=* +tokeninfo(#20070,8,#20001,19,"=") +#20071=@"loc,{#10000},7,12,7,12" +locations_default(#20071,#10000,7,12,7,12) +hasLocation(#20070,#20071) +#20072=* +tokeninfo(#20072,3,#20001,20,"123_4500") +#20073=@"loc,{#10000},7,14,7,21" +locations_default(#20073,#10000,7,14,7,21) +hasLocation(#20072,#20073) +#20074=* +tokeninfo(#20074,8,#20001,21,";") +#20075=@"loc,{#10000},7,22,7,22" +locations_default(#20075,#10000,7,22,7,22) +hasLocation(#20074,#20075) +#20076=* +tokeninfo(#20076,7,#20001,22,"let") +#20077=@"loc,{#10000},8,1,8,3" +locations_default(#20077,#10000,8,1,8,3) +hasLocation(#20076,#20077) +next_token(#20012,#20076) +#20078=* +tokeninfo(#20078,6,#20001,23,"amount") +#20079=@"loc,{#10000},8,5,8,10" +locations_default(#20079,#10000,8,5,8,10) +hasLocation(#20078,#20079) +#20080=* +tokeninfo(#20080,8,#20001,24,"=") +#20081=@"loc,{#10000},8,12,8,12" +locations_default(#20081,#10000,8,12,8,12) +hasLocation(#20080,#20081) +#20082=* +tokeninfo(#20082,3,#20001,25,"1_234_500") +#20083=@"loc,{#10000},8,14,8,22" +locations_default(#20083,#10000,8,14,8,22) +hasLocation(#20082,#20083) +#20084=* +tokeninfo(#20084,8,#20001,26,";") +#20085=@"loc,{#10000},8,23,8,23" +locations_default(#20085,#10000,8,23,8,23) +hasLocation(#20084,#20085) +#20086=* +tokeninfo(#20086,0,#20001,27,"") +#20087=@"loc,{#10000},9,1,9,0" +locations_default(#20087,#10000,9,1,9,0) +hasLocation(#20086,#20087) +next_token(#20014,#20086) +toplevels(#20001,0) +#20088=@"loc,{#10000},1,1,9,0" +locations_default(#20088,#10000,1,1,9,0) +hasLocation(#20001,#20088) +#20089=@"var;{fee};{#20000}" +variables(#20089,"fee",#20000) +#20090=@"var;{amount};{#20000}" +variables(#20090,"amount",#20000) +#20091=* +stmts(#20091,2,#20001,0,"1_000_000_000") +hasLocation(#20091,#20033) +stmt_containers(#20091,#20001) +#20092=* +exprs(#20092,3,#20091,0,"1_000_000_000") +hasLocation(#20092,#20033) +enclosing_stmt(#20092,#20091) +expr_containers(#20092,#20001) +literals("1000000000","1_000_000_000",#20092) +#20093=* +stmts(#20093,2,#20001,1,"101_475_938.38") +hasLocation(#20093,#20035) +stmt_containers(#20093,#20001) +#20094=* +exprs(#20094,3,#20093,0,"101_475_938.38") +hasLocation(#20094,#20035) +enclosing_stmt(#20094,#20093) +expr_containers(#20094,#20001) +literals("1.0147593838E8","101_475_938.38",#20094) +#20095=* +stmts(#20095,23,#20001,2,"let fee = 123_00;") +#20096=@"loc,{#10000},4,1,4,17" +locations_default(#20096,#10000,4,1,4,17) +hasLocation(#20095,#20096) +stmt_containers(#20095,#20001) +#20097=* +exprs(#20097,64,#20095,0,"fee = 123_00") +#20098=@"loc,{#10000},4,5,4,16" +locations_default(#20098,#10000,4,5,4,16) +hasLocation(#20097,#20098) +enclosing_stmt(#20097,#20095) +expr_containers(#20097,#20001) +#20099=* +exprs(#20099,78,#20097,0,"fee") +hasLocation(#20099,#20039) +enclosing_stmt(#20099,#20095) +expr_containers(#20099,#20001) +literals("fee","fee",#20099) +decl(#20099,#20089) +#20100=* +exprs(#20100,3,#20097,1,"123_00") +hasLocation(#20100,#20043) +enclosing_stmt(#20100,#20095) +expr_containers(#20100,#20001) +literals("12300","123_00",#20100) +#20101=* +stmts(#20101,23,#20001,3,"let fee = 12_300;") +#20102=@"loc,{#10000},5,1,5,17" +locations_default(#20102,#10000,5,1,5,17) +hasLocation(#20101,#20102) +stmt_containers(#20101,#20001) +#20103=* +exprs(#20103,64,#20101,0,"fee = 12_300") +#20104=@"loc,{#10000},5,5,5,16" +locations_default(#20104,#10000,5,5,5,16) +hasLocation(#20103,#20104) +enclosing_stmt(#20103,#20101) +expr_containers(#20103,#20001) +#20105=* +exprs(#20105,78,#20103,0,"fee") +hasLocation(#20105,#20049) +enclosing_stmt(#20105,#20101) +expr_containers(#20105,#20001) +literals("fee","fee",#20105) +decl(#20105,#20089) +#20106=* +exprs(#20106,3,#20103,1,"12_300") +hasLocation(#20106,#20053) +enclosing_stmt(#20106,#20101) +expr_containers(#20106,#20001) +literals("12300","12_300",#20106) +#20107=* +stmts(#20107,23,#20001,4,"let amo ... 345_00;") +#20108=@"loc,{#10000},6,1,6,22" +locations_default(#20108,#10000,6,1,6,22) +hasLocation(#20107,#20108) +stmt_containers(#20107,#20001) +#20109=* +exprs(#20109,64,#20107,0,"amount = 12345_00") +#20110=@"loc,{#10000},6,5,6,21" +locations_default(#20110,#10000,6,5,6,21) +hasLocation(#20109,#20110) +enclosing_stmt(#20109,#20107) +expr_containers(#20109,#20001) +#20111=* +exprs(#20111,78,#20109,0,"amount") +hasLocation(#20111,#20059) +enclosing_stmt(#20111,#20107) +expr_containers(#20111,#20001) +literals("amount","amount",#20111) +decl(#20111,#20090) +#20112=* +exprs(#20112,3,#20109,1,"12345_00") +hasLocation(#20112,#20063) +enclosing_stmt(#20112,#20107) +expr_containers(#20112,#20001) +literals("1234500","12345_00",#20112) +#20113=* +stmts(#20113,23,#20001,5,"let amo ... 3_4500;") +#20114=@"loc,{#10000},7,1,7,22" +locations_default(#20114,#10000,7,1,7,22) +hasLocation(#20113,#20114) +stmt_containers(#20113,#20001) +#20115=* +exprs(#20115,64,#20113,0,"amount = 123_4500") +#20116=@"loc,{#10000},7,5,7,21" +locations_default(#20116,#10000,7,5,7,21) +hasLocation(#20115,#20116) +enclosing_stmt(#20115,#20113) +expr_containers(#20115,#20001) +#20117=* +exprs(#20117,78,#20115,0,"amount") +hasLocation(#20117,#20069) +enclosing_stmt(#20117,#20113) +expr_containers(#20117,#20001) +literals("amount","amount",#20117) +decl(#20117,#20090) +#20118=* +exprs(#20118,3,#20115,1,"123_4500") +hasLocation(#20118,#20073) +enclosing_stmt(#20118,#20113) +expr_containers(#20118,#20001) +literals("1234500","123_4500",#20118) +#20119=* +stmts(#20119,23,#20001,6,"let amo ... 34_500;") +#20120=@"loc,{#10000},8,1,8,23" +locations_default(#20120,#10000,8,1,8,23) +hasLocation(#20119,#20120) +stmt_containers(#20119,#20001) +#20121=* +exprs(#20121,64,#20119,0,"amount = 1_234_500") +#20122=@"loc,{#10000},8,5,8,22" +locations_default(#20122,#10000,8,5,8,22) +hasLocation(#20121,#20122) +enclosing_stmt(#20121,#20119) +expr_containers(#20121,#20001) +#20123=* +exprs(#20123,78,#20121,0,"amount") +hasLocation(#20123,#20079) +enclosing_stmt(#20123,#20119) +expr_containers(#20123,#20001) +literals("amount","amount",#20123) +decl(#20123,#20090) +#20124=* +exprs(#20124,3,#20121,1,"1_234_500") +hasLocation(#20124,#20083) +enclosing_stmt(#20124,#20119) +expr_containers(#20124,#20001) +literals("1234500","1_234_500",#20124) +#20125=* +entry_cfg_node(#20125,#20001) +#20126=@"loc,{#10000},1,1,1,0" +locations_default(#20126,#10000,1,1,1,0) +hasLocation(#20125,#20126) +#20127=* +exit_cfg_node(#20127,#20001) +hasLocation(#20127,#20087) +successor(#20119,#20123) +successor(#20124,#20121) +successor(#20123,#20124) +successor(#20121,#20127) +successor(#20113,#20117) +successor(#20118,#20115) +successor(#20117,#20118) +successor(#20115,#20119) +successor(#20107,#20111) +successor(#20112,#20109) +successor(#20111,#20112) +successor(#20109,#20113) +successor(#20101,#20105) +successor(#20106,#20103) +successor(#20105,#20106) +successor(#20103,#20107) +successor(#20095,#20099) +successor(#20100,#20097) +successor(#20099,#20100) +successor(#20097,#20101) +successor(#20093,#20094) +successor(#20094,#20095) +successor(#20091,#20092) +successor(#20092,#20093) +successor(#20125,#20091) +numlines(#10000,8,7,7) +filetype(#10000,"javascript") From 4bc91c4439a36f09fb6ea249e3d9703c76c6bdc6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 17 Sep 2020 14:10:07 +0200 Subject: [PATCH 5/6] add support for Promise.any --- javascript/ql/src/semmle/javascript/Promises.qll | 4 ++-- javascript/ql/test/library-tests/Promises/flow2.js | 6 ++++++ .../ql/test/library-tests/Promises/tests.expected | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index a8231d75dce..4f730b36f0a 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -117,11 +117,11 @@ class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition { } /** - * An aggregated promise produced either by `Promise.all` or `Promise.race`. + * An aggregated promise produced either by `Promise.all`, `Promise.race`, or `Promise.any`. */ class AggregateES2015PromiseDefinition extends PromiseCreationCall { AggregateES2015PromiseDefinition() { - exists(string m | m = "all" or m = "race" | + exists(string m | m = "all" or m = "race" or m = "any" | this = DataFlow::globalVarRef("Promise").getAMemberCall(m) ) } diff --git a/javascript/ql/test/library-tests/Promises/flow2.js b/javascript/ql/test/library-tests/Promises/flow2.js index ef91740e0d5..ccafb83fd3f 100644 --- a/javascript/ql/test/library-tests/Promises/flow2.js +++ b/javascript/ql/test/library-tests/Promises/flow2.js @@ -18,4 +18,10 @@ var [clean3, tainted3] = await Promise.all(["clean", Promise.resolve(source)]); sink(clean3); // OK sink(tainted3); // NOT OK - but only flagged by taint-tracking + + var tainted4 = await Promise.race(["clean", Promise.resolve(source)]); + sink(tainted4); // NOT OK - but only flagged by taint-tracking + + var tainted5 = await Promise.any(["clean", Promise.resolve(source)]); + sink(tainted5); // NOT OK - but only flagged by taint-tracking }); \ No newline at end of file diff --git a/javascript/ql/test/library-tests/Promises/tests.expected b/javascript/ql/test/library-tests/Promises/tests.expected index 21c685e0c40..00320cc83fc 100644 --- a/javascript/ql/test/library-tests/Promises/tests.expected +++ b/javascript/ql/test/library-tests/Promises/tests.expected @@ -9,6 +9,12 @@ test_ResolvedPromiseDefinition | flow2.js:18:33:18:79 | Promise ... urce)]) | flow2.js:18:46:18:52 | "clean" | | flow2.js:18:33:18:79 | Promise ... urce)]) | flow2.js:18:55:18:77 | Promise ... source) | | flow2.js:18:55:18:77 | Promise ... source) | flow2.js:18:71:18:76 | source | +| flow2.js:22:23:22:70 | Promise ... urce)]) | flow2.js:22:37:22:43 | "clean" | +| flow2.js:22:23:22:70 | Promise ... urce)]) | flow2.js:22:46:22:68 | Promise ... source) | +| flow2.js:22:46:22:68 | Promise ... source) | flow2.js:22:62:22:67 | source | +| flow2.js:25:23:25:69 | Promise ... urce)]) | flow2.js:25:36:25:42 | "clean" | +| flow2.js:25:23:25:69 | Promise ... urce)]) | flow2.js:25:45:25:67 | Promise ... source) | +| flow2.js:25:45:25:67 | Promise ... source) | flow2.js:25:61:25:66 | source | | flow.js:4:11:4:33 | Promise ... source) | flow.js:4:27:4:32 | source | | flow.js:20:2:20:24 | Promise ... source) | flow.js:20:18:20:23 | source | | flow.js:22:2:22:24 | Promise ... source) | flow.js:22:18:22:23 | source | @@ -201,6 +207,8 @@ flow | flow2.js:2:15:2:22 | "source" | flow2.js:6:8:6:13 | arr[0] | | flow2.js:2:15:2:22 | "source" | flow2.js:12:7:12:13 | tainted | | flow2.js:2:15:2:22 | "source" | flow2.js:16:7:16:14 | tainted2 | +| flow2.js:2:15:2:22 | "source" | flow2.js:23:7:23:14 | tainted4 | +| flow2.js:2:15:2:22 | "source" | flow2.js:26:7:26:14 | tainted5 | | flow.js:2:15:2:22 | "source" | flow.js:5:7:5:14 | await p1 | | flow.js:2:15:2:22 | "source" | flow.js:8:7:8:14 | await p2 | | flow.js:2:15:2:22 | "source" | flow.js:17:8:17:8 | e | @@ -255,6 +263,12 @@ typetrack | flow2.js:18:27:18:79 | await P ... urce)]) | flow2.js:18:33:18:79 | Promise ... urce)]) | load $PromiseResolveField$ | | flow2.js:18:33:18:79 | Promise ... urce)]) | flow2.js:18:45:18:78 | ["clean ... ource)] | copy $PromiseResolveField$ | | flow2.js:18:33:18:79 | Promise ... urce)]) | flow2.js:18:45:18:78 | ["clean ... ource)] | store $PromiseResolveField$ | +| flow2.js:22:17:22:70 | await P ... urce)]) | flow2.js:22:23:22:70 | Promise ... urce)]) | load $PromiseResolveField$ | +| flow2.js:22:23:22:70 | Promise ... urce)]) | flow2.js:22:46:22:68 | Promise ... source) | copy $PromiseResolveField$ | +| flow2.js:22:23:22:70 | Promise ... urce)]) | flow2.js:22:46:22:68 | Promise ... source) | store $PromiseResolveField$ | +| flow2.js:25:17:25:69 | await P ... urce)]) | flow2.js:25:23:25:69 | Promise ... urce)]) | load $PromiseResolveField$ | +| flow2.js:25:23:25:69 | Promise ... urce)]) | flow2.js:25:45:25:67 | Promise ... source) | copy $PromiseResolveField$ | +| flow2.js:25:23:25:69 | Promise ... urce)]) | flow2.js:25:45:25:67 | Promise ... source) | store $PromiseResolveField$ | | flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | copy $PromiseResolveField$ | | flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | store $PromiseResolveField$ | | flow.js:20:31:20:31 | x | flow.js:20:2:20:24 | Promise ... source) | load $PromiseResolveField$ | From 4571ba38a5f1249be8e2a766bc567bc5e655e644 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 21 Sep 2020 10:51:36 +0200 Subject: [PATCH 6/6] add change-note for es2021 --- change-notes/1.26/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.26/analysis-javascript.md b/change-notes/1.26/analysis-javascript.md index 392e4bebeb7..81ceb96b0ac 100644 --- a/change-notes/1.26/analysis-javascript.md +++ b/change-notes/1.26/analysis-javascript.md @@ -18,6 +18,7 @@ - [underscore](https://www.npmjs.com/package/underscore) * Analyzing files with the ".cjs" extension is now supported. +* ES2021 features are now supported. ## New queries