llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.62k stars 11.83k forks source link

clang-format: Crash in MacroCallReconstructor::reconstruct with conflicting macro definition and use #64275

Open galenelias opened 1 year ago

galenelias commented 1 year ago

Hit this when just testing some clang-format behavior (using current main branch), so probably not much of a 'real' use case, but still probably shouldn't crash / trigger an access violation.

When the clang-format file specifies a macro expansion that conflicts with actual usage in some files:

_clang-format:

Macros:
  - A(x)=x

Source:

void A() {}

Command line to repro:

echo "void A() {}" | clang-format --style="{'Macros': ['A(x)=x']}"

Crashing line:

void MacroCallReconstructor::reconstruct(FormatToken *Token) {
  // ...
  assert(!ActiveExpansions.empty());
  if (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE) {

Debug crash callstack: (I think Release probably just crashes with an access violation on the following line)

Exception Code: 0x80000003
 #0 0x00007ff7f926149c HandleAbort D:\src\llvm\llvm\lib\Support\Windows\Signals.inc:419:0
 #1 0x00007ff962a8e5f5 (C:\WINDOWS\System32\ucrtbase.dll+0x7e5f5)
 #2 0x00007ff962a8f601 (C:\WINDOWS\System32\ucrtbase.dll+0x7f601)
 #3 0x00007ff962a9106a (C:\WINDOWS\System32\ucrtbase.dll+0x8106a)
 #4 0x00007ff962a90f5d (C:\WINDOWS\System32\ucrtbase.dll+0x80f5d)
 #5 0x00007ff962a911f1 (C:\WINDOWS\System32\ucrtbase.dll+0x811f1)
 #6 0x00007ff7f94ff55c clang::format::MacroCallReconstructor::reconstruct(struct clang::format::FormatToken *) D:\src\llvm\clang\lib\Format\MacroCallReconstructor.cpp:221:0
 #7 0x00007ff7f94fec9f clang::format::MacroCallReconstructor::add(struct clang::format::FormatToken *, struct clang::format::FormatToken *, bool) D:\src\llvm\clang\lib\Format\MacroCallReconstructor.cpp:111:0
 #8 0x00007ff7f95016e0 `clang::format::MacroCallReconstructor::addLine'::`2'::<lambda_1>::operator() D:\src\llvm\clang\lib\Format\MacroCallReconstructor.cpp:57:0
 #9 0x00007ff7f9504248 clang::format::forEachToken<`clang::format::MacroCallReconstructor::addLine'::`2'::<lambda_1> > D:\src\llvm\clang\lib\Format\MacroCallReconstructor.cpp:37:0
#10 0x00007ff7f94fe843 clang::format::MacroCallReconstructor::addLine(struct clang::format::UnwrappedLine const &) D:\src\llvm\clang\lib\Format\MacroCallReconstructor.cpp:59:0
#11 0x00007ff7f94e0a8c clang::format::UnwrappedLineParser::addUnwrappedLine(enum clang::format::UnwrappedLineParser::LineLevel) D:\src\llvm\clang\lib\Format\UnwrappedLineParser.cpp:4362:0
#12 0x00007ff7f94d04d2 clang::format::UnwrappedLineParser::parse(void) D:\src\llvm\clang\lib\Format\UnwrappedLineParser.cpp:220:0
#13 0x00007ff7f945a3b5 clang::format::TokenAnalyzer::process(bool) D:\src\llvm\clang\lib\Format\TokenAnalyzer.cpp:114:0
#14 0x00007ff7f939fe96 `clang::format::internal::reformat'::`39'::<lambda_6>::operator() D:\src\llvm\clang\lib\Format\Format.cpp:3646:0
#15 0x00007ff7f93c23e8 std::invoke<`clang::format::internal::reformat'::`39'::<lambda_6> &,clang::format::Environment const &> C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\type_traits:1586:0
#16 0x00007ff7f93aeb08 std::_Invoker_ret<std::pair<clang::tooling::Replacements,unsigned int> >::_Call<`clang::format::internal::reformat'::`39'::<lambda_6> &,clang::format::Environment const &> C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\functional:659:0
#17 0x00007ff7f93a1dcf std::_Func_impl_no_alloc<`clang::format::internal::reformat'::`39'::<lambda_6>,std::pair<clang::tooling::Replacements,unsigned int>,clang::format::Environment const &>::_Do_call C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\functional:820:0
#18 0x00007ff7f93e042d std::_Func_class<struct std::pair<class clang::tooling::Replacements, unsigned int>, class clang::format::Environment const &>::operator()(class clang::format::Environment const &) const C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\functional:861:0
#19 0x00007ff7f9393e5e clang::format::internal::reformat(struct clang::format::FormatStyle const &, class llvm::StringRef, class llvm::ArrayRef<class clang::tooling::Range>, unsigned int, unsigned int, unsigned int, class llvm::StringRef, struct clang::format::FormattingAttemptStatus *) D:\src\llvm\clang\lib\Format\Format.cpp:3686:0
#20 0x00007ff7f9390ae9 clang::format::reformat(struct clang::format::FormatStyle const &, class llvm::StringRef, class llvm::ArrayRef<class clang::tooling::Range>, class llvm::StringRef, struct clang::format::FormattingAttemptStatus *) D:\src\llvm\clang\lib\Format\Format.cpp:3729:0
#21 0x00007ff7f913fc23 clang::format::format D:\src\llvm\clang\tools\clang-format\ClangFormat.cpp:499:0
#22 0x00007ff7f9141052 main D:\src\llvm\clang\tools\clang-format\ClangFormat.cpp:615:0
llvmbot commented 1 year ago

@llvm/issue-subscribers-clang-format

jcsxky commented 1 year ago

The code becomes void {} by preprocessor and can't be compiled.

Psycho900 commented 1 month ago

Would it make any sense to make it so clang-format only does macro replacement when there is the correct number of parameters? E.g. if I have #define MyMacro(param1, param2, param3) then can we make it so clang-format only does the macro replacement if the callsite has exactly 3 arguments? (no more & no less)