Skip to content

Commit efb19b6

Browse files
committed
[-Wunsafe-buffer-usage] Add unique_ptr <T[]> accesses
1 parent eb9afef commit efb19b6

File tree

4 files changed

+56
-5
lines changed

4 files changed

+56
-5
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,7 @@ static bool isSupportedVariable(const DeclRefExpr &Node) {
13191319
return D != nullptr && isa<VarDecl>(D);
13201320
}
13211321

1322+
// Returns true for RecordDecl of type std::unique_ptr<T[]>
13221323
static bool isUniquePtrArray(const CXXRecordDecl *RecordDecl) {
13231324
if (!RecordDecl || !RecordDecl->isInStdNamespace() ||
13241325
RecordDecl->getNameAsString() != "unique_ptr")
@@ -1343,6 +1344,7 @@ static bool isUniquePtrArray(const CXXRecordDecl *RecordDecl) {
13431344
}
13441345

13451346
class UniquePtrArrayAccessGadget : public WarningGadget {
1347+
private:
13461348
static constexpr const char *const AccessorTag = "unique_ptr_array_access";
13471349
const CXXOperatorCallExpr *AccessorExpr;
13481350

@@ -1374,13 +1376,21 @@ class UniquePtrArrayAccessGadget : public WarningGadget {
13741376
if (!Method)
13751377
return false;
13761378

1377-
if (Method->getNameAsString() != "operator[]")
1379+
if (Method->getOverloadedOperator() != OO_Subscript)
13781380
return false;
13791381

13801382
const CXXRecordDecl *RecordDecl = Method->getParent();
13811383
if (!isUniquePtrArray(RecordDecl))
13821384
return false;
13831385

1386+
const Expr *IndexExpr = OpCall->getArg(1);
1387+
llvm::APSInt IndexValue;
1388+
1389+
// Allow [0]
1390+
if (IndexExpr->EvaluateAsInt(IndexValue, Ctx) && IndexValue.isZero()) {
1391+
return false;
1392+
}
1393+
13841394
Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
13851395
return true;
13861396
}

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2613,10 +2613,8 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
26132613
std::string Message;
26142614

26152615
Loc = Node.get<Stmt>()->getBeginLoc();
2616-
Message = "Direct operator[] access on std::unique_ptr<T[]> is unsafe "
2617-
"(no bounds check).";
26182616
S.Diag(Loc, diag::warn_unsafe_buffer_usage_unique_ptr_array_access)
2619-
<< Message << Node.getSourceRange();
2617+
<< Node.getSourceRange();
26202618
}
26212619

26222620
bool isSafeBufferOptOut(const SourceLocation &Loc) const override {

clang/test/SemaCXX/warn-unsafe-buffer-usage-debug-unclaimed/warn-unsafe-buffer-usage-debug-unclaimed.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ template <class T> class unique_ptr {
4242

4343
void basic_unique_ptr() {
4444
std::unique_ptr<int[]> p1;
45-
p1[0]; // expected-warning{{direct access using operator[] on std::unique_ptr<T[]> is unsafe due to lack of bounds checking}}
45+
p1[1]; // expected-warning{{direct access using operator[] on std::unique_ptr<T[]> is unsafe due to lack of bounds checking}}
4646
}
4747

4848
// CHECK: Root # 1
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %clang_cc1 -Wno-unused-value -Wunsafe-buffer-usage -fsafe-buffer-usage-suggestions -std=c++20 -verify=expected %s
2+
3+
// This debugging facility is only available in debug builds.
4+
//
5+
// REQUIRES: asserts
6+
7+
namespace std {
8+
inline namespace __1 {
9+
template <class T> class unique_ptr {
10+
public:
11+
T &operator[](long long i) const;
12+
};
13+
} // namespace __1
14+
} // namespace std
15+
16+
void basic_unique_ptr() {
17+
std::unique_ptr<int[]> p1;
18+
int i = 2;
19+
20+
p1[0]; // This is allowed
21+
22+
p1[1]; // expected-warning{{direct access using operator[] on std::unique_ptr<T[]> is unsafe due to lack of bounds checking}}
23+
24+
p1[i]; // expected-warning{{direct access using operator[] on std::unique_ptr<T[]> is unsafe due to lack of bounds checking}}
25+
26+
p1[i + 5]; // expected-warning{{direct access using operator[] on std::unique_ptr<T[]> is unsafe due to lack of bounds checking}}
27+
}
28+
29+
// CHECK: Root # 1
30+
// CHECK: |- DeclRefExpr # 4
31+
// CHECK: |-- UnaryOperator(++) # 1
32+
// CHECK: |--- CompoundStmt # 1
33+
// CHECK: |-- ImplicitCastExpr(LValueToRValue) # 1
34+
// CHECK: |--- BinaryOperator(+) # 1
35+
// CHECK: |---- ParenExpr # 1
36+
// CHECK: |----- BinaryOperator(+) # 1
37+
// CHECK: |------ ParenExpr # 1
38+
// CHECK: |------- UnaryOperator(*) # 1
39+
// CHECK: |-------- CompoundStmt # 1
40+
// CHECK: |-- BinaryOperator(-=) # 1
41+
// CHECK: |--- CompoundStmt # 1
42+
// CHECK: |-- UnaryOperator(--) # 1
43+
// CHECK: |--- CompoundStmt # 1

0 commit comments

Comments
 (0)