Skip to content

Commit

Permalink
Merge pull request #303 from correctcomputation/typedefs
Browse files Browse the repository at this point in the history
Adds support for typedefs
  • Loading branch information
Aaron Eline authored Dec 9, 2020
2 parents f2e3d1c + c81d7e2 commit eeaf25a
Show file tree
Hide file tree
Showing 17 changed files with 390 additions and 25 deletions.
36 changes: 33 additions & 3 deletions clang/include/clang/3C/ConstraintVariables.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class ConstraintVariable {
// to be used inside an itype
virtual std::string mkString(const EnvironmentMap &E, bool EmitName = true,
bool ForItype = false,
bool EmitPointee = false) const = 0;
bool EmitPointee = false, bool UnmaskTypedef = false) const = 0;

// Debug printing of the constraint variable.
virtual void print(llvm::raw_ostream &O) const = 0;
Expand Down Expand Up @@ -181,6 +181,17 @@ bool isAValidPVConstraint(const ConstraintVariable *C);
class PointerVariableConstraint;
class FunctionVariableConstraint;

// We need to store the level inside the type AST at which the first
// typedef occurs. This allows us to stop rewriting once we hit the
// first typedef. (All subsequent typedefs will not be rewritten, as
// rewriting will stop)
struct InternalTypedefInfo {
bool hasTypedef;
int typedefLevel;
std::string typedefName;
};


// Represents an individual constraint on a pointer variable.
// This could contain a reference to a FunctionVariableConstraint
// in the case of a function pointer declaration.
Expand Down Expand Up @@ -261,6 +272,18 @@ class PointerVariableConstraint : public ConstraintVariable {
// pointers.
bool IsZeroWidthArray;

// Was this variable a checked pointer in the input program?
// This is important for two reasons: (1) externs that are checked should be
// kept that way during solving, (2) nothing that was originally checked
// should be modified during rewriting.
bool OriginallyChecked;

bool IsTypedef = false;
TypedefNameDecl* TDT;
std::string typedefString;
// Does the type internally contain a typedef, and if so: at what level and what is it's name?
struct InternalTypedefInfo typedeflevelinfo;

public:
// Constructor for when we know a CVars and a type string.
PointerVariableConstraint(CAtoms V, std::string T, std::string Name,
Expand All @@ -278,6 +301,9 @@ class PointerVariableConstraint : public ConstraintVariable {
// Check if any of the pointers is either a sized or unsized arr.
bool hasSomeSizedArr() const;

bool isTypedef(void);
void setTypedef(TypedefNameDecl *TypedefType, std::string);

// Is an itype present for this constraint? If yes,
// what is the text of that itype?
bool hasItype() const override { return ItypeStr.size() > 0; }
Expand Down Expand Up @@ -335,7 +361,9 @@ class PointerVariableConstraint : public ConstraintVariable {

std::string mkString(const EnvironmentMap &E, bool EmitName = true,
bool ForItype = false,
bool EmitPointee = false) const override;
bool EmitPointee = false,
bool UnmaskTypedef = false)
const override;

FunctionVariableConstraint *getFV() const { return FV; }

Expand Down Expand Up @@ -448,7 +476,9 @@ class FunctionVariableConstraint : public ConstraintVariable {

std::string mkString(const EnvironmentMap &E, bool EmitName = true,
bool ForItype = false,
bool EmitPointee = false) const override;
bool EmitPointee = false,
bool UnmaskTypedef = false)
const override;
void print(llvm::raw_ostream &O) const override;
void dump() const override { print(llvm::errs()); }
void dumpJson(llvm::raw_ostream &O) const override;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/3C/DeclRewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class DeclRewriter {
void doDeclRewrite(SourceRange &SR, DeclReplacement *N);

void rewriteFunctionDecl(FunctionDeclReplacement *N);
void rewriteTypedefDecl(TypedefDeclReplacement *TDT, RSet &ToRewrite);
void getDeclsOnSameLine(DeclReplacement *N, std::vector<Decl *> &Decls);
bool isSingleDeclaration(DeclReplacement *N);
bool areDeclarationsOnSameLine(DeclReplacement *N1, DeclReplacement *N2);
Expand Down
18 changes: 18 additions & 0 deletions clang/include/clang/3C/ProgramInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,30 @@ class ProgramInfo : public ProgramVariableAdder {
void constrainWildIfMacro(ConstraintVariable *CV, SourceLocation Location,
PersistentSourceLoc *PSL = nullptr);


void unifyIfTypedef(const clang::Type*, clang::ASTContext&,
clang::DeclaratorDecl*, PVConstraint*);

std::pair<CVarSet, bool> lookupTypedef(PersistentSourceLoc PSL);

bool seenTypedef(PersistentSourceLoc PSL);

void addTypedef(PersistentSourceLoc PSL, bool ShouldCheck);

private:
// List of constraint variables for declarations, indexed by their location in
// the source. This information persists across invocations of the constraint
// analysis from compilation unit to compilation unit.
VariableMap Variables;

// Map storing constraint information for typedefed types
// The set contains all the constraint variables that also use this tyepdef
// TODO this could be replaced w/ a signle CVar
// The bool informs the rewriter whether or not this typedef should be
// rewritten. It will be false for typedefs we don't support rewritting,
// such as typedefs that are pointers to anonymous structs
std::map<PersistentSourceLoc, std::pair<CVarSet, bool>> typedefVars;

// Map with the same purpose as the Variables map, this stores constraint
// variables for non-declaration expressions.
std::map<PersistentSourceLoc, CVarSet> ExprConstraintVars;
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/3C/RewriteUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class DeclReplacement {
}

// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
enum DRKind { DRK_VarDecl, DRK_ParmVarDecl, DRK_FunctionDecl, DRK_FieldDecl };
enum DRKind { DRK_VarDecl, DRK_ParmVarDecl, DRK_FunctionDecl, DRK_FieldDecl, DRK_TypedefDecl };

DRKind getKind() const { return Kind; }

Expand Down Expand Up @@ -73,6 +73,8 @@ typedef DeclReplacementTempl<ParmVarDecl, DeclReplacement::DRK_ParmVarDecl>
ParmVarDeclReplacement;
typedef DeclReplacementTempl<FieldDecl, DeclReplacement::DRK_FieldDecl>
FieldDeclReplacement;
typedef DeclReplacementTempl<TypedefDecl, DeclReplacement::DRK_TypedefDecl>
TypedefDeclReplacement;

class FunctionDeclReplacement
: public DeclReplacementTempl<FunctionDecl,
Expand Down
65 changes: 64 additions & 1 deletion clang/lib/3C/ConstraintBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// visitors create constraints based on the AST of the program.
//===----------------------------------------------------------------------===//

#include <algorithm>
#include "clang/3C/ConstraintBuilder.h"
#include "clang/3C/3CGlobalOptions.h"
#include "clang/3C/ArrayBoundsInferenceConsumer.h"
Expand Down Expand Up @@ -398,6 +399,52 @@ class FunctionVisitor : public RecursiveASTVisitor<FunctionVisitor> {
TypeVarInfo &TVInfo;
};

class PtrToStructDef : public RecursiveASTVisitor<PtrToStructDef> {
public:
explicit PtrToStructDef(TypedefDecl *TDT) : TDT(TDT) {}

bool VisitPointerType(clang::PointerType *PT) {
ispointer = true;
return true;
}

bool VisitRecordType(RecordType *RT) {
auto decl = RT->getDecl();
auto declRange = decl->getSourceRange();
auto typedefRange = TDT->getSourceRange();
bool declContained = (typedefRange.getBegin() < declRange.getBegin())
&& !(typedefRange.getEnd() < typedefRange.getEnd());
if (declContained) {
structDefInTD = true;
return false;
} else {
return true;
}
}

bool VisitFunctionProtoType(FunctionProtoType *FPT) {
ispointer = true;
return true;
}

bool getResult(void) {
return structDefInTD;
}

static bool containsPtrToStructDef(TypedefDecl *TDT) {
PtrToStructDef traverser(TDT);
traverser.TraverseDecl(TDT);
return traverser.getResult();
}

private:
TypedefDecl* TDT = nullptr;
bool ispointer = false;
bool structDefInTD = false;

};


// This class visits a global declaration, generating constraints
// for functions, variables, types, etc. that are visited
class ConstraintGenVisitor : public RecursiveASTVisitor<ConstraintGenVisitor> {
Expand All @@ -406,6 +453,20 @@ class ConstraintGenVisitor : public RecursiveASTVisitor<ConstraintGenVisitor> {
TypeVarInfo &TVI)
: Context(Context), Info(I), CB(Info, Context), TVInfo(TVI) {}

bool VisitTypedefDecl(TypedefDecl* TD) {
CVarSet empty;
auto PSL = PersistentSourceLoc::mkPSL(TD, *Context);
// If we haven't seen this typedef before, initialize it's entry in the
// typedef map. If we have seen it before, and we need to preserve the
// constraints contained within it
if (!Info.seenTypedef(PSL))
// Add this typedef to the program info, if it contains a ptr to
// an anonymous struct we mark as not being rewritable
Info.addTypedef(PSL, !PtrToStructDef::containsPtrToStructDef(TD));

return true;
}

bool VisitVarDecl(VarDecl *G) {

if (G->hasGlobalStorage() && isPtrOrArrayType(G->getType())) {
Expand Down Expand Up @@ -485,7 +546,8 @@ class ConstraintGenVisitor : public RecursiveASTVisitor<ConstraintGenVisitor> {
class VariableAdderVisitor : public RecursiveASTVisitor<VariableAdderVisitor> {
public:
explicit VariableAdderVisitor(ASTContext *Context, ProgramVariableAdder &VA)
: Context(Context), VarAdder(VA) {}
: Context(Context), VarAdder(VA) {}


bool VisitVarDecl(VarDecl *D) {
FullSourceLoc FL = Context->getFullLoc(D->getBeginLoc());
Expand Down Expand Up @@ -542,6 +604,7 @@ void ConstraintBuilderConsumer::HandleTranslationUnit(ASTContext &C) {
errs() << "Analyzing\n";
}


VariableAdderVisitor VAV = VariableAdderVisitor(&C, Info);
TypeVarVisitor TV = TypeVarVisitor(&C, Info);
ConstraintResolver CSResolver(Info, &C);
Expand Down
86 changes: 81 additions & 5 deletions clang/lib/3C/ConstraintVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <sstream>

using namespace clang;
// Macro for boolean implication
#define IMPLIES(a,b) ((a) ? (b) : true)

static llvm::cl::OptionCategory OptimizationCategory("Optimization category");
static llvm::cl::opt<bool>
Expand Down Expand Up @@ -112,8 +114,58 @@ PointerVariableConstraint::PointerVariableConstraint(

PointerVariableConstraint::PointerVariableConstraint(DeclaratorDecl *D,
ProgramInfo &I,
const ASTContext &C)
: PointerVariableConstraint(D->getType(), D, D->getName(), I, C) {}
const ASTContext &C) :
PointerVariableConstraint(D->getType(), D, D->getName(),
I, C) { }


// Simple recursive visitor for determining if a type contains a typedef
// entrypoint is find()
class TypedefLevelFinder : public RecursiveASTVisitor<TypedefLevelFinder> {
public:

static struct InternalTypedefInfo find(const QualType &QT) {
TypedefLevelFinder TLF;
QualType tosearch;
// If the type is currently a typedef, desugar that.
// This is so we can see if the type _contains_ a typedef
if (auto TDT = dyn_cast<TypedefType>(QT))
tosearch = TDT->desugar();
else
tosearch = QT;
TLF.TraverseType(tosearch);
// If we found a typedef the we need to have filled out the name field
assert(IMPLIES(TLF.hastypedef, TLF.TDname != ""));
struct InternalTypedefInfo info =
{ TLF.hastypedef, TLF.typedeflevel, TLF.TDname };
return info;
}

bool VisitTypedefType(TypedefType *TT) {
hastypedef = true;
auto TDT = TT->getDecl();
TDname = TDT->getNameAsString();
return false;
}

bool VisitPointerType(PointerType *PT) {
typedeflevel++;
return true;
}

bool VisitArrayType(ArrayType *AT) {
typedeflevel++;
return true;
}


private:
int typedeflevel = 0;
std::string TDname = "";
bool hastypedef = false;

};


PointerVariableConstraint::PointerVariableConstraint(
const QualType &QT, DeclaratorDecl *D, std::string N, ProgramInfo &I,
Expand All @@ -125,6 +177,7 @@ PointerVariableConstraint::PointerVariableConstraint(
QualType QTy = QT;
const Type *Ty = QTy.getTypePtr();
auto &CS = I.getConstraints();
typedeflevelinfo = TypedefLevelFinder::find(QT);
// If the type is a decayed type, then maybe this is the result of
// decaying an array to a pointer. If the original type is some
// kind of array type, we want to use that instead.
Expand Down Expand Up @@ -551,12 +604,29 @@ void PointerVariableConstraint::addArrayAnnotations(
assert(CheckedArrs.empty());
}


bool PointerVariableConstraint::isTypedef(void) {
return IsTypedef;
}

void PointerVariableConstraint::setTypedef(TypedefNameDecl* T, std::string s) {
IsTypedef = true;
TDT = T;
typedefString = s;
}


// Mesh resolved constraints with the PointerVariableConstraints set of
// variables and potentially nested function pointer declaration. Produces a
// string that can be replaced in the source code.

std::string PointerVariableConstraint::mkString(const EnvironmentMap &E,
bool EmitName, bool ForItype,
bool EmitPointee) const {
bool EmitPointee, bool UnmaskTypedef) const {
if (IsTypedef && !UnmaskTypedef) {
return typedefString + (EmitName && getName() != RETVAR ? (" " + getName()) : " ");
}

std::ostringstream Ss;
// This deque will store all the type strings that need to pushed
// to the end of the type string. This is typically things like
Expand All @@ -581,11 +651,14 @@ std::string PointerVariableConstraint::mkString(const EnvironmentMap &E,
uint32_t TypeIdx = 0;

auto It = Vars.begin();
auto i = 0;
// Skip over first pointer level if only emitting pointee string.
// This is needed when inserting type arguments.
if (EmitPointee)
++It;
for (; It != Vars.end(); ++It) {
// Interate through the vars(), but if we have an internal typedef, then stop once you reach the
// typedef's level
for (; It != Vars.end() && IMPLIES(typedeflevelinfo.hasTypedef, i < typedeflevelinfo.typedefLevel); ++It, i++) {
const auto &V = *It;
ConstAtom *C = nullptr;
if (ConstAtom *CA = dyn_cast<ConstAtom>(V)) {
Expand Down Expand Up @@ -708,6 +781,9 @@ std::string PointerVariableConstraint::mkString(const EnvironmentMap &E,
// type.
if (FV) {
Ss << FV->mkString(E);
} else if (typedeflevelinfo.hasTypedef) {
auto name = typedeflevelinfo.typedefName;
Ss << name;
} else {
Ss << BaseType;
}
Expand Down Expand Up @@ -1227,7 +1303,7 @@ bool FunctionVariableConstraint::solutionEqualTo(

std::string FunctionVariableConstraint::mkString(const EnvironmentMap &E,
bool EmitName, bool ForItype,
bool EmitPointee) const {
bool EmitPointee, bool UnmaskTypedef) const {
std::string Ret = "";
Ret = ReturnVar->mkString(E);
Ret = Ret + "(";
Expand Down
Loading

0 comments on commit eeaf25a

Please sign in to comment.