Skip to content

Commit a32b023

Browse files
DidierBessetWohops
authored andcommitted
SONARJAVA-1538 - CFG SE : nested statements in try catch end up with wrong CFG
1 parent a5684b9 commit a32b023

5 files changed

Lines changed: 139 additions & 18 deletions

File tree

its/ruling/src/test/resources/jdk6/squid-S2259.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
361,
5353
],
5454
'jdk6:java/net/SocksSocketImpl.java':[
55+
398,
5556
714,
5657
],
5758
'jdk6:java/net/URI.java':[
@@ -64,10 +65,6 @@
6465
'jdk6:java/security/CodeSource.java':[
6566
531,
6667
],
67-
'jdk6:java/security/Signature.java':[
68-
976,
69-
1015,
70-
],
7168
'jdk6:java/security/UnresolvedPermission.java':[
7269
558,
7370
],

its/ruling/src/test/resources/jdk6/squid-S2583.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@
3030
'jdk6:java/math/BigDecimal.java':[
3131
3660,
3232
],
33-
'jdk6:java/net/ServerSocket.java':[
34-
470,
35-
475,
36-
],
3733
'jdk6:java/nio/ByteBuffer.java':[
3834
1104,
3935
1131,

java-frontend/src/main/java/org/sonar/java/cfg/CFG.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464

6565
import javax.annotation.CheckForNull;
6666
import javax.annotation.Nullable;
67+
6768
import java.util.ArrayList;
6869
import java.util.Deque;
6970
import java.util.LinkedHashSet;
@@ -254,6 +255,10 @@ private void prune() {
254255
block.id = id;
255256
id += 1;
256257
}
258+
inactiveBlocks.removeAll(blocks);
259+
if (!inactiveBlocks.isEmpty()) {
260+
prune();
261+
}
257262
}
258263
}
259264

@@ -765,21 +770,13 @@ private void buildTryStatement(TryStatementTree tryStatementTree) {
765770
}
766771
currentBlock = beforeFinally;
767772
build(tryStatementTree.block());
768-
if(currentBlock.exitBlock != null && currentBlock.exitBlock.isFinallyBlock) {
769-
for (Block catchBlock : catches) {
770-
currentBlock.exitBlock.addSuccessor(catchBlock);
771-
}
772-
} else {
773-
for (Block catchBlock : catches) {
774-
currentBlock.addSuccessor(catchBlock);
775-
}
776-
}
773+
linkToCatchBlocks(beforeFinally, catches);
777774
build((List<? extends Tree>) tryStatementTree.resources());
778775
currentBlock = createBlock(currentBlock);
779776
currentBlock.elements.add(tryStatementTree);
780777
if (finallyBlockTree != null) {
781778
exitBlocks.pop();
782-
if(catches.isEmpty()) {
779+
if (catches.isEmpty()) {
783780
currentBlock.addExitSuccessor(finallyOrEndBlock);
784781
}
785782
}
@@ -788,6 +785,16 @@ private void buildTryStatement(TryStatementTree tryStatementTree) {
788785
}
789786
}
790787

788+
protected void linkToCatchBlocks(Block block, List<Block> catches) {
789+
Block blockForSuccessor = block;
790+
if (block.exitBlock != null && block.exitBlock.isFinallyBlock) {
791+
blockForSuccessor = block.exitBlock;
792+
}
793+
for (Block catchBlock : catches) {
794+
blockForSuccessor.addSuccessor(catchBlock);
795+
}
796+
}
797+
791798
private void buildThrowStatement(ThrowStatementTree throwStatementTree) {
792799
// FIXME this won't work if it is intended to be caught by a try statement.
793800
currentBlock = createUnconditionalJump(throwStatementTree, exitBlock());

java-frontend/src/test/files/se/ConditionAlwaysTrueOrFalseCheck.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,3 +1567,41 @@ void testAfterAddAssignment(int y) {
15671567
}
15681568
}
15691569
}
1570+
1571+
public class TryCatchCFG {
1572+
1573+
private Object monitor;
1574+
private boolean shutdown;
1575+
1576+
private void doSomething() {
1577+
}
1578+
1579+
void fun(boolean abort) {
1580+
while (!abort) {
1581+
try {
1582+
synchronized (monitor) {
1583+
long delay = 1000L;
1584+
while (!shutdown && delay > 0) {
1585+
long now = System.currentTimeMillis();
1586+
monitor.wait(delay);
1587+
delay -= (System.currentTimeMillis() - now);
1588+
}
1589+
if (shutdown) {
1590+
abort = true;
1591+
}
1592+
doSomething(); // may throw an exception
1593+
}
1594+
1595+
} catch (RuntimeException e) {
1596+
if (abort) {
1597+
System.out.println("Abort");
1598+
} else {
1599+
System.out.println("Retry");
1600+
}
1601+
} catch (InterruptedException e) {
1602+
Thread.currentThread().interrupt();
1603+
}
1604+
}
1605+
}
1606+
}
1607+

java-frontend/src/test/java/org/sonar/java/cfg/CFGTest.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,4 +1302,87 @@ public void method_reference() throws Exception {
13021302
).successors(0));
13031303
cfgChecker.check(cfg);
13041304
}
1305+
1306+
@Test
1307+
public void try_statement_with_CFG_blocks() {
1308+
CFG cfg = buildCFG(
1309+
" private void f(boolean action) {\n" +
1310+
" try {\n" +
1311+
" if (action) {" +
1312+
" performAction();" +
1313+
" }" +
1314+
" doSomething();" +
1315+
"} catch(Exception e) { foo();} bar(); }");
1316+
CFGChecker cfgChecker = checker(
1317+
block(
1318+
element(Tree.Kind.TRY_STATEMENT)).successors(3, 5),
1319+
block(
1320+
element(Tree.Kind.IDENTIFIER, "action")).terminator(Kind.IF_STATEMENT).successors(2, 4),
1321+
block(
1322+
element(Tree.Kind.IDENTIFIER, "performAction"),
1323+
element(Kind.METHOD_INVOCATION)).successors(2),
1324+
block(
1325+
element(Tree.Kind.IDENTIFIER, "foo"),
1326+
element(Kind.METHOD_INVOCATION)).successors(1),
1327+
block(
1328+
element(Tree.Kind.IDENTIFIER, "doSomething"),
1329+
element(Kind.METHOD_INVOCATION)).successors(1, 3),
1330+
block(
1331+
element(Tree.Kind.IDENTIFIER, "bar"),
1332+
element(Kind.METHOD_INVOCATION)).successors(0));
1333+
cfgChecker.check(cfg);
1334+
cfg = buildCFG(
1335+
" private void f(boolean action) {\n" +
1336+
" try {\n" +
1337+
" doSomething();" +
1338+
" if (action) {" +
1339+
" performAction();" +
1340+
" }" +
1341+
"} catch(Exception e) { foo();} bar(); }");
1342+
cfgChecker = checker(
1343+
block(
1344+
element(Tree.Kind.TRY_STATEMENT)).successors(3, 5),
1345+
block(
1346+
element(Tree.Kind.IDENTIFIER, "doSomething"),
1347+
element(Kind.METHOD_INVOCATION),
1348+
element(Tree.Kind.IDENTIFIER, "action")).terminator(Kind.IF_STATEMENT).successors(2, 4),
1349+
block(
1350+
element(Tree.Kind.IDENTIFIER, "performAction"),
1351+
element(Kind.METHOD_INVOCATION)).successors(2),
1352+
block(
1353+
element(Tree.Kind.IDENTIFIER, "foo"),
1354+
element(Kind.METHOD_INVOCATION)).successors(1),
1355+
new BlockChecker(1, 3),
1356+
block(
1357+
element(Tree.Kind.IDENTIFIER, "bar"),
1358+
element(Kind.METHOD_INVOCATION)).successors(0));
1359+
cfgChecker.check(cfg);
1360+
cfg = buildCFG(
1361+
" private void f(boolean action) {\n" +
1362+
" try {\n" +
1363+
" if (action) {" +
1364+
" performAction();" +
1365+
" }" +
1366+
" doSomething();" +
1367+
"} finally { foo();} bar(); }");
1368+
cfgChecker = checker(
1369+
block(
1370+
element(Tree.Kind.TRY_STATEMENT)).successors(2, 5),
1371+
block(
1372+
element(Tree.Kind.IDENTIFIER, "action")).terminator(Kind.IF_STATEMENT).successors(3, 4),
1373+
block(
1374+
element(Tree.Kind.IDENTIFIER, "performAction"),
1375+
element(Kind.METHOD_INVOCATION)).successors(3),
1376+
block(
1377+
element(Tree.Kind.IDENTIFIER, "doSomething"),
1378+
element(Kind.METHOD_INVOCATION)).successors(2),
1379+
block(
1380+
element(Tree.Kind.IDENTIFIER, "foo"),
1381+
element(Kind.METHOD_INVOCATION)).successors(0, 1),
1382+
block(
1383+
element(Tree.Kind.IDENTIFIER, "bar"),
1384+
element(Kind.METHOD_INVOCATION)).successors(0));
1385+
cfgChecker.check(cfg);
1386+
}
1387+
13051388
}

0 commit comments

Comments
 (0)