diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt index 6fce3256e8..7373388204 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt @@ -41,6 +41,7 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression import de.fraunhofer.aisec.cpg.graph.types.* import de.fraunhofer.aisec.cpg.graph.unknownType import de.fraunhofer.aisec.cpg.isDerivedFrom +import de.fraunhofer.aisec.cpg.wrapState import java.io.File import kotlin.reflect.KClass import kotlin.reflect.full.primaryConstructor @@ -214,8 +215,13 @@ abstract class Language> : Node() { } /** - * This function checks, if [type] is derived from [superType]. Optionally, the nodes that hold - * the respective type can be supplied as [hint] and [superHint]. + * This function checks, if [type] is derived from [superType]. Note, this also takes the + * [WrapState] of the type into account, which means that pointer types of derived types will + * not match with a non-pointer type of its base type. But, if both are pointer types, they will + * match. + * + * Optionally, the nodes that hold the respective type can be supplied as [hint] and + * [superHint]. */ open fun isDerivedFrom( type: Type, @@ -223,12 +229,24 @@ abstract class Language> : Node() { hint: HasType?, superHint: HasType? ): Boolean { + // We can take a shortcut if it is the same type + if (type == superType) { + return true + } + + // We can also take a shortcut: if they are not of the same subclass, they will never + // match + if (type::class != superType::class) { + return false + } + // Retrieve all ancestor types of our type (more concretely of the root type) val root = type.root val superTypes = root.ancestors.map { it.type } - // Check, if super type (or its root) is in the list - return superType.root in superTypes + // Check, if super type (or its root) is in the list. Also, the wrap state needs to be the + // same + return superType.root in superTypes && type.wrapState == superType.wrapState } /** diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageTest.kt new file mode 100644 index 0000000000..ba4571e5d5 --- /dev/null +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageTest.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, Fraunhofer AISEC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $$$$$$\ $$$$$$$\ $$$$$$\ + * $$ __$$\ $$ __$$\ $$ __$$\ + * $$ / \__|$$ | $$ |$$ / \__| + * $$ | $$$$$$$ |$$ |$$$$\ + * $$ | $$ ____/ $$ |\_$$ | + * $$ | $$\ $$ | $$ | $$ | + * \$$$$$ |$$ | \$$$$$ | + * \______/ \__| \______/ + * + */ +package de.fraunhofer.aisec.cpg.frontends + +import de.fraunhofer.aisec.cpg.graph.newRecordDeclaration +import de.fraunhofer.aisec.cpg.graph.objectType +import de.fraunhofer.aisec.cpg.graph.pointer +import de.fraunhofer.aisec.cpg.isDerivedFrom +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class LanguageTest { + + @Test + fun testLanguageDerived() { + with(TestLanguageFrontend()) { + val baseType = objectType("baseType") + + val myTypeRecord = newRecordDeclaration("myType", "class") + myTypeRecord.superClasses = mutableListOf(baseType) + val myType = myTypeRecord.toType() + + val pointerBaseType = baseType.pointer() + val pointerMyType = myType.pointer() + + // pointer-type and non-pointer types -> will not match in any case + var matches = pointerMyType.isDerivedFrom(myType) + assertFalse(matches) + + // the same type will always match + matches = pointerMyType.isDerivedFrom(pointerMyType) + assertTrue(matches) + + // a pointer to the derived type will match a pointer to its base type + matches = pointerMyType.isDerivedFrom(pointerBaseType) + assertTrue(matches) + + // non-pointer types as well + matches = myType.isDerivedFrom(baseType) + assertTrue(matches) + } + } +} diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CLanguage.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CLanguage.kt index a031c07d1c..ab4b3fbd5c 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CLanguage.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CLanguage.kt @@ -161,4 +161,24 @@ open class CLanguage : ) return resolveWithImplicitCast(call, initialInvocationCandidates) } + + override fun isDerivedFrom( + type: Type, + superType: Type, + hint: HasType?, + superHint: HasType? + ): Boolean { + val match = super.isDerivedFrom(type, superType, hint, superHint) + if (match) { + return true + } + + // As a special rule, a non-nested pointer and array of the same type are completely + // interchangeable + if (type.root == superType.root && type is PointerType && superType is PointerType) { + return true + } + + return false + } } diff --git a/cpg-language-cxx/src/test/resources/variables_extended/cpp/scope_variables.cpp b/cpg-language-cxx/src/test/resources/variables_extended/cpp/scope_variables.cpp index 2546c166a4..a8cca2b5ba 100644 --- a/cpg-language-cxx/src/test/resources/variables_extended/cpp/scope_variables.cpp +++ b/cpg-language-cxx/src/test/resources/variables_extended/cpp/scope_variables.cpp @@ -47,7 +47,7 @@ class ScopeVariables{ try { throw new error(); - } catch (const error& varName) { + } catch (error* varName) { printLog("func2_catch_varName", varName); }; ScopeVariables scopeVariables;