From 73abf9c7c57d63cf0e9d52fe3f519cd72d5a9034 Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Fri, 31 Jul 2026 08:51:09 -0700 Subject: [PATCH 1/6] Python: Annotate nested unresolved calls Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../library-tests/dataflow/fieldflow/UnresolvedCalls.expected | 4 ---- python/ql/test/library-tests/dataflow/fieldflow/test.py | 2 +- python/ql/test/library-tests/dataflow/fieldflow/test_dict.py | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.expected b/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.expected index 593b6e118874..e69de29bb2d1 100644 --- a/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.expected +++ b/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.expected @@ -1,4 +0,0 @@ -| test.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | -| test.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | -| test_dict.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | -| test_dict.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | diff --git a/python/ql/test/library-tests/dataflow/fieldflow/test.py b/python/ql/test/library-tests/dataflow/fieldflow/test.py index f0152ad38a84..26551392b281 100644 --- a/python/ql/test/library-tests/dataflow/fieldflow/test.py +++ b/python/ql/test/library-tests/dataflow/fieldflow/test.py @@ -1,7 +1,7 @@ import sys import os -sys.path.append(os.path.dirname(os.path.dirname((__file__)))) # $ unresolved_call=sys.path.append(..) +sys.path.append(os.path.dirname(os.path.dirname((__file__)))) # $ unresolved_call=sys.path.append(..) unresolved_call=os.path.dirname(..) unresolved_call=os.path.dirname(..) from testlib import expects # These are defined so that we can evaluate the test code. diff --git a/python/ql/test/library-tests/dataflow/fieldflow/test_dict.py b/python/ql/test/library-tests/dataflow/fieldflow/test_dict.py index f64a5187925d..e49d9ed2a8ce 100644 --- a/python/ql/test/library-tests/dataflow/fieldflow/test_dict.py +++ b/python/ql/test/library-tests/dataflow/fieldflow/test_dict.py @@ -1,7 +1,7 @@ import sys import os -sys.path.append(os.path.dirname(os.path.dirname((__file__)))) # $ unresolved_call=sys.path.append(..) +sys.path.append(os.path.dirname(os.path.dirname((__file__)))) # $ unresolved_call=sys.path.append(..) unresolved_call=os.path.dirname(..) unresolved_call=os.path.dirname(..) from testlib import expects # These are defined so that we can evaluate the test code. From b6447fdf0ea8067e3ee473eb3c1a3e51818aca83 Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Fri, 31 Jul 2026 09:04:00 -0700 Subject: [PATCH 2/6] Ruby: Annotate array type-tracking results Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../dataflow/array-flow/array-flow.expected | 36 ++++++++++ .../dataflow/array-flow/array_flow.rb | 68 +++++++++---------- .../type-tracking-array-flow.expected | 36 ---------- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected b/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected index b92ce5c33bf6..3375ba7ff6c9 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected @@ -4877,6 +4877,42 @@ subpaths | array_flow.rb:1678:9:1678:9 | a : Array [element 2] | array_flow.rb:1678:19:1678:19 | x | array_flow.rb:1679:9:1679:9 | x | array_flow.rb:1678:9:1680:7 | call to map : [collection] [element] | | array_flow.rb:1704:17:1704:27 | call to source | array_flow.rb:1693:10:1693:14 | *args : Array [element 1] | array_flow.rb:1694:5:1694:21 | call to [] : Array [element 1] | array_flow.rb:1704:9:1704:31 | call to m141 : Array [element 1] | testFailures +| array_flow.rb:107:15:107:35 | # $ hasValueFlow=11.2 | Missing result: hasValueFlow=11.2 | +| array_flow.rb:226:16:226:34 | # $ hasValueFlow=25 | Missing result: hasValueFlow=25 | +| array_flow.rb:319:15:319:35 | # $ hasValueFlow=36.1 | Missing result: hasValueFlow=36.1 | +| array_flow.rb:320:15:320:35 | # $ hasValueFlow=36.1 | Missing result: hasValueFlow=36.1 | +| array_flow.rb:321:15:321:35 | # $ hasValueFlow=36.1 | Missing result: hasValueFlow=36.1 | +| array_flow.rb:328:15:328:55 | # $ hasValueFlow=37.1 $ hasValueFlow=37.2 | Missing result: hasValueFlow=37.1 | +| array_flow.rb:486:16:486:56 | # $ hasValueFlow=54.2 $ hasValueFlow=54.3 | Missing result: hasValueFlow=54.2 | +| array_flow.rb:490:16:490:76 | # $ hasValueFlow=54.2 $ hasValueFlow=54.3 $ hasValueFlow=54.4 | Missing result: hasValueFlow=54.2 | +| array_flow.rb:490:16:490:76 | # $ hasValueFlow=54.2 $ hasValueFlow=54.3 $ hasValueFlow=54.4 | Missing result: hasValueFlow=54.3 | +| array_flow.rb:494:16:494:96 | # $ hasValueFlow=54.2 $ hasValueFlow=54.3 $ hasValueFlow=54.4 $ hasValueFlow=54.5 | Missing result: hasValueFlow=54.2 | +| array_flow.rb:494:16:494:96 | # $ hasValueFlow=54.2 $ hasValueFlow=54.3 $ hasValueFlow=54.4 $ hasValueFlow=54.5 | Missing result: hasValueFlow=54.3 | +| array_flow.rb:659:15:659:55 | # $ hasValueFlow=70.1 $ hasValueFlow=70.3 | Missing result: hasValueFlow=70.1 | +| array_flow.rb:664:15:664:55 | # $ hasValueFlow=70.1 $ hasValueFlow=70.3 | Missing result: hasValueFlow=70.1 | +| array_flow.rb:928:16:928:56 | # $ hasValueFlow=90.1 $ hasValueFlow=90.2 | Missing result: hasValueFlow=90.1 | +| array_flow.rb:1099:15:1099:78 | # $ hasValueFlow=105.1 $ hasValueFlow=105.2 $ hasValueFlow=105.3 | Missing result: hasValueFlow=105.2 | +| array_flow.rb:1100:15:1100:57 | # $ hasValueFlow=105.1 $ hasValueFlow=105.3 | Missing result: hasValueFlow=105.3 | +| array_flow.rb:1110:15:1110:57 | # $ hasValueFlow=105.1 $ hasValueFlow=105.2 | Missing result: hasValueFlow=105.2 | +| array_flow.rb:1111:15:1111:57 | # $ hasValueFlow=105.1 $ hasValueFlow=105.3 | Missing result: hasValueFlow=105.3 | +| array_flow.rb:1162:15:1162:36 | # $ hasValueFlow=108.1 | Missing result: hasValueFlow=108.1 | +| array_flow.rb:1164:15:1164:36 | # $ hasValueFlow=108.2 | Missing result: hasValueFlow=108.2 | +| array_flow.rb:1170:15:1170:57 | # $ hasValueFlow=108.1 $ hasValueFlow=108.2 | Missing result: hasValueFlow=108.1 | +| array_flow.rb:1172:15:1172:36 | # $ hasValueFlow=108.2 | Missing result: hasValueFlow=108.2 | +| array_flow.rb:1224:15:1224:57 | # $ hasValueFlow=111.1 $ hasValueFlow=111.2 | Missing result: hasValueFlow=111.1 | +| array_flow.rb:1233:15:1233:36 | # $ hasValueFlow=111.1 | Missing result: hasValueFlow=111.1 | +| array_flow.rb:1238:15:1238:36 | # $ hasValueFlow=111.1 | Missing result: hasValueFlow=111.1 | +| array_flow.rb:1265:15:1265:36 | # $ hasValueFlow=112.1 | Missing result: hasValueFlow=112.1 | +| array_flow.rb:1286:15:1286:36 | # $ hasValueFlow=112.1 | Missing result: hasValueFlow=112.1 | +| array_flow.rb:1288:15:1288:36 | # $ hasValueFlow=112.2 | Missing result: hasValueFlow=112.2 | +| array_flow.rb:1297:15:1297:57 | # $ hasValueFlow=112.1 $ hasValueFlow=112.2 | Missing result: hasValueFlow=112.1 | +| array_flow.rb:1299:15:1299:36 | # $ hasValueFlow=112.2 | Missing result: hasValueFlow=112.2 | +| array_flow.rb:1308:15:1308:57 | # $ hasValueFlow=112.1 $ hasValueFlow=112.2 | Missing result: hasValueFlow=112.1 | +| array_flow.rb:1310:15:1310:36 | # $ hasValueFlow=112.2 | Missing result: hasValueFlow=112.2 | +| array_flow.rb:1346:15:1346:36 | # $ hasValueFlow=112.1 | Missing result: hasValueFlow=112.1 | +| array_flow.rb:1457:16:1457:37 | # $ hasValueFlow=121.2 | Missing result: hasValueFlow=121.2 | +| array_flow.rb:1458:16:1458:58 | # $ hasValueFlow=121.1 $ hasValueFlow=121.2 | Missing result: hasValueFlow=121.2 | +| array_flow.rb:1565:16:1565:58 | # $ hasValueFlow=132.1 $ hasValueFlow=132.2 | Missing result: hasValueFlow=132.1 | arrayLiteral | array_flow.rb:9:9:9:25 | call to [] | | array_flow.rb:33:9:33:22 | call to [] | diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/array_flow.rb b/ruby/ql/test/library-tests/dataflow/array-flow/array_flow.rb index 2edfef21688d..da709832883e 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/array_flow.rb +++ b/ruby/ql/test/library-tests/dataflow/array-flow/array_flow.rb @@ -104,7 +104,7 @@ def m11(i) b = a[0...2] # exclusive range sink b[0] sink b[1] # $ hasValueFlow=11.1 - sink b[2] + sink b[2] # $ hasValueFlow=11.2 a = [0, source(11.1), 1, source(11.2)] b = a[1 .. -2] # we can't model negative ranges precisely @@ -223,7 +223,7 @@ def m24 def m25 a = [0, 1, source(25)] b = a.clear() - sink(a[2]) + sink(a[2]) # $ hasValueFlow=25 sink(b[2]) end @@ -316,16 +316,16 @@ def m36 a = [0, 1, source(36.1)] b = a.delete(2) { source(36.2) } sink b # $ hasValueFlow=36.1 $ hasValueFlow=36.2 - sink a[0] - sink a[1] - sink a[2] + sink a[0] # $ hasValueFlow=36.1 + sink a[1] # $ hasValueFlow=36.1 + sink a[2] # $ hasValueFlow=36.1 end def m37(i) a = [0, 1, source(37.1), source(37.2)] b = a.delete_at(2) sink b # $ hasValueFlow=37.1 - sink a[2] # $ hasValueFlow=37.2 + sink a[2] # $ hasValueFlow=37.1 $ hasValueFlow=37.2 a = [0, 1, source(37.1), source(37.2)] b = a.delete_at(i) @@ -483,15 +483,15 @@ def m54 a.fill(source(54.2), 1, 1) sink(a[3]) # $ hasValueFlow=54.1 $ hasValueFlow=54.2 a.fill(source(54.3)) - sink(a[0]) # $ hasValueFlow=54.3 + sink(a[0]) # $ hasValueFlow=54.2 $ hasValueFlow=54.3 a.fill do |i| source(54.4) end - sink(a[0]) # $ hasValueFlow=54.4 + sink(a[0]) # $ hasValueFlow=54.2 $ hasValueFlow=54.3 $ hasValueFlow=54.4 a.fill(2) do |i| source(54.5) end - sink(a[0]) # $ hasValueFlow=54.4 $ hasValueFlow=54.5 + sink(a[0]) # $ hasValueFlow=54.2 $ hasValueFlow=54.3 $ hasValueFlow=54.4 $ hasValueFlow=54.5 end def m55 @@ -656,12 +656,12 @@ def m70(i) b = a.insert(1, source(70.2), source(70.3)) sink a[0] # 0 sink a[1] # $ hasValueFlow=70.2 - sink a[2] # $ hasValueFlow=70.3 + sink a[2] # $ hasValueFlow=70.1 $ hasValueFlow=70.3 sink a[3] # 1 sink a[4] # $ hasValueFlow=70.1 sink b[0] # 0 sink b[1] # $ hasValueFlow=70.2 - sink b[2] # $ hasValueFlow=70.3 + sink b[2] # $ hasValueFlow=70.1 $ hasValueFlow=70.3 sink b[3] # 1 sink b[4] # $ hasValueFlow=70.1 @@ -925,7 +925,7 @@ def m90 a.prepend(2, 3, source(90.2)) sink(a[0]) sink(a[1]) - sink(a[2]) # $ hasValueFlow=90.2 + sink(a[2]) # $ hasValueFlow=90.1 $ hasValueFlow=90.2 sink(a[3]) sink(a[4]) sink(a[5]) # $ hasValueFlow=90.1 @@ -1096,8 +1096,8 @@ def m105(i) b = a.rotate! sink a[0] # $ hasValueFlow=105.1 sink a[1] # $ hasValueFlow=105.1 $ hasValueFlow=105.2 - sink a[2] # $ hasValueFlow=105.1 $ hasValueFlow=105.3 - sink a[3] # $ hasValueFlow=105.1 + sink a[2] # $ hasValueFlow=105.1 $ hasValueFlow=105.2 $ hasValueFlow=105.3 + sink a[3] # $ hasValueFlow=105.1 $ hasValueFlow=105.3 sink b[0] # $ hasValueFlow=105.1 sink b[1] # $ hasValueFlow=105.1 $ hasValueFlow=105.2 sink b[2] # $ hasValueFlow=105.1 $ hasValueFlow=105.3 @@ -1107,8 +1107,8 @@ def m105(i) b = a.rotate!(2) sink a[0] # $ hasValueFlow=105.1 $ hasValueFlow=105.2 sink a[1] # $ hasValueFlow=105.1 $ hasValueFlow=105.3 - sink a[2] # $ hasValueFlow=105.1 - sink a[3] # $ hasValueFlow=105.1 + sink a[2] # $ hasValueFlow=105.1 $ hasValueFlow=105.2 + sink a[3] # $ hasValueFlow=105.1 $ hasValueFlow=105.3 sink b[0] # $ hasValueFlow=105.1 $ hasValueFlow=105.2 sink b[1] # $ hasValueFlow=105.1 $ hasValueFlow=105.3 sink b[2] # $ hasValueFlow=105.1 @@ -1159,17 +1159,17 @@ def m108(i) a = [source(108.1), 1, source(108.2)] b = a.shift sink b # $ hasValueFlow=108.1 - sink a[0] + sink a[0] # $ hasValueFlow=108.1 sink a[1] # $ hasValueFlow=108.2 - sink a[2] + sink a[2] # $ hasValueFlow=108.2 a = [source(108.1), 1, source(108.2)] b = a.shift(2) sink b[0] # $ hasValueFlow=108.1 sink b[1] - sink a[0] # $ hasValueFlow=108.2 + sink a[0] # $ hasValueFlow=108.1 $ hasValueFlow=108.2 sink a[1] - sink a[2] + sink a[2] # $ hasValueFlow=108.2 a = [source(108.1), 1, source(108.2)] b = a.shift(i) @@ -1221,7 +1221,7 @@ def m111(i) b = a.slice(2, 3) sink b[0] # $ hasValueFlow=111.1 sink b[1] - sink b[2] # $ hasValueFlow=111.2 + sink b[2] # $ hasValueFlow=111.1 $ hasValueFlow=111.2 b = a.slice(1, i) # unknown range sink b[0] # $ hasValueFlow=111.1 $ hasValueFlow=111.2 @@ -1230,12 +1230,12 @@ def m111(i) b = a.slice(2..3) # inclusive range sink b[0] # $ hasValueFlow=111.1 sink b[1] - sink b[2] + sink b[2] # $ hasValueFlow=111.1 b = a.slice(2...4) # exclusive range sink b[0] # $ hasValueFlow=111.1 sink b[1] - sink b[2] + sink b[2] # $ hasValueFlow=111.1 b = a.slice(3..i) # unknown range sink b[0] # $ hasValueFlow=111.1 $ hasValueFlow=111.2 @@ -1262,7 +1262,7 @@ def m112(i) sink b # $ hasValueFlow=112.1 sink a[0] sink a[1] - sink a[2] + sink a[2] # $ hasValueFlow=112.1 sink a[3] # $ hasValueFlow=112.2 a = [0, 1, source(112.1), 2, source(112.2)] @@ -1283,9 +1283,9 @@ def m112(i) sink b[2] # $ hasValueFlow=112.2 sink a[0] sink a[1] - sink a[2] + sink a[2] # $ hasValueFlow=112.1 sink a[3] - sink a[4] + sink a[4] # $ hasValueFlow=112.2 a = [0, 1, source(112.1), 2, source(112.2)] b = a.slice!(2..3) # inclusive range @@ -1294,9 +1294,9 @@ def m112(i) sink b[2] sink a[0] sink a[1] - sink a[2] # $ hasValueFlow=112.2 + sink a[2] # $ hasValueFlow=112.1 $ hasValueFlow=112.2 sink a[3] - sink a[4] + sink a[4] # $ hasValueFlow=112.2 a = [0, 1, source(112.1), 2, source(112.2)] b = a.slice!(2...4) # exclusive range @@ -1305,9 +1305,9 @@ def m112(i) sink b[2] sink a[0] sink a[1] - sink a[2] # $ hasValueFlow=112.2 + sink a[2] # $ hasValueFlow=112.1 $ hasValueFlow=112.2 sink a[3] - sink a[4] + sink a[4] # $ hasValueFlow=112.2 a = [0, 1, source(112.1), 2, source(112.2)] b = a.slice!(2, i) # unknown range @@ -1343,7 +1343,7 @@ def m112(i) sink b[2] # $ hasValueFlow=112.1 sink a[0] sink a[1] # $ hasValueFlow=112.2 - sink a[2] + sink a[2] # $ hasValueFlow=112.1 a = [0, 1, source(112.1), 2, source(112.2)] b = a.slice!(3..) # unknown range @@ -1454,8 +1454,8 @@ def m121(i) sink(b[0]) sink(b[1]) sink(b[2]) # $ hasValueFlow=121.1 - sink(b[3]) - sink(b[i]) # $ hasValueFlow=121.1 + sink(b[3]) # $ hasValueFlow=121.2 + sink(b[i]) # $ hasValueFlow=121.1 $ hasValueFlow=121.2 b = a.take(133) sink(b[0]) sink(b[1]) @@ -1562,7 +1562,7 @@ def m132 a.unshift(2, 3, source(132.2)) sink(a[0]) sink(a[1]) - sink(a[2]) # $ hasValueFlow=132.2 + sink(a[2]) # $ hasValueFlow=132.1 $ hasValueFlow=132.2 sink(a[3]) sink(a[4]) sink(a[5]) # $ hasValueFlow=132.1 diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected b/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected index af0a1e7ef11b..92342e6925ad 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected @@ -1,28 +1,14 @@ -| array_flow.rb:107:10:107:13 | ...[...] | Unexpected result: hasValueFlow=11.2 | | array_flow.rb:179:28:179:46 | # $ hasValueFlow=19 | Missing result: hasValueFlow=19 | | array_flow.rb:180:28:180:46 | # $ hasValueFlow=19 | Missing result: hasValueFlow=19 | -| array_flow.rb:226:10:226:13 | ...[...] | Unexpected result: hasValueFlow=25 | -| array_flow.rb:319:10:319:13 | ...[...] | Unexpected result: hasValueFlow=36.1 | -| array_flow.rb:320:10:320:13 | ...[...] | Unexpected result: hasValueFlow=36.1 | -| array_flow.rb:321:10:321:13 | ...[...] | Unexpected result: hasValueFlow=36.1 | -| array_flow.rb:328:10:328:13 | ...[...] | Unexpected result: hasValueFlow=37.1 | | array_flow.rb:360:22:360:42 | # $ hasValueFlow=40.2 | Missing result: hasValueFlow=40.2 | -| array_flow.rb:486:10:486:13 | ...[...] | Unexpected result: hasValueFlow=54.2 | -| array_flow.rb:490:10:490:13 | ...[...] | Unexpected result: hasValueFlow=54.2 | -| array_flow.rb:490:10:490:13 | ...[...] | Unexpected result: hasValueFlow=54.3 | -| array_flow.rb:494:10:494:13 | ...[...] | Unexpected result: hasValueFlow=54.2 | -| array_flow.rb:494:10:494:13 | ...[...] | Unexpected result: hasValueFlow=54.3 | | array_flow.rb:586:16:586:34 | # $ hasValueFlow=63 | Missing result: hasValueFlow=63 | | array_flow.rb:591:19:591:37 | # $ hasValueFlow=64 | Missing result: hasValueFlow=64 | | array_flow.rb:593:16:593:34 | # $ hasValueFlow=64 | Missing result: hasValueFlow=64 | | array_flow.rb:594:19:594:47 | # $ SPURIOUS: hasValueFlow=64 | Fixed spurious result: hasValueFlow=64 | | array_flow.rb:595:16:595:34 | # $ hasValueFlow=64 | Missing result: hasValueFlow=64 | | array_flow.rb:596:19:596:47 | # $ SPURIOUS: hasValueFlow=64 | Fixed spurious result: hasValueFlow=64 | -| array_flow.rb:659:10:659:13 | ...[...] | Unexpected result: hasValueFlow=70.1 | -| array_flow.rb:664:10:664:13 | ...[...] | Unexpected result: hasValueFlow=70.1 | | array_flow.rb:871:18:871:36 | # $ hasValueFlow=87 | Missing result: hasValueFlow=87 | | array_flow.rb:872:18:872:36 | # $ hasValueFlow=87 | Missing result: hasValueFlow=87 | -| array_flow.rb:928:10:928:13 | ...[...] | Unexpected result: hasValueFlow=90.1 | | array_flow.rb:939:18:939:78 | # $ hasValueFlow=91.1 $ hasValueFlow=91.2 $ hasValueFlow=91.3 | Missing result: hasValueFlow=91.1 | | array_flow.rb:939:18:939:78 | # $ hasValueFlow=91.1 $ hasValueFlow=91.2 $ hasValueFlow=91.3 | Missing result: hasValueFlow=91.2 | | array_flow.rb:939:18:939:78 | # $ hasValueFlow=91.1 $ hasValueFlow=91.2 $ hasValueFlow=91.3 | Missing result: hasValueFlow=91.3 | @@ -31,31 +17,9 @@ | array_flow.rb:940:18:940:78 | # $ hasValueFlow=91.1 $ hasValueFlow=91.2 $ hasValueFlow=91.3 | Missing result: hasValueFlow=91.3 | | array_flow.rb:957:28:957:46 | # $ hasValueFlow=93 | Missing result: hasValueFlow=93 | | array_flow.rb:958:28:958:46 | # $ hasValueFlow=93 | Missing result: hasValueFlow=93 | -| array_flow.rb:1099:10:1099:13 | ...[...] | Unexpected result: hasValueFlow=105.2 | -| array_flow.rb:1100:10:1100:13 | ...[...] | Unexpected result: hasValueFlow=105.3 | -| array_flow.rb:1110:10:1110:13 | ...[...] | Unexpected result: hasValueFlow=105.2 | -| array_flow.rb:1111:10:1111:13 | ...[...] | Unexpected result: hasValueFlow=105.3 | -| array_flow.rb:1162:10:1162:13 | ...[...] | Unexpected result: hasValueFlow=108.1 | -| array_flow.rb:1164:10:1164:13 | ...[...] | Unexpected result: hasValueFlow=108.2 | -| array_flow.rb:1170:10:1170:13 | ...[...] | Unexpected result: hasValueFlow=108.1 | -| array_flow.rb:1172:10:1172:13 | ...[...] | Unexpected result: hasValueFlow=108.2 | -| array_flow.rb:1224:10:1224:13 | ...[...] | Unexpected result: hasValueFlow=111.1 | -| array_flow.rb:1233:10:1233:13 | ...[...] | Unexpected result: hasValueFlow=111.1 | -| array_flow.rb:1238:10:1238:13 | ...[...] | Unexpected result: hasValueFlow=111.1 | -| array_flow.rb:1265:10:1265:13 | ...[...] | Unexpected result: hasValueFlow=112.1 | -| array_flow.rb:1286:10:1286:13 | ...[...] | Unexpected result: hasValueFlow=112.1 | -| array_flow.rb:1288:10:1288:13 | ...[...] | Unexpected result: hasValueFlow=112.2 | -| array_flow.rb:1297:10:1297:13 | ...[...] | Unexpected result: hasValueFlow=112.1 | -| array_flow.rb:1299:10:1299:13 | ...[...] | Unexpected result: hasValueFlow=112.2 | -| array_flow.rb:1308:10:1308:13 | ...[...] | Unexpected result: hasValueFlow=112.1 | -| array_flow.rb:1310:10:1310:13 | ...[...] | Unexpected result: hasValueFlow=112.2 | -| array_flow.rb:1346:10:1346:13 | ...[...] | Unexpected result: hasValueFlow=112.1 | -| array_flow.rb:1457:10:1457:13 | ...[...] | Unexpected result: hasValueFlow=121.2 | -| array_flow.rb:1458:10:1458:13 | ...[...] | Unexpected result: hasValueFlow=121.2 | | array_flow.rb:1512:18:1512:39 | # $ hasValueFlow=128.1 | Missing result: hasValueFlow=128.1 | | array_flow.rb:1513:18:1513:39 | # $ hasValueFlow=128.2 | Missing result: hasValueFlow=128.2 | | array_flow.rb:1514:18:1514:39 | # $ hasValueFlow=128.3 | Missing result: hasValueFlow=128.3 | -| array_flow.rb:1565:10:1565:13 | ...[...] | Unexpected result: hasValueFlow=132.1 | | array_flow.rb:1601:18:1601:39 | # $ hasValueFlow=134.3 | Missing result: hasValueFlow=134.3 | | array_flow.rb:1602:18:1602:39 | # $ hasValueFlow=134.2 | Missing result: hasValueFlow=134.2 | | array_flow.rb:1603:18:1603:39 | # $ hasValueFlow=134.1 | Missing result: hasValueFlow=134.1 | From 71ee3192ed292fa7e6743fdaa8beaccfcba7aa44 Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Fri, 31 Jul 2026 09:09:09 -0700 Subject: [PATCH 3/6] Ruby: Annotate hash type-tracking results Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../dataflow/hash-flow/hash-flow.expected | 12 ++++++++++ .../dataflow/hash-flow/hash_flow.rb | 24 +++++++++---------- .../type-tracking-hash-flow.expected | 12 ---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected index 17433b1cd776..b5799c4b1944 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected @@ -2280,6 +2280,18 @@ nodes | hash_flow.rb:1014:14:1014:14 | k | semmle.label | k | subpaths testFailures +| hash_flow.rb:117:20:117:39 | # $ hasValueFlow=7.1 | Missing result: hasValueFlow=7.1 | +| hash_flow.rb:119:20:119:58 | # $ hasValueFlow=7.1 $ hasValueFlow=7.2 | Missing result: hasValueFlow=7.1 | +| hash_flow.rb:163:20:163:39 | # $ hasValueFlow=9.1 | Missing result: hasValueFlow=9.1 | +| hash_flow.rb:187:20:187:40 | # $ hasValueFlow=12.1 | Missing result: hasValueFlow=12.1 | +| hash_flow.rb:291:17:291:37 | # $ hasValueFlow=19.1 | Missing result: hasValueFlow=19.1 | +| hash_flow.rb:294:17:294:37 | # $ hasValueFlow=19.3 | Missing result: hasValueFlow=19.3 | +| hash_flow.rb:515:22:515:62 | # $ hasValueFlow=31.2 $ hasValueFlow=31.3 | Missing result: hasValueFlow=31.3 | +| hash_flow.rb:673:21:673:61 | # $ hasValueFlow=41.1 $ hasValueFlow=41.3 | Missing result: hasValueFlow=41.1 | +| hash_flow.rb:776:17:776:37 | # $ hasValueFlow=46.1 | Missing result: hasValueFlow=46.1 | +| hash_flow.rb:779:17:779:37 | # $ hasValueFlow=46.3 | Missing result: hasValueFlow=46.3 | +| hash_flow.rb:781:20:781:40 | # $ hasValueFlow=46.1 | Missing result: hasValueFlow=46.1 | +| hash_flow.rb:784:20:784:40 | # $ hasValueFlow=46.3 | Missing result: hasValueFlow=46.3 | hashLiteral | hash_flow.rb:10:12:21:5 | call to [] | | hash_flow.rb:55:13:55:37 | ...[...] | diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb b/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb index d5d7ce4801ed..22168a156002 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb @@ -114,9 +114,9 @@ def m7(x) sink(hash[:a]) # $ hasValueFlow=7.1 sink(b) # $ hasValueFlow=7.1 hash.store(:a, 1) - sink(hash[:a]) + sink(hash[:a]) # $ hasValueFlow=7.1 c = hash.store(x, taint(7.2)) - sink(hash[:a]) # $ hasValueFlow=7.2 + sink(hash[:a]) # $ hasValueFlow=7.1 $ hasValueFlow=7.2 sink(hash[10]) # $ hasValueFlow=7.2 sink(c) # $ hasValueFlow=7.2 end @@ -160,7 +160,7 @@ def m10() :b => 1 } hash.clear - sink(hash[:a]) + sink(hash[:a]) # $ hasValueFlow=9.1 end m10() @@ -184,7 +184,7 @@ def m12() } a = hash.delete(:a) sink(a) # $ hasValueFlow=12.1 - sink(hash[:a]) + sink(hash[:a]) # $ hasValueFlow=12.1 end m12() @@ -288,10 +288,10 @@ def m19(x) :d => taint(19.3) } x = hash.except(:a,x,:d) - sink(x[:a]) + sink(x[:a]) # $ hasValueFlow=19.1 sink(x[:b]) sink(x[:c]) # $ hasValueFlow=19.2 - sink(x[:d]) + sink(x[:d]) # $ hasValueFlow=19.3 end m19(:c) @@ -512,7 +512,7 @@ def m31() hash2.replace(hash) sink (hash2[:a]) # $ hasValueFlow=31.1 sink (hash2[:b]) - sink (hash2[:c]) # $ hasValueFlow=31.2 + sink (hash2[:c]) # $ hasValueFlow=31.2 $ hasValueFlow=31.3 end def m32() @@ -670,7 +670,7 @@ def m41() sink value # $ hasValueFlow=41.1 $ hasValueFlow=41.2 taint(41.3) end - sink (hash[:a]) # $ hasValueFlow=41.3 + sink (hash[:a]) # $ hasValueFlow=41.1 $ hasValueFlow=41.3 end m41() @@ -773,15 +773,15 @@ def m46(x) x = hash.except!(:a, x, :d) - sink(x[:a]) + sink(x[:a]) # $ hasValueFlow=46.1 sink(x[:b]) sink(x[:c]) # $ hasValueFlow=46.2 - sink(x[:d]) + sink(x[:d]) # $ hasValueFlow=46.3 - sink(hash[:a]) + sink(hash[:a]) # $ hasValueFlow=46.1 sink(hash[:b]) sink(hash[:c]) # $ hasValueFlow=46.2 - sink(hash[:d]) + sink(hash[:d]) # $ hasValueFlow=46.3 end m46(:c) diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/type-tracking-hash-flow.expected b/ruby/ql/test/library-tests/dataflow/hash-flow/type-tracking-hash-flow.expected index e812393899ef..246044ca15ae 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/type-tracking-hash-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/type-tracking-hash-flow.expected @@ -1,22 +1,10 @@ | hash_flow.rb:65:21:65:40 | # $ hasValueFlow=3.3 | Missing result: hasValueFlow=3.3 | | hash_flow.rb:66:21:66:49 | # $ SPURIOUS hasValueFlow=3.3 | Missing result: hasValueFlow=3.3 | -| hash_flow.rb:117:10:117:17 | ...[...] | Unexpected result: hasValueFlow=7.1 | -| hash_flow.rb:119:10:119:17 | ...[...] | Unexpected result: hasValueFlow=7.1 | | hash_flow.rb:152:16:152:36 | # $ hasValueFlow=10.1 | Missing result: hasValueFlow=10.1 | -| hash_flow.rb:163:10:163:17 | ...[...] | Unexpected result: hasValueFlow=9.1 | -| hash_flow.rb:187:10:187:17 | ...[...] | Unexpected result: hasValueFlow=12.1 | | hash_flow.rb:219:27:219:47 | # $ hasValueFlow=14.2 | Missing result: hasValueFlow=14.2 | -| hash_flow.rb:291:10:291:14 | ...[...] | Unexpected result: hasValueFlow=19.1 | -| hash_flow.rb:294:10:294:14 | ...[...] | Unexpected result: hasValueFlow=19.3 | | hash_flow.rb:467:16:467:36 | # $ hasValueFlow=28.1 | Missing result: hasValueFlow=28.1 | -| hash_flow.rb:515:10:515:20 | ( ... ) | Unexpected result: hasValueFlow=31.3 | | hash_flow.rb:559:17:559:57 | # $ hasValueFlow=34.1 $ hasValueFlow=34.2 | Missing result: hasValueFlow=34.1 | | hash_flow.rb:559:17:559:57 | # $ hasValueFlow=34.1 $ hasValueFlow=34.2 | Missing result: hasValueFlow=34.2 | | hash_flow.rb:571:18:571:38 | # $ hasValueFlow=35.1 | Missing result: hasValueFlow=35.1 | | hash_flow.rb:591:20:591:60 | # $ hasValueFlow=36.1 $ hasValueFlow=36.2 | Missing result: hasValueFlow=36.1 | | hash_flow.rb:591:20:591:60 | # $ hasValueFlow=36.1 $ hasValueFlow=36.2 | Missing result: hasValueFlow=36.2 | -| hash_flow.rb:673:10:673:19 | ( ... ) | Unexpected result: hasValueFlow=41.1 | -| hash_flow.rb:776:10:776:14 | ...[...] | Unexpected result: hasValueFlow=46.1 | -| hash_flow.rb:779:10:779:14 | ...[...] | Unexpected result: hasValueFlow=46.3 | -| hash_flow.rb:781:10:781:17 | ...[...] | Unexpected result: hasValueFlow=46.1 | -| hash_flow.rb:784:10:784:17 | ...[...] | Unexpected result: hasValueFlow=46.3 | From 8aff1e5f26a80b756a1bb1e430ca9f510b2a3b6a Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Fri, 31 Jul 2026 11:52:26 -0700 Subject: [PATCH 4/6] Ruby: Document global type-tracking imprecision Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ruby/ql/test/library-tests/dataflow/global/Flow.expected | 5 +++++ .../dataflow/global/TypeTrackingInlineTest.expected | 5 ----- ruby/ql/test/library-tests/dataflow/global/callbacks.rb | 2 +- .../test/library-tests/dataflow/global/captured_variables.rb | 4 ++-- .../test/library-tests/dataflow/global/instance_variables.rb | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/global/Flow.expected b/ruby/ql/test/library-tests/dataflow/global/Flow.expected index f320bf8f5e94..40d775e848d1 100644 --- a/ruby/ql/test/library-tests/dataflow/global/Flow.expected +++ b/ruby/ql/test/library-tests/dataflow/global/Flow.expected @@ -600,6 +600,11 @@ subpaths | instance_variables.rb:120:6:120:10 | foo16 : Foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field : Foo [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:120:6:120:20 | call to get_field | | instance_variables.rb:120:6:120:10 | foo16 : Foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field : Foo [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:120:6:120:20 | call to get_field | testFailures +| callbacks.rb:29:42:29:69 | # $ SPURIOUS: hasValueFlow=2 | Fixed spurious result: hasValueFlow=2 | +| captured_variables.rb:87:13:87:57 | # $ hasValueFlow=6 $ SPURIOUS: hasValueFlow=7 | Fixed spurious result: hasValueFlow=7 | +| captured_variables.rb:112:20:112:66 | # $ hasValueFlow=10 $ SPURIOUS: hasValueFlow=11 | Fixed spurious result: hasValueFlow=11 | +| instance_variables.rb:49:16:49:90 | # $ hasValueFlow=36 $ SPURIOUS: hasValueFlow=30 $ SPURIOUS: hasValueFlow=35 | Fixed spurious result: hasValueFlow=30 | +| instance_variables.rb:49:16:49:90 | # $ hasValueFlow=36 $ SPURIOUS: hasValueFlow=30 $ SPURIOUS: hasValueFlow=35 | Fixed spurious result: hasValueFlow=35 | #select | blocks.rb:8:10:8:14 | yield ... | blocks.rb:14:12:14:20 | call to source | blocks.rb:8:10:8:14 | yield ... | $@ | blocks.rb:14:12:14:20 | call to source | call to source | | blocks.rb:25:8:25:8 | x | blocks.rb:24:3:24:11 | call to source | blocks.rb:25:8:25:8 | x | $@ | blocks.rb:24:3:24:11 | call to source | call to source | diff --git a/ruby/ql/test/library-tests/dataflow/global/TypeTrackingInlineTest.expected b/ruby/ql/test/library-tests/dataflow/global/TypeTrackingInlineTest.expected index 07e85877ca5d..5d053ff4900f 100644 --- a/ruby/ql/test/library-tests/dataflow/global/TypeTrackingInlineTest.expected +++ b/ruby/ql/test/library-tests/dataflow/global/TypeTrackingInlineTest.expected @@ -1,20 +1,15 @@ | blocks.rb:4:10:4:10 | r | Fixed missing result: hasValueFlow=1 | | callbacks.rb:17:41:17:58 | # $ hasValueFlow=1 | Missing result: hasValueFlow=1 | -| callbacks.rb:29:37:29:37 | x | Unexpected result: hasValueFlow=2 | | captured_variables.rb:50:10:50:10 | x | Fixed missing result: hasValueFlow=2 | | captured_variables.rb:68:25:68:68 | # $ hasValueFlow=3 $ MISSING: hasValueFlow=4 | Missing result: hasValueFlow=3 | | captured_variables.rb:72:21:72:66 | # $ hasValueFlow=4 $ SPURIOUS: hasValueFlow=3 | Fixed spurious result: hasValueFlow=3 | | captured_variables.rb:72:21:72:66 | # $ hasValueFlow=4 $ SPURIOUS: hasValueFlow=3 | Missing result: hasValueFlow=4 | | captured_variables.rb:83:21:83:38 | # $ hasValueFlow=5 | Missing result: hasValueFlow=5 | -| captured_variables.rb:87:10:87:10 | y | Unexpected result: hasValueFlow=7 | -| captured_variables.rb:112:18:112:18 | x | Unexpected result: hasValueFlow=11 | | captured_variables.rb:126:14:126:14 | x | Fixed missing result: hasValueFlow=12 | | captured_variables.rb:154:17:154:35 | # $ hasValueFlow=13 | Missing result: hasValueFlow=13 | | instance_variables.rb:20:16:20:33 | # $ hasValueFlow=7 | Missing result: hasValueFlow=7 | | instance_variables.rb:36:36:36:54 | # $ hasValueFlow=34 | Missing result: hasValueFlow=34 | | instance_variables.rb:39:36:39:54 | # $ hasValueFlow=35 | Missing result: hasValueFlow=35 | -| instance_variables.rb:49:14:49:14 | x | Unexpected result: hasValueFlow=30 | -| instance_variables.rb:49:14:49:14 | x | Unexpected result: hasValueFlow=35 | | instance_variables.rb:55:21:55:39 | # $ hasValueFlow=42 | Missing result: hasValueFlow=42 | | instance_variables.rb:67:22:67:40 | # $ hasValueFlow=21 | Missing result: hasValueFlow=21 | | instance_variables.rb:71:18:71:36 | # $ hasValueFlow=22 | Missing result: hasValueFlow=22 | diff --git a/ruby/ql/test/library-tests/dataflow/global/callbacks.rb b/ruby/ql/test/library-tests/dataflow/global/callbacks.rb index e11747ca6d5e..bc3146487f81 100644 --- a/ruby/ql/test/library-tests/dataflow/global/callbacks.rb +++ b/ruby/ql/test/library-tests/dataflow/global/callbacks.rb @@ -26,4 +26,4 @@ def apply_block_wrap (x, &block) end apply_block_wrap(taint(2)) { |x| sink(x) } # $ hasValueFlow=2 -apply_block_wrap("safe") { |x| sink(x) } \ No newline at end of file +apply_block_wrap("safe") { |x| sink(x) } # $ SPURIOUS: hasValueFlow=2 \ No newline at end of file diff --git a/ruby/ql/test/library-tests/dataflow/global/captured_variables.rb b/ruby/ql/test/library-tests/dataflow/global/captured_variables.rb index 8c7c5049b2d0..feb423589551 100644 --- a/ruby/ql/test/library-tests/dataflow/global/captured_variables.rb +++ b/ruby/ql/test/library-tests/dataflow/global/captured_variables.rb @@ -84,7 +84,7 @@ def get_field y = taint(6) fn = -> { - sink(y) # $ hasValueFlow=6 + sink(y) # $ hasValueFlow=6 $ SPURIOUS: hasValueFlow=7 y = taint(7) } fn.call @@ -109,7 +109,7 @@ def capture_nested x = taint(10) middle = -> { inner = -> { - sink x # $ hasValueFlow=10 + sink x # $ hasValueFlow=10 $ SPURIOUS: hasValueFlow=11 x = taint(11) } inner.call diff --git a/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb b/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb index 9943b3cb5792..fa12ec062ae8 100644 --- a/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb +++ b/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb @@ -46,7 +46,7 @@ def self.new arg class Baz < Foo def initialize x - sink x # $ hasValueFlow=36 + sink x # $ hasValueFlow=36 $ SPURIOUS: hasValueFlow=30 $ SPURIOUS: hasValueFlow=35 end end From 48656b453f1ea73cf27ce3b04c8c2b7c299f42b8 Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Sun, 2 Aug 2026 19:06:51 -0700 Subject: [PATCH 5/6] C++: Correct leap-year inline query IDs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...ckedLeapYearAfterYearModification.expected | 44 ---------- .../test.cpp | 82 +++++++++---------- 2 files changed, 41 insertions(+), 85 deletions(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/UncheckedLeapYearAfterYearModification.expected b/cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/UncheckedLeapYearAfterYearModification.expected index 4896657bbe6a..41ef6df5ce34 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/UncheckedLeapYearAfterYearModification.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/UncheckedLeapYearAfterYearModification.expected @@ -141,47 +141,3 @@ nodes | test.cpp:1697:2:1697:22 | ... += ... | semmle.label | ... += ... | | test.cpp:1773:2:1773:22 | ... += ... | semmle.label | ... += ... | subpaths -testFailures -| test.cpp:422:2:422:14 | ... += ... | Unexpected result: Alert | -| test.cpp:440:2:440:11 | ... ++ | Unexpected result: Alert | -| test.cpp:456:2:456:12 | ... ++ | Unexpected result: Alert | -| test.cpp:681:2:681:23 | ... += ... | Unexpected result: Alert | -| test.cpp:813:2:813:40 | ... = ... | Unexpected result: Alert | -| test.cpp:813:21:813:40 | ... + ... | Unexpected result: Alert | -| test.cpp:818:2:818:24 | ... = ... | Unexpected result: Alert | -| test.cpp:818:13:818:24 | ... + ... | Unexpected result: Alert | -| test.cpp:951:3:951:25 | ... = ... | Unexpected result: Alert | -| test.cpp:951:14:951:25 | ... + ... | Unexpected result: Alert | -| test.cpp:969:3:969:12 | ... ++ | Unexpected result: Alert | -| test.cpp:1051:2:1051:11 | ... ++ | Unexpected result: Alert | -| test.cpp:1071:16:1071:23 | increment_arg output argument | Unexpected result: Alert | -| test.cpp:1075:27:1075:35 | increment_arg_by_pointer output argument | Unexpected result: Alert | -| test.cpp:1129:2:1129:26 | ... = ... | Unexpected result: Alert | -| test.cpp:1129:14:1129:26 | ... - ... | Unexpected result: Alert | -| test.cpp:1180:2:1180:19 | ... = ... | Unexpected result: Alert | -| test.cpp:1219:2:1219:28 | ... = ... | Unexpected result: Alert | -| test.cpp:1219:16:1219:28 | ... + ... | Unexpected result: Alert | -| test.cpp:1234:2:1234:28 | ... = ... | Unexpected result: Alert | -| test.cpp:1234:16:1234:28 | ... + ... | Unexpected result: Alert | -| test.cpp:1248:2:1248:28 | ... = ... | Unexpected result: Alert | -| test.cpp:1248:16:1248:28 | ... + ... | Unexpected result: Alert | -| test.cpp:1262:2:1262:26 | ... = ... | Unexpected result: Alert | -| test.cpp:1262:14:1262:26 | ... + ... | Unexpected result: Alert | -| test.cpp:1276:2:1276:26 | ... = ... | Unexpected result: Alert | -| test.cpp:1276:14:1276:26 | ... + ... | Unexpected result: Alert | -| test.cpp:1282:2:1282:28 | ... = ... | Unexpected result: Alert | -| test.cpp:1282:16:1282:28 | ... + ... | Unexpected result: Alert | -| test.cpp:1294:2:1294:28 | ... = ... | Unexpected result: Alert | -| test.cpp:1294:16:1294:28 | ... + ... | Unexpected result: Alert | -| test.cpp:1307:2:1307:26 | ... = ... | Unexpected result: Alert | -| test.cpp:1307:14:1307:26 | ... + ... | Unexpected result: Alert | -| test.cpp:1319:2:1319:26 | ... = ... | Unexpected result: Alert | -| test.cpp:1319:14:1319:26 | ... + ... | Unexpected result: Alert | -| test.cpp:1361:2:1361:17 | ... = ... | Unexpected result: Alert | -| test.cpp:1535:2:1535:15 | ... = ... | Unexpected result: Alert | -| test.cpp:1565:2:1565:22 | ... += ... | Unexpected result: Alert | -| test.cpp:1573:2:1573:22 | ... += ... | Unexpected result: Alert | -| test.cpp:1652:2:1652:22 | ... += ... | Unexpected result: Alert | -| test.cpp:1664:2:1664:22 | ... += ... | Unexpected result: Alert | -| test.cpp:1697:2:1697:22 | ... += ... | Unexpected result: Alert | -| test.cpp:1773:2:1773:22 | ... += ... | Unexpected result: Alert | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/test.cpp index d8c3d0595a63..3331b17bd880 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/test.cpp @@ -419,10 +419,10 @@ void AntiPattern_unchecked_filetime_conversion2a() GetSystemTime(&st); // BUG - UncheckedLeapYearAfterYearModification - st.wYear += 2; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + st.wYear += 2; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // BUG - UncheckedReturnValueForTimeFunctions - SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/leap-year/unchecked-return-value-for-time-conversion-function] + SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/microsoft/public/leap-year/unchecked-return-value-for-time-conversion-function] } /** @@ -437,10 +437,10 @@ void AntiPattern_unchecked_filetime_conversion2b() GetSystemTime(&st); // BUG - UncheckedLeapYearAfterYearModification - st.wYear++; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + st.wYear++; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // BUG - UncheckedReturnValueForTimeFunctions - SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/leap-year/unchecked-return-value-for-time-conversion-function] + SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/microsoft/public/leap-year/unchecked-return-value-for-time-conversion-function] } /** @@ -453,10 +453,10 @@ void AntiPattern_unchecked_filetime_conversion2b(SYSTEMTIME* st) FILETIME ft; // BUG - UncheckedLeapYearAfterYearModification - st->wYear++; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + st->wYear++; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // BUG - UncheckedReturnValueForTimeFunctions - SystemTimeToFileTime(st, &ft); // $ Alert[cpp/leap-year/unchecked-return-value-for-time-conversion-function] + SystemTimeToFileTime(st, &ft); // $ Alert[cpp/microsoft/public/leap-year/unchecked-return-value-for-time-conversion-function] } /** @@ -678,7 +678,7 @@ void AntiPattern_IncorrectGuard(int yearsToAdd) GetSystemTime(&st); // BUG - UncheckedLeapYearAfterYearModification - st.wYear += yearsToAdd; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + st.wYear += yearsToAdd; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // Incorrect Guard if (st.wMonth == 2 && st.wDay == 29) @@ -810,12 +810,12 @@ void test(int x) // BUG - UncheckedLeapYearAfterYearModification // Positive Case - Anti-pattern 1: [year +-n, month, day] - timeinfo.tm_year = x + timeinfo.tm_year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + timeinfo.tm_year = x + timeinfo.tm_year; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] st.wYear = x; // BUG - UncheckedLeapYearAfterYearModification // Positive Case - Anti-pattern 1: [year +-n, month, day] - st.wYear = x + st.wYear; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + st.wYear = x + st.wYear; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } /** @@ -948,9 +948,9 @@ void tp_intermediaryVar(struct timespec now, struct logtime ×tamp_remote) GetSystemTime(&st); // BUG - UncheckedLeapYearAfterYearModification - st.wYear = st.wYear + 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + st.wYear = st.wYear + 1; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] - SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/leap-year/unchecked-return-value-for-time-conversion-function] + SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/microsoft/public/leap-year/unchecked-return-value-for-time-conversion-function] } /** @@ -966,9 +966,9 @@ void tp_intermediaryVar(struct timespec now, struct logtime ×tamp_remote) GetSystemTime(&st); // BUG - UncheckedLeapYearAfterYearModification - st.wYear++; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + st.wYear++; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] - SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/leap-year/unchecked-return-value-for-time-conversion-function] + SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/microsoft/public/leap-year/unchecked-return-value-for-time-conversion-function] } /** @@ -1048,11 +1048,11 @@ void fp_daymonth_guard(){ // FALSE POSITIVE: year is incremented but month is checked and day corrected // in a ternary operation. It may be possible to fix this with a more sophisticated // data flow analysis. - st.wYear++; // $ SPURIOUS: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + st.wYear++; // $ SPURIOUS: Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] st.wDay = st.wMonth == 2 && st.wDay == 29 ? 28 : st.wDay; - SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/leap-year/unchecked-return-value-for-time-conversion-function] + SystemTimeToFileTime(&st, &ft); // $ Alert[cpp/microsoft/public/leap-year/unchecked-return-value-for-time-conversion-function] } void increment_arg(WORD &x){ @@ -1068,11 +1068,11 @@ void fn_year_set_through_out_arg(){ SYSTEMTIME st; GetSystemTime(&st); // BAD, year incremented without check - increment_arg(st.wYear); // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + increment_arg(st.wYear); // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // GetSystemTime(&st); // Bad, year incremented without check - increment_arg_by_pointer(&st.wYear); // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + increment_arg_by_pointer(&st.wYear); // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } @@ -1126,7 +1126,7 @@ typedef struct _TIME_FIELDS { void tp_ptime(PTIME_FIELDS ptm){ - ptm->Year = ptm->Year - 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + ptm->Year = ptm->Year - 1; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } @@ -1177,7 +1177,7 @@ void leap_year_checked_raw_false_positive2(WORD year, WORD offset, WORD day){ year += offset; // $ Source - tmp.tm_year = year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.tm_year = year; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } @@ -1216,7 +1216,7 @@ void inverted_leap_year_check(WORD year, WORD offset, WORD day){ day = 28; } - tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.tm_year = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } @@ -1231,7 +1231,7 @@ void simplified_leap_year_check1(WORD year, WORD offset){ } // Modified after check, could be dangerous - tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.tm_year = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } void simplified_leap_year_check2(WORD year, WORD offset){ @@ -1245,7 +1245,7 @@ void simplified_leap_year_check2(WORD year, WORD offset){ } // Modified after check, could be dangerous - tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.tm_year = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } void simplified_leap_year_check3(WORD year, WORD offset){ @@ -1259,7 +1259,7 @@ void simplified_leap_year_check3(WORD year, WORD offset){ } // Modified after check, could be dangerous - tmp.wYear = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.wYear = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } void simplified_leap_year_check4(WORD year, WORD offset){ @@ -1273,13 +1273,13 @@ void simplified_leap_year_check4(WORD year, WORD offset){ } // Modified after check, could be dangerous - tmp.wYear = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.wYear = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } void bad_simplified_leap_year_check1(WORD year, WORD offset){ struct tm tmp; - tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.tm_year = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // incorrect logic, should negate the %4 result bool isLeap = ((tmp.tm_year + 1900) % 4) && ((tmp.tm_year + 1900) % 100 || !((tmp.tm_year + 1900) % 400)); @@ -1291,7 +1291,7 @@ void bad_simplified_leap_year_check1(WORD year, WORD offset){ void bad_simplified_leap_year_check2(WORD year, WORD offset){ struct tm tmp; - tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.tm_year = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // incorrect logic, should not negate the %4 result @@ -1304,7 +1304,7 @@ void bad_simplified_leap_year_check2(WORD year, WORD offset){ void bad_simplified_leap_year_check3(WORD year, WORD offset){ SYSTEMTIME tmp; - tmp.wYear = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.wYear = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // incorrect logic, should negate the %4 result bool isLeap = (tmp.wYear % 4) && (tmp.wYear % 100 || !(tmp.wYear % 400)); @@ -1316,7 +1316,7 @@ void bad_simplified_leap_year_check3(WORD year, WORD offset){ void bad_simplified_leap_year_check4(WORD year, WORD offset){ SYSTEMTIME tmp; - tmp.wYear = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.wYear = year + offset; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // incorrect logic, should not negate the %4 result @@ -1358,7 +1358,7 @@ void indirect_time_conversion_check(WORD year, WORD offset){ void set_time(WORD year, WORD month, WORD day){ SYSTEMTIME tmp; - tmp.wYear = year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + tmp.wYear = year; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] tmp.wMonth = month; tmp.wDay = day; } @@ -1492,7 +1492,7 @@ void modification_after_conversion1(tm timeinfo){ // and never reassigned to another struct. WORD year = timeinfo.tm_year + 1900; - year += 1; // $ MISSING: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + year += 1; // $ MISSING: Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } WORD get_civil_year(tm timeinfo){ @@ -1504,7 +1504,7 @@ void modification_after_conversion2(tm timeinfo){ // This case shows a false negative where the year might be used and it is incorrectly modified, // and never reassigned to another struct. WORD year = get_civil_year(timeinfo); - year += 1; // $ MISSING: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + year += 1; // $ MISSING: Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } void modification_after_conversion_saved_to_other_time_struct1(tm timeinfo){ @@ -1518,7 +1518,7 @@ void modification_after_conversion_saved_to_other_time_struct1(tm timeinfo){ SYSTEMTIME s; // FALSE NEGATIVE: missing this because the conversion happens locally before // the year adjustment, which seems as though it is part of a conversion itself - s.wYear = year; // $ MISSING: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + s.wYear = year; // $ MISSING: Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } @@ -1532,7 +1532,7 @@ void modification_after_conversion_saved_to_other_time_struct2(tm timeinfo){ year += 1; // $ Source SYSTEMTIME s; - s.wYear = year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + s.wYear = year; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } void modification_after_conversion_saved_to_other_time_struct3(tm timeinfo){ @@ -1546,7 +1546,7 @@ void modification_after_conversion_saved_to_other_time_struct3(tm timeinfo){ SYSTEMTIME s; // FALSE NEGATIVE: missing this because the conversion happens locally before // the year adjustment, which seems as though it is part of a conversion itself - s.wYear = year; // $ MISSING: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + s.wYear = year; // $ MISSING: Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } @@ -1558,11 +1558,11 @@ void year_saved_to_variable_then_modified1(tm timeinfo){ // NOTE: should we even try to detect cases like this? // Our current rationale is that a year in a struct is more dangerous than a year in isolation // A year in isolation is harder to interpret - year += 1; // MISSING: $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + year += 1; // MISSING: $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] } void modification_before_conversion1(tm timeinfo){ - timeinfo.tm_year += 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + timeinfo.tm_year += 1; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // convert a tm year into a civil year, then modify after conversion // This case shows a false negative where the year might be used and it is incorrectly modified, // and never reassigned to another struct. @@ -1570,7 +1570,7 @@ void modification_before_conversion1(tm timeinfo){ } void modification_before_conversion2(tm timeinfo){ - timeinfo.tm_year += 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + timeinfo.tm_year += 1; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // convert a tm year into a civil year, then modify after conversion // This case shows a false negative where the year might be used and it is incorrectly modified, // and never reassigned to another struct. @@ -1649,7 +1649,7 @@ void odd_leap_year_check1(tm timeinfo){ } void odd_leap_year_check2(tm timeinfo){ - timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // Using an odd sytle of checking divisible by 4 presumably as an optimization trick // but also check unrelated conditions on the year as an optimization to rule out irrelevant years @@ -1661,7 +1661,7 @@ void odd_leap_year_check2(tm timeinfo){ } void odd_leap_year_check3(tm timeinfo){ - timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // Using an odd sytle of checking divisible by 4 presumably as an optimization trick // but also check unrelated conditions on the year as an optimization to rule out irrelevant years @@ -1694,7 +1694,7 @@ void odd_leap_year_check5(tm timeinfo){ void date_adjusted_through_mkgmtime(tm timeinfo){ - timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] // Using an odd sytle of checking divisible by 4 presumably as an optimization trick // but also check unrelated conditions on the year as an optimization to rule out irrelevant years @@ -1770,7 +1770,7 @@ void assumed_maketime_conversion1(tm timeinfo) void bad_leap_year_check_logic1(tm timeinfo){ - timeinfo.tm_year += 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification] + timeinfo.tm_year += 1; // $ Alert[cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification] WORD year = get_civil_year(timeinfo); From f3eb153c124f555d65804ce711d3d1c1bac0e1b4 Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Mon, 3 Aug 2026 05:21:35 -0700 Subject: [PATCH 6/6] PowerShell: Exclude pipeline parameters from command-line sources Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../semmle/code/powershell/dataflow/flowsources/Local.qll | 6 +++++- .../frameworks/system_net_sockets/test.expected | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/flowsources/Local.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/flowsources/Local.qll index 4ffff2d35c62..b3a7fd66b433 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/flowsources/Local.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/flowsources/Local.qll @@ -59,7 +59,11 @@ private class ExternalCommandLineArgumentSource extends CommandLineArgumentSourc * A data flow source that represents the parameters of the `Main` method of a program. */ private class MainMethodArgumentSource extends CommandLineArgumentSource { - MainMethodArgumentSource() { this.asParameter().getFunction() instanceof TopLevelFunction } + MainMethodArgumentSource() { + this.asParameter().getFunction() instanceof TopLevelFunction and + not this.asParameter() instanceof PipelineParameter and + not this.asParameter() instanceof PipelineByPropertyNameParameter + } } /** diff --git a/powershell/ql/test/library-tests/frameworks/system_net_sockets/test.expected b/powershell/ql/test/library-tests/frameworks/system_net_sockets/test.expected index 4a55f3a35549..e69de29bb2d1 100644 --- a/powershell/ql/test/library-tests/frameworks/system_net_sockets/test.expected +++ b/powershell/ql/test/library-tests/frameworks/system_net_sockets/test.expected @@ -1 +0,0 @@ -| test.ps1:1:1:43:0 | [synth] pipeline | Unexpected result: type="command line argument" |