Skip to content

Commit c2ed30c

Browse files
committed
allow redundant bounds annotations in API notes
1 parent 9b72e2c commit c2ed30c

File tree

7 files changed

+156
-23
lines changed

7 files changed

+156
-23
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15514,7 +15514,8 @@ class Sema final : public SemaBase {
1551415514
void applyPtrCountedByEndedByAttr(Decl *D, unsigned Level,
1551515515
AttributeCommonInfo::Kind Kind,
1551615516
Expr *AttrArg, SourceLocation Loc,
15517-
SourceRange Range, StringRef DiagName);
15517+
SourceRange Range, StringRef DiagName,
15518+
bool OriginatesInAPINotes = false);
1551815519

1551915520
/// Perform Bounds Safety Semantic checks for assigning to a `__counted_by` or
1552015521
/// `__counted_by_or_null` pointer type \param LHSTy.

clang/lib/Sema/SemaAPINotes.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,9 @@ static void applyBoundsSafety(Sema &S, ValueDecl *D,
452452
break;
453453
}
454454

455-
S.applyPtrCountedByEndedByAttr(D, *Info.getLevel(), Kind, ParsedExpr.get(),
456-
D->getLocation(), D->getSourceRange(),
457-
AttrName);
455+
S.applyPtrCountedByEndedByAttr(
456+
D, *Info.getLevel(), Kind, ParsedExpr.get(), D->getLocation(),
457+
D->getSourceRange(), AttrName, /* originates in API notes */ true);
458458
}
459459
}
460460
/* TO_UPSTREAM(BoundsSafety) OFF */

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5411,16 +5411,17 @@ class ConstructDynamicBoundType
54115411
const BoundsAttributedType *ConstructedType = nullptr;
54125412
unsigned Level;
54135413
bool ScopeCheck;
5414+
bool AllowRedecl;
54145415
bool AutoPtrAttributed = false;
5415-
bool AllowCountRedecl = false;
54165416
bool AtomicErrorEmitted = false;
54175417

54185418
public:
54195419
explicit ConstructDynamicBoundType(Sema &S, unsigned Level,
54205420
const StringRef DiagName, Expr *ArgExpr,
5421-
SourceLocation Loc, bool ScopeCheck)
5421+
SourceLocation Loc, bool ScopeCheck,
5422+
bool AllowRedecl)
54225423
: S(S), DiagName(DiagName), ArgExpr(ArgExpr), Loc(Loc), Level(Level),
5423-
ScopeCheck(ScopeCheck) {}
5424+
ScopeCheck(ScopeCheck), AllowRedecl(AllowRedecl) {}
54245425

54255426
QualType Visit(QualType T) {
54265427
SplitQualType SQT = T.split();
@@ -5449,7 +5450,6 @@ class ConstructDynamicBoundType
54495450

54505451
QualType VisitFunctionProtoType(const FunctionProtoType *FPT) {
54515452
// The attribute applies to the return type.
5452-
SaveAndRestore<bool> AllowCountRedeclLocal(AllowCountRedecl, true);
54535453
QualType QT = Visit(FPT->getReturnType());
54545454
if (QT.isNull())
54555455
return QualType();
@@ -5461,7 +5461,6 @@ class ConstructDynamicBoundType
54615461

54625462
QualType VisitFunctionNoProtoType(const FunctionNoProtoType *FPT) {
54635463
// The attribute applies to the return type.
5464-
SaveAndRestore<bool> AllowCountRedeclLocal(AllowCountRedecl, true);
54655464
QualType QT = Visit(FPT->getReturnType());
54665465
if (QT.isNull())
54675466
return QualType();
@@ -5592,8 +5591,10 @@ class ConstructCountAttributedType :
55925591
explicit ConstructCountAttributedType(Sema &S, unsigned Level,
55935592
const StringRef DiagName, Expr *ArgExpr,
55945593
SourceLocation Loc, bool CountInBytes,
5595-
bool OrNull, bool ScopeCheck = false)
5596-
: ConstructDynamicBoundType(S, Level, DiagName, ArgExpr, Loc, ScopeCheck),
5594+
bool OrNull, bool AllowRedecl,
5595+
bool ScopeCheck = false)
5596+
: ConstructDynamicBoundType(S, Level, DiagName, ArgExpr, Loc, ScopeCheck,
5597+
AllowRedecl),
55975598
CountInBytes(CountInBytes), OrNull(OrNull) {
55985599
if (!ArgExpr->getType()->isIntegralOrEnumerationType()) {
55995600
S.Diag(Loc, diag::err_attribute_argument_type_for_bounds_safety_count)
@@ -5661,7 +5662,7 @@ class ConstructCountAttributedType :
56615662
}
56625663

56635664
QualType DiagnoseConflictingType(const CountAttributedType *T) {
5664-
if (AllowCountRedecl) {
5665+
if (AllowRedecl) {
56655666
QualType NewTy = BuildDynamicBoundType(T->desugar());
56665667
const auto *NewDCPTy = NewTy->getAs<CountAttributedType>();
56675668
// We don't have a way to distinguish if '__counted_by' is conflicting or has been
@@ -5684,6 +5685,16 @@ class ConstructCountAttributedType :
56845685
return QualType();
56855686
}
56865687

5688+
QualType VisitFunctionProtoType(const FunctionProtoType *FPT) {
5689+
SaveAndRestore<bool> AllowRedeclLocal(AllowRedecl, true);
5690+
return ConstructDynamicBoundType::VisitFunctionProtoType(FPT);
5691+
}
5692+
5693+
QualType VisitFunctionNoProtoType(const FunctionNoProtoType *FPT) {
5694+
SaveAndRestore<bool> AllowRedeclLocal(AllowRedecl, true);
5695+
return ConstructDynamicBoundType::VisitFunctionNoProtoType(FPT);
5696+
}
5697+
56875698
QualType DiagnoseConflictingType(const DynamicRangePointerType *T) {
56885699
S.Diag(Loc, diag::err_bounds_safety_conflicting_count_range_attributes);
56895700
return QualType();
@@ -5858,9 +5869,10 @@ class ConstructDynamicRangePointerType :
58585869
public:
58595870
explicit ConstructDynamicRangePointerType(
58605871
Sema &S, unsigned Level, const StringRef DiagName, Expr *ArgExpr,
5861-
SourceLocation Loc, bool ScopeCheck = false,
5872+
SourceLocation Loc, bool AllowRedecl, bool ScopeCheck = false,
58625873
std::optional<TypeCoupledDeclRefInfo> StartPtrInfo = std::nullopt)
5863-
: ConstructDynamicBoundType(S, Level, DiagName, ArgExpr, Loc, ScopeCheck),
5874+
: ConstructDynamicBoundType(S, Level, DiagName, ArgExpr, Loc, ScopeCheck,
5875+
AllowRedecl),
58645876
StartPtrInfo(StartPtrInfo) {
58655877
assert(ArgExpr->getType()->isPointerType());
58665878
}
@@ -5900,11 +5912,11 @@ class ConstructDynamicRangePointerType :
59005912
}
59015913

59025914
QualType VisitDynamicRangePointerType(const DynamicRangePointerType *T) {
5903-
if (Level == 0 && T->getEndPointer() == nullptr) {
5904-
// T is a started_by() pointer type.
5915+
if (Level == 0 && (AllowRedecl || T->getEndPointer() == nullptr)) {
5916+
// T could be a started_by() pointer type.
59055917
Expr *StartPtr = T->getStartPointer();
59065918
auto StartPtrDecls = T->getStartPtrDecls();
5907-
assert(StartPtr);
5919+
assert(StartPtr || AllowRedecl);
59085920

59095921
assert(ConstructedType == nullptr);
59105922
// Construct an ended_by() pointer type.
@@ -5917,6 +5929,20 @@ class ConstructDynamicRangePointerType :
59175929
Expr *EndPtr = DRPT->getEndPointer();
59185930
auto EndPtrDecls = DRPT->getEndPtrDecls();
59195931
assert(EndPtr);
5932+
if (auto OldEndPtr = T->getEndPointer()) {
5933+
assert(AllowRedecl);
5934+
llvm::FoldingSetNodeID NewID;
5935+
llvm::FoldingSetNodeID OldID;
5936+
EndPtr->Profile(NewID, S.Context, /*Canonical*/ true);
5937+
OldEndPtr->Profile(OldID, S.Context, /*Canonical*/ true);
5938+
5939+
if (NewID != OldID) {
5940+
S.Diag(Loc, diag::err_bounds_safety_conflicting_pointer_attributes)
5941+
<< /* pointer */ 1 << /* end */ 3;
5942+
ConstructedType = nullptr;
5943+
return QualType();
5944+
}
5945+
}
59205946

59215947
// ConstructType was already set while visiting the nested PointerType.
59225948
// Reconstruct DRPT by merging started_by and ended_by.
@@ -6383,7 +6409,8 @@ diagnoseRangeDependentDecls(Sema &S, const ValueDecl *TheDepender,
63836409
void Sema::applyPtrCountedByEndedByAttr(Decl *D, unsigned Level,
63846410
AttributeCommonInfo::Kind Kind,
63856411
Expr *AttrArg, SourceLocation Loc,
6386-
SourceRange Range, StringRef DiagName) {
6412+
SourceRange Range, StringRef DiagName,
6413+
bool OriginatesInAPINotes) {
63876414
// If the decl is invalid, the indirection Level might not exist in the type,
63886415
// since the type may have not been constructed correctly. Example:
63896416
// 'int (*param)[__counted_by_or_null(10)][]'
@@ -6571,13 +6598,15 @@ void Sema::applyPtrCountedByEndedByAttr(Decl *D, unsigned Level,
65716598
}
65726599

65736600
auto TypeConstructor = ConstructDynamicRangePointerType(
6574-
*this, Level, DiagName, AttrArg, Loc, ScopeCheck, StartPtrInfo);
6601+
*this, Level, DiagName, AttrArg, Loc, OriginatesInAPINotes, ScopeCheck,
6602+
StartPtrInfo);
65756603
NewDeclTy = TypeConstructor.Visit(DeclTy);
65766604
HadAtomicError = TypeConstructor.hadAtomicError();
65776605
ConstructedType = TypeConstructor.getConstructedType();
65786606
} else {
65796607
auto TypeConstructor = ConstructCountAttributedType(
6580-
*this, Level, DiagName, AttrArg, Loc, CountInBytes, OrNull, ScopeCheck);
6608+
*this, Level, DiagName, AttrArg, Loc, CountInBytes, OrNull,
6609+
OriginatesInAPINotes, ScopeCheck);
65816610
NewDeclTy = TypeConstructor.Visit(DeclTy);
65826611
HadAtomicError = TypeConstructor.hadAtomicError();
65836612
ConstructedType = TypeConstructor.getConstructedType();

clang/test/APINotes/Inputs/Headers/BoundsUnsafe.apinotes

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,58 @@ Functions:
7878
BoundsSafety:
7979
Kind: counted_by
8080
BoundedBy: len
81+
- Name: asdf_counted_redundant
82+
Parameters:
83+
- Position: 0
84+
BoundsSafety:
85+
Kind: counted_by
86+
BoundedBy: len
87+
- Name: asdf_ended_chained
88+
Parameters:
89+
- Position: 0
90+
BoundsSafety:
91+
Kind: ended_by
92+
Level: 0
93+
BoundedBy: mid
94+
- Position: 1
95+
BoundsSafety:
96+
Kind: ended_by
97+
Level: 0
98+
BoundedBy: end
99+
- Name: asdf_ended_chained_reverse
100+
Parameters:
101+
- Position: 1
102+
BoundsSafety:
103+
Kind: ended_by
104+
Level: 0
105+
BoundedBy: end
106+
- Position: 0
107+
BoundsSafety:
108+
Kind: ended_by
109+
Level: 0
110+
BoundedBy: mid
111+
- Name: asdf_ended_already_started
112+
Parameters:
113+
- Position: 1
114+
BoundsSafety:
115+
Kind: ended_by
116+
Level: 0
117+
BoundedBy: end
118+
- Name: asdf_ended_already_ended
119+
Parameters:
120+
- Position: 0
121+
BoundsSafety:
122+
Kind: ended_by
123+
Level: 0
124+
BoundedBy: mid
125+
- Name: asdf_ended_redundant
126+
Parameters:
127+
- Position: 0
128+
BoundsSafety:
129+
Kind: ended_by
130+
Level: 0
131+
BoundedBy: end
81132
- Name: asdf_nterm
82133
Parameters:
83134
- Position: 0
84135
Type: "int * __attribute__((__terminated_by__(0)))"
85-

clang/test/APINotes/Inputs/Headers/BoundsUnsafe.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,12 @@ void asdf_counted_const(int * buf);
1010
void asdf_counted_nullable(int len, int * _Nullable buf);
1111
void asdf_counted_noescape(int * buf, int len);
1212
void asdf_counted_default_level(int * buf, int len);
13+
void asdf_counted_redundant(int * __attribute__((__counted_by__(len))) buf, int len);
14+
15+
void asdf_ended_chained(int * buf, int * mid, int * end);
16+
void asdf_ended_chained_reverse(int * buf, int * mid, int * end);
17+
void asdf_ended_already_started(int * __attribute__((__ended_by__(mid))) buf, int * mid, int * end);
18+
void asdf_ended_already_ended(int * buf, int * mid __attribute__((__ended_by__(end))), int * end);
19+
void asdf_ended_redundant(int * __attribute__((__ended_by__(end))) buf, int * end);
1320

1421
void asdf_nterm(char * buf);

clang/test/APINotes/boundssafety-errors.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ Name: OOBLevel
5555
Kind: counted_by
5656
Level: 0
5757
BoundedBy: static_len
58+
- Name: mismatching_count
59+
Parameters:
60+
- Position: 0
61+
BoundsSafety:
62+
Kind: counted_by
63+
Level: 0
64+
BoundedBy: apinote_len
65+
- Name: mismatching_end
66+
Parameters:
67+
- Position: 0
68+
BoundsSafety:
69+
Kind: ended_by
70+
Level: 0
71+
BoundedBy: apinote_end
5872
//--- SemaErrors.h
5973
// CHECK: SemaErrors.h:{{.*}}:{{.*}}: error: __counted_by attribute only applies to pointer arguments
6074
// CHECK-NEXT: oob_level
@@ -73,6 +87,12 @@ void wrong_name(int * buf, int len2);
7387
// CHECK-NEXT: wrong_scope
7488
int static_len = 5;
7589
void wrong_scope(int * buf);
90+
// CHECK: SemaErrors.h:{{.*}}:{{.*}}: error: pointer cannot have more than one count attribute
91+
// CHECK-NEXT: mismatching_count
92+
void mismatching_count(int * __attribute__((__counted_by__(header_len))) buf, int apinote_len, int header_len);
93+
// CHECK: SemaErrors.h:{{.*}}:{{.*}}: error: pointer cannot have more than one end attribute
94+
// CHECK-NEXT: mismatching_end
95+
void mismatching_end(int * __attribute__((__ended_by__(header_end))) buf, int * apinote_end, int * header_end);
7696
// CHECK: SemaErrors.c:{{.*}}:{{.*}}: fatal error: could not build module 'SemaErrors'
7797

7898

clang/test/APINotes/boundssafety.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// CHECK: asdf_sized_n 'void (int * __sized_by_or_null(size), int)'
1616
// CHECK: buf 'int * __sized_by_or_null(size)':'int *'
1717

18-
// CHECK: asdf_ended 'void (int * __ended_by(end), int * /* __started_by(buf) */ )'
18+
// CHECK: asdf_ended 'void (int * __ended_by(end), int * /* __started_by(buf) */ )'
1919
// CHECK: buf 'int * __ended_by(end)':'int *'
2020
// CHECK: end 'int * /* __started_by(buf) */ ':'int *'
2121

@@ -38,6 +38,32 @@
3838
// CHECK: asdf_counted_default_level 'void (int * __counted_by(len), int)'
3939
// CHECK: buf 'int * __counted_by(len)':'int *'
4040

41+
// CHECK: asdf_counted_redundant 'void (int * __counted_by(len), int)'
42+
// CHECK: buf 'int * __counted_by(len)':'int *'
43+
44+
// CHECK: asdf_ended_chained 'void (int * __ended_by(mid), int * __ended_by(end) /* __started_by(buf) */ , int * /* __started_by(mid) */ )'
45+
// CHECK: buf 'int * __ended_by(mid)':'int *'
46+
// CHECK: mid 'int * __ended_by(end) /* __started_by(buf) */ ':'int *'
47+
// CHECK: end 'int * /* __started_by(mid) */ ':'int *'
48+
49+
// CHECK: asdf_ended_chained_reverse 'void (int * __ended_by(mid), int * __ended_by(end) /* __started_by(buf) */ , int * /* __started_by(mid) */ )'
50+
// CHECK: buf 'int * __ended_by(mid)':'int *'
51+
// CHECK: mid 'int * __ended_by(end) /* __started_by(buf) */ ':'int *'
52+
// CHECK: end 'int * /* __started_by(mid) */ ':'int *'
53+
54+
// CHECK: asdf_ended_already_started 'void (int * __ended_by(mid), int * __ended_by(end) /* __started_by(buf) */ , int * /* __started_by(mid) */ )'
55+
// CHECK: buf 'int * __ended_by(mid)':'int *'
56+
// CHECK: mid 'int * __ended_by(end) /* __started_by(buf) */ ':'int *'
57+
// CHECK: end 'int * /* __started_by(mid) */ ':'int *'
58+
59+
// CHECK: asdf_ended_already_ended 'void (int * __ended_by(mid), int * __ended_by(end) /* __started_by(buf) */ , int * /* __started_by(mid) */ )'
60+
// CHECK: buf 'int * __ended_by(mid)':'int *'
61+
// CHECK: mid 'int * __ended_by(end) /* __started_by(buf) */ ':'int *'
62+
// CHECK: end 'int * /* __started_by(mid) */ ':'int *'
63+
64+
// CHECK: asdf_ended_redundant 'void (int * __ended_by(end), int * /* __started_by(buf) */ )'
65+
// CHECK: buf 'int * __ended_by(end)':'int *'
66+
// CHECK: end 'int * /* __started_by(buf) */ ':'int *'
67+
4168
// CHECK: asdf_nterm 'void (int * __terminated_by(0))'
4269
// CHECK: buf 'int * __terminated_by(0)':'int *'
43-

0 commit comments

Comments
 (0)