Skip to content

Fix null-deref thanks to an attribute on a global declarator chunk #83611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,9 @@ Bug Fixes to C++ Support
of templates. Previously we were diagnosing on any non-function template
instead of only on class, alias, and variable templates, as last updated by
CWG2032. Fixes (#GH83461)

- Fixed an issue where an attribute on a declarator would cause the attribute to
be destructed prematurely. This fixes a pair of Chromium that were brought to
our attention by an attempt to fix in (#GH77703). Fixes (#GH83611).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
16 changes: 16 additions & 0 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -2359,11 +2359,27 @@ class Declarator {
SetRangeEnd(EndLoc);
}

/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
/// EndLoc, which should be the last token of the chunk. This overload is for
/// copying a 'chunk' from another declarator, so it takes the pool that the
/// other Declarator owns so that it can 'take' the attributes from it.
void AddTypeInfo(const DeclaratorChunk &TI, AttributePool &OtherPool,
SourceLocation EndLoc) {
DeclTypeInfo.push_back(TI);
getAttributePool().takeFrom(DeclTypeInfo.back().getAttrs(), OtherPool);

if (!EndLoc.isInvalid())
SetRangeEnd(EndLoc);
}

/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
/// EndLoc, which should be the last token of the chunk.
void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) {
DeclTypeInfo.push_back(TI);

assert(TI.AttrList.empty() &&
"Cannot add a declarator chunk with attributes with this overload");

if (!EndLoc.isInvalid())
SetRangeEnd(EndLoc);
}
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/ParsedAttr.h
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ class AttributeFactory {
~AttributeFactory();
};

class ParsedAttributesView;
class AttributePool {
friend class AttributeFactory;
friend class ParsedAttributes;
Expand Down Expand Up @@ -734,6 +735,10 @@ class AttributePool {
pool.Attrs.clear();
}

/// Removes the attributes from \c List, which are owned by \c Pool, and adds
/// them at the end of this \c AttributePool.
void takeFrom(ParsedAttributesView &List, AttributePool &Pool);

ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
ArgsUnion *args, unsigned numArgs, ParsedAttr::Form form,
Expand Down Expand Up @@ -816,6 +821,7 @@ class AttributePool {
};

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

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7928,7 +7928,7 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
// Adding back the bracket info to the end of the Declarator.
for (unsigned i = 0, e = TempDeclarator.getNumTypeObjects(); i < e; ++i) {
const DeclaratorChunk &Chunk = TempDeclarator.getTypeObject(i);
D.AddTypeInfo(Chunk, SourceLocation());
D.AddTypeInfo(Chunk, TempDeclarator.getAttributePool(), SourceLocation());
}

// The missing identifier would have been diagnosed in ParseDirectDeclarator.
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/ParsedAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ void AttributePool::takePool(AttributePool &pool) {
pool.Attrs.clear();
}

void AttributePool::takeFrom(ParsedAttributesView &List, AttributePool &Pool) {
assert(&Pool != this && "AttributePool can't take attributes from itself");
llvm::for_each(List.AttrList, [&Pool](ParsedAttr *A) { Pool.remove(A); });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove from the pool after we added them to the Attrs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean reverse the order of the remove/add? Based on takeAllFrom and takeOneFrom (https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Sema/ParsedAttr.h#L953), we are consistently inconsistent :)

In this case, I was working from takeOneFrom so I ended up in this order, but if there is a good reason to prefer one over the other, I can switch.

Attrs.insert(Attrs.end(), List.AttrList.begin(), List.AttrList.end());
}

namespace {

#include "clang/Sema/AttrParsedAttrImpl.inc"
Expand Down
8 changes: 8 additions & 0 deletions clang/test/Parser/cxx-declarator-attribute-crash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s

// expected-error@+5{{brackets are not allowed here}}
// expected-error@+4{{a type specifier is required for all declarations}}
// expected-warning@+3{{unknown attribute 'h' ignored}}
// expected-error@+2{{definition of variable with array type}}
// expected-error@+1{{expected ';'}}
[][[h]]l