fix Issue 18026 - Stack overflow in dmd/dtemplate.d:6248, TemplateInstance::needsCodegen()#14787
fix Issue 18026 - Stack overflow in dmd/dtemplate.d:6248, TemplateInstance::needsCodegen()#14787Geod24 merged 5 commits intodlang:stablefrom
Conversation
|
Thanks for your pull request, @ibuclaw! Bugzilla references
Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "stable + dmd#14787" |
|
Tested on weka's codebase, no issues. |
128cb88 to
24c08e8
Compare
…tance::needsCodegen()
|
Changed so that the nested function returns a ThreeState instead. |
|
Thx for working on this. - My biggest concern is that iterating over the siblings doesn't clear their |
|
One nice effect of this, AFAICT, is that |
Though calling |
I don't like this side effect of |
I'd prefer the assert, as it really shouldn't happen anymore, and then makes my point wrt. missing reset for secondary siblings moot. This was an observation last time I looked at this brainfuck mess, and I was thinking about adding a 2nd Every secondary sibling should only be checked at most once then, when checking the siblings of the primary instance. And the primary one gets its |
Looks like there's no guarantee that non-primary instantiations have been set-up correctly, getting asserts from the |
e6d392f to
390b448
Compare
|
@kinke and looks like I still need a https://buildkite.com/dlang/dmd/builds/29578#018598fd-7e4b-47c8-827a-7fb55b19597e |
Yep that should be fine. All the |
|
Note that I came across this sometime later: https://github.com/dlang/dmd/pull/13731/files |
2363567 to
6739d65
Compare
…st' was set to null
|
Is this ready? |
|
How lucky do you feel? |
| return false; | ||
| } | ||
| else if (needsCodegen != ThreeState.none) | ||
| break; |
There was a problem hiding this comment.
Codecov says this is not covered, is it Codecov's issue or really not covered ?
There was a problem hiding this comment.
It's really not covered, because the interior function never returns ThreeState.no.
I left it in to guard us in case that were to change in the future, and also to align with the non-allinst branch.
I think these two branches could be factored because the outer shell is mostly a duplicate now, but I'll leave that for something to look at in far future - maybe one of the strategies will have to go anyway because missing symbols is one of the "big problems" at the moment, and the default strategy to prune prune prune is a massive PITA that isn't helping any cause.
This is best reviewed with whitespace changes hidden. https://github.com/dlang/dmd/pull/14787/files?w=1
Problem:
needsCodegencalls itself recursively, this results in a stack overflow when checking an instance that has a sufficient number of siblings, or is lexically nested deep enough in other template instances, or a quadratic combination of both.To solve: I have isolated the meat of the needsCodegen algorithm (there are two; (1) for
-allinst, (2) for the default emission strategy). Then, the recursive call for instance siblings has been replaced with aforloop.How was the "meat" determined?
The first check is done on the "main" template instance (stored in the
tempdecl.instancesAA), which is the same for every sibling. No need to check this repeatedly, so we leave this block alone and save some processing time as well.dmd/compiler/src/dmd/dtemplate.d
Lines 6258 to 6262 in fc695ff
The
tnextbranch in both the default and allinst emission strategies are there for caching the result ofneedsCodegenonly. They can be part of theforloop body, no need to include them in the nested function.dmd/compiler/src/dmd/dtemplate.d
Lines 6282 to 6296 in fc695ff
dmd/compiler/src/dmd/dtemplate.d
Lines 6339 to 6356 in fc695ff
Everything between (1) and (2) then is the part of the algorithm used to detect whether codegen is required. These have been moved into static nested functions named
needsCodegenAllInst(returnsfalseif no condition hit).dmd/compiler/src/dmd/dtemplate.d
Lines 6268 to 6279 in fc695ff
and
needsCodegenRootOnly(returnstrueif no condition hit).dmd/compiler/src/dmd/dtemplate.d
Lines 6322 to 6336 in fc695ff
There is a case to handle in
needsCodegenRootOnlyfor when theneedsCodegenvariable istrue- meaning "do codegen if the ancestor needs it". For this, thetnextof the instance is set tonullso that no siblings (or further siblings) are checked.There is still recursive checking done for parents (
tinst) of the template instance, so the possibility for a stack overflow is still present if we are handling a deeply nested instance (as in, 100,000+ levels of lexical nestedness). I'm willing to leave that risk in until someone presents a reasonable example which triggers that.Are there any cases that I might have missed here? Do we need to check
tnext.errorson every sibling too?