LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 20635 - SemaCXX/constant-expression-cxx11.cpp test fails on 32-bit x86 due to stack exhaustion
Summary: SemaCXX/constant-expression-cxx11.cpp test fails on 32-bit x86 due to stack e...
Status: NEW
Alias: None
Product: clang
Classification: Unclassified
Component: -New Bugs (show other bugs)
Version: trunk
Hardware: PC FreeBSD
: P normal
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-08-12 12:19 PDT by Dimitry Andric
Modified: 2014-08-16 15:16 PDT (History)
5 users (show)

See Also:
Fixed By Commit(s):


Attachments
Minimized test case, derived from test/SemaCXX/constant-expression-cxx11.cpp (171 bytes, application/octet-stream)
2014-08-12 12:19 PDT, Dimitry Andric
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dimitry Andric 2014-08-12 12:19:46 PDT
Created attachment 12884 [details]
Minimized test case, derived from test/SemaCXX/constant-expression-cxx11.cpp

During clang 3.5.0-rc2 testing, I ran into the following failure, which *only* occurs on 32-bit x86 (in this case, i386-unknown-freebsd10):

FAIL: Clang :: SemaCXX/constant-expression-cxx11.cpp (5186 of 18744)
******************** TEST 'Clang :: SemaCXX/constant-expression-cxx11.cpp' FAILED ********************
Script:
--
/home/dim/llvm-3.5.0/rc2/Phase3/Release/llvmCore-3.5.0-rc2.obj/Release/bin/clang -cc1 -internal-isystem /home/dim/llvm-3.5.0/rc2/Phase3/Release/llvmCore-3.5.0-rc2.obj/Release/bin/../lib/clang/3.5.0/include -triple i686-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic /home/dim/llvm-3.5.0/rc2/cfe.src/test/SemaCXX/constant-expression-cxx11.cpp -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
--
Exit Code: 132

This turns out to be a stack overflow, leading to either a segfault, or an illegal instruction:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 2ac03080 (LWP 100095)]
0x091e5e34 in clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::LValueExprEvaluator, bool>::Visit (this=0xbf9ff6c8, S=0x2ac9cb3c) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/../../include/clang/AST/StmtVisitor.h:39
39        RetTy Visit(PTR(Stmt) S) {
(gdb) bt
#0  0x091e5e34 in clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::LValueExprEvaluator, bool>::Visit (this=0xbf9ff6c8, S=0x2ac9cb3c) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/../../include/clang/AST/StmtVisitor.h:39
#1  0x09197564 in EvaluateLValue (E=<optimized out>, Result=..., Info=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:4395
#2  0x091ce138 in VisitCastExpr (E=<optimized out>, this=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:4130
#3  (anonymous namespace)::PointerExprEvaluator::VisitCastExpr (this=0xbf9ff6c8, E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:4818
#4  0x091cc036 in VisitExplicitCastExpr (this=0xbfa00010, S=<optimized out>) at /home/dim/obj/llvm-215430-1/tools/clang/lib/AST/../../include/clang/AST/StmtNodes.inc:329
#5  VisitCStyleCastExpr (this=<optimized out>, S=<optimized out>) at /home/dim/obj/llvm-215430-1/tools/clang/lib/AST/../../include/clang/AST/StmtNodes.inc:333
#6  clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::PointerExprEvaluator, bool>::Visit (this=<optimized out>, S=0x2ac9cb3c) at /home/dim/obj/llvm-215430-1/tools/clang/lib/AST/../../include/clang/AST/StmtNodes.inc:333
#7  0x091b064a in EvaluatePointer (E=<optimized out>, Result=..., Info=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:4691
#8  0x0919b2c0 in Evaluate (Result=..., Info=..., E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:8002
#9  0x0919d6fb in EvaluateArgs (ArgValues=..., Info=..., Args=..., ArgValues=..., Info=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:3601
#10 HandleFunctionCall (CallLoc=..., Callee=0xbf9ff6c8, This=0x2ac9cb3c, Args=..., Body=0x2ac9cb3c, Info=..., Result=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:3618
#11 0x091aa103 in VisitCallExpr (this=<optimized out>, E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:4060
#12 (anonymous namespace)::IntExprEvaluator::VisitCallExpr (this=<optimized out>, E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:6012
#13 0x091a2421 in clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::IntExprEvaluator, bool>::Visit (this=<optimized out>, S=<optimized out>) at /home/dim/obj/llvm-215430-1/tools/clang/lib/AST/../../include/clang/AST/StmtNodes.inc:293
#14 0x0919b1ea in Evaluate (Result=..., Info=..., E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:7998
#15 0x091a091d in EvaluateStmt (Result=..., Info=..., S=<optimized out>, Case=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:3362
#16 0x091a0652 in EvaluateStmt (Result=..., Info=..., S=<optimized out>, Case=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:3372
#17 0x0919d988 in HandleFunctionCall (CallLoc=..., Callee=0xbf9ff6c8, This=<optimized out>, Args=..., Body=0x2ac9cb3c, Info=..., Result=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:3646
#18 0x091aa103 in VisitCallExpr (this=<optimized out>, E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:4060
[... repeats thousands of times ...]
#3171 0x0919b1ea in Evaluate (Result=..., Info=..., E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:7998
#3172 0x091a091d in EvaluateStmt (Result=..., Info=..., S=<optimized out>, Case=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:3362
#3173 0x091a0652 in EvaluateStmt (Result=..., Info=..., S=<optimized out>, Case=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:3372
#3174 0x0919d988 in HandleFunctionCall (CallLoc=..., Callee=0xbf9ff6c8, This=<optimized out>, Args=..., Body=0x2ac9cb3c, Info=..., Result=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:3646
#3175 0x091aa103 in VisitCallExpr (this=<optimized out>, E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:4060
#3176 (anonymous namespace)::IntExprEvaluator::VisitCallExpr (this=<optimized out>, E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:6012
#3177 0x091a2421 in clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::IntExprEvaluator, bool>::Visit (this=<optimized out>, S=<optimized out>) at /home/dim/obj/llvm-215430-1/tools/clang/lib/AST/../../include/clang/AST/StmtNodes.inc:293
#3178 0x0919b1ea in Evaluate (Result=..., Info=..., E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:7998
#3179 0x091af8f5 in EvaluateAsBooleanCondition (Result=<optimized out>, Info=..., E=<optimized out>, Result=<optimized out>, Info=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:1477
#3180 (anonymous namespace)::IntExprEvaluator::VisitCastExpr (this=<optimized out>, E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:7194
#3181 0x091a23d3 in VisitExplicitCastExpr (this=<optimized out>, S=<optimized out>) at /home/dim/obj/llvm-215430-1/tools/clang/lib/AST/../../include/clang/AST/StmtNodes.inc:329
#3182 VisitCStyleCastExpr (this=<optimized out>, S=<optimized out>) at /home/dim/obj/llvm-215430-1/tools/clang/lib/AST/../../include/clang/AST/StmtNodes.inc:333
#3183 clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::IntExprEvaluator, bool>::Visit (this=<optimized out>, S=<optimized out>) at /home/dim/obj/llvm-215430-1/tools/clang/lib/AST/../../include/clang/AST/StmtNodes.inc:333
#3184 0x0919b1ea in Evaluate (Result=..., Info=..., E=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:7998
#3185 0x09196c94 in EvaluateAsRValue (Info=..., E=<optimized out>, Result=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:8087
#3186 0x09196a33 in clang::Expr::EvaluateAsRValue (this=<optimized out>, Result=..., Ctx=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/ExprConstant.cpp:8142
#3187 0x0895f5ff in clang::Sema::VerifyIntegerConstantExpression (this=<optimized out>, E=<optimized out>, Result=<optimized out>, Diagnoser=..., AllowFold=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Sema/SemaExpr.cpp:11161
#3188 0x0895d02d in clang::Sema::VerifyIntegerConstantExpression (this=<optimized out>, E=<optimized out>, Result=<optimized out>, DiagID=<optimized out>, AllowFold=<optimized out>, this=<optimized out>, E=<optimized out>, Result=<optimized out>, DiagID=<optimized out>, AllowFold=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Sema/SemaExpr.cpp:11068
#3189 0x088c7563 in clang::Sema::BuildStaticAssertDeclaration (this=0x2ac98000, StaticAssertLoc=..., AssertExpr=0x2, AssertMessage=<optimized out>, RParenLoc=..., Failed=<error reading variable: Cannot access memory at address 0x1>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Sema/SemaDeclCXX.cpp:11519
#3190 0x088c746e in clang::Sema::ActOnStaticAssertDeclaration (this=<optimized out>, StaticAssertLoc=..., AssertExpr=<optimized out>, AssertMessageExpr=<optimized out>, RParenLoc=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Sema/SemaDeclCXX.cpp:11500
#3191 0x086f4885 in clang::Parser::ParseStaticAssertDeclaration (this=0x2ac4e600, DeclEnd=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Parse/ParseDeclCXX.cpp:725
#3192 0x086d954c in clang::Parser::ParseDeclaration (this=0x2ac4e600, Stmts=..., Context=<optimized out>, DeclEnd=..., attrs=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Parse/ParseDecl.cpp:1338
#3193 0x086c71eb in clang::Parser::ParseExternalDeclaration (this=0x2ac4e600, attrs=..., DS=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Parse/Parser.cpp:701
#3194 0x086c6682 in clang::Parser::ParseTopLevelDecl (this=0x2ac4e600, Result=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Parse/Parser.cpp:559
#3195 0x086c3286 in clang::ParseAST (S=..., PrintStats=<optimized out>, SkipFunctionBodies=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Parse/ParseAST.cpp:145
#3196 0x082d54e7 in clang::ASTFrontendAction::ExecuteAction (this=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Frontend/FrontendAction.cpp:513
#3197 0x082d4dfc in clang::FrontendAction::Execute (this=0xbf9ff6c8) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Frontend/FrontendAction.cpp:415
#3198 0x082a351f in clang::CompilerInstance::ExecuteAction (this=<optimized out>, Act=...) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/Frontend/CompilerInstance.cpp:810
#3199 0x082851b5 in clang::ExecuteCompilerInvocation (Clang=0x2ac32080) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:222
#3200 0x0827a29d in cc1_main (ArgBegin=<optimized out>, ArgEnd=<optimized out>, Argv0=<optimized out>, MainAddr=<optimized out>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/tools/driver/cc1_main.cpp:112
#3201 0x08282ae6 in main (argc_=-1077942272, argv_=0x827fcc0 <GetExecutablePath(char const*, bool)>) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/tools/driver/driver.cpp:318

The specific test that it explodes on is this one from test/SemaCXX/constant-expression-cxx11.cpp:

namespace RecursiveOpaqueExpr {
  template<typename Iter>
  constexpr auto LastNonzero(Iter p, Iter q) -> decltype(+*p) {
    return p != q ? (LastNonzero(p+1, q) ?: *p) : 0; // expected-warning {{GNU}}
  }

  constexpr int arr1[] = { 1, 0, 0, 3, 0, 2, 0, 4, 0, 0 };
  static_assert(LastNonzero(begin(arr1), end(arr1)) == 4, "");

  constexpr int arr2[] = { 1, 0, 0, 3, 0, 2, 0, 4, 0, 5 };
  static_assert(LastNonzero(begin(arr2), end(arr2)) == 5, "");

  constexpr int arr3[] = {
    1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
    1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
    1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
    1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
    1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
    1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
    1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
    2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  static_assert(LastNonzero(begin(arr3), end(arr3)) == 2, "");
}

I reduced this to the following minimal testcase, constant-expression-cxx11-minimal.cpp:

template <typename Iter>
constexpr auto LastNonzero(Iter p, Iter q) -> decltype(0) {
  return LastNonzero(p, q)
}
int arr3[]{};
static_assert(LastNonzero(arr3, arr3) , ""

Compiling this with "-cc1 -triple i686-linux -fsyntax-only -verify -std=c++11" leads to the crash.

I had to go back quite far in the Subversion history to find the commit that introduces this crash:

http://llvm.org/viewvc/llvm-project?view=revision&revision=187025

Before this commit, using clang trunk r187024:

clang -cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 constant-expression-cxx11-minimal.cpp
error: no expected directives found: consider use of 'expected-no-diagnostics'
error: 'error' diagnostics seen but not expected:
  File constant-expression-cxx11-minimal.cpp Line 3: expected ';' after return statement
  File constant-expression-cxx11-minimal.cpp Line 6: expected ')'
  File constant-expression-cxx11-minimal.cpp Line 6: expected ';' after static_assert
  File constant-expression-cxx11-minimal.cpp Line 6: static_assert expression is not an integral constant expression
error: 'note' diagnostics seen but not expected:
  File constant-expression-cxx11-minimal.cpp Line 6: to match this '('
  File constant-expression-cxx11-minimal.cpp Line 3: constexpr evaluation exceeded maximum depth of 512 calls
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 3: (skipping 502 calls in backtrace; use -fconstexpr-backtrace-limit=0 to see all)
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 3: in call to 'LastNonzero(&arr3[0], &arr3[0])'
  File constant-expression-cxx11-minimal.cpp Line 6: in call to 'LastNonzero(&arr3[0], &arr3[0])'
18 errors generated.

After this commit, using clang trunk r187025:

clang -cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 constant-expression-cxx11-minimal.cpp
Illegal instruction (core dumped)

Note that the problem is not always repeatable: different compiliation options and/or environments seem to make this crash disappear or reappear randomly.  I have encountered it a few times in the last months, but it always went away magically, only to return later.

I suspect there is some sort of undefined behaviour going on, either in the code added by r187025, or somewhere else...
Comment 1 Richard Smith 2014-08-12 14:18:20 PDT
The first thing to check is whether this is a simple stack overflow: check whether $rsp in frame 0 is at the bottom of the containing mmap'd region, and see if increasing your stack ulimit makes the problem disappear.
Comment 2 Richard Smith 2014-08-12 14:18:59 PDT
(We have seen similar issues in template instantiation in the past; I seem to recall that x86 freebsd has particularly low default stack limits.)
Comment 3 Dimitry Andric 2014-08-12 15:14:19 PDT
(In reply to comment #1)
> The first thing to check is whether this is a simple stack overflow: check
> whether $rsp in frame 0 is at the bottom of the containing mmap'd region,
> and see if increasing your stack ulimit makes the problem disappear.

Hmm, this actually seems to be the cause:

(gdb) frame 3201
#3201 0x08282ae6 in main (argc_=-1077942284, argv_=0x827fcc0 <GetExecutablePath(char const*, bool)>)
    at /home/dim/llvm-3.5.0/llvm.src/tools/clang/tools/driver/driver.cpp:318
318           return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0],
(gdb) info registers
eax            0x2ac9cb3c       717867836
ecx            0xbf9ff698       -1080035688
edx            0x2ac9cb3c       717867836
ebx            0xa342518        171189528
esp            0xbfbfdae0       0xbfbfdae0
...
(gdb) frame 0
#0  0x091e5ef4 in clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::LValueExprEvaluator, bool>::Visit (this=0xbf9ff698,
    S=0x2ac9cb3c) at /home/dim/llvm-3.5.0/llvm.src/tools/clang/lib/AST/../../include/clang/AST/StmtVisitor.h:39
39        RetTy Visit(PTR(Stmt) S) {
(gdb) info registers
eax            0x2ac9cb3c       717867836
ecx            0xbf9ff698       -1080035688
edx            0x2ac9cb3c       717867836
ebx            0xa342518        171189528
esp            0xbf9fee38       0xbf9fee38
...

The difference between the esp values is 2,092,200 bytes, which is just below 2 MiB.  According to this recent discussion: https://lists.freebsd.org/pipermail/freebsd-current/2014-August/051585.html the main thread stack size is quite limited, 4MiB on amd64, and just 2MiB on i386!

And indeed, the program seems to hit the stack redzone (the page at 0xbf9fe000-0xbf9ff000 with '---' permissions):

$ procstat -v 48126
  PID      START        END PRT  RES PRES REF SHD   FL TP PATH
48126  0x8048000  0xa291000 r-x 4351 136798   9   1 CN-- vn /home/dim/obj/llvm-215430-1/Release+Debug+Asserts/bin/clang
48126  0xa291000  0xa347000 rw-  182    0   1   0 C--- vn /home/dim/obj/llvm-215430-1/Release+Debug+Asserts/bin/clang
48126  0xa347000  0xa350000 rw-    9    9   1   0 ---- df
48126 0x2a291000 0x2a2a8000 r-x   23    0   1   0 C--- vn /libexec/ld-elf.so.1
48126 0x2a2a8000 0x2a2b1000 rw-    9    9   1   0 ---- df
48126 0x2a2b2000 0x2a2c6000 r-x   18   18  14   6 CN-- vn /lib/libz.so.6
48126 0x2a2c6000 0x2a2c7000 rw-    1    0   1   0 C--- vn /lib/libz.so.6
48126 0x2a2c7000 0x2a2de000 r-x   23    0   1   0 C--- vn /lib/libthr.so.3
48126 0x2a2de000 0x2a2df000 rw-    1    0   1   0 C--- vn /lib/libthr.so.3
48126 0x2a2df000 0x2a2e8000 rw-    8    8   1   0 ---- df
48126 0x2a2e8000 0x2a307000 r-x   31   33   2   1 CN-- vn /lib/libedit.so.7
48126 0x2a307000 0x2a309000 rw-    2    0   1   0 C--- vn /lib/libedit.so.7
48126 0x2a309000 0x2a30b000 rw-    0    0   0   0 ---- --
48126 0x2a30b000 0x2a345000 r-x   56   59  20  10 CN-- vn /lib/libncurses.so.8
48126 0x2a345000 0x2a348000 rw-    3    0   1   0 C--- vn /lib/libncurses.so.8
48126 0x2a348000 0x2a36c000 r-x   27   31   8   4 CN-- vn /lib/libm.so.5
48126 0x2a36c000 0x2a36d000 rw-    1    0   1   0 C--- vn /lib/libm.so.5
48126 0x2a36d000 0x2a416000 r-x   86  101   5   2 CN-- vn /usr/lib/libc++.so.1
48126 0x2a416000 0x2a41a000 rw-    4    0   1   0 C--- vn /usr/lib/libc++.so.1
48126 0x2a41a000 0x2a41b000 rw-    1    1   1   0 ---- df
48126 0x2a41b000 0x2a42f000 r-x   12   13   4   2 CN-- vn /lib/libcxxrt.so.1
48126 0x2a42f000 0x2a430000 rw-    1    0   1   0 C--- vn /lib/libcxxrt.so.1
48126 0x2a430000 0x2a434000 rw-    0    0   0   0 ---- --
48126 0x2a434000 0x2a57c000 r-x  266  290  73  35 CN-- vn /lib/libc.so.7
48126 0x2a57c000 0x2a583000 rw-    7    0   1   0 C--- vn /lib/libc.so.7
48126 0x2a583000 0x2a5a8000 rw-    9    9   1   0 ---- df
48126 0x2a5a8000 0x2a5b3000 r-x   11   12   4   2 CN-- vn /lib/libgcc_s.so.1
48126 0x2a5b3000 0x2a5b4000 rw-    1    0   1   0 C--- vn /lib/libgcc_s.so.1
48126 0x2a5b4000 0x2a610000 rw-   62  175   2   0 ---- df
48126 0x2a800000 0x2b000000 rw-  113  175   2   0 ---- df
48126 0xbf9fe000 0xbf9ff000 ---    0    0   0   0 ---- --
48126 0xbf9ff000 0xbfa1f000 rwx   32   32   1   0 ---D df
48126 0xbfa1f000 0xbfa3f000 rwx   32   32   1   0 ---- df
48126 0xbfa3f000 0xbfa5f000 rwx   32   32   1   0 ---- df
48126 0xbfa5f000 0xbfa7f000 rwx   32   32   1   0 ---- df
48126 0xbfa7f000 0xbfa9f000 rwx   32   32   1   0 ---- df
48126 0xbfa9f000 0xbfabf000 rwx   32   32   1   0 ---- df
48126 0xbfabf000 0xbfadf000 rwx   32   32   1   0 ---- df
48126 0xbfadf000 0xbfaff000 rwx   32   32   1   0 ---- df
48126 0xbfaff000 0xbfb1f000 rwx   32   32   1   0 ---- df
48126 0xbfb1f000 0xbfb3f000 rwx   32   32   1   0 ---- df
48126 0xbfb3f000 0xbfb5f000 rwx   32   32   1   0 ---- df
48126 0xbfb5f000 0xbfb7f000 rwx   32   32   1   0 ---- df
48126 0xbfb7f000 0xbfb9f000 rwx   32   32   1   0 ---- df
48126 0xbfb9f000 0xbfbbf000 rwx   32   32   1   0 ---- df
48126 0xbfbbf000 0xbfbdf000 rwx   32   32   1   0 ---- df
48126 0xbfbdf000 0xbfbff000 rwx   32   32   1   0 ---- df
48126 0xbfbff000 0xbfc00000 r-x    1    1  42   0 ---- ph

I'm not sure if there currently is another way to tweak the default main thread size, except modifying FreeBSD's libthr sources, and recompiling the library. :-/  I did it though, and when I doubled the size to 4MiB, the testcase succeeded!

I guess I should now go and put in a FreeBSD PR for this, but in the mean time, isn't there some way to limit the stack recursion in clang, or in the testcase?  I'd say more than 3000 stack frames is a bit much for such a simple expression...
Comment 4 Richard Smith 2014-08-12 17:17:45 PDT
IIRC, the point of this test was to check for an iterator invalidation issue caused by having sufficiently many OpaqueValueExpr evaluations simultaneously in-flight, so I don't think we can reduce the recursion depth here without risking neutering the test.

Do you see this for optimized builds of clang, or only for -O0 builds? At least historically, LLVM-generated -O0 code has been very stack-hungry.
Comment 5 Dimitry Andric 2014-08-13 02:05:22 PDT
(In reply to comment #4)
> IIRC, the point of this test was to check for an iterator invalidation issue
> caused by having sufficiently many OpaqueValueExpr evaluations
> simultaneously in-flight, so I don't think we can reduce the recursion depth
> here without risking neutering the test.
> 
> Do you see this for optimized builds of clang, or only for -O0 builds? At
> least historically, LLVM-generated -O0 code has been very stack-hungry.

This happens with both optimized and unoptimized builds; I just tried it with a Debug+Asserts build.  (Btw, in my experience, optimized builds can also consume quite a bit of stack, due to aggressive inlining.  But this really depends on the code.)

One thing I just noticed in the 'working' case, is that it says "constexpr evaluation exceeded maximum depth of 512 calls".  If I add -fconstexpr-depth 256 to the compile options, it doesn't crash with the default main thread stack size of 2MB.  The maximum I can get it to is -fconstexpr-depth 466.

Maybe there are some other things that could be done to reduce the stack size of the constexpr evaluation, but it's hard to tell without more data.  I'll see if I can lift something from the stack traces.
Comment 6 Richard Smith 2014-08-13 12:58:21 PDT
(In reply to comment #5)
> One thing I just noticed in the 'working' case, is that it says "constexpr
> evaluation exceeded maximum depth of 512 calls".

This is really weird: this test passes for me with -fconstexpr-depth 201 (LastNonzero should recurse 200 times, because 'arr3' has 200 elements). So perhaps there are really two separate issues here:

1) For whatever reason, evaluation of this constant expression is hitting an infinite recursion for you, and

2) Under freebsd, the stack limit is low so you get a crash before you reach the depth limit.

It certainly looks like there's a bug here beyond the stack exhaustion, but without a way to reproduce this, it'll be hard for me to figure out what's causing #1. Can you do some investigation for me?

 - does this fail when evaluating the arr3 static_assert, or for arr1 or arr2?
 - set -fconstexpr-depth 201 and put a breakpoint on the diagnostic in CheckCallLimit in lib/AST/ExprConstant.cpp; it would be useful to know how we get there (presumably the outer conditional operator is evaluating its middle operand, but it shouldn't be, so I'd be interested to know why)
Comment 7 Dimitry Andric 2014-08-16 15:16:44 PDT
(In reply to comment #6)
> (In reply to comment #5)
> > One thing I just noticed in the 'working' case, is that it says "constexpr
> > evaluation exceeded maximum depth of 512 calls".
> 
> This is really weird: this test passes for me with -fconstexpr-depth 201
> (LastNonzero should recurse 200 times, because 'arr3' has 200 elements).

Actually, I already see the 'infinite' recursion with just this minimized version:

template <typename Iter>
constexpr auto LastNonzero(Iter p, Iter q) -> decltype(0) {
  return LastNonzero(p, q)
}
int arr3[]{};
static_assert(LastNonzero(arr3, arr3) , ""

Though creduce has mangled the test so that it never halts anyway. :)


> So
> perhaps there are really two separate issues here:
> 
> 1) For whatever reason, evaluation of this constant expression is hitting an
> infinite recursion for you, and

Yes, this is the part I can't explain.  It seems to depend on random factors whether this occurs or not.  For example, I just did a complete rebuild of 3.5.0rc2 for Release+Asserts+Debug, and then the problem does *not* occur with the constant-expression-cxx11.cpp testcase, only with the minimized version.

I suspect there is a code fragment somewhere in there with undefined behaviour, and this could cause the actual results depend on whatever happened to be on the stack in each of the hundreds of functions called...


> 2) Under freebsd, the stack limit is low so you get a crash before you reach
> the depth limit.

As shown by the minimize testcase, this limit is at a depth of roughly 450.


> It certainly looks like there's a bug here beyond the stack exhaustion, but
> without a way to reproduce this, it'll be hard for me to figure out what's
> causing #1. Can you do some investigation for me?
> 
>  - does this fail when evaluating the arr3 static_assert, or for arr1 or
> arr2?

It's definitely arr3; when I #if 0'd out arr1 and arr2 completely, no crash was reproducible, but with the reverse it easily crashed.


>  - set -fconstexpr-depth 201 and put a breakpoint on the diagnostic in
> CheckCallLimit in lib/AST/ExprConstant.cpp; it would be useful to know how
> we get there (presumably the outer conditional operator is evaluating its
> middle operand, but it shouldn't be, so I'd be interested to know why)

I'm having trouble reproducing this with a build with debug symbols at the moment.  I'm going to try a few things, and hope that it works.  Otherwise, I will have to make do with the build I had without debug symbols...