constexpr template function recursion error
- 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
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