Skip to content

Commit a6302b6

Browse files
committed
[-Wunsafe-buffer-usage] Check source location validity before using TypeLocs
The safe-buffer analysis analyzes TypeLocs of types of variable declarations in order to get source locations of them. However, in some cases, the source locations of a TypeLoc are not valid. Using invalid source locations results in assertion violation or incorrect analysis or fix-its. It is still not clear to me in what circumstances a TypeLoc does not have valid source locations (it looks like a bug in Clang to me, but it is not our responsibility to fix it). So we will conservatively give up the analysis when required source locations are not valid. Reviewed By: NoQ (Artem Dergachev) Differential Revision: https://reviews.llvm.org/D155667
1 parent dc37d5e commit a6302b6

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,8 +1385,18 @@ getPointeeTypeText(const ParmVarDecl *VD, const SourceManager &SM,
13851385
TypeLoc PteTyLoc = TyLoc.getUnqualifiedLoc().getNextTypeLoc();
13861386
SourceLocation VDNameStartLoc = VD->getLocation();
13871387

1388-
if (!SM.isBeforeInTranslationUnit(PteTyLoc.getSourceRange().getEnd(),
1389-
VDNameStartLoc)) {
1388+
if (!(VDNameStartLoc.isValid() && PteTyLoc.getSourceRange().isValid())) {
1389+
// We are expecting these locations to be valid. But in some cases, they are
1390+
// not all valid. It is a Clang bug to me and we are not responsible for
1391+
// fixing it. So we will just give up for now when it happens.
1392+
return std::nullopt;
1393+
}
1394+
1395+
// Note that TypeLoc.getEndLoc() returns the begin location of the last token:
1396+
SourceLocation PteEndOfTokenLoc =
1397+
Lexer::getLocForEndOfToken(PteTyLoc.getEndLoc(), 0, SM, LangOpts);
1398+
1399+
if (!SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, VDNameStartLoc)) {
13901400
// We only deal with the cases where the source text of the pointee type
13911401
// appears on the left-hand side of the variable identifier completely,
13921402
// including the following forms:
@@ -1401,13 +1411,8 @@ getPointeeTypeText(const ParmVarDecl *VD, const SourceManager &SM,
14011411
// `PteTy` via source ranges.
14021412
*QualifiersToAppend = PteTy.getQualifiers();
14031413
}
1404-
1405-
// Note that TypeLoc.getEndLoc() returns the begin location of the last token:
1406-
SourceRange CSR{
1407-
PteTyLoc.getBeginLoc(),
1408-
Lexer::getLocForEndOfToken(PteTyLoc.getEndLoc(), 0, SM, LangOpts)};
1409-
1410-
return getRangeText(CSR, SM, LangOpts)->str();
1414+
return getRangeText({PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts)
1415+
->str();
14111416
}
14121417

14131418
// Returns the text of the name (with qualifiers) of a `FunctionDecl`.

clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@ void unnamedPointeeType(PTR_TO_ANON p) { // expected-warning{{'p' is an unsafe
3333
}
3434
}
3535

36+
// The analysis requires accurate source location informations from
37+
// `TypeLoc`s of types of variable (parameter) declarations in order
38+
// to generate fix-its for them. But those information is not always
39+
// available (probably due to some bugs in clang but it is irrelevant
40+
// to the safe-buffer project). The following is an example. When
41+
// `_Atomic` is used, we cannot get valid source locations of the
42+
// pointee type of `unsigned *`. The analysis gives up in such a
43+
// case.
44+
// CHECK-NOT: fix-it:
45+
void typeLocSourceLocationInvalid(_Atomic unsigned *map) { // expected-warning{{'map' is an unsafe pointer used for buffer access}}
46+
map[5] = 5; // expected-note{{used in buffer access here}}
47+
}
48+
49+
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:33-[[@LINE+1]]:46}:"std::span<unsigned> map"
50+
void typeLocSourceLocationValid(unsigned *map) { // expected-warning{{'map' is an unsafe pointer used for buffer access}} \
51+
expected-note{{change type of 'map' to 'std::span' to preserve bounds information}}
52+
map[5] = 5; // expected-note{{used in buffer access here}}
53+
}
54+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void typeLocSourceLocationValid(unsigned *map) {return typeLocSourceLocationValid(std::span<unsigned>(map, <# size #>));}\n"
55+
3656
// We do not fix parameters participating unsafe operations for the
3757
// following functions/methods or function-like expressions:
3858

@@ -128,4 +148,3 @@ void parmWithDefaultValueDecl(int * x) {
128148
int tmp;
129149
tmp = x[5]; // expected-note{{used in buffer access here}}
130150
}
131-

0 commit comments

Comments
 (0)