Skip to content
This repository was archived by the owner on Oct 15, 2020. It is now read-only.

Commit 9dc2098

Browse files
authored
Include JumpTarget nodes in the CFG (#216)
* Include `JumpTarget` nodes in the CFG and adjust tests * Fix typos
1 parent 3feb6c7 commit 9dc2098

File tree

2 files changed

+60
-50
lines changed

2 files changed

+60
-50
lines changed

src/main/scala/io/shiftleft/fuzzyc2cpg/passes/CfgCreationPass.scala

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,10 @@ class CfgCreatorForMethod(entryNode: nodes.Method) {
6969
private var markerStack = List[Option[nodes.CfgNode]]()
7070
private case class FringeElement(node: nodes.CfgNode, cfgEdgeType: CfgEdgeType)
7171
private var labeledNodes = Map[String, nodes.CfgNode]()
72-
private var pendingGotoLabels = List[String]()
73-
private var pendingCaseLabels = List[String]()
7472
private var returns = List[nodes.CfgNode]()
7573
private val breakStack = new LayeredStack[nodes.CfgNode]()
7674
private val continueStack = new LayeredStack[nodes.CfgNode]()
77-
private val caseStack = new LayeredStack[(nodes.CfgNode, Boolean)]()
75+
private val caseStack = new LayeredStack[nodes.CfgNode]()
7876
private var gotos = List[(nodes.CfgNode, String)]()
7977

8078
def run(): Iterator[DiffGraph] = {
@@ -166,10 +164,16 @@ class CfgCreatorForMethod(entryNode: nodes.Method) {
166164
private def handleJumpTarget(n: nodes.JumpTarget): Unit = {
167165
val labelName = n.name
168166
if (labelName.startsWith("case") || labelName.startsWith("default")) {
169-
pendingCaseLabels = labelName :: pendingCaseLabels
167+
// Under normal conditions this is always true.
168+
// But if the parser missed a switch statement, caseStack
169+
// might be empty.
170+
if (caseStack.numberOfLayers > 0) {
171+
caseStack.store(n)
172+
}
170173
} else {
171-
pendingGotoLabels = labelName :: pendingGotoLabels
174+
labeledNodes = labeledNodes + (labelName -> n)
172175
}
176+
extendCfg(n)
173177
}
174178

175179
private def handleConditionalExpression(call: nodes.Call): Unit = {
@@ -212,7 +216,7 @@ class CfgCreatorForMethod(entryNode: nodes.Method) {
212216
extendCfg(node)
213217
// Under normal conditions this is always true.
214218
// But if the parser missed a loop or switch statement, breakStack
215-
// might by empty.
219+
// might be empty.
216220
if (breakStack.numberOfLayers > 0) {
217221
fringe = Nil
218222
breakStack.store(node)
@@ -223,7 +227,7 @@ class CfgCreatorForMethod(entryNode: nodes.Method) {
223227
extendCfg(node)
224228
// Under normal conditions this is always true.
225229
// But if the parser missed a loop statement, continueStack
226-
// might by empty.
230+
// might be empty.
227231
if (continueStack.numberOfLayers > 0) {
228232
fringe = Nil
229233
continueStack.store(node)
@@ -366,15 +370,13 @@ class CfgCreatorForMethod(entryNode: nodes.Method) {
366370
node.start.whenTrue.foreach(postOrderLeftToRightExpand)
367371
val switchFringe = fringe
368372

369-
caseStack.getTopElements.foreach {
370-
case (caseNode, _) =>
371-
fringe = conditionFringe
372-
extendCfg(caseNode)
373+
caseStack.getTopElements.foreach { caseNode =>
374+
fringe = conditionFringe
375+
extendCfg(caseNode)
373376
}
374377

375-
val hasDefaultCase = caseStack.getTopElements.exists {
376-
case (_, isDefault) =>
377-
isDefault
378+
val hasDefaultCase = caseStack.getTopElements.exists { caseNode =>
379+
caseNode.asInstanceOf[nodes.JumpTarget].name == "default"
378380
}
379381

380382
fringe = switchFringe.add(breakStack.getTopElements, AlwaysEdge)
@@ -435,25 +437,6 @@ class CfgCreatorForMethod(entryNode: nodes.Method) {
435437
markerStack = List.fill(leadingNoneLength)(Some(dstNode)) ++ markerStack
436438
.drop(leadingNoneLength)
437439
}
438-
439-
if (pendingGotoLabels.nonEmpty) {
440-
pendingGotoLabels.foreach { label =>
441-
labeledNodes = labeledNodes + (label -> dstNode)
442-
}
443-
pendingGotoLabels = List()
444-
}
445-
446-
// TODO at the moment we discard the case labels
447-
if (pendingCaseLabels.nonEmpty) {
448-
// Under normal conditions this is always true.
449-
// But if the parser missed a switch statement, caseStack
450-
// might by empty.
451-
if (caseStack.numberOfLayers > 0) {
452-
val containsDefaultLabel = pendingCaseLabels.contains("default")
453-
caseStack.store((dstNode, containsDefaultLabel))
454-
}
455-
pendingCaseLabels = List()
456-
}
457440
}
458441

459442
}

src/test/scala/io/shiftleft/fuzzyc2cpg/passes/CfgCreationPassTests.scala

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,14 @@ class CfgCreationPassTests extends WordSpec with Matchers {
183183
succOf("y") shouldBe expected(("x", TrueEdge), ("z", FalseEdge))
184184
succOf("z") shouldBe expected(("x", TrueEdge), ("RET", FalseEdge))
185185
}
186+
187+
"be correct for do-while-loop with empty body" in
188+
new CfgFixture("do { } while(x > 1);") {
189+
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
190+
succOf("1") shouldBe expected(("x > 1", AlwaysEdge))
191+
succOf("x > 1") shouldBe expected(("x", TrueEdge), ("RET", FalseEdge))
192+
}
193+
186194
}
187195

188196
"Cfg for for-loop" should {
@@ -300,79 +308,98 @@ class CfgCreationPassTests extends WordSpec with Matchers {
300308
new CfgFixture("x; goto l1; y; l1:") {
301309
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
302310
succOf("x") shouldBe expected(("goto l1;", AlwaysEdge))
303-
succOf("goto l1;") shouldBe expected(("RET", AlwaysEdge))
304-
succOf("y") shouldBe expected(("RET", AlwaysEdge))
311+
succOf("goto l1;") shouldBe expected(("l1:", AlwaysEdge))
312+
succOf("l1:") shouldBe expected(("RET", AlwaysEdge))
313+
succOf("y") shouldBe expected(("l1:", AlwaysEdge))
305314
}
306315

307316
"be correct for multiple labels" in
308317
new CfgFixture("x;goto l1; l2: y; l1:") {
309318
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
310319
succOf("x") shouldBe expected(("goto l1;", AlwaysEdge))
311-
succOf("goto l1;") shouldBe expected(("RET", AlwaysEdge))
312-
succOf("y") shouldBe expected(("RET", AlwaysEdge))
320+
succOf("goto l1;") shouldBe expected(("l1:", AlwaysEdge))
321+
succOf("y") shouldBe expected(("l1:", AlwaysEdge))
322+
succOf("l1:") shouldBe expected(("RET", AlwaysEdge))
313323
}
314324

315325
"be correct for multiple labels on same spot" in
316326
new CfgFixture("x;goto l2;y;l1:l2:") {
317327
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
318328
succOf("x") shouldBe expected(("goto l2;", AlwaysEdge))
319-
succOf("goto l2;") shouldBe expected(("RET", AlwaysEdge))
320-
succOf("y") shouldBe expected(("RET", AlwaysEdge))
329+
succOf("goto l2;") shouldBe expected(("l2:", AlwaysEdge))
330+
succOf("y") shouldBe expected(("l1:", AlwaysEdge))
331+
succOf("l1:") shouldBe expected(("l2:", AlwaysEdge))
332+
succOf("l2:") shouldBe expected(("RET", AlwaysEdge))
321333
}
322334
}
323335

324336
"Cfg for switch" should {
325337
"be correct with one case" in
326338
new CfgFixture("switch (x) { case 1: y; }") {
327339
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
328-
succOf("x") shouldBe expected(("y", CaseEdge), ("RET", CaseEdge))
340+
succOf("x") shouldBe expected(("case 1:", CaseEdge), ("RET", CaseEdge))
341+
succOf("case 1:") shouldBe expected(("y", AlwaysEdge))
329342
succOf("y") shouldBe expected(("RET", AlwaysEdge))
330343
}
331344

332345
"be correct with multiple cases" in
333346
new CfgFixture("switch (x) { case 1: y; case 2: z;}") {
334347
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
335-
succOf("x") shouldBe expected(("y", CaseEdge), ("z", CaseEdge), ("RET", CaseEdge))
336-
succOf("y") shouldBe expected(("z", AlwaysEdge))
348+
succOf("x") shouldBe expected(("case 1:", CaseEdge), ("case 2:", CaseEdge), ("RET", CaseEdge))
349+
succOf("case 1:") shouldBe expected(("y", AlwaysEdge))
350+
succOf("y") shouldBe expected(("case 2:", AlwaysEdge))
351+
succOf("case 2:") shouldBe expected(("z", AlwaysEdge))
337352
succOf("z") shouldBe expected(("RET", AlwaysEdge))
338353
}
339354

340355
"be correct with multiple cases on same spot" in
341356
new CfgFixture("switch (x) { case 1: case 2: y; }") {
342357
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
343-
succOf("x") shouldBe expected(("y", CaseEdge), ("RET", CaseEdge))
358+
succOf("x") shouldBe expected(("case 1:", CaseEdge), ("case 2:", CaseEdge), ("RET", CaseEdge))
359+
succOf("case 1:") shouldBe expected(("case 2:", AlwaysEdge))
344360
succOf("y") shouldBe expected(("RET", AlwaysEdge))
345361
}
346362

347363
"be correct with multiple cases and multiple cases on same spot" in
348364
new CfgFixture("switch (x) { case 1: case 2: y; case 3: z;}") {
349365
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
350-
succOf("x") shouldBe expected(("y", CaseEdge), ("z", CaseEdge), ("RET", CaseEdge))
351-
succOf("y") shouldBe expected(("z", AlwaysEdge))
366+
succOf("x") shouldBe expected(("case 1:", CaseEdge),
367+
("case 2:", CaseEdge),
368+
("case 3:", CaseEdge),
369+
("RET", CaseEdge))
370+
succOf("case 1:") shouldBe expected(("case 2:", AlwaysEdge))
371+
succOf("case 2:") shouldBe expected(("y", AlwaysEdge))
372+
succOf("y") shouldBe expected(("case 3:", AlwaysEdge))
373+
succOf("case 3:") shouldBe expected(("z", AlwaysEdge))
352374
succOf("z") shouldBe expected(("RET", AlwaysEdge))
353375
}
354376

355377
"be correct with default case" in
356378
new CfgFixture("switch (x) { default: y; }") {
357379
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
358-
succOf("x") shouldBe expected(("y", CaseEdge))
380+
succOf("x") shouldBe expected(("default:", CaseEdge))
381+
succOf("default:") shouldBe expected(("y", AlwaysEdge))
359382
succOf("y") shouldBe expected(("RET", AlwaysEdge))
360383
}
361384

362385
"be correct for case and default combined" in
363386
new CfgFixture("switch (x) { case 1: y; break; default: z;}") {
364387
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
365-
succOf("x") shouldBe expected(("y", CaseEdge), ("z", CaseEdge))
388+
succOf("x") shouldBe expected(("case 1:", CaseEdge), ("default:", CaseEdge))
389+
succOf("case 1:") shouldBe expected(("y", AlwaysEdge))
366390
succOf("y") shouldBe expected(("break;", AlwaysEdge))
367391
succOf("break;") shouldBe expected(("RET", AlwaysEdge))
392+
succOf("default:") shouldBe expected(("z", AlwaysEdge))
368393
succOf("z") shouldBe expected(("RET", AlwaysEdge))
369394
}
370395

371396
"be correct for nested switch" in
372-
new CfgFixture("switch (x) { default: switch(y) { default: z; } }") {
397+
new CfgFixture("switch (x) { case 1: switch(y) { default: z; } }") {
373398
succOf("func ()") shouldBe expected(("x", AlwaysEdge))
374-
succOf("x") shouldBe expected(("y", CaseEdge))
375-
succOf("y") shouldBe expected(("z", CaseEdge))
399+
succOf("x") shouldBe expected(("case 1:", CaseEdge), ("RET", CaseEdge))
400+
succOf("case 1:") shouldBe expected(("y", AlwaysEdge))
401+
succOf("y") shouldBe expected(("default:", CaseEdge))
402+
succOf("default:") shouldBe expected(("z", AlwaysEdge))
376403
succOf("z") shouldBe expected(("RET", AlwaysEdge))
377404
}
378405
}

0 commit comments

Comments
 (0)