Skip to content

Commit bd7bce2

Browse files
authored
Fix null-deref thanks to an attribute on a global declarator chunk (#83611)
This was reported (sort of) in a PR: #77703. The problem is that a declarator 'owns' an attributes allocation via an `AttributePool`. However, this example tries to copy a DeclaratorChunk from one Declarator to another, so when the temporary Declarator goes out of scope, it deletes the attribute it has tried to pass on via the chunk. This patch ensures that we copy the 'ownership' of the attribute correctly, and adds an assert to catch any other casess where this happens. Additionally, this was put in as a bug report, so this Fixes #83611
1 parent 252f3c9 commit bd7bce2

File tree

6 files changed

+40
-2
lines changed

6 files changed

+40
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,9 @@ Bug Fixes to C++ Support
295295
of templates. Previously we were diagnosing on any non-function template
296296
instead of only on class, alias, and variable templates, as last updated by
297297
CWG2032. Fixes (#GH83461)
298-
298+
- Fixed an issue where an attribute on a declarator would cause the attribute to
299+
be destructed prematurely. This fixes a pair of Chromium that were brought to
300+
our attention by an attempt to fix in (#GH77703). Fixes (#GH83611).
299301

300302
Bug Fixes to AST Handling
301303
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/DeclSpec.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,11 +2359,27 @@ class Declarator {
23592359
SetRangeEnd(EndLoc);
23602360
}
23612361

2362+
/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
2363+
/// EndLoc, which should be the last token of the chunk. This overload is for
2364+
/// copying a 'chunk' from another declarator, so it takes the pool that the
2365+
/// other Declarator owns so that it can 'take' the attributes from it.
2366+
void AddTypeInfo(const DeclaratorChunk &TI, AttributePool &OtherPool,
2367+
SourceLocation EndLoc) {
2368+
DeclTypeInfo.push_back(TI);
2369+
getAttributePool().takeFrom(DeclTypeInfo.back().getAttrs(), OtherPool);
2370+
2371+
if (!EndLoc.isInvalid())
2372+
SetRangeEnd(EndLoc);
2373+
}
2374+
23622375
/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
23632376
/// EndLoc, which should be the last token of the chunk.
23642377
void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) {
23652378
DeclTypeInfo.push_back(TI);
23662379

2380+
assert(TI.AttrList.empty() &&
2381+
"Cannot add a declarator chunk with attributes with this overload");
2382+
23672383
if (!EndLoc.isInvalid())
23682384
SetRangeEnd(EndLoc);
23692385
}

clang/include/clang/Sema/ParsedAttr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ class AttributeFactory {
680680
~AttributeFactory();
681681
};
682682

683+
class ParsedAttributesView;
683684
class AttributePool {
684685
friend class AttributeFactory;
685686
friend class ParsedAttributes;
@@ -734,6 +735,10 @@ class AttributePool {
734735
pool.Attrs.clear();
735736
}
736737

738+
/// Removes the attributes from \c List, which are owned by \c Pool, and adds
739+
/// them at the end of this \c AttributePool.
740+
void takeFrom(ParsedAttributesView &List, AttributePool &Pool);
741+
737742
ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange,
738743
IdentifierInfo *scopeName, SourceLocation scopeLoc,
739744
ArgsUnion *args, unsigned numArgs, ParsedAttr::Form form,
@@ -816,6 +821,7 @@ class AttributePool {
816821
};
817822

818823
class ParsedAttributesView {
824+
friend class AttributePool;
819825
using VecTy = llvm::SmallVector<ParsedAttr *>;
820826
using SizeType = decltype(std::declval<VecTy>().size());
821827

clang/lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7928,7 +7928,7 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
79287928
// Adding back the bracket info to the end of the Declarator.
79297929
for (unsigned i = 0, e = TempDeclarator.getNumTypeObjects(); i < e; ++i) {
79307930
const DeclaratorChunk &Chunk = TempDeclarator.getTypeObject(i);
7931-
D.AddTypeInfo(Chunk, SourceLocation());
7931+
D.AddTypeInfo(Chunk, TempDeclarator.getAttributePool(), SourceLocation());
79327932
}
79337933

79347934
// The missing identifier would have been diagnosed in ParseDirectDeclarator.

clang/lib/Sema/ParsedAttr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ void AttributePool::takePool(AttributePool &pool) {
100100
pool.Attrs.clear();
101101
}
102102

103+
void AttributePool::takeFrom(ParsedAttributesView &List, AttributePool &Pool) {
104+
assert(&Pool != this && "AttributePool can't take attributes from itself");
105+
llvm::for_each(List.AttrList, [&Pool](ParsedAttr *A) { Pool.remove(A); });
106+
Attrs.insert(Attrs.end(), List.AttrList.begin(), List.AttrList.end());
107+
}
108+
103109
namespace {
104110

105111
#include "clang/Sema/AttrParsedAttrImpl.inc"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
// expected-error@+5{{brackets are not allowed here}}
4+
// expected-error@+4{{a type specifier is required for all declarations}}
5+
// expected-warning@+3{{unknown attribute 'h' ignored}}
6+
// expected-error@+2{{definition of variable with array type}}
7+
// expected-error@+1{{expected ';'}}
8+
[][[h]]l

0 commit comments

Comments
 (0)