Skip to content

Commit c3d3e5d

Browse files
kyleheadleyjohn-h-kastnerAaron Elinemattmccutchen-cci
authored
No longer generate extra atoms to compare generic types (#655)
* switch max atoms to min atoms to avoid excess * make type param info more available * Provide typevars to constraint collection * reset cache when typevar constraint is added * trivial test changes * Use constraint from TypeVarInfo in for malloc in possible * Fix root cause output for constraint variables deleted from persistent constraints * Fix failing array bounds tests * special case for realloc * include now-passing test in main test file * Tweak change from 2a5db6f to also handle unsage allocator calls * This fixes the 0 atoms affected root cause in test root_cause.c * better comment * Update clang/test/3C/root_cause.c Co-authored-by: Aaron Eline <[email protected]> * whitespace in test checked line * Update clang/test/3C/hash.c Co-authored-by: Matt McCutchen (Correct Computation) <[email protected]> Co-authored-by: John Kastner <[email protected]> Co-authored-by: Aaron Eline <[email protected]> Co-authored-by: Matt McCutchen (Correct Computation) <[email protected]>
1 parent 3975661 commit c3d3e5d

10 files changed

+118
-82
lines changed

clang/include/clang/3C/3CInteractiveData.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ConstraintsInfo {
5050
CVars TotalNonDirectWildAtoms;
5151
CVars InSrcNonDirectWildAtoms;
5252
std::set<std::string> ValidSourceFiles;
53-
std::map<ConstraintKey, const PersistentSourceLoc *> AtomSourceMap;
53+
std::map<ConstraintKey, PersistentSourceLoc> AtomSourceMap;
5454

5555
private:
5656
// Root cause map: This is the map of a Constraint var and a set of

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class ProgramInfo : public ProgramVariableAdder {
9090
// Store CVarSet with an empty set of BoundsKey into persistent contents.
9191
void storePersistentConstraints(clang::Expr *E, const CVarSet &Vars,
9292
ASTContext *C);
93+
void removePersistentConstraints(Expr *E, ASTContext *C);
9394

9495
// Get constraint variable for the provided Decl
9596
CVarOption getVariable(clang::Decl *D, clang::ASTContext *C);
@@ -169,6 +170,8 @@ class ProgramInfo : public ProgramVariableAdder {
169170
// expected that multiple entries will map to the same source location.
170171
std::map<IDAndTranslationUnit, PersistentSourceLoc> ExprLocations;
171172

173+
std::map<ConstraintKey, PersistentSourceLoc> DeletedAtomLocations;
174+
172175
//Performance stats
173176
PerformanceStats PerfS;
174177

@@ -210,8 +213,7 @@ class ProgramInfo : public ProgramVariableAdder {
210213
// Retrieves a FVConstraint* from a Decl (which could be static, or global)
211214
FVConstraint *getFuncFVConstraint(FunctionDecl *FD, ASTContext *C);
212215

213-
void insertIntoPtrSourceMap(const PersistentSourceLoc *PSL,
214-
ConstraintVariable *CV);
216+
void insertIntoPtrSourceMap(PersistentSourceLoc PSL, ConstraintVariable *CV);
215217

216218
void computePtrLevelStats();
217219

clang/lib/3C/ConstraintBuilder.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,8 @@ class InlineStructDetector {
131131
// and imposing constraints on variables it uses
132132
class FunctionVisitor : public RecursiveASTVisitor<FunctionVisitor> {
133133
public:
134-
explicit FunctionVisitor(ASTContext *C, ProgramInfo &I, FunctionDecl *FD,
135-
TypeVarInfo &TVI)
136-
: Context(C), Info(I), Function(FD), CB(Info, Context), TVInfo(TVI),
134+
explicit FunctionVisitor(ASTContext *C, ProgramInfo &I, FunctionDecl *FD)
135+
: Context(C), Info(I), Function(FD), CB(Info, Context),
137136
ISD() {}
138137

139138
// T x = e
@@ -217,9 +216,10 @@ class FunctionVisitor : public RecursiveASTVisitor<FunctionVisitor> {
217216

218217
// Collect type parameters for this function call that are
219218
// consistently instantiated as single type in this function call.
220-
std::set<unsigned int> ConsistentTypeParams;
221-
if (TFD != nullptr)
222-
TVInfo.getConsistentTypeParams(E, ConsistentTypeParams);
219+
auto ConsistentTypeParams =
220+
Info.hasTypeParamBindings(E,Context) ?
221+
Info.getTypeParamBindings(E,Context) :
222+
ProgramInfo::CallTypeParamBindingsT();
223223

224224
// Now do the call: Constrain arguments to parameters (but ignore returns)
225225
if (FVCons.empty()) {
@@ -436,7 +436,6 @@ class FunctionVisitor : public RecursiveASTVisitor<FunctionVisitor> {
436436
ProgramInfo &Info;
437437
FunctionDecl *Function;
438438
ConstraintResolver CB;
439-
TypeVarInfo &TVInfo;
440439
InlineStructDetector ISD;
441440
};
442441

@@ -485,9 +484,8 @@ class PtrToStructDef : public RecursiveASTVisitor<PtrToStructDef> {
485484
// for functions, variables, types, etc. that are visited.
486485
class ConstraintGenVisitor : public RecursiveASTVisitor<ConstraintGenVisitor> {
487486
public:
488-
explicit ConstraintGenVisitor(ASTContext *Context, ProgramInfo &I,
489-
TypeVarInfo &TVI)
490-
: Context(Context), Info(I), CB(Info, Context), TVInfo(TVI), ISD() {}
487+
explicit ConstraintGenVisitor(ASTContext *Context, ProgramInfo &I)
488+
: Context(Context), Info(I), CB(Info, Context), ISD() {}
491489

492490
bool VisitVarDecl(VarDecl *G) {
493491

@@ -526,7 +524,7 @@ class ConstraintGenVisitor : public RecursiveASTVisitor<ConstraintGenVisitor> {
526524
if (FL.isValid()) { // TODO: When would this ever be false?
527525
if (D->hasBody() && D->isThisDeclarationADefinition()) {
528526
Stmt *Body = D->getBody();
529-
FunctionVisitor FV = FunctionVisitor(Context, Info, D, TVInfo);
527+
FunctionVisitor FV = FunctionVisitor(Context, Info, D);
530528
FV.TraverseStmt(Body);
531529
if (AllTypes) {
532530
// Only do this, if all types is enabled.
@@ -551,7 +549,6 @@ class ConstraintGenVisitor : public RecursiveASTVisitor<ConstraintGenVisitor> {
551549
ASTContext *Context;
552550
ProgramInfo &Info;
553551
ConstraintResolver CB;
554-
TypeVarInfo &TVInfo;
555552
InlineStructDetector ISD;
556553
};
557554

@@ -669,7 +666,7 @@ void ConstraintBuilderConsumer::HandleTranslationUnit(ASTContext &C) {
669666
ConstraintResolver CSResolver(Info, &C);
670667
ContextSensitiveBoundsKeyVisitor CSBV =
671668
ContextSensitiveBoundsKeyVisitor(&C, Info, &CSResolver);
672-
ConstraintGenVisitor GV = ConstraintGenVisitor(&C, Info, TV);
669+
ConstraintGenVisitor GV = ConstraintGenVisitor(&C, Info);
673670
TranslationUnitDecl *TUD = C.getTranslationUnitDecl();
674671
StatsRecorder SR(&C, &Info);
675672

@@ -681,13 +678,16 @@ void ConstraintBuilderConsumer::HandleTranslationUnit(ASTContext &C) {
681678

682679
CSBV.TraverseDecl(D);
683680
TV.TraverseDecl(D);
684-
GV.TraverseDecl(D);
685-
SR.TraverseDecl(D);
686681
}
687682

688683
// Store type variable information for use in rewriting
689684
TV.setProgramInfoTypeVars();
690685

686+
for (const auto &D : TUD->decls()) {
687+
GV.TraverseDecl(D);
688+
SR.TraverseDecl(D);
689+
}
690+
691691
if (Verbose)
692692
errs() << "Done analyzing\n";
693693

clang/lib/3C/ConstraintResolver.cpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,26 @@ inline CSetBkeyPair pairWithEmptyBkey(const CVarSet &Vars) {
151151
return std::make_pair(Vars, EmptyBSet);
152152
}
153153

154+
// Get the return type of the function from the TypeVars, that is, from
155+
// the local instantiation of a generic function. Or the regular return
156+
// constraint if it's not generic
157+
ConstraintVariable *localReturnConstraint(
158+
FVConstraint *FV,
159+
ProgramInfo::CallTypeParamBindingsT TypeVars,
160+
Constraints &CS) {
161+
int TyVarIdx = FV->getExternalReturn()->getGenericIndex();
162+
// Check if local type vars are available
163+
if (TypeVars.find(TyVarIdx) != TypeVars.end() &&
164+
TypeVars[TyVarIdx] != nullptr) {
165+
ConstraintVariable *CV = TypeVars[TyVarIdx];
166+
if (FV->getExternalReturn()->hasBoundsKey())
167+
CV->setBoundsKey(FV->getExternalReturn()->getBoundsKey());
168+
return CV;
169+
} else {
170+
return FV->getExternalReturn();
171+
}
172+
}
173+
154174
// Returns a pair of set of ConstraintVariables and set of BoundsKey
155175
// after evaluating the expression E. Will explore E recursively, but will
156176
// ignore parts of it that do not contribute to the final result.
@@ -403,6 +423,10 @@ CSetBkeyPair ConstraintResolver::getExprConstraintVars(Expr *E) {
403423
CVarSet ReturnCVs;
404424
BKeySet ReturnBSet = EmptyBSet;
405425

426+
ProgramInfo::CallTypeParamBindingsT TypeVars;
427+
if (Info.hasTypeParamBindings(CE, Context))
428+
TypeVars = Info.getTypeParamBindings(CE, Context);
429+
406430
// Here, we need to look up the target of the call and return the
407431
// constraints for the return value of that function.
408432
QualType ExprType = E->getType();
@@ -418,22 +442,24 @@ CSetBkeyPair ConstraintResolver::getExprConstraintVars(Expr *E) {
418442

419443
for (ConstraintVariable *C : Tmp.first) {
420444
if (FVConstraint *FV = dyn_cast<FVConstraint>(C)) {
421-
ReturnCVs.insert(FV->getExternalReturn());
445+
ReturnCVs.insert(localReturnConstraint(FV,TypeVars,CS));
422446
} else if (PVConstraint *PV = dyn_cast<PVConstraint>(C)) {
423447
if (FVConstraint *FV = PV->getFV())
424-
ReturnCVs.insert(FV->getExternalReturn());
448+
ReturnCVs.insert(localReturnConstraint(FV,TypeVars,CS));
425449
}
426450
}
427451
} else if (DeclaratorDecl *FD = dyn_cast<DeclaratorDecl>(D)) {
428452
/* Allocator call */
429453
if (isFunctionAllocator(std::string(FD->getName()))) {
430454
bool DidInsert = false;
431455
IsAllocator = true;
432-
if (CE->getNumArgs() > 0) {
456+
if (TypeVars.find(0) != TypeVars.end() && TypeVars[0] != nullptr) {
457+
ReturnCVs.insert(TypeVars[0]);
458+
DidInsert = true;
459+
} else if (CE->getNumArgs() > 0) {
433460
QualType ArgTy;
434461
std::string FuncName = FD->getNameAsString();
435-
ConstAtom *A;
436-
A = analyzeAllocExpr(CE, CS, ArgTy, FuncName, Context);
462+
ConstAtom *A = analyzeAllocExpr(CE, CS, ArgTy, FuncName, Context);
437463
if (A) {
438464
std::string N(FD->getName());
439465
N = "&" + N;
@@ -465,13 +491,13 @@ CSetBkeyPair ConstraintResolver::getExprConstraintVars(Expr *E) {
465491
assert(CV.hasValue() && "Function without constraint variable.");
466492
/* Direct function call */
467493
if (FVConstraint *FVC = dyn_cast<FVConstraint>(&CV.getValue()))
468-
ReturnCVs.insert(FVC->getExternalReturn());
494+
ReturnCVs.insert(localReturnConstraint(FVC,TypeVars,CS));
469495
/* Call via function pointer */
470496
else {
471497
PVConstraint *Tmp = dyn_cast<PVConstraint>(&CV.getValue());
472498
assert(Tmp != nullptr);
473499
if (FVConstraint *FVC = Tmp->getFV())
474-
ReturnCVs.insert(FVC->getExternalReturn());
500+
ReturnCVs.insert(localReturnConstraint(FVC,TypeVars,CS));
475501
else {
476502
// No FVConstraint -- make WILD.
477503
auto *TmpFV = new FVConstraint();

clang/lib/3C/ConstraintVariables.cpp

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,10 +1786,11 @@ void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS,
17861786

17871787
// Only generate constraint if LHS is not a base type.
17881788
if (CLHS.size() != 0) {
1789-
if (CLHS.size() == CRHS.size() || PCLHS->getIsGeneric() ||
1790-
PCRHS->getIsGeneric()) {
1791-
unsigned Max = std::max(CLHS.size(), CRHS.size());
1792-
for (unsigned N = 0; N < Max; N++) {
1789+
if (CLHS.size() == CRHS.size() ||
1790+
(CLHS.size() < CRHS.size() && PCLHS->getIsGeneric()) ||
1791+
(CLHS.size() > CRHS.size() && PCRHS->getIsGeneric())) {
1792+
unsigned Min = std::min(CLHS.size(), CRHS.size());
1793+
for (unsigned N = 0; N < Min; N++) {
17931794
Atom *IAtom = PCLHS->getAtom(N, CS);
17941795
Atom *JAtom = PCRHS->getAtom(N, CS);
17951796
if (IAtom == nullptr || JAtom == nullptr)
@@ -1931,20 +1932,8 @@ void PointerVariableConstraint::mergeDeclaration(ConstraintVariable *FromCV,
19311932
}
19321933

19331934
Atom *PointerVariableConstraint::getAtom(unsigned AtomIdx, Constraints &CS) {
1934-
if (AtomIdx < Vars.size()) {
1935-
// If index is in bounds, just return the atom.
1936-
return Vars[AtomIdx];
1937-
}
1938-
if (getIsGeneric() && AtomIdx == Vars.size()) {
1939-
// Polymorphic types don't know how "deep" their pointers are beforehand so,
1940-
// we need to create new atoms for new pointer levels on the fly.
1941-
std::string Stars(Vars.size(), '*');
1942-
Atom *A = CS.getFreshVar(Name + Stars, VarAtom::V_Other);
1943-
Vars.push_back(A);
1944-
SrcVars.push_back(CS.getWild());
1945-
return A;
1946-
}
1947-
return nullptr;
1935+
assert(AtomIdx < Vars.size());
1936+
return Vars[AtomIdx];
19481937
}
19491938

19501939
void PointerVariableConstraint::equateWithItype(

clang/lib/3C/ProgramInfo.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,24 @@ void ProgramInfo::storePersistentConstraints(Expr *E, const CSetBkeyPair &Vars,
829829
ExprLocations[Key] = PSL;
830830
}
831831

832+
void ProgramInfo::removePersistentConstraints(Expr *E, ASTContext *C) {
833+
assert(hasPersistentConstraints(E, C) &&
834+
"Persistent constraints not present.");
835+
836+
IDAndTranslationUnit Key = getExprKey(E, C);
837+
838+
// Save VarAtom locations so they can be used to assign source locations to
839+
// root causes.
840+
for (auto *CV : ExprConstraintVars[Key].first)
841+
if (auto *PVC = dyn_cast<PointerVariableConstraint>(CV))
842+
for (Atom *A : PVC->getCvars())
843+
if (auto *VA = dyn_cast<VarAtom>(A))
844+
DeletedAtomLocations[VA->getLoc()] = ExprLocations[Key];
845+
846+
ExprConstraintVars.erase(Key);
847+
ExprLocations.erase(Key);
848+
}
849+
832850
// The Rewriter won't let us re-write things that are in macros. So, we
833851
// should check to see if what we just added was defined within a macro.
834852
// If it was, we should constrain it to top. This is sad. Hopefully,
@@ -1043,22 +1061,24 @@ bool ProgramInfo::computeInterimConstraintState(
10431061
// Variables before ExprConstraintVars and making insertIntoPtrSourceMap not
10441062
// overwrite a PSL already recorded for a given atom.
10451063
for (const auto &I : Variables)
1046-
insertIntoPtrSourceMap(&(I.first), I.second);
1064+
insertIntoPtrSourceMap(I.first, I.second);
10471065
for (const auto &I : ExprConstraintVars) {
1048-
PersistentSourceLoc *PSL = &ExprLocations[I.first];
1066+
PersistentSourceLoc PSL = ExprLocations[I.first];
10491067
for (auto *J : I.second.first)
10501068
insertIntoPtrSourceMap(PSL, J);
10511069
}
1070+
for (auto E : DeletedAtomLocations)
1071+
CState.AtomSourceMap.insert(std::make_pair(E.first, E.second));
10521072

10531073
auto &WildPtrsReason = CState.RootWildAtomsWithReason;
10541074
for (auto *CurrC : CS.getConstraints()) {
10551075
if (Geq *EC = dyn_cast<Geq>(CurrC)) {
10561076
VarAtom *VLhs = dyn_cast<VarAtom>(EC->getLHS());
10571077
if (EC->constraintIsChecked() && dyn_cast<WildAtom>(EC->getRHS())) {
10581078
PersistentSourceLoc PSL = EC->getLocation();
1059-
const PersistentSourceLoc *APSL = CState.AtomSourceMap[VLhs->getLoc()];
1060-
if (!PSL.valid() && APSL && APSL->valid())
1061-
PSL = *APSL;
1079+
PersistentSourceLoc APSL = CState.AtomSourceMap[VLhs->getLoc()];
1080+
if (!PSL.valid() && APSL.valid())
1081+
PSL = APSL;
10621082
WildPointerInferenceInfo Info(EC->getReason(), PSL);
10631083
WildPtrsReason.insert(std::make_pair(VLhs->getLoc(), Info));
10641084
}
@@ -1069,9 +1089,9 @@ bool ProgramInfo::computeInterimConstraintState(
10691089
return true;
10701090
}
10711091

1072-
void ProgramInfo::insertIntoPtrSourceMap(const PersistentSourceLoc *PSL,
1092+
void ProgramInfo::insertIntoPtrSourceMap(PersistentSourceLoc PSL,
10731093
ConstraintVariable *CV) {
1074-
std::string FilePath = PSL->getFileName();
1094+
std::string FilePath = PSL.getFileName();
10751095
if (canWrite(FilePath))
10761096
CState.ValidSourceFiles.insert(FilePath);
10771097

clang/lib/3C/TypeVariableAnalysis.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,27 @@ bool TypeVarVisitor::VisitCallExpr(CallExpr *CE) {
127127

128128
// Constrain this variable GEQ the function arguments using the type
129129
// variable so if any of them are wild, the type argument will also be
130-
// an unchecked pointer.
131-
constrainConsVarGeq(P, TVEntry.second.getConstraintVariables(),
130+
// an unchecked pointer. Except for realloc, which has special casing
131+
// elsewhere, especially `ConstraintResolver::getExprConstraintVars`
132+
// using variable `ReallocFlow`. Because `realloc` can take a wild
133+
// pointer and return a safe one.
134+
if (FD->getNameAsString() == "realloc") {
135+
constrainConsVarGeq(P, TVEntry.second.getConstraintVariables(),
136+
Info.getConstraints(), nullptr, Wild_to_Safe, false,
137+
&Info);
138+
139+
} else {
140+
constrainConsVarGeq(P, TVEntry.second.getConstraintVariables(),
132141
Info.getConstraints(), nullptr, Safe_to_Wild, false,
133142
&Info);
143+
}
134144

135145
TVEntry.second.setTypeParamConsVar(P);
146+
// Since we've changed the constraint variable for this context, we
147+
// need to remove the cache from the old one. Our new info will be
148+
// used next request.
149+
if (Info.hasPersistentConstraints(CE,Context))
150+
Info.removePersistentConstraints(CE,Context);
136151
} else {
137152
// TODO: This might be too cautious.
138153
CR.constraintAllCVarsToWild(TVEntry.second.getConstraintVariables(),

clang/test/3C/hash.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ _Itype_for_any(T) void vsf_sysutil_memclr(void *p_dest
1313
: itype(_Array_ptr<T>)
1414
byte_count(size),
1515
unsigned int size)
16-
// CHECK_ALL: _Itype_for_any(T) void vsf_sysutil_memclr(void *p_dest : itype(_Array_ptr<T>) byte_count(size), unsigned int size)
16+
// CHECK_ALL: _Itype_for_any(T) void vsf_sysutil_memclr(void *p_dest
17+
// CHECK_ALL-NEXT: : itype(_Array_ptr<T>)
18+
// CHECK_ALL-NEXT: byte_count(size),
19+
// CHECK_ALL-NEXT: unsigned int size)
1720
{
1821
/* Safety */
1922
if (size == 0) {

clang/test/3C/type_params.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ void *example1(void *ptr, unsigned int size) {
175175
// Issue #349. Check that the parameter doesn't inherit the double pointer
176176
// argument within do_doubleptr
177177
_Itype_for_any(T) void incoming_doubleptr(void *ptr : itype(_Array_ptr<T>)) {
178-
// CHECK_ALL: _Itype_for_any(T) void incoming_doubleptr(void *ptr : itype(_Array_ptr<T>)) {
178+
// CHECK_ALL: _Itype_for_any(T) void incoming_doubleptr(void *ptr : itype(_Array_ptr<T>) count(5)) {
179179
return;
180180
}
181181

@@ -185,3 +185,12 @@ void do_doubleptr(int count) {
185185
incoming_doubleptr(arr);
186186
// CHECK_ALL: incoming_doubleptr<_Ptr<int>>(arr);
187187
}
188+
189+
// make sure adding this function doesn't infer
190+
// with the type of the previous one
191+
// Though it does currently add the `count(5)`
192+
// to the param of incomming_doubleptr
193+
void interfere_doubleptr(void) {
194+
float fl _Checked[5][5] = {};
195+
incoming_doubleptr(fl);
196+
}

0 commit comments

Comments
 (0)