https://github.com/term-est created 
https://github.com/llvm/llvm-project/pull/88637

Henlo frens! 🍓 

We folks at Armelsan Defense has been using LLVM for quite some time. Recently 
we encountered an issue with clangd where it tries to allocate 137 gigs of 
memory in one of our template heavy codebases.

We recompiled the trunk with sanitizers, and got this -> 
```
I[20:24:45.715] <-- reply(1)
LLVM ERROR: SmallVector capacity unable to grow. Requested capacity 
(4294963200) is larger than maximum value for size type (4294967295)
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and 
include the crash backtrace.
```

So this is not a leak. Notice that requested capacity is 4294963200, which is 
quite near to i32 max.


Further tests has showed that

```cpp
  /// Prepare to directly deduce arguments of the parameter with index \p Index.
  PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams,
                     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                     TemplateDeductionInfo &Info, unsigned Index)
      : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
    addPack(Index);
    finishConstruction(1);
  }
  
private:
  void addPack(unsigned Index) {
    // Save the deduced template argument for the parameter pack expanded
    // by this pack expansion, then clear out the deduction.
    DeducedFromEarlierParameter = !Deduced[Index].isNull();
    DeducedPack Pack(Index);
    Pack.Saved = Deduced[Index];
    Deduced[Index] = TemplateArgument();

    // FIXME: What if we encounter multiple packs with different numbers of
    // pre-expanded expansions? (This should already have been diagnosed
    // during substitution.)
    if (std::optional<unsigned> ExpandedPackExpansions =
            getExpandedPackSize(TemplateParams->getParam(Index)))
      FixedNumExpansions = ExpandedPackExpansions;

    Packs.push_back(Pack);
[clangd-stacktrace.txt](https://github.com/llvm/llvm-project/files/14968656/clangd-stacktrace.txt)

  }
  
  
  ```
  
  `addPack` might not initialize the `std::optional<unsigned> 
FixedNumExpansions` given that `getExpandedPackSize` returns a `nullopt`, which 
causes the access to `FixedNumExpansions` via the `operator*` to be Undefined. 
`PackElements` is eventually used in `SmallVector::grow_pod`, and vector tries 
to allocate 137 gigs. 


Attached, you can find the full stacktrace. 
[clangd-stacktrace.txt](https://github.com/llvm/llvm-project/files/14968658/clangd-stacktrace.txt)

I can supply the exact code that causes this issue if needed, but I would 
appreciate if you frends can point me to any tools that can generate an 
obfuscated minimal reproducible example. 

Although this was discovered in clangd, it also appears to affect clang++ as 
well.  
![image](https://github.com/llvm/llvm-project/assets/62337595/74b907c6-4511-40cf-97cf-f6c096dff05a)
![image](https://github.com/llvm/llvm-project/assets/62337595/b905f1e0-6f41-4987-8b57-8891efe02b06)

After this change, both seems to work just fine with clangd using only 300mb 
and clang++ compiling the codebase successfully and correctly.

Thank you for your amazing work and thanks for the review~ 

>From 1c639842d1b5b79692c097df24757a90eeac888f Mon Sep 17 00:00:00 2001
From: term-est <62337595+term-...@users.noreply.github.com>
Date: Sat, 13 Apr 2024 23:04:00 +0300
Subject: [PATCH] Fix the bug which causes the SmallVector to be not so small.

PackDeductionScope::PackDeductionScope calls PackDeductionScope::addPack, which 
might not assign a value to PackDeductionScope::FixedNumExpansions given that 
getExpandedPackSize returns a nullopt.

Access to an empty std::optional via the operator* is UB, and there is a case 
where IsExpanded is true while FixedNumberExpansions is empty. We access the 
empty optional, and this value is eventually used to in a call to 
SmallVector::reserve, which ends up trying to reserve 137 gigs of space and 
crashes clangd/clang++
---
 clang/lib/Sema/SemaTemplateDeduction.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 0b6375001f5326..1679852cdb386b 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -831,7 +831,7 @@ class PackDeductionScope {
     if (IsPartiallyExpanded)
       PackElements += NumPartialPackArgs;
     else if (IsExpanded)
-      PackElements += *FixedNumExpansions;
+      PackElements += FixedNumExpansions.value_or(1);
 
     for (auto &Pack : Packs) {
       if (Info.PendingDeducedPacks.size() > Pack.Index)

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to