Skip to content

Commit c207954

Browse files
Don't add range bounds for fields or global variables
1 parent 96eff3a commit c207954

File tree

5 files changed

+63
-14
lines changed

5 files changed

+63
-14
lines changed

clang/include/clang/3C/AVarBoundsInfo.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,13 @@ class AVarBoundsInfo {
253253
// Check if the given bounds key has a pointer arithmetic done on it.
254254
bool hasPointerArithmetic(BoundsKey BK);
255255

256+
// Check if range bounds can be inferred by 3C for the pointer corresponding
257+
// to the bounds key.
258+
bool canInferRangeBounds(BoundsKey BK);
259+
256260
// Check if the bounds keys will need to be rewritten with range bounds. This
257261
// is true for bounds keys that are subject to pointer arithmetic but
258262
// otherwise have inferred bounds.
259-
// TODO: disqualify pointers based on other conditions: e.g., fields probably
260-
// can't get range bound.
261263
bool needsRangeBound(BoundsKey BK);
262264

263265
// Get the ProgramVar for the provided VarKey.
@@ -319,9 +321,18 @@ class AVarBoundsInfo {
319321
std::map<BoundsKey, std::map<BoundsPriority, ABounds *>> BInfo;
320322
// Set that contains BoundsKeys of variables which have invalid bounds.
321323
std::set<BoundsKey> InvalidBounds;
324+
322325
// These are the bounds key of the pointers that has arithmetic operations
323-
// performed on them.
326+
// performed on them. These pointers cannot have the standard `count(n)`
327+
// bounds and instead must use range bounds e.g., `bounds(p, p + n)`.
324328
std::set<BoundsKey> ArrPointersWithArithmetic;
329+
330+
// Some pointers, however, cannot be automatically given range bounds. This
331+
// includes global variables and structure fields. If a pointer is in both the
332+
// above pointer arithmetic set and this set, then it cannot be assigned any
333+
// bound.
334+
std::set<BoundsKey> IneligibleForRangeBounds;
335+
325336
// Set of BoundsKeys that correspond to pointers.
326337
std::set<BoundsKey> PointerBoundsKey;
327338
// Set of BoundsKey that correspond to array pointers.

clang/lib/3C/AVarBoundsInfo.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,6 @@ bool AvarBoundsInference::getReachableBoundKeys(const ProgramVarScope *DstScope,
352352

353353
void AvarBoundsInference::getRelevantBounds(BoundsKey BK,
354354
BndsKindMap &ResBounds) {
355-
// Try to get the bounds of all RBKeys.
356355
if (CurrIterInferBounds.find(BK) != CurrIterInferBounds.end()) {
357356
// get the bounds inferred from the current iteration
358357
ResBounds = CurrIterInferBounds[BK];
@@ -812,8 +811,11 @@ BoundsKey AVarBoundsInfo::getVariable(clang::VarDecl *VD) {
812811
auto *PVar =
813812
ProgramVar::createNewProgramVar(NK, VD->getNameAsString(), PVS);
814813
insertProgramVar(NK, PVar);
815-
if (isPtrOrArrayType(VD->getType()))
814+
if (isPtrOrArrayType(VD->getType())) {
816815
PointerBoundsKey.insert(NK);
816+
if (!VD->isLocalVarDeclOrParm())
817+
IneligibleForRangeBounds.insert(NK);
818+
}
817819
}
818820
return getVarKey(PSL);
819821
}
@@ -876,8 +878,10 @@ BoundsKey AVarBoundsInfo::getVariable(clang::FieldDecl *FD) {
876878
const StructScope *SS = StructScope::getStructScope(StName);
877879
auto *PVar = ProgramVar::createNewProgramVar(NK, FD->getNameAsString(), SS);
878880
insertProgramVar(NK, PVar);
879-
if (isPtrOrArrayType(FD->getType()))
881+
if (isPtrOrArrayType(FD->getType())) {
880882
PointerBoundsKey.insert(NK);
883+
IneligibleForRangeBounds.insert(NK);
884+
}
881885
}
882886
return getVarKey(PSL);
883887
}
@@ -938,7 +942,8 @@ void AVarBoundsInfo::addAssignment(BoundsKey L, BoundsKey R) {
938942
// pointer. For future work, all bounds "down stream" of pointer arithmetic
939943
// could also use range bounds using the same base pointer.
940944
auto AddEdgeUnlessPointerArithmetic = [this](BoundsKey From, BoundsKey To) {
941-
if (!hasPointerArithmetic(From))
945+
if (!hasPointerArithmetic(From) &&
946+
(!hasPointerArithmetic(To) || canInferRangeBounds(To)))
942947
ProgVarGraph.addUniqueEdge(From, To);
943948
};
944949

@@ -987,10 +992,17 @@ bool AVarBoundsInfo::hasPointerArithmetic(BoundsKey BK) {
987992
return ArrPointersWithArithmetic.find(BK) != ArrPointersWithArithmetic.end();
988993
}
989994

990-
// A pointer needs range bounds if it is computed by pointer arithmetic and
991-
// would otherwise need bounds.
995+
bool AVarBoundsInfo::canInferRangeBounds(BoundsKey BK) {
996+
return IneligibleForRangeBounds.find(BK) == IneligibleForRangeBounds.end();
997+
}
998+
992999
bool AVarBoundsInfo::needsRangeBound(BoundsKey BK) {
993-
return hasPointerArithmetic(BK) && getBounds(BK) != nullptr;
1000+
// A pointer should get range bounds if it is computed by pointer arithmetic
1001+
// and would otherwise need bounds. Some pointers (global variables and struct
1002+
// fields) can't be rewritten to use range bounds (by 3C; Checked C does
1003+
// permit it), so we return false on these.
1004+
return hasPointerArithmetic(BK) && canInferRangeBounds(BK) &&
1005+
getBounds(BK) != nullptr;
9941006
}
9951007

9961008
ProgramVar *AVarBoundsInfo::getProgramVar(BoundsKey VK) {

clang/lib/3C/DeclRewriter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void DeclRewriter::buildItypeDecl(PVConstraint *Defn, DeclaratorDecl *Decl,
4242
Info.getABoundsInfo().needsRangeBound(Defn->getBoundsKey());
4343
assert("Adding range bounds on return, global variable, or field!" &&
4444
(!NeedsRangeBound || (isa_and_nonnull<VarDecl>(Decl) &&
45-
cast<VarDecl>(Decl)->hasLocalStorage())));
45+
cast<VarDecl>(Decl)->isLocalVarDeclOrParm())));
4646

4747
std::string DeclName = Decl ? Decl->getNameAsString() : "";
4848
// The idea here is that the name should only be empty if this is an unnamed
@@ -135,7 +135,7 @@ void DeclRewriter::buildCheckedDecl(PVConstraint *Defn, DeclaratorDecl *Decl,
135135
Info.getABoundsInfo().needsRangeBound(Defn->getBoundsKey());
136136
assert("Adding range bounds on return, global variable, or field!" &&
137137
(!NeedsRangeBound || (isa_and_nonnull<VarDecl>(Decl) &&
138-
cast<VarDecl>(Decl)->hasLocalStorage())));
138+
cast<VarDecl>(Decl)->isLocalVarDeclOrParm())));
139139

140140
std::string DeclName = UseName;
141141
// The idea here is that the name should only be empty if this is an unnamed

clang/lib/3C/RewriteUtils.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,10 @@ std::string ArrayBoundsRewriter::getBoundsString(const PVConstraint *PV,
594594

595595
if (ValidBKey && !PV->hasSomeSizedArr()) {
596596
ABounds *ArrB = ABInfo.getBounds(DK);
597-
// Only we we have bounds and no pointer arithmetic on the variable.
598-
if (ArrB != nullptr) {
597+
// If we have pointer arithmetic and cannot add range bounds, then do not
598+
// emit any bounds string.
599+
if (ArrB != nullptr &&
600+
(!ABInfo.hasPointerArithmetic(DK) || ABInfo.canInferRangeBounds(DK))) {
599601
if (UseRange)
600602
BString = ArrB->mkRangeString(&ABInfo, D, BasePtr);
601603
else

clang/test/3C/range_bounds.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,27 @@ void test7(int *s) {
141141
for (int i = 0; i < 5; i++)
142142
s[i];
143143
}
144+
145+
// A structure field is handled as it was before implementing range bounds.
146+
// Future work could insert a new field, and update all struct initializer to
147+
// include it.
148+
struct s {
149+
int *a;
150+
// CHECK_ALL: _Array_ptr<int> a;
151+
};
152+
void test8() {
153+
struct s t;
154+
t.a++;
155+
t.a[0];
156+
// expected-error@-1 {{expression has unknown bounds}}
157+
}
158+
159+
// Same as above. Future work might figure out how to emit range bounds for
160+
// global variables.
161+
int *glob;
162+
// CHECK_ALL: _Array_ptr<int> glob = ((void *)0);
163+
void test9() {
164+
glob++;
165+
glob[0];
166+
// expected-error@-1 {{expression has unknown bounds}}
167+
}

0 commit comments

Comments
 (0)