llvm / llvm/llvm-project

constexpr template function recursion error

Open
#211,602 1 comment 0 reactions 0 assignees View on GitHub
clang:frontend constexpr crash needs-reduction
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

### Component
clang compiler

### LLVM Version

clang version 22.1.3 with msvc like command line
Target: x86_64-pc-windows-msvc
Thread model: posix
(the one shipped with visual studio 18)

### Operating System and Architecture

windows 11 25H2

### Description of the Bug

I accidently wrote some trash code about constexpr and crashed the compiler. I was not supposed to call a particular constexpr template (constexprLog10) from non constexpr/consteval but I went out of my mind and did so. I suspected a recursion depth limit is missing when the template argument is recursive. See the source for detail.

### Steps to Reproduce
```cmd
"F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe" /nologo -TP -DGTEST_LINKED_AS_SHARED_LIBRARY=1 -DUSING_UV_SHARED=1 -imsvcE:\vcpkg\installed\x64-windows\include -imsvcE:\vcpkg\installed\x64-windows\include\server --target=amd64-pc-windows-msvc -fdiagnostics-absolute-paths /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1 -std:c++latest -clang:-MD -clang:-MTCMakeFiles\nozomi_test.dir\Tests\TestDatabase.cpp.obj -clang:-MFCMakeFiles\nozomi_test.dir\Tests\TestDatabase.cpp.obj.d /FoCMakeFiles\nozomi_test.dir\Tests\TestDatabase.cpp.obj /FdCMakeFiles\nozomi_test.dir\ -c -- C:\Users\alessia\source\repos\nozomi\Tests\TestDatabase.cpp
```

### Minimized Test Case

```cpp
#ifndef Decimal_h
#define Decimal_h

#include
#include
#include
#include
#include
#include

namespace nozomi::database {

#ifdef _WIN32
#undef max
#undef min
#endif

template
class Decimal {
private:
size_t integer = 0;
size_t decimal = 0;
bool positive = 0;
std::array decimalString;

template
struct EraseIndex {
T value;
constexpr EraseIndex(T &&value) noexcept : value(value) {}
constexpr T operator()() noexcept { return value; }
};

struct EmitPrecisionWarning {
[[deprecated("Precision is narrowed when casting")]]
consteval EmitPrecisionWarning() {}
};

template
constexpr static size_t
constexprPow10Impl(size_t n,
std::index_sequence) noexcept {
return (1 * ... * EraseIndex(10)());
}

template
constexpr static size_t constexprPow10() noexcept {
return constexprPow10Impl(n, std::make_index_sequence{});
}

template
static void toStringImpl(char *out, size_t n,
std::index_sequence) {
(...,
(out[indexSequences] =
(char)(n / constexprPow10()) + '0'));
}

template
constexpr static size_t constexprLog10Impl(const size_t base) {
if constexpr (constexprPow10() < base) {
return constexprLog10Impl(base);
} else
return I;
}

constexpr static size_t constexprLog11(const size_t base) {
return constexprLog10Impl<0>(base);
}

static void toStringDetail(char *out, size_t n) {
toStringImpl(out, n, std::make_index_sequence{});
}

public:
/**
* @brief construct a decimal
* @param i integer part
* @param d decimal part
* @param positive if the value is positive
*/
Decimal(const size_t i, const size_t d, bool positive = true) noexcept
: positive(positive) {
size_t l = std::log10l(d);
if (l > D) {
integer = (d / constexprPow10()) + i;
decimal = d % constexprPow10();
} else {
integer = i;
decimal = d;
}
}

/**
* @brief construct a decimal based on another
* @param rhs the right hand size
* @param DRight the percision of right hand size, if this is lower than
* D, than a warning will emit
*/
template
Decimal(const Decimal &rhs) noexcept
: integer(rhs.integer), positive(rhs.positive) {
if constexpr (D >= DRight) {
// this precision greater than right hand side, perfect
constexpr size_t padding = constexprPow10();
decimal = rhs.decimal * padding;
} else {
// narrow down precision
EmitPrecisionWarning{};
constexpr size_t narrow = constexprPow10();
decimal = rhs.decimal / narrow;
}
}

Decimal(const Decimal &rhs) noexcept
: positive(rhs.positive), integer(rhs.integer),
decimal(rhs.decimal) {}

template
bool operator<=(const Decimal &rhs) const noexcept {
if (rhs.positive && !positive)
return false; // evaluate the sign immediately
// same sign
constexpr size_t maxDecimal = std::max(D, DRight);
constexpr size_t nleft =
maxDecimal > DRight ? maxDecimal - DRight
: 0; // how many to pad for left hand side
constexpr size_t nright =
maxDecimal > D ? maxDecimal - D
: 0; // how many to pad for right hand size
constexpr size_t paddingRight = constexprPow10();
constexpr size_t paddingLeft = constexprPow10();
constexpr size_t padding = constexprPow10();
size_t sumLeft = padding * integer + paddingLeft * decimal;
size_t sumRight =
padding * rhs.integer + paddingRight * rhs.decimal;
return positive ? sumLeft <= sumRight : sumLeft >= sumRight;
}

template
bool operator==(const Decimal &rhs) const noexcept {
return *this <= rhs && rhs <= *this;
}

template
bool operator<(const Decimal &rhs) const noexcept {
return *this < rhs && !(*this == rhs);
}

std::string operator()() const noexcept {
decimalString.fill('0');
decimalString[D] = 0;
return std::format("{}{:d}.{}", positive ? "" : "-", integer,
std::string_view{decimalString.data()});
}

template
friend class Decimal;
};

template class>
struct DecimalTrait : public std::false_type {
constexpr static size_t decimal = ~0;
};

template
struct DecimalTrait, Decimal> : public std::true_type {
constexpr static size_t decimal = D;
};

}; // namespace nozomi::database

#endif
```

### Expected Behavior

don't crash when calling toStringDetail

### Actual Behavior / Stack Trace
compiler crashed because allocation

```text
C:\Users\alessia\source\repos\nozomi\out\build\x64-debug\EXEC : LLVM error : out of memory
Allocation 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: "F:\\Microsoft Visual Studio\\18\\Community\\VC\\Tools\\Llvm\\x64\\bin\\clang-cl.exe" /nologo -TP -DGTEST_LINKED_AS_SHARED_LIBRARY=1 -DUSING_UV_SHARED=1 -imsvcE:\\vcpkg\\installed\\x64-windows\\include -imsvcE:\\vcpkg\\installed\\x64-windows\\include\\server --target=amd64-pc-windows-msvc -fdiagnostics-absolute-paths /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1 -std:c++latest -clang:-MD -clang:-MTCMakeFiles\\nozomi_test.dir\\Tests\\TestDatabase.cpp.obj -clang:-MFCMakeFiles\\nozomi_test.dir\\Tests\\TestDatabase.cpp.obj.d /FoCMakeFiles\\nozomi_test.dir\\Tests\\TestDatabase.cpp.obj /FdCMakeFiles\\nozomi_test.dir\\ -c -- C:\\Users\\alessia\\source\\repos\\nozomi\\Tests\\TestDatabase.cpp
1. parser at end of file
2. C:\Users\alessia\source\repos\nozomi\Tests\../Database/Decimal.h:100:3: instantiating function definition 'nozomi::database::Decimal<2>::Decimal<4ULL>'
3. C:\Users\alessia\source\repos\nozomi\Tests\../Database/Decimal.h:46:27: instantiating function definition 'nozomi::database::Decimal<2>::constexprPow10<18446744073709551614ULL>'
Exception Code: 0xC000001D
#0 0x00007ff7babc9846 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x22b9846)
#1 0x00007ff7ba989fc1 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x2079fc1)
#2 0x00007ff7ba981b10 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x2071b10)
#3 0x00007ff7babef654 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x22df654)
#4 0x00007ff7b9b993d3 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x12893d3)
#5 0x00007ff7b9fb4250 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x16a4250)
#6 0x00007ff7b9fa3933 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1693933)
#7 0x00007ff7b9fce8d1 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x16be8d1)
#8 0x00007ff7b9fbef98 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x16aef98)
#9 0x00007ff7b9faffd8 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x169ffd8)
#10 0x00007ff7b9fa3933 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1693933)
#11 0x00007ff7b9fce8d1 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x16be8d1)
#12 0x00007ff7b9fbef98 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x16aef98)
#13 0x00007ff7b9faffd8 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x169ffd8)
#14 0x00007ff7b9f98377 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1688377)
#15 0x00007ff7b9f92786 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1682786)
#16 0x00007ff7b9c4a3bd (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x133a3bd)
#17 0x00007ff7b896b418 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x5b418)
#18 0x00007ff7b9c2c193 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x131c193)
#19 0x00007ff7ba628eb5 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d18eb5)
#20 0x00007ff7ba628254 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d18254)
#21 0x00007ff7ba627745 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d17745)
#22 0x00007ff7ba623d88 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d13d88)
#23 0x00007ff7ba622aa7 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d12aa7)
#24 0x00007ff7b9eace9d (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x159ce9d)
#25 0x00007ff7b9eace2d (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x159ce2d)
#26 0x00007ff7b9d6e033 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x145e033)
#27 0x00007ff7b9d67ee5 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1457ee5)
#28 0x00007ff7b9d262d9 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x14162d9)
#29 0x00007ff7b9d25313 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1415313)
#30 0x00007ff7b9d1ad3e (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x140ad3e)
#31 0x00007ff7b9c2c2ca (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x131c2ca)
#32 0x00007ff7ba484836 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1b74836)
#33 0x00007ff7b9c3dc44 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x132dc44)
#34 0x00007ff7b9fe2abf (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x16d2abf)
#35 0x00007ff7b9fad56d (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x169d56d)
#36 0x00007ff7ba91ff68 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x200ff68)
#37 0x00007ff7b9eace9d (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x159ce9d)
#38 0x00007ff7b9eace2d (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x159ce2d)
#39 0x00007ff7ba5821f9 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1c721f9)
#40 0x00007ff7ba628fa0 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d18fa0)
#41 0x00007ff7ba62827a (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d1827a)
#42 0x00007ff7ba6281ba (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d181ba)
#43 0x00007ff7ba627745 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d17745)
#44 0x00007ff7ba623d88 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1d13d88)
#45 0x00007ff7b91586be (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x8486be)
#46 0x00007ff7b91574a6 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x8474a6)
#47 0x00007ff7ba8cd322 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x1fbd322)
#48 0x00007ff7b9d9fb6b (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x148fb6b)
#49 0x00007ff7b9d9f5ae (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x148f5ae)
#50 0x00007ff7b8f48493 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x638493)
#51 0x00007ff7b8f480cd (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x6380cd)
#52 0x00007ff7b8f462c9 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x6362c9)
#53 0x00007ff7b8f421af (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x6321af)
#54 0x00007ff7b8f40b25 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x630b25)
#55 0x00007ff7b9898a5d (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0xf88a5d)
#56 0x00007ff7b91101d5 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x8001d5)
#57 0x00007ff7b910ffc8 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x7fffc8)
#58 0x00007ff7b8a5083b (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x14083b)
#59 0x00007ff7b8a5017e (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x14017e)
#60 0x00007ff7b8a4fe92 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x13fe92)
#61 0x00007ff7b8a47b0d (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x137b0d)
#62 0x00007ff7b8a44a83 (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x134a83)
#63 0x00007ff7ba96c9ec (F:\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-cl.exe+0x205c9ec)
#64 0x00007ffcaeede957 (C:\WINDOWS\System32\KERNEL32.DLL+0x2e957)
#65 0x00007ffcafdaad6c (C:\WINDOWS\SYSTEM32\ntdll.dll+0xaad6c)
```

### Additional Context
I was told to upload these files, please remove the .txt extension otherwise I am not able to upload
[TestDatabase-62635a.sh](https://github.com/user-attachments/files/30314799/TestDatabase-62635a.sh)
[TestDatabase-62635a.cpp.txt](https://github.com/user-attachments/files/30314841/TestDatabase-62635a.cpp.txt)

Contributor guide

Open the contributing guide

Research direction

Reproduce with the provided clang-cl command and minimized source, then inspect the stack around Database/Decimal.h lines 100 and 46, where Decimal<2>::Decimal<4ULL> instantiates constexprPow10<18446744073709551614ULL>. Compare the behavior when calling toStringDetail; done means the compiler no longer runs out of memory or crashes on this reproducer.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.