This is an archive of the discontinued LLVM Phabricator instance.

Reland: [clang][ExprConstant] fix __builtin_object_size for flexible array members
ClosedPublic

Authored by nickdesaulniers on May 18 2023, 11:14 AM.

Details

Summary

As reported by @kees, GCC treats __builtin_object_size of structures
containing flexible array members (aka arrays with incomplete type) not
just as the sizeof the underlying type, but additionally the size of the
members in a designated initializer list.

Fixes: https://github.com/llvm/llvm-project/issues/62789

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald TranscriptMay 18 2023, 11:14 AM
nickdesaulniers requested review of this revision.May 18 2023, 11:14 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 18 2023, 11:14 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
erichkeane added inline comments.May 18 2023, 11:17 AM
clang/lib/AST/ExprConstant.cpp
11755

Isn't this a possible null-deref?

clang/lib/AST/ExprConstant.cpp
11755

I don't think so; in fact, I can use cast and get rather than dyn_cast_or_null and dyn_cast here.

Just because we have a pointer doesn't mean it's possibly nullptr; I don't think we can reach this code patch for evaluating the __builtin_object_size of a struct with a flexible array member if the LValue doesn't have a corresponding VarDecl.

  • use stronger casts, combine patches
erichkeane added inline comments.May 18 2023, 11:30 AM
clang/lib/AST/ExprConstant.cpp
11755

Of course that is a possibility. You shouldn't use dyn_cast right before a dereference, this should definitely be using cast/get, since they assert.

What does the LValue have when the dynamic struct does not have an initializer? Or just an empty one?

clang/lib/AST/ExprConstant.cpp
11755

s/code patch/code path/

erichkeane added a reviewer: Restricted Project.May 18 2023, 11:33 AM

Added clang-vendors in case this is a breaking change? It also needs a release note (likely both in the potentially breaking changes section, and the bug fix section).

clang/lib/AST/ExprConstant.cpp
11755

What does the LValue have when the dynamic struct does not have an initializer? Or just an empty one?

Tested:

struct foo {
    int x;
    int y[];
};

static struct foo instance = {
    .x = 3,
    // .y = { 5, 10, 15, },
};

unsigned long foo (void) {
    return __builtin_object_size(&instance, 1);
}

With the following values for .y in instance:

  1. .y = { 5, 10, 15 }: foo returns 16.
  2. .y = {},: foo returns 4.
  3. <.y is not specified or explicitly initialized>: foo returns 4.
  • add release note

Thanks for testing those! Can you add them to the object-size.c if they aren't already tested?

  • add release note on bugfix
erichkeane added inline comments.May 18 2023, 11:41 AM
clang/docs/ReleaseNotes.rst
296

We should probably also release-note in this seciton.

nickdesaulniers marked 3 inline comments as done.May 18 2023, 11:45 AM
  • slightly reword bug fix release note
erichkeane accepted this revision.May 18 2023, 11:52 AM

I'm OK with this, but please give the clang-vendors folks a few days to comment before committing this. Thanks for your patience!

This revision is now accepted and ready to land.May 18 2023, 11:52 AM

Sure, thanks for the quick turnaround time on reviews! 🍻

This also changes the behavior of __builtin_dynamic_object_size (see @kees ' full example: https://github.com/llvm/llvm-project/issues/62789#issue-1714764560). s/changes/fixes/. Let me add more tests and notes about that.

  • test __builtin_dynamic_object_size too, add that to release notes
efriedma added inline comments.
clang/lib/AST/ExprConstant.cpp
11755

This might have been missed in the discussion here, but what actually ensures we have a VarDecl here? I guess most other LValueBases can't actually have a struct type, but a CompoundLiteralExpr can. (Looking briefly at the code, I can't find any other possibilities at the moment, but in any case, the assumption seems pretty fragile.)

clang/lib/AST/ExprConstant.cpp
11755

I assume that the code works as such:

struct foo my_foo;
return __builtin_object_size(&foo, 1);

foo is a VarDecl otherwise how do you take the address? What other expression could be passed to __builtin_object_size that isn't a reference to a variable?

efriedma added inline comments.May 22 2023, 1:08 PM
clang/lib/AST/ExprConstant.cpp
11755

__builtin_object_size(&(struct S){}, 1)? Not really a useful construct, but we don't reject it.

clang/lib/AST/ExprConstant.cpp
11755

This change causes an assertion failure on the following test case. The memset is important for some reason.

saugustine@saugustine-desktop:~/llvm/build $ cat t.c
struct foo {
  unsigned char x;
  unsigned char	data[];
};

extern void *memset (void *__s, int __c, unsigned long __n);

void bar(void)
{
  struct foo bat;
  memset(&bat, 0, sizeof(bat));
}
saugustine@saugustine-desktop:~/llvm/build $ ./bin/clang -c t.c
clang: /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/AST/Decl.cpp:2786: clang::CharUnits clang::VarDecl::getFlexibleArrayInitChars(const clang::ASTContext &) const: Assertion `hasInit() && "Expect initializer to check for flexible array init"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: ./bin/clang -c t.c
1.	t.c:11:30: current parser token ')'
2.	t.c:9:1: parsing function body 'bar'
3.	t.c:9:1: in compound statement ('{}')
 #0 0x000055bf947c1d7d llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /usr/local/google/home/saugustine/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:602:11
 #1 0x000055bf947c21fb PrintStackTraceSignalHandler(void*) /usr/local/google/home/saugustine/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:675:1
 #2 0x000055bf947c0496 llvm::sys::RunSignalHandlers() /usr/local/google/home/saugustine/llvm/llvm-project/llvm/lib/Support/Signals.cpp:104:5
 #3 0x000055bf947c15ee llvm::sys::CleanupOnSignal(unsigned long) /usr/local/google/home/saugustine/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:368:1
 #4 0x000055bf946ff954 (anonymous namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) /usr/local/google/home/saugustine/llvm/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:0:7
 #5 0x000055bf946ffd12 CrashRecoverySignalHandler(int) /usr/local/google/home/saugustine/llvm/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:391:1
 #6 0x00007f95ab65af90 (/lib/x86_64-linux-gnu/libc.so.6+0x3bf90)
 #7 0x00007f95ab6a9ccc __pthread_kill_implementation ./nptl/./nptl/pthread_kill.c:44:76
 #8 0x00007f95ab65aef2 raise ./signal/../sysdeps/posix/raise.c:27:6
 #9 0x00007f95ab645472 abort ./stdlib/./stdlib/abort.c:81:7
#10 0x00007f95ab645395 _nl_load_domain ./intl/./intl/loadmsgcat.c:1177:9
#11 0x00007f95ab653df2 (/lib/x86_64-linux-gnu/libc.so.6+0x34df2)
#12 0x000055bf9a6a62cf clang::VarDecl::getFlexibleArrayInitChars(clang::ASTContext const&) const /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/AST/Decl.cpp:0:3
#13 0x000055bf9a89094b determineEndOffset((anonymous namespace)::EvalInfo&, clang::SourceLocation, unsigned int, (anonymous namespace)::LValue const&, clang::CharUnits&)::$_15::operator()(clang::QualType, clang::CharUnits&) const /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/AST/ExprConstant.cpp:11741:21
#14 0x000055bf9a89024e determineEndOffset((anonymous namespace)::EvalInfo&, clang::SourceLocation, unsigned int, (anonymous namespace)::LValue const&, clang::CharUnits&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/AST/ExprConstant.cpp:11763:5
#15 0x000055bf9a7dbb62 tryEvaluateBuiltinObjectSize(clang::Expr const*, unsigned int, (anonymous namespace)::EvalInfo&, unsigned long&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/AST/ExprConstant.cpp:11848:7
#16 0x000055bf9a7db953 clang::Expr::tryEvaluateObjectSize(unsigned long&, clang::ASTContext&, unsigned int) const /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/AST/ExprConstant.cpp:16274:3
#17 0x000055bf98a86e07 clang::Sema::checkFortifiedBuiltinMemoryFunction(clang::FunctionDecl*, clang::CallExpr*)::$_1::operator()(unsigned int) const /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Sema/SemaChecking.cpp:1111:9
#18 0x000055bf98a86913 clang::Sema::checkFortifiedBuiltinMemoryFunction(clang::FunctionDecl*, clang::CallExpr*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Sema/SemaChecking.cpp:1318:21
#19 0x000055bf98fdcb51 clang::Sema::BuildResolvedCallExpr(clang::Expr*, clang::NamedDecl*, clang::SourceLocation, llvm::ArrayRef<clang::Expr*>, clang::SourceLocation, clang::Expr*, bool, clang::CallExpr::ADLCallKind) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Sema/SemaExpr.cpp:7463:9
#20 0x000055bf98fbbf78 clang::Sema::BuildCallExpr(clang::Scope*, clang::Expr*, clang::SourceLocation, llvm::MutableArrayRef<clang::Expr*>, clang::SourceLocation, clang::Expr*, bool, bool) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Sema/SemaExpr.cpp:7112:10
#21 0x000055bf98fda08f clang::Sema::ActOnCallExpr(clang::Scope*, clang::Expr*, clang::SourceLocation, llvm::MutableArrayRef<clang::Expr*>, clang::SourceLocation, clang::Expr*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Sema/SemaExpr.cpp:6880:7
#22 0x000055bf988f57cf clang::Parser::ParsePostfixExpressionSuffix(clang::ActionResult<clang::Expr*, true>) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseExpr.cpp:2125:23
#23 0x000055bf988fca6f clang::Parser::ParseCastExpression(clang::Parser::CastParseKind, bool, bool&, clang::Parser::TypeCastState, bool, bool*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseExpr.cpp:1852:9
#24 0x000055bf988f3fe9 clang::Parser::ParseCastExpression(clang::Parser::CastParseKind, bool, clang::Parser::TypeCastState, bool, bool*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseExpr.cpp:683:20
#25 0x000055bf988f24d8 clang::Parser::ParseAssignmentExpression(clang::Parser::TypeCastState) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseExpr.cpp:175:20
#26 0x000055bf988f238f clang::Parser::ParseExpression(clang::Parser::TypeCastState) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseExpr.cpp:126:18
#27 0x000055bf98981928 clang::Parser::ParseExprStatement(clang::Parser::ParsedStmtContext) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseStmt.cpp:525:19
#28 0x000055bf9897fe5e clang::Parser::ParseStatementOrDeclarationAfterAttributes(llvm::SmallVector<clang::Stmt*, 32u>&, clang::Parser::ParsedStmtContext, clang::SourceLocation*, clang::ParsedAttributes&, clang::ParsedAttributes&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseStmt.cpp:279:14
#29 0x000055bf9897f4db clang::Parser::ParseStatementOrDeclaration(llvm::SmallVector<clang::Stmt*, 32u>&, clang::Parser::ParsedStmtContext, clang::SourceLocation*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseStmt.cpp:117:20
#30 0x000055bf9898822e clang::Parser::ParseCompoundStatementBody(bool) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseStmt.cpp:1200:11
#31 0x000055bf98989934 clang::Parser::ParseFunctionStatementBody(clang::Decl*, clang::Parser::ParseScope&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseStmt.cpp:2464:21
#32 0x000055bf9887db1f clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&, clang::Parser::ParsedTemplateInfo const&, clang::Parser::LateParsedAttrList*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/Parser.cpp:1471:3
#33 0x000055bf9889f2cb clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, clang::DeclaratorContext, clang::ParsedAttributes&, clang::SourceLocation*, clang::Parser::ForRangeInit*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseDecl.cpp:2175:27
#34 0x000055bf9887c99a clang::Parser::ParseDeclOrFunctionDefInternal(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec&, clang::AccessSpecifier) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/Parser.cpp:1210:10
#35 0x000055bf9887bedf clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*, clang::AccessSpecifier) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/Parser.cpp:1225:12
#36 0x000055bf9887b7a4 clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/Parser.cpp:1040:14
#37 0x000055bf9887967c clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/Parser.cpp:742:12
#38 0x000055bf988744d7 clang::ParseAST(clang::Sema&, bool, bool) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Parse/ParseAST.cpp:163:16
#39 0x000055bf957d311c clang::ASTFrontendAction::ExecuteAction() /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1168:1
#40 0x000055bf9629da04 clang::CodeGenAction::ExecuteAction() /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/CodeGen/CodeGenAction.cpp:1174:5
#41 0x000055bf957d2b1c clang::FrontendAction::Execute() /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1060:7
#42 0x000055bf956fbe48 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1049:23
#43 0x000055bf9599b5c7 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:264:8
#44 0x000055bf92b09533 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) /usr/local/google/home/saugustine/llvm/llvm-project/clang/tools/driver/cc1_main.cpp:249:13
#45 0x000055bf92af4f6a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/tools/driver/driver.cpp:366:5
#46 0x000055bf92af68dd clang_main(int, char**, llvm::ToolContext const&)::$_0::operator()(llvm::SmallVectorImpl<char const*>&) const /usr/local/google/home/saugustine/llvm/llvm-project/clang/tools/driver/driver.cpp:506:7
#47 0x000055bf92af68ad int llvm::function_ref<int (llvm::SmallVectorImpl<char const*>&)>::callback_fn<clang_main(int, char**, llvm::ToolContext const&)::$_0>(long, llvm::SmallVectorImpl<char const*>&) /usr/local/google/home/saugustine/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:45:5
#48 0x000055bf955aa499 llvm::function_ref<int (llvm::SmallVectorImpl<char const*>&)>::operator()(llvm::SmallVectorImpl<char const*>&) const /usr/local/google/home/saugustine/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:68:5
#49 0x000055bf955a68b8 clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, bool*) const::$_1::operator()() const /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Driver/Job.cpp:439:34
#50 0x000055bf955a6885 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, bool*) const::$_1>(long) /usr/local/google/home/saugustine/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:45:5
#51 0x000055bf9345b379 llvm::function_ref<void ()>::operator()() const /usr/local/google/home/saugustine/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:68:5
#52 0x000055bf946ff76a llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) /usr/local/google/home/saugustine/llvm/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:427:3
#53 0x000055bf955a6017 clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, bool*) const /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Driver/Job.cpp:439:7
#54 0x000055bf95540bdf clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Driver/Compilation.cpp:199:15
#55 0x000055bf95540de7 clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*> >&, bool) const /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Driver/Compilation.cpp:253:13
#56 0x000055bf9555b4f8 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*> >&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/lib/Driver/Driver.cpp:1868:7
#57 0x000055bf92af4a28 clang_main(int, char**, llvm::ToolContext const&) /usr/local/google/home/saugustine/llvm/llvm-project/clang/tools/driver/driver.cpp:542:9
#58 0x000055bf92b2ccdd main /usr/local/google/home/saugustine/llvm/build/tools/clang/tools/driver/clang-driver.cpp:15:3
#59 0x00007f95ab64618a __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#60 0x00007f95ab646245 call_init ./csu/../csu/libc-start.c:128:20
#61 0x00007f95ab646245 __libc_start_main ./csu/../csu/libc-start.c:368:5
#62 0x000055bf92af36c1 _start (./bin/clang+0x19096c1)
clang: error: clang frontend command failed with exit code 134 (use -v to see invocation)
clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4faf3aaf28226a4e950c103a14f6fc1d1fdabb1b)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/google/home/saugustine/llvm/build/./bin
clang: note: diagnostic msg: 
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/t-4b8223.c
clang: note: diagnostic msg: /tmp/t-4b8223.sh
clang: note: diagnostic msg: 

********************
iii added a subscriber: iii.May 23 2023, 6:13 AM
nickdesaulniers reopened this revision.May 23 2023, 9:24 AM
This revision is now accepted and ready to land.May 23 2023, 9:24 AM
nickdesaulniers planned changes to this revision.May 23 2023, 9:24 AM
nickdesaulniers retitled this revision from [clang][ExprConstant] fix __builtin_object_size for flexible array members to Reland: [clang][ExprConstant] fix __builtin_object_size for flexible array members.
This revision is now accepted and ready to land.May 23 2023, 10:18 AM
  • prefer OBJECT_SIZE_BUILTIN to builtin_object_size to additionally test dynamic_builtin_object_size
This revision was landed with ongoing or failed builds.May 23 2023, 2:51 PM
This revision was automatically updated to reflect the committed changes.