Skip to content

Commit

Permalink
c2cpg: fixed handling of macros in binary expressions (#2347)
Browse files Browse the repository at this point in the history
* Test branch for issue 2335

* Fix for IASTBinaryExpression.
  • Loading branch information
max-leuthaeuser authored Mar 7, 2023
1 parent b435f09 commit 3c427af
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -413,12 +413,9 @@ trait AstCreatorHelper { this: AstCreator =>

protected def astForNode(node: IASTNode): Ast = {
node match {
case id: IASTIdExpression if id.getName.isInstanceOf[CPPASTQualifiedName] =>
astForQualifiedName(id.getName.asInstanceOf[CPPASTQualifiedName])
case id: IASTIdExpression => astForIdentifier(id)
case expr: IASTExpression => astForExpression(expr)
case name: IASTName => astForIdentifier(name)
case decl: IASTDeclSpecifier => astForIdentifier(decl)
case expr: IASTExpression => astForExpression(expr)
case l: IASTInitializerList => astForInitializerList(l)
case c: ICPPASTConstructorInitializer => astForCPPASTConstructorInitializer(c)
case d: ICASTDesignatedInitializer => astForCASTDesignatedInitializer(d)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import io.shiftleft.codepropertygraph.generated.nodes.{AstNodeNew, ExpressionNew
import io.joern.x2cpg.Ast
import org.apache.commons.lang.StringUtils
import org.eclipse.cdt.core.dom.ast.{IASTMacroExpansionLocation, IASTNode, IASTPreprocessorMacroDefinition}
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression
import org.eclipse.cdt.core.dom.ast.IASTFileLocation
import org.eclipse.cdt.internal.core.model.ASTStringUtil
import org.eclipse.cdt.internal.core.parser.scanner.MacroArgumentExtractor

Expand Down Expand Up @@ -149,11 +151,17 @@ trait MacroHandler { this: AstCreator =>
private def isExpandedFromMacro(node: IASTNode): Boolean = expandedFromMacro(node).nonEmpty

private def expandedFromMacro(node: IASTNode): Option[IASTMacroExpansionLocation] = {
val locations = node.getNodeLocations
if (locations.nonEmpty) {
node.getNodeLocations.headOption.collect { case x: IASTMacroExpansionLocation => x }
} else {
None
val locations = node.getNodeLocations.toList
val locationsSorted = node match {
// For binary expressions the expansion locations may occur in any order.
// We manually sort them here to ignore this.
// TODO: This may also happen with other expressions that allow for multiple sub elements.
case _: IASTBinaryExpression => locations.sortBy(_.isInstanceOf[IASTMacroExpansionLocation])
case _ => locations
}
locationsSorted match {
case (head: IASTMacroExpansionLocation) :: _ => Option(head)
case _ => None
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import io.joern.dataflowengineoss.language._
import io.shiftleft.codepropertygraph.generated.DispatchTypes
import io.shiftleft.codepropertygraph.generated.Operators
import io.shiftleft.codepropertygraph.generated.nodes.Block
import io.shiftleft.codepropertygraph.generated.nodes.Call
import io.shiftleft.codepropertygraph.generated.nodes.Identifier
import io.shiftleft.semanticcpg.language._

class MacroHandlingTests extends CCodeToCpgSuite {
Expand All @@ -14,9 +16,9 @@ class MacroHandlingTests extends CCodeToCpgSuite {
val cpg = code("""
|#define A_MACRO(x,c) (x = 10 + c)
|int foo() {
|int *y;
|A_MACRO(*y, 2);
|return 10 * y;
| int *y;
| A_MACRO(*y, 2);
| return 10 * y;
|}
""".stripMargin)

Expand Down Expand Up @@ -224,7 +226,30 @@ class MacroHandlingTests extends CCodeToCpgSuite {
"should not result in malformed CFGs when expanding a nested macro with block" in {
cpg.all.collectAll[Block].l.count(b => b.cfgOut.size > 1) shouldBe 0
}
}

"MacroHandlingTests8" should {
val cpg = code("""
|#define FLAG_A 1
|
|int func(int x) {
| if(x & FLAG_A) {
| return 0;
| } else if (FLAG_A & x) {
| return 1;
| }
|}""".stripMargin)

"should expand the macro on both sides of binary operators" in {
cpg.call.name(Operators.and).code.l shouldBe List("x & FLAG_A", "FLAG_A & x")
val List(andCall1, andCall2) = cpg.call.name(Operators.and).l
val List(andCall1Arg1: Identifier, andCall1Arg2: Call) = andCall1.argument.l
andCall1Arg1.name shouldBe "x"
andCall1Arg2.name shouldBe "FLAG_A"
val List(andCall2Arg1: Call, andCall2Arg2: Identifier) = andCall2.argument.l
andCall2Arg1.name shouldBe "FLAG_A"
andCall2Arg2.name shouldBe "x"
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class StructTypeTests extends CCodeToCpgSuite {
val List(argBInit) = bInitCall.argument.l
argBInit.code shouldBe "SIZE - 1"
val List(subtractionCall) = bInitCall.ast.isCall.nameExact(Operators.subtraction).l
subtractionCall.code shouldBe "5 - 1"
subtractionCall.code shouldBe "SIZE - 1"

cInitCall.code shouldBe "c[10]"
val List(argCInit) = cInitCall.argument.l
Expand Down

0 comments on commit 3c427af

Please sign in to comment.