Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit 582f8e4

Browse files
authored
Merge pull request #393 from smowton/smowton/fix/cfg-assignment-underscores
CFG: fix lastNode relating to assignments with underscores on the LHS
2 parents 3c84f11 + 3b927f3 commit 582f8e4

File tree

6 files changed

+114
-24
lines changed

6 files changed

+114
-24
lines changed

ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -759,18 +759,11 @@ module CFG {
759759
override predicate lastNode(ControlFlow::Node last, Completion cmpl) {
760760
ControlFlowTree.super.lastNode(last, cmpl)
761761
or
762-
exists(int nl, int nr | nl = getNumLhs() and nr = getNumRhs() |
763-
last = MkAssignNode(this, nl - 1)
762+
(
763+
last = max(int i | | epilogueNode(i) order by i)
764764
or
765-
not exists(MkAssignNode(this, nl - 1)) and
766-
(
767-
exists(ControlFlow::Node rhs | lastNode(getRhs(nr - 1), rhs, normalCompletion()) |
768-
if nl = nr then last = rhs else last = MkExtractNode(this, nl - 1)
769-
)
770-
or
771-
not exists(getRhs(nr - 1)) and
772-
lastNode(getLhs(nl - 1), last, normalCompletion())
773-
)
765+
not exists(epilogueNode(_)) and
766+
lastNode(getLastSubExprInEvalOrder(), last, normalCompletion())
774767
) and
775768
cmpl = Done()
776769
}
@@ -787,7 +780,7 @@ module CFG {
787780
firstNode(getRhs(0), succ)
788781
or
789782
not exists(getRhs(_)) and
790-
succ = epilogueNodeRanked(1)
783+
succ = epilogueNodeRanked(0)
791784
)
792785
)
793786
or
@@ -796,6 +789,10 @@ module CFG {
796789
firstNode(getRhs(i + 1), succ)
797790
)
798791
or
792+
not this instanceof RecvStmt and
793+
lastNode(getRhs(getNumRhs() - 1), pred, normalCompletion()) and
794+
succ = epilogueNodeRanked(0)
795+
or
799796
exists(int i |
800797
pred = epilogueNodeRanked(i) and
801798
succ = epilogueNodeRanked(i + 1)
@@ -809,16 +806,17 @@ module CFG {
809806
)
810807
}
811808

809+
private Expr getSubExprInEvalOrder(int evalOrder) {
810+
if evalOrder < getNumLhs()
811+
then result = getLhs(evalOrder)
812+
else result = getRhs(evalOrder - getNumLhs())
813+
}
814+
815+
private Expr getLastSubExprInEvalOrder() {
816+
result = max(int i | | getSubExprInEvalOrder(i) order by i)
817+
}
818+
812819
private ControlFlow::Node epilogueNode(int i) {
813-
not this instanceof RecvStmt and
814-
i = -2 and
815-
(
816-
lastNode(getRhs(getNumRhs() - 1), result, normalCompletion())
817-
or
818-
not exists(getRhs(_)) and
819-
lastNode(getLhs(getNumLhs() - 1), result, normalCompletion())
820-
)
821-
or
822820
i = -1 and
823821
result = MkCompoundAssignRhsNode(this)
824822
or

ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@
635635
| main.go:79:2:79:13 | call to Print | main.go:80:1:80:1 | exit |
636636
| main.go:79:12:79:12 | z | main.go:79:2:79:13 | call to Print |
637637
| main.go:82:1:82:1 | entry | main.go:82:18:82:18 | zero value for a |
638-
| main.go:82:1:86:1 | function declaration | main.go:0:0:0:0 | exit |
638+
| main.go:82:1:86:1 | function declaration | main.go:88:6:88:23 | skip |
639639
| main.go:82:6:82:13 | skip | main.go:82:1:86:1 | function declaration |
640640
| main.go:82:18:82:18 | implicit read of a | main.go:82:25:82:25 | implicit read of b |
641641
| main.go:82:18:82:18 | initialization of a | main.go:82:25:82:25 | zero value for b |
@@ -655,6 +655,36 @@
655655
| main.go:84:11:84:12 | 19 | main.go:84:9:84:12 | ...+... |
656656
| main.go:84:15:84:15 | x | main.go:84:2:84:2 | assignment to x |
657657
| main.go:85:2:85:7 | return statement | main.go:82:18:82:18 | implicit read of a |
658+
| main.go:88:1:88:1 | entry | main.go:88:25:88:25 | argument corresponding to x |
659+
| main.go:88:1:96:1 | function declaration | main.go:0:0:0:0 | exit |
660+
| main.go:88:6:88:23 | skip | main.go:88:1:96:1 | function declaration |
661+
| main.go:88:25:88:25 | argument corresponding to x | main.go:88:25:88:25 | initialization of x |
662+
| main.go:88:25:88:25 | initialization of x | main.go:89:2:89:2 | skip |
663+
| main.go:89:2:89:2 | assignment to a | main.go:89:5:89:5 | assignment to b |
664+
| main.go:89:2:89:2 | skip | main.go:89:5:89:5 | skip |
665+
| main.go:89:5:89:5 | assignment to b | main.go:90:5:90:8 | cond |
666+
| main.go:89:5:89:5 | skip | main.go:89:10:89:10 | x |
667+
| main.go:89:10:89:10 | x | main.go:89:13:89:13 | 0 |
668+
| main.go:89:13:89:13 | 0 | main.go:89:2:89:2 | assignment to a |
669+
| main.go:90:5:90:8 | cond | main.go:90:5:90:10 | call to cond |
670+
| main.go:90:5:90:10 | call to cond | main.go:90:10:90:10 | call to cond is false |
671+
| main.go:90:5:90:10 | call to cond | main.go:90:10:90:10 | call to cond is true |
672+
| main.go:90:5:90:10 | call to cond | main.go:96:1:96:1 | exit |
673+
| main.go:90:10:90:10 | call to cond is false | main.go:93:3:93:3 | skip |
674+
| main.go:90:10:90:10 | call to cond is true | main.go:91:3:91:3 | skip |
675+
| main.go:91:3:91:3 | assignment to a | main.go:95:9:95:9 | a |
676+
| main.go:91:3:91:3 | skip | main.go:91:6:91:6 | skip |
677+
| main.go:91:6:91:6 | skip | main.go:91:10:91:10 | b |
678+
| main.go:91:10:91:10 | b | main.go:91:13:91:13 | a |
679+
| main.go:91:13:91:13 | a | main.go:91:3:91:3 | assignment to a |
680+
| main.go:93:3:93:3 | skip | main.go:93:6:93:6 | skip |
681+
| main.go:93:6:93:6 | assignment to b | main.go:95:9:95:9 | a |
682+
| main.go:93:6:93:6 | skip | main.go:93:10:93:10 | b |
683+
| main.go:93:10:93:10 | b | main.go:93:13:93:13 | a |
684+
| main.go:93:13:93:13 | a | main.go:93:6:93:6 | assignment to b |
685+
| main.go:95:2:95:12 | return statement | main.go:96:1:96:1 | exit |
686+
| main.go:95:9:95:9 | a | main.go:95:12:95:12 | b |
687+
| main.go:95:12:95:12 | b | main.go:95:2:95:12 | return statement |
658688
| noretfunctions.go:0:0:0:0 | entry | noretfunctions.go:3:1:6:1 | skip |
659689
| noretfunctions.go:3:1:6:1 | skip | noretfunctions.go:8:6:8:12 | skip |
660690
| noretfunctions.go:8:1:8:1 | entry | noretfunctions.go:9:2:9:8 | selection of Exit |
@@ -734,7 +764,7 @@
734764
| stmts2.go:12:9:12:13 | ...+... | stmts2.go:12:2:12:13 | return statement |
735765
| stmts2.go:12:13:12:13 | y | stmts2.go:12:9:12:13 | ...+... |
736766
| stmts2.go:15:1:15:1 | entry | stmts2.go:15:13:15:14 | argument corresponding to ch |
737-
| stmts2.go:15:1:28:1 | function declaration | stmts2.go:0:0:0:0 | exit |
767+
| stmts2.go:15:1:28:1 | function declaration | stmts2.go:30:6:30:12 | skip |
738768
| stmts2.go:15:6:15:11 | skip | stmts2.go:15:1:28:1 | function declaration |
739769
| stmts2.go:15:13:15:14 | argument corresponding to ch | stmts2.go:15:13:15:14 | initialization of ch |
740770
| stmts2.go:15:13:15:14 | initialization of ch | stmts2.go:17:13:17:14 | ch |
@@ -778,6 +808,29 @@
778808
| stmts2.go:25:16:25:17 | ch | stmts2.go:16:2:26:2 | select statement |
779809
| stmts2.go:27:2:27:9 | return statement | stmts2.go:28:1:28:1 | exit |
780810
| stmts2.go:27:9:27:9 | 1 | stmts2.go:27:2:27:9 | return statement |
811+
| stmts2.go:30:1:30:1 | entry | stmts2.go:31:2:31:2 | skip |
812+
| stmts2.go:30:1:34:1 | function declaration | stmts2.go:0:0:0:0 | exit |
813+
| stmts2.go:30:6:30:12 | skip | stmts2.go:30:1:34:1 | function declaration |
814+
| stmts2.go:31:2:31:2 | assignment to x | stmts2.go:31:2:31:14 | ... := ...[1] |
815+
| stmts2.go:31:2:31:2 | skip | stmts2.go:31:5:31:5 | skip |
816+
| stmts2.go:31:2:31:14 | ... := ...[0] | stmts2.go:31:2:31:2 | assignment to x |
817+
| stmts2.go:31:2:31:14 | ... := ...[1] | stmts2.go:32:6:32:6 | skip |
818+
| stmts2.go:31:5:31:5 | skip | stmts2.go:31:10:31:12 | gen |
819+
| stmts2.go:31:10:31:12 | gen | stmts2.go:31:10:31:14 | call to gen |
820+
| stmts2.go:31:10:31:14 | call to gen | stmts2.go:31:2:31:14 | ... := ...[0] |
821+
| stmts2.go:31:10:31:14 | call to gen | stmts2.go:34:1:34:1 | exit |
822+
| stmts2.go:32:6:32:6 | assignment to y | stmts2.go:32:6:32:17 | value declaration specifier[1] |
823+
| stmts2.go:32:6:32:6 | skip | stmts2.go:32:9:32:9 | skip |
824+
| stmts2.go:32:6:32:17 | value declaration specifier[0] | stmts2.go:32:6:32:6 | assignment to y |
825+
| stmts2.go:32:6:32:17 | value declaration specifier[1] | stmts2.go:33:9:33:9 | x |
826+
| stmts2.go:32:9:32:9 | skip | stmts2.go:32:13:32:15 | gen |
827+
| stmts2.go:32:13:32:15 | gen | stmts2.go:32:13:32:17 | call to gen |
828+
| stmts2.go:32:13:32:17 | call to gen | stmts2.go:32:6:32:17 | value declaration specifier[0] |
829+
| stmts2.go:32:13:32:17 | call to gen | stmts2.go:34:1:34:1 | exit |
830+
| stmts2.go:33:2:33:13 | return statement | stmts2.go:34:1:34:1 | exit |
831+
| stmts2.go:33:9:33:9 | x | stmts2.go:33:13:33:13 | y |
832+
| stmts2.go:33:9:33:13 | ...+... | stmts2.go:33:2:33:13 | return statement |
833+
| stmts2.go:33:13:33:13 | y | stmts2.go:33:9:33:13 | ...+... |
781834
| stmts3.go:0:0:0:0 | entry | stmts3.go:3:1:3:13 | skip |
782835
| stmts3.go:3:1:3:13 | skip | stmts3.go:5:6:5:11 | skip |
783836
| stmts3.go:5:1:5:1 | entry | stmts3.go:7:3:7:5 | skip |
@@ -814,7 +867,7 @@
814867
| stmts3.go:19:22:19:23 | skip | stmts3.go:19:23:19:23 | exit |
815868
| stmts4.go:0:0:0:0 | entry | stmts4.go:3:5:3:5 | skip |
816869
| stmts4.go:3:5:3:5 | skip | stmts4.go:3:5:3:5 | zero value for _ |
817-
| stmts4.go:3:5:3:5 | skip | stmts4.go:5:6:5:11 | skip |
870+
| stmts4.go:3:5:3:5 | zero value for _ | stmts4.go:5:6:5:11 | skip |
818871
| stmts4.go:5:1:5:26 | function declaration | stmts4.go:0:0:0:0 | exit |
819872
| stmts4.go:5:6:5:11 | skip | stmts4.go:5:1:5:26 | function declaration |
820873
| stmts5.go:0:0:0:0 | entry | stmts5.go:3:1:5:1 | skip |

ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,13 @@ func multiRes() (a int, b float32) {
8484
x, a = x+19, x
8585
return
8686
}
87+
88+
func fooWithUnderscores(x int) (int, int) {
89+
a, b := x, 0
90+
if cond() {
91+
a, _ = b, a
92+
} else {
93+
_, b = b, a
94+
}
95+
return a, b
96+
}

ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/stmts2.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,9 @@ func test14(ch chan int) int {
2626
}
2727
return 1
2828
}
29+
30+
func test13b() int {
31+
x, _ := gen()
32+
var y, _ = gen()
33+
return x + y
34+
}

ql/test/query-tests/RedundantCode/DeadStoreOfLocal/DeadStoreOfLocal.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@
2727
| testdata.go:488:3:488:3 | assignment to x | This definition of x is never used. |
2828
| testdata.go:542:3:542:3 | assignment to x | This definition of x is never used. |
2929
| testdata.go:580:4:580:4 | assignment to x | This definition of x is never used. |
30+
| testdata.go:629:3:629:4 | assignment to v1 | This definition of v1 is never used. |

ql/test/query-tests/RedundantCode/DeadStoreOfLocal/testdata.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,4 +610,26 @@ func _() {
610610
_ = x
611611
}
612612

613+
func _(v1, v2 int32) (int32, int32) {
614+
if v1 > v2 {
615+
v1, _ = v2, v1
616+
}
617+
return v1, v2
618+
}
619+
620+
func _(v1, v2 int32) (int32, int32) {
621+
if v1 > v2 {
622+
_, v1 = v2, v1
623+
}
624+
return v1, v2
625+
}
626+
627+
func _(v1, v2 int32) (int32, int32) {
628+
if v1 > v2 {
629+
v1, _ = v2, v1
630+
}
631+
v1, v2 = 0, 0
632+
return v1, v2
633+
}
634+
613635
func anyFunctionMightPanic()

0 commit comments

Comments
 (0)