Skip to content

Commit df738a4

Browse files
Insert itypes for parameters with typedef types (#690)
This allows a function using an otherwise unchecked typedef type to expose an checked interface. It also lets a function use a typedef'ed parameter unsafely without forcing the entire typedef to be unchecked. In the following example, the typedef td is unchecked because of the unsafe use of b. Prior to this change, test would not be rewritten, leaving it with a fully unchecked type. The new rewriting is `void test(td a : itype(_Ptr<int>))`. typedef int *td; void test(td a) { td b = 1; } In the other direction, the parameter can be used unsafely, but the typedef will still be rewritten to `_Ptr<int>`, and the parameter will get an itype `int * : itype(td)`. typedef int *td; void test(td a) { a = 1; }
1 parent d7b9b2d commit df738a4

File tree

7 files changed

+184
-37
lines changed

7 files changed

+184
-37
lines changed

clang/include/clang/3C/ConstraintVariables.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ class PointerVariableConstraint : public ConstraintVariable {
365365
bool IsZeroWidthArray;
366366

367367
bool IsTypedef = false;
368-
TypedefNameDecl *TDT;
368+
ConstraintVariable *TypedefVar;
369369
std::string TypedefString;
370370
// Does the type internally contain a typedef, and if so: at what level and
371371
// what is it's name?
@@ -381,7 +381,7 @@ class PointerVariableConstraint : public ConstraintVariable {
381381
ConstraintVariable(PointerVariable, "", Name), FV(nullptr),
382382
SrcHasItype(false), PartOfFuncPrototype(false), Parent(nullptr),
383383
SourceGenericIndex(-1), InferredGenericIndex(-1),
384-
IsZeroWidthArray(false), IsTypedef(false), TDT(nullptr),
384+
IsZeroWidthArray(false), IsTypedef(false),
385385
TypedefLevelInfo({}), IsVoidPtr(false) {}
386386

387387
public:
@@ -392,8 +392,9 @@ class PointerVariableConstraint : public ConstraintVariable {
392392
// Check if any of the pointers is either a sized or unsized arr.
393393
bool hasSomeSizedArr() const;
394394

395-
bool isTypedef(void);
396-
void setTypedef(TypedefNameDecl *T, std::string S);
395+
bool isTypedef(void) const;
396+
const ConstraintVariable *getTypedefVar() const;
397+
void setTypedef(ConstraintVariable *TDVar, std::string S);
397398

398399
// Return true if this constraint had an itype in the original source code.
399400
bool srcHasItype() const override { return SrcHasItype; }

clang/include/clang/3C/ProgramInfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ class ProgramInfo : public ProgramVariableAdder {
162162
void ensureNtCorrect(const QualType &QT, const ASTContext &C,
163163
PointerVariableConstraint *PV);
164164

165-
void unifyIfTypedef(const clang::Type *, clang::ASTContext &,
166-
clang::DeclaratorDecl *, PVConstraint *);
165+
void unifyIfTypedef(const QualType &QT, clang::ASTContext &,
166+
PVConstraint *, ConsAction CA = Same_to_Same);
167167

168168
CVarOption lookupTypedef(PersistentSourceLoc PSL);
169169

clang/lib/3C/ConstraintVariables.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ PointerVariableConstraint::PointerVariableConstraint(
130130
SourceGenericIndex(Ot->SourceGenericIndex),
131131
InferredGenericIndex(Ot->InferredGenericIndex),
132132
IsZeroWidthArray(Ot->IsZeroWidthArray),
133-
IsTypedef(Ot->IsTypedef), TDT(Ot->TDT), TypedefString(Ot->TypedefString),
133+
IsTypedef(Ot->IsTypedef), TypedefString(Ot->TypedefString),
134134
TypedefLevelInfo(Ot->TypedefLevelInfo), IsVoidPtr(Ot->IsVoidPtr) {
135135
// These are fields of the super class Constraint Variable
136136
this->HasEqArgumentConstraints = Ot->HasEqArgumentConstraints;
@@ -206,8 +206,7 @@ PointerVariableConstraint::PointerVariableConstraint(
206206
const ASTContext &C, std::string *InFunc, int ForceGenericIndex,
207207
bool PotentialGeneric,
208208
bool VarAtomForChecked, TypeSourceInfo *TSInfo, const QualType &ITypeT)
209-
: ConstraintVariable(ConstraintVariable::PointerVariable,
210-
tyToStr(QT.getTypePtr()), N),
209+
: ConstraintVariable(ConstraintVariable::PointerVariable, qtyToStr(QT), N),
211210
FV(nullptr), SrcHasItype(false), PartOfFuncPrototype(InFunc != nullptr),
212211
Parent(nullptr) {
213212
QualType QTy = QT;
@@ -704,14 +703,20 @@ void PointerVariableConstraint::addArrayAnnotations(
704703
assert(ConstArrs.empty());
705704
}
706705

707-
bool PointerVariableConstraint::isTypedef(void) { return IsTypedef; }
706+
bool PointerVariableConstraint::isTypedef(void) const { return IsTypedef; }
708707

709-
void PointerVariableConstraint::setTypedef(TypedefNameDecl *T, std::string S) {
708+
void PointerVariableConstraint::setTypedef(ConstraintVariable *TDVar,
709+
std::string S) {
710710
IsTypedef = true;
711-
TDT = T;
711+
TypedefVar = TDVar;
712712
TypedefString = S;
713713
}
714714

715+
const ConstraintVariable *PointerVariableConstraint::getTypedefVar() const {
716+
assert(isTypedef());
717+
return TypedefVar;
718+
}
719+
715720
// Mesh resolved constraints with the PointerVariableConstraints set of
716721
// variables and potentially nested function pointer declaration. Produces a
717722
// string that can be replaced in the source code.
@@ -736,8 +741,12 @@ PointerVariableConstraint::mkString(Constraints &CS,
736741
UseName = getName();
737742

738743
if (IsTypedef && !UnmaskTypedef) {
739-
return gatherQualStrings() + TypedefString +
740-
(EmitName && !IsReturn ? (" " + UseName) : " ");
744+
std::string QualTypedef = gatherQualStrings() + TypedefString;
745+
if (!ForItype)
746+
QualTypedef += " ";
747+
if (EmitName && !IsReturn)
748+
QualTypedef += UseName;
749+
return QualTypedef;
741750
}
742751

743752
std::ostringstream Ss;

clang/lib/3C/DeclRewriter.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,33 @@ using namespace clang;
3535
void DeclRewriter::buildItypeDecl(PVConstraint *Defn, DeclaratorDecl *Decl,
3636
std::string &Type, std::string &IType,
3737
ProgramInfo &Info, ArrayBoundsRewriter &ABR) {
38+
const EnvironmentMap &Env = Info.getConstraints().getVariables();
39+
bool IsTypedefVarUnchecked =
40+
Defn->isTypedef() && (ItypesForExtern ||
41+
!Defn->getTypedefVar()->isSolutionChecked(Env));
3842
if (Defn->getFV()) {
3943
// This declaration is for a function pointer. Writing itypes on function
4044
// pointers is a little bit harder since the original type string will not
4145
// work for the unchecked portion of the itype. We need to generate the
4246
// unchecked type from the PVConstraint. The last argument of this call
4347
// tells mkString to generate a string using unchecked types instead of
4448
// checked types.
45-
Type = Defn->mkString(Info.getConstraints(),
46-
MKSTRING_OPTS(ForItypeBase = true));
49+
if (Defn->isTypedef() && !IsTypedefVarUnchecked)
50+
Type = Defn->mkString(Info.getConstraints(),
51+
MKSTRING_OPTS(UnmaskTypedef = true,
52+
ForItypeBase = true));
53+
else
54+
Type = Defn->mkString(Info.getConstraints(),
55+
MKSTRING_OPTS(ForItypeBase = true));
4756
} else {
48-
Type = Defn->getRewritableOriginalTy();
57+
if (Defn->isTypedef() && !IsTypedefVarUnchecked)
58+
Type = Defn->mkString(Info.getConstraints(),
59+
MKSTRING_OPTS(UnmaskTypedef = true,
60+
ForItypeBase = true,
61+
EmitName = false));
62+
else
63+
Type = Defn->getRewritableOriginalTy();
64+
4965
if (isa_and_nonnull<ParmVarDecl>(Decl)) {
5066
if (Decl->getName().empty())
5167
Type += Defn->getName();
@@ -59,7 +75,8 @@ void DeclRewriter::buildItypeDecl(PVConstraint *Defn, DeclaratorDecl *Decl,
5975
}
6076

6177
IType = " : itype(";
62-
if (ItypesForExtern && Defn->isTypedef()) {
78+
79+
if (IsTypedefVarUnchecked) {
6380
// In -itypes-for-extern mode we do not rewrite typedefs to checked types.
6481
// They are given a checked itype instead. The unchecked portion of the
6582
// itype continues to use the original typedef, but the typedef in the

clang/lib/3C/ProgramInfo.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -640,22 +640,22 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
640640
NewCV = F;
641641

642642
auto RetTy = FD->getReturnType();
643-
unifyIfTypedef(RetTy.getTypePtr(), *AstContext, FD, F->getExternalReturn());
644-
unifyIfTypedef(RetTy.getTypePtr(), *AstContext, FD, F->getInternalReturn());
643+
unifyIfTypedef(RetTy, *AstContext, F->getExternalReturn(), Wild_to_Safe);
644+
unifyIfTypedef(RetTy, *AstContext, F->getInternalReturn(), Safe_to_Wild);
645645
ensureNtCorrect(RetTy, *AstContext, F->getExternalReturn());
646646
ensureNtCorrect(RetTy, *AstContext, F->getInternalReturn());
647647

648648
// Add mappings from the parameters PLoc to the constraint variables for
649649
// the parameters.
650650
for (unsigned I = 0; I < FD->getNumParams(); I++) {
651651
ParmVarDecl *PVD = FD->getParamDecl(I);
652-
const Type *Ty = PVD->getType().getTypePtr();
652+
QualType ParamTy = PVD->getType();
653653
PVConstraint *PVInternal = F->getInternalParam(I);
654654
PVConstraint *PVExternal = F->getExternalParam(I);
655-
unifyIfTypedef(Ty, *AstContext, PVD, PVInternal);
656-
unifyIfTypedef(Ty, *AstContext, PVD, PVExternal);
657-
ensureNtCorrect(PVD->getType(), *AstContext, PVInternal);
658-
ensureNtCorrect(PVD->getType(), *AstContext, PVExternal);
655+
unifyIfTypedef(ParamTy, *AstContext, PVExternal, Wild_to_Safe);
656+
unifyIfTypedef(ParamTy, *AstContext, PVInternal, Safe_to_Wild);
657+
ensureNtCorrect(ParamTy, *AstContext, PVInternal);
658+
ensureNtCorrect(ParamTy, *AstContext, PVExternal);
659659
PVInternal->setValidDecl();
660660
PersistentSourceLoc PSL = PersistentSourceLoc::mkPSL(PVD, *AstContext);
661661
// Constraint variable is stored on the parent function, so we need to
@@ -675,13 +675,13 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
675675

676676
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
677677
assert(!isa<ParmVarDecl>(VD));
678-
const Type *Ty = VD->getTypeSourceInfo()->getTypeLoc().getTypePtr();
679-
if (Ty->isPointerType() || Ty->isArrayType()) {
678+
QualType QT = VD->getTypeSourceInfo()->getTypeLoc().getType();
679+
if (QT->isPointerType() || QT->isArrayType()) {
680680
PVConstraint *P = new PVConstraint(D, *this, *AstContext);
681681
P->setValidDecl();
682682
NewCV = P;
683683
std::string VarName(VD->getName());
684-
unifyIfTypedef(Ty, *AstContext, VD, P);
684+
unifyIfTypedef(QT, *AstContext, P);
685685
ensureNtCorrect(VD->getType(), *AstContext, P);
686686
if (VD->hasGlobalStorage()) {
687687
// If we see a definition for this global variable, indicate so in
@@ -699,10 +699,10 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
699699
}
700700

701701
} else if (FieldDecl *FlD = dyn_cast<FieldDecl>(D)) {
702-
const Type *Ty = FlD->getTypeSourceInfo()->getTypeLoc().getTypePtr();
703-
if (Ty->isPointerType() || Ty->isArrayType()) {
702+
QualType QT = FlD->getTypeSourceInfo()->getTypeLoc().getType();
703+
if (QT->isPointerType() || QT->isArrayType()) {
704704
PVConstraint *P = new PVConstraint(D, *this, *AstContext);
705-
unifyIfTypedef(Ty, *AstContext, FlD, P);
705+
unifyIfTypedef(QT, *AstContext, P);
706706
NewCV = P;
707707
NewCV->setValidDecl();
708708
}
@@ -725,16 +725,16 @@ void ProgramInfo::ensureNtCorrect(const QualType &QT, const ASTContext &C,
725725
}
726726
}
727727

728-
void ProgramInfo::unifyIfTypedef(const Type *Ty, ASTContext &Context,
729-
DeclaratorDecl *Decl, PVConstraint *P) {
730-
if (const auto *TDT = dyn_cast<TypedefType>(Ty)) {
728+
void ProgramInfo::unifyIfTypedef(const QualType &QT, ASTContext &Context,
729+
PVConstraint *P, ConsAction CA) {
730+
if (const auto *TDT = dyn_cast<TypedefType>(QT.getTypePtr())) {
731731
auto *TDecl = TDT->getDecl();
732732
auto PSL = PersistentSourceLoc::mkPSL(TDecl, Context);
733733
auto O = lookupTypedef(PSL);
734734
if (O.hasValue()) {
735735
auto *Bounds = &O.getValue();
736-
P->setTypedef(TDecl, TDecl->getNameAsString());
737-
constrainConsVarGeq(P, Bounds, CS, &PSL, Same_to_Same, true, this);
736+
P->setTypedef(Bounds, TDecl->getNameAsString());
737+
constrainConsVarGeq(P, Bounds, CS, &PSL, CA, false, this);
738738
}
739739
}
740740
}

clang/test/3C/basic_checks.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void mut_pa(PA p) {
3838
p->a = 0;
3939
p->b = 1;
4040
}
41-
//CHECK: void mut_pa(PA p) {
41+
//CHECK: void mut_pa(PA p : itype(_Ptr<struct _A>)) {
4242

4343
void pa_driver(void) {
4444
A a = {0};

clang/test/3C/itype_typedef.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// RUN: rm -rf %t*
2+
// RUN: 3c -base-dir=%S -alltypes -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ALL","CHECK" %s
3+
// RUN: 3c -base-dir=%S -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_NOALL","CHECK" %s
4+
// RUN: 3c -base-dir=%S -addcr %s -- | %clang -c -fcheckedc-extension -x c -o /dev/null -
5+
// RUN: 3c -base-dir=%S -alltypes -output-dir=%t.checked %s --
6+
// RUN: 3c -base-dir=%t.checked -alltypes %t.checked/itype_typedef.c -- | diff %t.checked/itype_typedef.c -
7+
8+
// Itype typedef on the paramter
9+
10+
typedef int *td0;
11+
void test0(td0 a) {
12+
//CHECK: typedef _Ptr<int> td0;
13+
//CHECK: void test0(int *a : itype(td0)) {
14+
a = 1;
15+
}
16+
17+
typedef int *td1;
18+
void test1(td1 a) {
19+
//CHECK: typedef int *td1;
20+
//CHECK: void test1(td1 a : itype(_Ptr<int>)) {
21+
td1 b = a;
22+
b = 1;
23+
}
24+
25+
typedef int *td2;
26+
void test2(td2 a) {
27+
//CHECK: typedef int *td2;
28+
//CHECK: void test2(td2 a : itype(_Ptr<int>)) {
29+
td2 b = 1;
30+
}
31+
32+
// Itype typedef on the return
33+
34+
typedef int *td3;
35+
td3 test3() {
36+
//CHECK: typedef _Ptr<int> td3;
37+
//CHECK: int * test3(void) : itype(td3) {
38+
return (int*) 1;
39+
}
40+
41+
typedef int *td4;
42+
td4 test4() {
43+
//CHECK: typedef int *td4;
44+
//CHECK: td4 test4(void) : itype(_Ptr<int>) {
45+
td4 a = 1;
46+
return a;
47+
}
48+
49+
// Itype typedef with array bounds
50+
51+
typedef int *td5;
52+
void test5(td5 a, int n) {
53+
//CHECK: typedef int *td5;
54+
//CHECK_ALL: void test5(td5 a : itype(_Array_ptr<int>) count(n), int n) {
55+
//CHECK_NOALL: void test5(td5 a : itype(_Ptr<int>), int n) {
56+
for (int i = 0; i < n; i++)
57+
a[i];
58+
td5 b = 1;
59+
}
60+
61+
typedef int *td6;
62+
void test6(td6 a, int n) {
63+
//CHECK_ALL: typedef _Array_ptr<int> td6;
64+
//CHECK_ALL: void test6(int *a : itype(td6) count(n), int n) {
65+
//CHECK_NOALL: typedef _Ptr<int> td6;
66+
//CHECK_NOALL: void test6(int *a : itype(td6), int n) {
67+
for (int i = 0; i < n; i++)
68+
a[i];
69+
a = 1;
70+
}
71+
72+
// Itype typedef with type qualifiers
73+
74+
typedef int *td7;
75+
void test7(const td7 a) {
76+
//CHECK: typedef _Ptr<int> td7;
77+
//CHECK: void test7(int *const a : itype(const td7)) {
78+
int *b = a;
79+
b = 1;
80+
}
81+
82+
typedef int *td8;
83+
void test8(const td8 a) {
84+
//CHECK: typedef int *td8;
85+
//CHECK: void test8(const td8 a : itype(const _Ptr<int>)) {
86+
td8 b = a;
87+
b = 1;
88+
}
89+
90+
typedef const int *td9;
91+
void test9(td9 a) {
92+
//CHECK: typedef _Ptr<const int> td9;
93+
//CHECK: void test9(const int *a : itype(td9)) {
94+
int *b = a;
95+
b = 1;
96+
}
97+
98+
typedef const int *td10;
99+
void test10(td10 a) {
100+
//CHECK: typedef const int *td10;
101+
//CHECK: void test10(td10 a : itype(_Ptr<const int>)) {
102+
td10 b = a;
103+
b = 1;
104+
}
105+
106+
// With functions pointers
107+
108+
typedef int (*fp_td0)(int);
109+
void fp_test0(fp_td0 a) {
110+
//CHECK: typedef _Ptr<int (int)> fp_td0;
111+
//CHECK: void fp_test0(int ((*a)(int)) : itype(fp_td0)) {
112+
a = 1;
113+
}
114+
115+
typedef int (*fp_td1)(int);
116+
void fp_test1(fp_td1 a) {
117+
//CHECK: typedef int (*fp_td1)(int);
118+
//CHECK: void fp_test1(fp_td1 a : itype(_Ptr<int (int)>)) {
119+
fp_td1 b = 1;
120+
}

0 commit comments

Comments
 (0)