Crash when trying to render a very deep HTML tree
Repro:
<div id="root">
0
</div>
<script>
const depth = 10000;
let root = document.getElementById("root");
let currentElement = root;
for (let i = 1; i <= depth; i++) {
let newElement = document.createElement("div");
newElement.innerText = i.toString();
currentElement.appendChild(newElement);
currentElement = newElement;
}
</script>
This crashes WebContent with no stack trace printed in the log. Running under debugger shows that it crashes due to EXC_BAD_ACCESS on macOS
The crash happens in a recursive call chain of BlockFormattingContext::layout_block_level_box()/BlockFormattingContext::layout_block_level_children()
Using the --debug-web-content option and connecting gdb, I get a segfault with the following stack trace:
#0 0x00007929608ab75f in _int_malloc (av=av@entry=0x792960a03ac0 <main_arena>, bytes=bytes@entry=280) at ./malloc/malloc.c:4059
#1 0x00007929608ad6e4 in __GI___libc_malloc (bytes=280) at ./malloc/malloc.c:3336
#2 0x00007929652c7c9f in kmalloc_array () at /home/tim/repos/ladybird/AK/kmalloc.h:42
#3 try_ensure_capacity () at /home/tim/repos/ladybird/AK/Vector.h:640
#4 0x0000792965306527 in try_grow_capacity () at /home/tim/repos/ladybird/AK/Vector.h:632
#5 try_append () at /home/tim/repos/ladybird/AK/Vector.h:551
#6 append () at /home/tim/repos/ladybird/AK/Vector.h:258
#7 ensure_last_line_box () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp:83
#8 0x0000792965304a6e in begin_new_line () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp:69
#9 0x00007929652fa59d in generate_line_boxes () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp:253
#10 0x00007929652fa3b7 in run () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp:84
#11 0x00007929652bd1a7 in layout_inline_children () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:476
#12 0x00007929652c4737 in layout_block_level_box () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:685
#13 0x00007929652bd390 in operator() () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:741
#14 for_each_child_of_type<Web::Layout::Box, (lambda at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:740:49)> ()
at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/TreeNode.h:239
#15 for_each_child_of_type<Web::Layout::Box, (lambda at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:740:49)> ()
at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/TreeNode.h:248
#16 layout_block_level_children () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:740
#17 0x00007929652c47ff in layout_block_level_box () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:699
#18 0x00007929652bd390 in operator() () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:741
#19 for_each_child_of_type<Web::Layout::Box, (lambda at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:740:49)> ()
at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/TreeNode.h:239
#20 for_each_child_of_type<Web::Layout::Box, (lambda at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:740:49)> ()
at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/TreeNode.h:248
#21 layout_block_level_children () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:740
#22 0x00007929652c47ff in layout_block_level_box () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:699
#23 0x00007929652bd390 in operator() () at /home/tim/repos/ladybird/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp:741
...
The full stack trace is >30000 frames on my machine.
Stack trace on macOS with lldb (last 30 frames):
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x16d557fe0)
* frame #0: 0x0000000106233b40 liblagom-web.0.dylib`Web::Layout::FormattingContext::content_box_rect_in_ancestor_coordinate_space(this=<unavailable>, used_values=0x000000031d424060, ancestor_box=0x0000000117860440) const at FormattingContext.cpp:1957
frame #1: 0x000000010621583c liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::intrusion_by_floats_into_box(this=0x000000011fb28a90, box_used_values=0x000000031d424060, y_in_box=(m_value = 0)) const at BlockFormattingContext.cpp:1199:29
frame #2: 0x0000000106247c28 liblagom-web.0.dylib`Web::Layout::InlineFormattingContext::available_space_for_line(this=0x000000016d558398, y=<unavailable>) const at InlineFormattingContext.cpp:62:32
frame #3: 0x000000010625394c liblagom-web.0.dylib`Web::Layout::LineBuilder::recalculate_available_space(this=0x000000016d558138) at LineBuilder.cpp:343:51
frame #4: 0x0000000106251b9c liblagom-web.0.dylib`Web::Layout::LineBuilder::LineBuilder(Web::Layout::InlineFormattingContext&, Web::Layout::LayoutState&, Web::Layout::LayoutState::UsedValues&) [inlined] Web::Layout::LineBuilder::begin_new_line(this=0x000000016d558138, increment_y=false, is_first_break_in_sequence=true) at LineBuilder.cpp:68:5
frame #5: 0x0000000106251b94 liblagom-web.0.dylib`Web::Layout::LineBuilder::LineBuilder(this=0x000000016d558138, context=<unavailable>, layout_state=<unavailable>, containing_block_used_values=<unavailable>) at LineBuilder.cpp:19:5
frame #6: 0x0000000106247e68 liblagom-web.0.dylib`Web::Layout::InlineFormattingContext::generate_line_boxes(this=0x000000016d558398, layout_mode=Normal) at InlineFormattingContext.cpp:253:17
frame #7: 0x0000000106247cfc liblagom-web.0.dylib`Web::Layout::InlineFormattingContext::run(this=0x000000016d558398, (null)=<unavailable>, layout_mode=<unavailable>, available_space=<unavailable>) at InlineFormattingContext.cpp:84:5
frame #8: 0x000000010620e328 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_inline_children(this=0x000000011fb28a90, block_container=0x000000031b874840, layout_mode=Normal, available_space=0x000000016d558670) at BlockFormattingContext.cpp:476:13
frame #9: 0x00000001062144d4 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_box(this=0x000000011fb28a90, box=0x000000031b874840, block_container=0x000000031b874540, layout_mode=Normal, bottom_of_lowest_margin_box=<unavailable>, available_space=0x000000016d558b50) at BlockFormattingContext.cpp:685:13
frame #10: 0x000000010620e634 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) [inlined] Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&)::$_6::operator()(this=<unavailable>, box=0x000000031b874840) const at BlockFormattingContext.cpp:741:9
frame #11: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) at TreeNode.h:239:21
frame #12: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) [inlined] void Web::TreeNode<Web::Layout::Node>::for_each_child_of_type<Web::Layout::Box, Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&)::$_6>(this=0x000000031b874558, callback=<unavailable>) const at TreeNode.h:248:54
frame #13: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(this=0x000000011fb28a90, block_container=0x000000031b874540, layout_mode=Normal, available_space=0x000000016d558b50) at BlockFormattingContext.cpp:740:21
frame #14: 0x00000001062145b8 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_box(this=<unavailable>, box=<unavailable>, block_container=0x000000031b874340, layout_mode=<unavailable>, bottom_of_lowest_margin_box=<unavailable>, available_space=<unavailable>) at BlockFormattingContext.cpp:699:13
frame #15: 0x000000010620e634 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) [inlined] Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&)::$_6::operator()(this=<unavailable>, box=0x000000031b874540) const at BlockFormattingContext.cpp:741:9
frame #16: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) at TreeNode.h:239:21
frame #17: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) [inlined] void Web::TreeNode<Web::Layout::Node>::for_each_child_of_type<Web::Layout::Box, Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&)::$_6>(this=0x000000031b874358, callback=<unavailable>) const at TreeNode.h:248:54
frame #18: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(this=0x000000011fb28a90, block_container=0x000000031b874340, layout_mode=Normal, available_space=0x000000016d559030) at BlockFormattingContext.cpp:740:21
frame #19: 0x00000001062145b8 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_box(this=<unavailable>, box=<unavailable>, block_container=0x000000031b874140, layout_mode=<unavailable>, bottom_of_lowest_margin_box=<unavailable>, available_space=<unavailable>) at BlockFormattingContext.cpp:699:13
frame #20: 0x000000010620e634 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) [inlined] Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&)::$_6::operator()(this=<unavailable>, box=0x000000031b874340) const at BlockFormattingContext.cpp:741:9
frame #21: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) at TreeNode.h:239:21
frame #22: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) [inlined] void Web::TreeNode<Web::Layout::Node>::for_each_child_of_type<Web::Layout::Box, Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&)::$_6>(this=0x000000031b874158, callback=<unavailable>) const at TreeNode.h:248:54
frame #23: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(this=0x000000011fb28a90, block_container=0x000000031b874140, layout_mode=Normal, available_space=0x000000016d559510) at BlockFormattingContext.cpp:740:21
frame #24: 0x00000001062145b8 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_box(this=<unavailable>, box=<unavailable>, block_container=0x000000031b870e40, layout_mode=<unavailable>, bottom_of_lowest_margin_box=<unavailable>, available_space=<unavailable>) at BlockFormattingContext.cpp:699:13
frame #25: 0x000000010620e634 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) [inlined] Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&)::$_6::operator()(this=<unavailable>, box=0x000000031b874140) const at BlockFormattingContext.cpp:741:9
frame #26: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) at TreeNode.h:239:21
frame #27: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&) [inlined] void Web::TreeNode<Web::Layout::Node>::for_each_child_of_type<Web::Layout::Box, Web::Layout::BlockFormattingContext::layout_block_level_children(Web::Layout::BlockContainer const&, Web::Layout::LayoutMode, Web::Layout::AvailableSpace const&)::$_6>(this=0x000000031b870e58, callback=<unavailable>) const at TreeNode.h:248:54
frame #28: 0x000000010620e618 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_children(this=0x000000011fb28a90, block_container=0x000000031b870e40, layout_mode=Normal, available_space=0x000000016d5599f0) at BlockFormattingContext.cpp:740:21
frame #29: 0x00000001062145b8 liblagom-web.0.dylib`Web::Layout::BlockFormattingContext::layout_block_level_box(this=<unavailable>, box=<unavailable>, block_container=0x000000031b870c40, layout_mode=<unavailable>, bottom_of_lowest_margin_box=<unavailable>, available_space=<unavailable>) at BlockFormattingContext.cpp:699:13
...
The segfault is definitely caused by a stack overflow. On macOS (Aarch64) the crash happens on instruction stp x29, x30, [sp, #-0x10]!, which stores frame pointer (x29) and return address (x30) on the stack.
Is this still an issue? The example doesn't crash for me on the current master 11dc254d27e8f98ef95ef07d36da4610f0502299