Skip to content

Commit

Permalink
Merge pull request #169 from Fraunhofer-AISEC/julian/fix-leaking-types
Browse files Browse the repository at this point in the history
Fix leaking types
  • Loading branch information
konradweiss authored Jul 16, 2020
2 parents ff3dd6d + bf31210 commit 01aa624
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ public class TranslationConfiguration {
*/
public final List<String> includeBlacklist;

/**
* Switch off cleaning up TypeManager memory after analysis.
*
* <p>Set this to {@code true} only for testing.
*/
public boolean disableCleanup = false;

/** should the code of a node be shown as parameter in the node * */
public final boolean codeInNodes;

Expand Down Expand Up @@ -104,7 +111,8 @@ private TranslationConfiguration(
List<String> includeWhitelist,
List<String> includeBlacklist,
List<Pass> passes,
boolean codeInNodes) {
boolean codeInNodes,
boolean disableCleanup) {
this.symbols = symbols;
this.sourceLocations = sourceLocations;
this.topLevel = topLevel;
Expand All @@ -117,6 +125,7 @@ private TranslationConfiguration(
this.passes = passes != null ? passes : new ArrayList<>();
// Make sure to init this AFTER sourceLocations has been set
this.codeInNodes = codeInNodes;
this.disableCleanup = disableCleanup;
}

public static Builder builder() {
Expand Down Expand Up @@ -166,6 +175,7 @@ public static class Builder {
private List<String> includeBlacklist = new ArrayList<>();
private List<Pass> passes = new ArrayList<>();
private boolean codeInNodes = true;
private boolean disableCleanup = false;

public Builder symbols(Map<String, String> symbols) {
this.symbols = symbols;
Expand Down Expand Up @@ -256,6 +266,11 @@ public Builder includeWhitelist(String includeFile) {
return this;
}

public Builder disableCleanup() {
this.disableCleanup = true;
return this;
}

/**
* Adds the specified file to the include blacklist. Relative and absolute paths are supported.
*
Expand Down Expand Up @@ -326,7 +341,8 @@ public TranslationConfiguration build() {
includeWhitelist,
includeBlacklist,
passes,
codeInNodes);
codeInNodes,
disableCleanup);
}
}
}
16 changes: 9 additions & 7 deletions src/main/java/de/fraunhofer/aisec/cpg/TranslationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,17 @@ public CompletableFuture<TranslationResult> analyze() {
throw new CompletionException(ex);
} finally {
outerBench.stop();
log.debug("Cleaning up {} Passes", passesNeedCleanup.size());
passesNeedCleanup.forEach(Pass::cleanup);
if (!this.config.disableCleanup) {
log.debug("Cleaning up {} Passes", passesNeedCleanup.size());
passesNeedCleanup.forEach(Pass::cleanup);

if (frontendsNeedCleanup != null) {
log.debug("Cleaning up {} Frontends", frontendsNeedCleanup.size());
frontendsNeedCleanup.forEach(LanguageFrontend::cleanup);
}
if (frontendsNeedCleanup != null) {
log.debug("Cleaning up {} Frontends", frontendsNeedCleanup.size());
frontendsNeedCleanup.forEach(LanguageFrontend::cleanup);
}

TypeManager.getInstance().cleanup();
TypeManager.getInstance().cleanup();
}
}
return result;
});
Expand Down
16 changes: 12 additions & 4 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/TypeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -49,14 +51,16 @@ public class TypeManager {
List.of("byte", "short", "int", "long", "float", "double", "boolean", "char");
private static final Pattern funPointerPattern =
Pattern.compile("\\(?\\*(?<alias>[^()]+)\\)?\\(.*\\)");
private static TypeManager INSTANCE = new TypeManager();
@NonNull private static TypeManager INSTANCE = new TypeManager();

public enum Language {
JAVA,
CXX
}

private Map<String, RecordDeclaration> typeToRecord = new HashMap<>();
@NonNull private Map<String, RecordDeclaration> typeToRecord = new HashMap<>();

@NonNull
private Map<Type, List<Type>> typeState =
new HashMap<>(); // Stores all the unique types ObjectType as Key and Reference-/PointerTypes
// as Values
Expand All @@ -69,6 +73,7 @@ public static void reset() {
INSTANCE = new TypeManager();
}

@NonNull
public Map<Type, List<Type>> getTypeState() {
return typeState;
}
Expand Down Expand Up @@ -97,7 +102,7 @@ public static TypeManager getInstance() {
return INSTANCE;
}

public void setLanguageFrontend(LanguageFrontend frontend) {
public void setLanguageFrontend(@NonNull LanguageFrontend frontend) {
this.frontend = frontend;
}

Expand Down Expand Up @@ -178,7 +183,8 @@ private Set<Type> unwrapTypes(Collection<Type> types, WrapState wrapState) {
}
}

public Optional<Type> getCommonType(Collection<Type> types) {
@NonNull
public Optional<Type> getCommonType(@NonNull Collection<Type> types) {

boolean sameType =
types.stream().map(t -> t.getClass().getCanonicalName()).collect(Collectors.toSet()).size()
Expand Down Expand Up @@ -282,6 +288,7 @@ private Set<Ancestor> getAncestors(RecordDeclaration record, int depth) {
return ancestors;
}

@NonNull
public Language getLanguage() {
if (frontend instanceof JavaLanguageFrontend) {
return Language.JAVA;
Expand All @@ -290,6 +297,7 @@ public Language getLanguage() {
}
}

@Nullable
public LanguageFrontend getFrontend() {
return frontend;
}
Expand Down
74 changes: 46 additions & 28 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/type/TypeParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,15 @@
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
* Class responsible for parsing the type definition and create the same Type as described by the
* type string, but complying to the CPG TypeSystem
*/
public class TypeParser {

private TypeParser() {
throw new IllegalStateException("Do not instantiate the TypeParser");
}

public static final String UNKNOWN_TYPE_STRING = "UNKNOWN";
private static final List<String> primitives =
List.of("byte", "short", "int", "long", "float", "double", "boolean", "char");
Expand All @@ -63,6 +61,10 @@ private TypeParser() {
private static final String ELABORATED_TYPE_UNION = "union";
private static final String ELABORATED_TYPE_ENUM = "enum";

private TypeParser() {
throw new IllegalStateException("Do not instantiate the TypeParser");
}

public static void reset() {
TypeParser.languageSupplier = () -> TypeManager.getInstance().getLanguage();
}
Expand Down Expand Up @@ -227,14 +229,15 @@ private static int findMatching(char openBracket, char closeBracket, String stri
* @param type separated type string
* @return true if function pointer structure is found in typeString, false if not
*/
private static Matcher isFunctionPointer(List<String> type) {
@Nullable
private static Matcher getFunctionPtrMatcher(@NonNull List<String> type) {

StringBuilder typeStringBuilder = new StringBuilder();
for (String typePart : type) {
typeStringBuilder.append(typePart);
}

String typeString = typeStringBuilder.toString().strip();
String typeString = typeStringBuilder.toString().trim();

Matcher matcher = functionPtrRegex.matcher(typeString);
if (matcher.find()) {
Expand All @@ -244,7 +247,7 @@ private static Matcher isFunctionPointer(List<String> type) {
}

private static boolean isIncompleteType(String typeName) {
return typeName.strip().equals("void");
return typeName.trim().equals("void");
}

private static boolean isUnknownType(String typeName) {
Expand All @@ -258,7 +261,8 @@ private static boolean isUnknownType(String typeName) {
* @param type typeString
* @return typeString without spaces in the generic Expression
*/
private static String fixGenerics(String type) {
@NonNull
private static String fixGenerics(@NonNull String type) {
StringBuilder out = new StringBuilder();
int bracketCount = 0;
int iterator = 0;
Expand Down Expand Up @@ -300,7 +304,7 @@ private static String fixGenerics(String type) {
}

private static void processBlockUntilLastSplit(
String type, int lastSplit, int newPosition, List<String> typeBlocks) {
@NonNull String type, int lastSplit, int newPosition, @NonNull List<String> typeBlocks) {
String substr = type.substring(lastSplit, newPosition);
if (substr.length() != 0) {
typeBlocks.add(substr);
Expand All @@ -313,15 +317,16 @@ private static void processBlockUntilLastSplit(
* @param type string with the entire type definition
* @return list of strings in which every piece of type information is one element of the list
*/
public static List<String> separate(String type) {
@NonNull
public static List<String> separate(@NonNull String type) {

// Remove :: CPP operator, use . instead
type = type.replace("::", ".");
type = type.split("=")[0];

// Guarantee that there is no arbitraty number of whitespces
// Guarantee that there is no arbitrary number of whitespaces
String[] typeSubpart = type.split(" ");
type = String.join(" ", typeSubpart).strip();
type = String.join(" ", typeSubpart).trim();

List<String> typeBlocks = new ArrayList<>();

Expand Down Expand Up @@ -391,13 +396,13 @@ public static List<String> separate(String type) {

private static List<Type> getParameterList(String parameterList) {
if (parameterList.startsWith("(") && parameterList.endsWith(")")) {
parameterList = parameterList.strip().substring(1, parameterList.strip().length() - 1);
parameterList = parameterList.trim().substring(1, parameterList.trim().length() - 1);
}
List<Type> parameters = new ArrayList<>();
String[] parametersSplit = parameterList.split(",");
for (String parameter : parametersSplit) {
if (parameter.length() > 0) {
parameters.add(createFrom(parameter.strip(), true));
parameters.add(createFrom(parameter.trim(), true));
}
}

Expand All @@ -410,7 +415,7 @@ private static List<Type> getGenerics(String typeName) {
List<Type> genericList = new ArrayList<>();
String[] parametersSplit = generics.split(",");
for (String parameter : parametersSplit) {
genericList.add(createFrom(parameter.strip(), true));
genericList.add(createFrom(parameter.trim(), true));
}

return genericList;
Expand Down Expand Up @@ -457,12 +462,13 @@ private static Type performBracketContentAction(Type finalType, String part) {
* Makes sure to apply Expressions containing brackets that change the binding of operators e.g.
* () can change the binding order of operators
*
* @param finalType Modifications are applyed to this type which is the result of the preceding
* @param finalType Modifications are applied to this type which is the result of the preceding
* type calculations
* @param bracketExpressions List of Strings containing bracket expressions
* @return modified finalType performing the resolution of the bracket expressions
*/
private static Type resolveBracketExpression(Type finalType, List<String> bracketExpressions) {
private static Type resolveBracketExpression(
@NonNull Type finalType, @NonNull List<String> bracketExpressions) {
for (String bracketExpression : bracketExpressions) {
List<String> splitExpression =
separate(bracketExpression.substring(1, bracketExpression.length() - 1));
Expand All @@ -475,13 +481,13 @@ private static Type resolveBracketExpression(Type finalType, List<String> bracke
}

/**
* Help function that removes access modifier from the typeString
* Helper function that removes access modifier from the typeString.
*
* @param type provided typeString
* @return typeString without access modifier
*/
private static String clear(String type) {
return type.replaceAll("public|private|protected", "").strip();
private static String clear(@NonNull String type) {
return type.replaceAll("public|private|protected", "").trim();
}

/**
Expand All @@ -491,7 +497,7 @@ private static String clear(String type) {
* @param stringList
* @return
*/
private static boolean isPrimitiveType(List<String> stringList) {
private static boolean isPrimitiveType(@NonNull List<String> stringList) {
for (String s : stringList) {
if (primitives.contains(s)) {
return true;
Expand All @@ -507,7 +513,8 @@ private static boolean isPrimitiveType(List<String> stringList) {
* @param typeBlocks
* @return separated words of compound types are joined into one string
*/
private static List<String> joinPrimitive(List<String> typeBlocks) {
@NonNull
private static List<String> joinPrimitive(@NonNull List<String> typeBlocks) {
List<String> joinedTypeBlocks = new ArrayList<>();
StringBuilder primitiveType = new StringBuilder();
boolean foundPrimitive = false;
Expand Down Expand Up @@ -543,7 +550,8 @@ private static List<String> joinPrimitive(List<String> typeBlocks) {
* @param newRoot root the chain is swapped with
* @return oldchain but root replaced with newRoot
*/
public static Type reWrapType(Type oldChain, Type newRoot) {
@NonNull
public static Type reWrapType(@NonNull Type oldChain, @NonNull Type newRoot) {
if (oldChain.isFirstOrderType()) {
newRoot.setTypeOrigin(oldChain.getTypeOrigin());
}
Expand Down Expand Up @@ -578,12 +586,16 @@ public static Type reWrapType(Type oldChain, Type newRoot) {
* @param string the string representation of the type
* @return the type
*/
public static Type createIgnoringAlias(String string) {
@NonNull
public static Type createIgnoringAlias(@NonNull String string) {
return createFrom(string, false);
}

@NonNull
private static Type postTypeParsing(
List<String> subPart, Type finalType, List<String> bracketExpressions) {
@NonNull List<String> subPart,
@NonNull Type finalType,
@NonNull List<String> bracketExpressions) {
for (String part : subPart) {
if (part.equals("*")) {
// Creates a Pointer to the finalType
Expand Down Expand Up @@ -661,11 +673,12 @@ private static ObjectType.Modifier determineModifier(
* @param resolveAlias should replace with original type in typedefs
* @return new type representing the type string
*/
public static Type createFrom(String type, boolean resolveAlias) {
@NonNull
public static Type createFrom(@NonNull String type, boolean resolveAlias) {
// Check if Problems during Parsing
if (type.contains("?")
|| type.contains("org.eclipse.cdt.internal.core.dom.parser.ProblemType@")
|| type.length() == 0) {
|| type.trim().length() == 0) {
return UnknownType.getUnknownType();
}

Expand Down Expand Up @@ -712,14 +725,19 @@ public static Type createFrom(String type, boolean resolveAlias) {
Type.Qualifier qualifier = calcQualifier(qualifierList, null);

// Once all preceding known keywords (if any) are handled the next word must be the TypeName
if (counter >= typeBlocks.size()) {
// Note that "const auto ..." will end here with typeName="const" as auto is not supported.
return UnknownType.getUnknownType();
}
assert counter < typeBlocks.size();
String typeName = typeBlocks.get(counter);
counter++;

Type finalType;
TypeManager typeManager = TypeManager.getInstance();

// Check if type is FunctionPointer
Matcher funcptr = isFunctionPointer(typeBlocks.subList(counter, typeBlocks.size()));
Matcher funcptr = getFunctionPtrMatcher(typeBlocks.subList(counter, typeBlocks.size()));

if (funcptr != null) {
Type returnType = createFrom(typeName, false);
Expand Down
Loading

0 comments on commit 01aa624

Please sign in to comment.