From 03161bb68b5bda658a0eb3596c8f90b7073622db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20Leuth=C3=A4user?= <1417198+max-leuthaeuser@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:40:30 +0200 Subject: [PATCH] [c2cpg] Do not strip volatile from type names (#4784) --- .../c2cpg/astcreation/AstCreatorHelper.scala | 63 +++++++++++++------ .../passes/types/TypeNodePassTests.scala | 20 ++++++ 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstCreatorHelper.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstCreatorHelper.scala index e074518a73fb..68f90084e009 100644 --- a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstCreatorHelper.scala +++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstCreatorHelper.scala @@ -107,11 +107,10 @@ trait AstCreatorHelper(implicit withSchemaValidation: ValidationMode) { this: As } // Sadly, there is no predefined List / Enum of this within Eclipse CDT: - private val reservedTypeKeywords: List[String] = + private val ReservedTypeKeywords: List[String] = List( "const", "static", - "volatile", "restrict", "extern", "typedef", @@ -125,11 +124,13 @@ trait AstCreatorHelper(implicit withSchemaValidation: ValidationMode) { this: As "class" ) + private val KeepTypeKeywords: List[String] = List("unsigned", "volatile") + protected def cleanType(rawType: String, stripKeywords: Boolean = true): String = { if (rawType == Defines.Any) return rawType val tpe = if (stripKeywords) { - reservedTypeKeywords.foldLeft(rawType) { (cur, repl) => + ReservedTypeKeywords.foldLeft(rawType) { (cur, repl) => if (cur.contains(s"$repl ")) { dereferenceTypeFullName(cur.replace(s"$repl ", "")) } else { @@ -140,28 +141,54 @@ trait AstCreatorHelper(implicit withSchemaValidation: ValidationMode) { this: As rawType } StringUtils.normalizeSpace(tpe) match { - case "" => Defines.Any - case t if t.contains("org.eclipse.cdt.internal.core.dom.parser.ProblemType") => Defines.Any + case "" => + Defines.Any + case t if t.contains("org.eclipse.cdt.internal.core.dom.parser.ProblemType") => + Defines.Any case t if t.contains(" ->") && t.contains("}::") => - fixQualifiedName(t.substring(t.indexOf("}::") + 3, t.indexOf(" ->"))) + replaceWhitespaceAfterTypeKeyword(fixQualifiedName(t.substring(t.indexOf("}::") + 3, t.indexOf(" ->")))) case t if t.contains(" ->") => - fixQualifiedName(t.substring(0, t.indexOf(" ->"))) + replaceWhitespaceAfterTypeKeyword(fixQualifiedName(t.substring(0, t.indexOf(" ->")))) case t if t.contains("( ") => - fixQualifiedName(t.substring(0, t.indexOf("( "))) - case t if t.contains("?") => Defines.Any - case t if t.contains("#") => Defines.Any - case t if t.contains("::{") || t.contains("}::") => Defines.Any + replaceWhitespaceAfterTypeKeyword(fixQualifiedName(t.substring(0, t.indexOf("( ")))) + case t if t.contains("?") => + Defines.Any + case t if t.contains("#") => + Defines.Any + case t if t.contains("::{") || t.contains("}::") => + Defines.Any case t if t.contains("{") && t.contains("}") => val beforeBracket = t.substring(0, t.indexOf("{")) val afterBracket = t.substring(t.indexOf("}") + 1) val anonType = s"${uniqueName("type", "", "")._1}$beforeBracket$afterBracket" - anonType.replace(" ", "") - case t if t.startsWith("[") && t.endsWith("]") => Defines.Any - case t if t.contains(Defines.QualifiedNameSeparator) => fixQualifiedName(t) - case t if t.startsWith("unsigned ") => "unsigned " + t.substring(9).replace(" ", "") - case t if t.contains("[") && t.contains("]") => t.replace(" ", "") - case t if t.contains("*") => t.replace(" ", "") - case someType => someType + replaceWhitespaceAfterTypeKeyword(anonType) + case t if t.startsWith("[") && t.endsWith("]") => + Defines.Any + case t if t.contains(Defines.QualifiedNameSeparator) => + replaceWhitespaceAfterTypeKeyword(fixQualifiedName(t)) + case t if KeepTypeKeywords.exists(k => t.startsWith(s"$k ")) => + replaceWhitespaceAfterTypeKeyword(t) + case t if t.contains("[") && t.contains("]") => + replaceWhitespaceAfterTypeKeyword(t) + case t if t.contains("*") => + replaceWhitespaceAfterTypeKeyword(t) + case someType => + someType + } + } + + private def replaceWhitespaceAfterTypeKeyword(tpe: String): String = { + if (KeepTypeKeywords.exists(k => tpe.startsWith(s"$k "))) { + KeepTypeKeywords.foldLeft(tpe) { (cur, repl) => + val prefix = s"$repl " + if (cur.startsWith(prefix)) { + prefix + cur.substring(prefix.length).replace(" ", "") + } else { + cur + } + } + } else { + tpe.replace(" ", "") } } diff --git a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/types/TypeNodePassTests.scala b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/types/TypeNodePassTests.scala index 2795aa9a80ca..43f3457b662a 100644 --- a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/types/TypeNodePassTests.scala +++ b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/types/TypeNodePassTests.scala @@ -194,6 +194,26 @@ class TypeNodePassTests extends C2CpgSuite { } } } + + "be correct for volatile types" in { + val cpg = code(""" + |void func(void) { + | static volatile int **ipp; + | static int *ip; + | static volatile int i = 0; + | + | ipp = &ip; + | ipp = (int**) &ip; + | *ipp = &i; + | if (*ip != 0) {} + |}""".stripMargin) + cpg.identifier.nameExact("ipp").typeFullName.distinct.l shouldBe List("volatile int**") + cpg.identifier.nameExact("ip").typeFullName.distinct.l shouldBe List("int*") + cpg.identifier.nameExact("i").typeFullName.distinct.l shouldBe List("volatile int") + cpg.local.nameExact("ipp").typeFullName.l shouldBe List("volatile int**") + cpg.local.nameExact("ip").typeFullName.l shouldBe List("int*") + cpg.local.nameExact("i").typeFullName.l shouldBe List("volatile int") + } } }