Skip to content

Commit cc67aa9

Browse files
MachiryMandeep Singh Grang
authored and
Mandeep Singh Grang
committed
[checked-c-convert] Minor fixes to the checked-c-convert (#679)
Cherry-picked from commit ba778c3 - Add knowledge of calloc and realloc as allocator functions. - Add initializers for variables retyped as checked pointers. - Add initializers for structure variables containing members that have been retyped as checked pointers. - Avoid deletion of variable arguments.
1 parent 1d4cd65 commit cc67aa9

16 files changed

+373
-78
lines changed

clang/test/CheckedCRewriter/bounds_interface.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77

88

99
extern void bar(int *q : itype(_Ptr<int>));
10-
//CHECK: extern void bar(int* q : itype(_Ptr<int>));
10+
//CHECK: extern void bar(int *q : itype(_Ptr<int>));
1111

1212
extern void bar2(int *q : itype(_Ptr<int>), int *z : itype(_Ptr<int>));
13-
//CHECK: extern void bar2(int* q : itype(_Ptr<int>), int* z : itype(_Ptr<int>));
13+
//CHECK: extern void bar2(int *q : itype(_Ptr<int>), int *z : itype(_Ptr<int>));
1414

1515
extern int *baz(void) : itype(_Ptr<int>);
1616
//CHECK: extern int *baz(void) : itype(_Ptr<int>);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Tests for Checked C rewriter tool.
2+
//
3+
// Tests checked-c-convert tool for any regressions.
4+
//
5+
// RUN: checked-c-convert %s -- | FileCheck -match-full-lines %s
6+
//
7+
8+
#include <stdlib_checked.h>
9+
10+
int main() {
11+
12+
char *ptr1 = NULL;
13+
14+
ptr1 = (char *) calloc(1, sizeof(char));
15+
16+
return 0;
17+
}
18+
//CHECK: _Ptr<char> ptr1 = NULL;

clang/tools/checked-c-convert/CheckedCConvert.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ cl::opt<bool> enablePropThruIType( "enable-itypeprop",
7878
cl::init(false),
7979
cl::cat(ConvertCategory));
8080

81+
cl::opt<bool> considerAllocUnsafe( "alloc-unsafe",
82+
cl::desc("Consider the allocators (i.e., malloc/calloc) as unsafe."),
83+
cl::init(false),
84+
cl::cat(ConvertCategory));
85+
8186
static cl::opt<std::string>
8287
BaseDir("base-dir",
8388
cl::desc("Base directory for the code we're translating"),

clang/tools/checked-c-convert/ConstraintBuilder.cpp

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -268,27 +268,32 @@ class FunctionVisitor : public RecursiveASTVisitor<FunctionVisitor> {
268268
// to a NamedDecl?
269269
FunctionDecl *calleeDecl =
270270
dyn_cast<FunctionDecl>(CA->getCalleeDecl());
271-
if (calleeDecl && calleeDecl->getName() == "malloc") {
272-
// It's a call to malloc. What about the parameter to the call?
273-
if (CA->getNumArgs() > 0) {
274-
UnaryExprOrTypeTraitExpr *arg =
275-
dyn_cast<UnaryExprOrTypeTraitExpr>(CA->getArg(0));
276-
if (arg && arg->isArgumentType()) {
277-
// Check that the argument is a sizeof.
278-
if (arg->getKind() == UETT_SizeOf) {
279-
QualType argTy = arg->getArgumentType();
280-
// argTy should be made a pointer, then compared for
281-
// equality to lhsType and rhsTy.
282-
QualType argPTy = Context->getPointerType(argTy);
283-
284-
if (Info.checkStructuralEquality(V, RHSConstraints, argPTy, lhsType) &&
285-
Info.checkStructuralEquality(V, RHSConstraints, argPTy, rhsTy)) {
286-
rulesFired = true;
287-
// At present, I don't think we need to add an
288-
// implication based constraint since this rule only
289-
// fires if there is a cast from a call to malloc.
290-
// Since malloc is an external, there's no point in
291-
// adding constraints to it.
271+
if (calleeDecl) {
272+
// this is an allocator, should we treat it as safe?
273+
if (!considerAllocUnsafe && isFunctionAllocator(calleeDecl->getName()))
274+
rulesFired = true;
275+
else if (calleeDecl->getName().equals("malloc")) {
276+
// It's a call to malloc. What about the parameter to the call?
277+
if (CA->getNumArgs() > 0) {
278+
UnaryExprOrTypeTraitExpr *arg =
279+
dyn_cast<UnaryExprOrTypeTraitExpr>(CA->getArg(0));
280+
if (arg && arg->isArgumentType()) {
281+
// Check that the argument is a sizeof.
282+
if (arg->getKind() == UETT_SizeOf) {
283+
QualType argTy = arg->getArgumentType();
284+
// argTy should be made a pointer, then compared for
285+
// equality to lhsType and rhsTy.
286+
QualType argPTy = Context->getPointerType(argTy);
287+
288+
if (Info.checkStructuralEquality(V, RHSConstraints, argPTy, lhsType) &&
289+
Info.checkStructuralEquality(V, RHSConstraints, argPTy, rhsTy)) {
290+
rulesFired = true;
291+
// At present, I don't think we need to add an
292+
// implication based constraint since this rule
293+
// only fires if there is a cast from a call to malloc.
294+
// Since malloc is an external, there's no point in
295+
// adding constraints to it.
296+
}
292297
}
293298
}
294299
}

clang/tools/checked-c-convert/ConstraintVariables.cpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,15 @@
1616

1717
using namespace clang;
1818

19-
// Helper method to print a Type in a way that can be represented in the source.
20-
static
21-
std::string
22-
tyToStr(const Type *T) {
23-
QualType QT(T, 0);
24-
25-
return QT.getAsString();
26-
}
27-
2819
PointerVariableConstraint::PointerVariableConstraint(DeclaratorDecl *D,
2920
ConstraintKey &K, Constraints &CS, const ASTContext &C) :
3021
PointerVariableConstraint(D->getType(), K, D, D->getName(), CS, C) { }
3122

3223
PointerVariableConstraint::PointerVariableConstraint(const QualType &QT, ConstraintKey &K,
33-
DeclaratorDecl *D, std::string N, Constraints &CS, const ASTContext &C) :
24+
DeclaratorDecl *D, std::string N, Constraints &CS,
25+
const ASTContext &C, bool partOfFunc) :
3426
ConstraintVariable(ConstraintVariable::PointerVariable,
35-
tyToStr(QT.getTypePtr()),N),FV(nullptr)
27+
tyToStr(QT.getTypePtr()),N), partOFFuncPrototype(partOfFunc), FV(nullptr)
3628
{
3729
QualType QTy = QT;
3830
const Type *Ty = QTy.getTypePtr();
@@ -490,7 +482,7 @@ FunctionVariableConstraint::FunctionVariableConstraint(const Type *Ty,
490482
}
491483

492484
std::set<ConstraintVariable*> C;
493-
C.insert(new PVConstraint(QT, K, tmpD, paramName, CS, Ctx));
485+
C.insert(new PVConstraint(QT, K, tmpD, paramName, CS, Ctx, true));
494486
paramVars.push_back(C);
495487
}
496488

@@ -513,7 +505,7 @@ FunctionVariableConstraint::FunctionVariableConstraint(const Type *Ty,
513505
// as a type, then we will need the types for all the parameters and the
514506
// return values
515507

516-
returnVars.insert(new PVConstraint(returnType, K, D, "", CS, Ctx));
508+
returnVars.insert(new PVConstraint(returnType, K, D, "", CS, Ctx, true));
517509
for ( const auto &V : returnVars) {
518510
if (PVConstraint *PVC = dyn_cast<PVConstraint>(V)) {
519511
if (PVC->getFV())

clang/tools/checked-c-convert/ConstraintVariables.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,15 @@ class PointerVariableConstraint : public ConstraintVariable {
157157
// get the qualifier string (e.g., const, etc) for the provided constraint var (targetCvar)
158158
// into the provided string stream (ss)
159159
void getQualString(ConstraintKey targetCVar, std::ostringstream &ss);
160+
// flag to indicate that this constraint is a part of function prototype
161+
// e.g., Parameters or Return
162+
bool partOFFuncPrototype;
160163
public:
161164
// Constructor for when we know a CVars and a type string.
162165
PointerVariableConstraint(CVars V, std::string T, std::string Name,
163166
FunctionVariableConstraint *F, bool isArr, bool isItype, std::string is) :
164167
ConstraintVariable(PointerVariable, T, Name)
165-
,vars(V),FV(F),arrPresent(isArr), itypeStr(is) {}
168+
,vars(V),FV(F),arrPresent(isArr), itypeStr(is), partOFFuncPrototype(false) {}
166169

167170
bool getArrPresent() { return arrPresent; }
168171

@@ -179,7 +182,9 @@ class PointerVariableConstraint : public ConstraintVariable {
179182
// Constructor for when we only have a Type. Needs a string name
180183
// N for the name of the variable that this represents.
181184
PointerVariableConstraint(const clang::QualType &QT, ConstraintKey &K,
182-
clang::DeclaratorDecl *D, std::string N, Constraints &CS, const clang::ASTContext &C);
185+
clang::DeclaratorDecl *D, std::string N,
186+
Constraints &CS,
187+
const clang::ASTContext &C, bool partOfFunc = false);
183188

184189
const CVars &getCvars() const { return vars; }
185190

@@ -201,6 +206,8 @@ class PointerVariableConstraint : public ConstraintVariable {
201206
// get the highest type assigned to the cvars of this constraint variable
202207
ConstAtom *getHighestType(Constraints::EnvironmentMap &E);
203208

209+
bool isPartOfFunctionPrototype() const { return partOFFuncPrototype; }
210+
204211
bool isLt(const ConstraintVariable &other, ProgramInfo &P) const;
205212
bool isEq(const ConstraintVariable &other, ProgramInfo &P) const;
206213
bool isEmpty(void) const { return vars.size() == 0; }

clang/tools/checked-c-convert/PersistentSourceLoc.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,25 @@ PersistentSourceLoc::mkPSL(const Decl *D, ASTContext &C) {
2626
SL = C.getSourceManager().getSpellingLoc(PV->getLocation());
2727
else if (const VarDecl *V = dyn_cast<VarDecl>(D))
2828
SL = C.getSourceManager().getExpansionLoc(V->getLocation());
29-
29+
3030
return mkPSL(D->getSourceRange(), SL, C);
3131
}
3232

3333

3434
// Create a PersistentSourceLoc for a Stmt.
3535
PersistentSourceLoc
3636
PersistentSourceLoc::mkPSL(const Stmt *S, ASTContext &Context) {
37-
return mkPSL(S->getSourceRange(), S->getBeginLoc(), Context);
37+
return mkPSL(S->getSourceRange(),
38+
S->getBeginLoc(),
39+
Context);
3840
}
3941

4042
// Use the PresumedLoc infrastructure to get the absolute file name, expansion
4143
// line and column number for a SourceLocation and corresponding SourceRange
42-
PersistentSourceLoc
43-
PersistentSourceLoc::mkPSL(clang::SourceRange SR, SourceLocation SL, ASTContext &Context) {
44+
PersistentSourceLoc
45+
PersistentSourceLoc::mkPSL(clang::SourceRange SR,
46+
SourceLocation SL,
47+
ASTContext &Context) {
4448
SourceManager &SM = Context.getSourceManager();
4549
PresumedLoc PL = SM.getPresumedLoc(SL);
4650

clang/tools/checked-c-convert/PersistentSourceLoc.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,18 @@ class PersistentSourceLoc {
5555
void dump() const { print(llvm::errs()); }
5656

5757
static
58-
PersistentSourceLoc mkPSL(const clang::Decl *D, clang::ASTContext &Context);
58+
PersistentSourceLoc mkPSL(const clang::Decl *D, clang::ASTContext &Context);
5959

6060
static
61-
PersistentSourceLoc mkPSL(const clang::Stmt *S, clang::ASTContext &Context);
61+
PersistentSourceLoc mkPSL(const clang::Stmt *S, clang::ASTContext &Context);
6262

6363
private:
6464
// Create a PersistentSourceLoc based on absolute file path
6565
// from the given SourceRange and SourceLocation.
6666
static
67-
PersistentSourceLoc mkPSL(clang::SourceRange SR, clang::SourceLocation SL, clang::ASTContext &Context);
67+
PersistentSourceLoc mkPSL(clang::SourceRange SR,
68+
clang::SourceLocation SL,
69+
clang::ASTContext &Context);
6870
std::string fileName;
6971
uint32_t lineNo;
7072
uint32_t colNo;

clang/tools/checked-c-convert/ProgramInfo.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,7 @@ bool ProgramInfo::checkStructuralEquality(QualType D, QualType S) {
220220
if (D == S)
221221
return true;
222222

223-
if (D->isPointerType() == S->isPointerType())
224-
return true;
225-
226-
return false;
223+
return D->isPointerType() == S->isPointerType();
227224
}
228225

229226
bool ProgramInfo::isExternOkay(std::string ext) {
@@ -729,6 +726,21 @@ ProgramInfo::getVariableHelper( Expr *E,
729726
T = getVariableHelper(CO->getRHS(), V, C, ifc);
730727
R.insert(T.begin(), T.end());
731728
return R;
729+
} else if (StringLiteral *exr = dyn_cast<StringLiteral>(E)) {
730+
// if this is a string literal. i.e., "foo"
731+
// we create a new constraint variable and constrain it to be an Nt_array
732+
std::set<ConstraintVariable *> T;
733+
CVars V;
734+
V.insert(freeKey);
735+
CS.getOrCreateVar(freeKey);
736+
freeKey++;
737+
ConstraintVariable *newC = new PointerVariableConstraint(V, "const char*", exr->getBytes(),
738+
nullptr, false, false, "");
739+
// constrain the newly created variable to be NTArray.
740+
newC->constrainTo(CS, CS.getNTArr());
741+
T.insert(newC);
742+
return T;
743+
732744
} else {
733745
return std::set<ConstraintVariable*>();
734746
}

clang/tools/checked-c-convert/ProgramInfo.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,8 @@ class ProgramInfo {
109109

110110
std::set<Decl *> &getIdentifiedArrayVars() {
111111
#ifdef ARRDEBUG
112-
for(auto currD: IdentifiedArrayDecls) {
112+
for (auto currD: IdentifiedArrayDecls)
113113
currD->dump();
114-
}
115114
#endif
116115
return IdentifiedArrayDecls;
117116
}

0 commit comments

Comments
 (0)