This is an archive of the discontinued LLVM Phabricator instance.

[flang] Avoid crashing from recursion on very tall expression parse trees
ClosedPublic

Authored by klausler on Jan 27 2023, 9:58 AM.

Details

Summary

In the parse tree visitation framework (Parser/parse-tree-visitor.h)
and in the semantic analyzer for expressions (Semantics/expression.cpp)
avoid crashing due to stack size limitations by using an iterative
traversal algorithm rather than straightforward recursive tree walking.
The iterative approach is the obvious one of building a work queue and
using it to (in the case of the parse tree visitor) call the visitor
object's Pre() and Post() routines on subexpressions in the same order
as they would have been called during a recursive traversal.

This change helps the compiler survive some artificial stress tests
and perhaps with future exposure to machine-generated source code.

Diff Detail

Event Timeline

klausler created this revision.Jan 27 2023, 9:58 AM
Herald added a project: Restricted Project. · View Herald Transcript
klausler requested review of this revision.Jan 27 2023, 9:58 AM

The code looks good to me, but the torture test seems too big for windows bot: subprocess.CalledProcessError: Command '['c:\\ws\\w32-1\\llvm-project\\premerge-checks\\build\\bin\\flang-new.exe', '-fc1', '-fdebug-dump-symbols', 'C:\\ws\\w32-1\\llvm-project\\premerge-checks\\flang\\test\\Evaluate\\big-expr-tree.F90']' returned non-zero exit status 3221225477.

It led me to try this patch with a linux debug build (I had previously tried a release with no issue), and it crashed on the test. Unless both these crashes are exposing new critical stack overflow issue, I think it might be a bit too risky to put a torture test in default regression tests. Maybe that 4096 or even 1024 repetitions in default regression tests are enough (4096 passed in debug for me).

The stack overflow segfault I saw in debug mode is quite interesting because it happens inside the parser::Program destructor... See the reverse backtrace:

[... inner backtrace]
#177348 0x0000000004ec4df5 in Fortran::parser::ProgramUnit::~ProgramUnit (this=0x9f5a0c0) at flang/include/flang/Parser/parse-tree.h:549
#177349 0x0000000004ec4dd9 in std::__1::allocator_traits<std::__1::allocator<std::__1::__list_node<Fortran::parser::ProgramUnit, void*> > >::__destroy<Fortran::parser::ProgramUnit> (__p=0x9f5a0c0) at include/c++/v1/memory:1747
#177350 0x0000000004ec4c5d in std::__1::allocator_traits<std::__1::allocator<std::__1::__list_node<Fortran::parser::ProgramUnit, void*> > >::destroy<Fortran::parser::ProgramUnit> (__a=..., __p=0x9f5a0c0) at c++/v1/memory:1595
#177351 0x0000000004ec4af6 in std::__1::__list_imp<Fortran::parser::ProgramUnit, std::__1::allocator<Fortran::parser::ProgramUnit> >::clear (this=0x7fffffffc138)  at include/c++/v1/list:762
#177352 0x0000000004ec4a35 in std::__1::__list_imp<Fortran::parser::ProgramUnit, std::__1::allocator<Fortran::parser::ProgramUnit> >::~__list_imp (this=0x7fffffffc138) at include/c++/v1/list:741
#177353 0x0000000004ec4a18 in std::__1::list<Fortran::parser::ProgramUnit, std::__1::allocator<Fortran::parser::ProgramUnit> >::~list (this=0x7fffffffc138) at include/c++/v1/list:834
#177354 0x0000000004ec49f5 in Fortran::parser::Program::~Program (this=0x7fffffffc138) at flang/include/flang/Parser/parse-tree.h:561
#177355 0x0000000004ec49da in std::__1::__optional_destruct_base<Fortran::parser::Program, false>::~__optional_destruct_base (this=0x7fffffffc138)  at include/c++/v1/optional:225
#177356 0x0000000004ec49a8 in std::__1::__optional_storage_base<Fortran::parser::Program, false>::~__optional_storage_base (this=0x7fffffffc138)  at /include/c++/v1/optional:285
#177357 0x0000000004ec4988 in std::__1::__optional_copy_base<Fortran::parser::Program, false>::~__optional_copy_base (this=0x7fffffffc138)  at include/c++/v1/optional:454
#177358 0x0000000004ec4968 in std::__1::__optional_move_base<Fortran::parser::Program, false>::~__optional_move_base (this=0x7fffffffc138)   at include/c++/v1/optional:482
#177359 0x0000000004ec4948 in std::__1::__optional_copy_assign_base<Fortran::parser::Program, false>::~__optional_copy_assign_base (this=0x7fffffffc138)    at include/c++/v1/optional:515
#177360 0x0000000004ec4928 in std::__1::__optional_move_assign_base<Fortran::parser::Program, false>::~__optional_move_assign_base (this=0x7fffffffc138)   at include/c++/v1/optional:547
#177361 0x0000000004ec33c8 in std::__1::optional<Fortran::parser::Program>::~optional (this=0x7fffffffc138)   at include/c++/v1/optional:584
[... outer backtrace in the driver]

Not sure if Windows crash happens in the parse tree dtor too.

klausler updated this revision to Diff 493964.Feb 1 2023, 8:19 AM

Reduce test size so that it passes on Windows.

klausler updated this revision to Diff 493985.Feb 1 2023, 9:29 AM

Try again to tweak test so that it passes on Windows.

jeanPerier accepted this revision.Feb 1 2023, 10:46 AM

Thanks, LGTM

This revision is now accepted and ready to land.Feb 1 2023, 10:46 AM