LibWeb: Fix out-of-bound crash when there's more table cells than cols

Added a getter to ensure we are within a valid range.
This behavior is accepted by other browsers,
and crashed on some pages.
This commit is contained in:
Hermes Junior 2024-11-05 01:13:57 +01:00 committed by Sam Atkins
parent cd5d8f4d95
commit 5dabd468ed
Notes: github-actions[bot] 2024-11-06 09:37:32 +00:00
4 changed files with 111 additions and 14 deletions

View file

@ -0,0 +1,69 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x19 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text>
TableWrapper <(anonymous)> at (8,8) content-size 53.0625x19 [BFC] children: not-inline
Box <table> at (8,8) content-size 53.0625x19 table-box [TFC] children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <colgroup> (not painted) table-column-group children: not-inline
BlockContainer <col> (not painted) children: not-inline
BlockContainer <col> (not painted) children: not-inline
BlockContainer <col> (not painted) children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
Box <tbody> at (8,8) content-size 53.0625x19 table-row-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
Box <tr> at (8,8) content-size 53.0625x19 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> at (9,9) content-size 14.265625x17 table-cell [BFC] children: inline
frag 0 from TextNode start: 0, length: 1, rect: [9,9 14.265625x17] baseline: 13.296875
"A"
TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> at (25.265625,9) content-size 9.34375x17 table-cell [BFC] children: inline
frag 0 from TextNode start: 0, length: 1, rect: [25.265625,9 9.34375x17] baseline: 13.296875
"B"
TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> at (36.609375,9) content-size 10.3125x17 table-cell [BFC] children: inline
frag 0 from TextNode start: 0, length: 1, rect: [36.609375,9 10.3125x17] baseline: 13.296875
"C"
TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> at (48.921875,9) content-size 11.140625x17 table-cell [BFC] children: inline
frag 0 from TextNode start: 0, length: 1, rect: [48.921875,9 11.140625x17] baseline: 13.296875
"D"
TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <(anonymous)> at (8,27) content-size 784x0 children: inline
TextNode <#text>
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x600]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x19]
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
PaintableWithLines (TableWrapper(anonymous)) [8,8 53.0625x19]
PaintableBox (Box<TABLE>) [8,8 53.0625x19]
PaintableBox (Box<TBODY>) [8,8 53.0625x19]
PaintableBox (Box<TR>) [8,8 53.0625x19]
PaintableWithLines (BlockContainer<TD>) [8,8 16.265625x19]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<TD>) [24.265625,8 11.34375x19]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<TD>) [35.609375,8 12.3125x19]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<TD>) [47.921875,8 13.140625x19]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,27 784x0]

View file

@ -0,0 +1,23 @@
<style>
table {
border-collapse: collapse;
}
</style>
<body>
<table>
<colgroup>
<col />
<col />
<col />
</colgroup>
<tbody>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
</tr>
</tbody>
</table>
</body>

View file

@ -1504,22 +1504,20 @@ void TableFormattingContext::BorderConflictFinder::collect_row_group_conflicting
void TableFormattingContext::BorderConflictFinder::collect_column_group_conflicting_edges(Vector<ConflictingEdge>& result, Cell const& cell, TableFormattingContext::ConflictingSide edge) const void TableFormattingContext::BorderConflictFinder::collect_column_group_conflicting_edges(Vector<ConflictingEdge>& result, Cell const& cell, TableFormattingContext::ConflictingSide edge) const
{ {
// Left edge of the column group. // Left edge of the column group.
if (m_col_elements_by_index[cell.column_index] && edge == ConflictingSide::Left) { if (auto col_element = get_col_element(cell.column_index); col_element && edge == ConflictingSide::Left) {
result.append({ m_col_elements_by_index[cell.column_index], Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Left, {}, cell.column_index }); result.append({ col_element, Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Left, {}, cell.column_index });
} }
// Right edge of the column group to the left. // Right edge of the column group to the left.
if (cell.column_index >= cell.column_span && m_col_elements_by_index[cell.column_index - cell.column_span] && edge == ConflictingSide::Left) { if (auto col_element = get_col_element(cell.column_index - cell.column_span); col_element && cell.column_index >= cell.column_span && edge == ConflictingSide::Left) {
auto left_column_index = cell.column_index - cell.column_span; result.append({ col_element, Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Right, {}, cell.column_index - cell.column_span });
result.append({ m_col_elements_by_index[left_column_index], Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Right, {}, left_column_index });
} }
// Right edge of the column group. // Right edge of the column group.
if (m_col_elements_by_index[cell.column_index] && edge == ConflictingSide::Right) { if (auto col_element = get_col_element(cell.column_index); col_element && edge == ConflictingSide::Right) {
result.append({ m_col_elements_by_index[cell.column_index], Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Right, {}, cell.column_index }); result.append({ col_element, Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Right, {}, cell.column_index });
} }
// Left edge of the column group to the right. // Left edge of the column group to the right.
if (cell.column_index + cell.column_span < m_col_elements_by_index.size() && m_col_elements_by_index[cell.column_index + cell.column_span] && edge == ConflictingSide::Right) { if (auto col_element = get_col_element(cell.column_index - cell.column_span); col_element && edge == ConflictingSide::Right) {
auto right_column_index = cell.column_index + cell.column_span; result.append({ col_element, Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Left, {}, cell.column_index + cell.column_span });
result.append({ m_col_elements_by_index[right_column_index], Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Left, {}, right_column_index });
} }
} }
@ -1527,15 +1525,15 @@ void TableFormattingContext::BorderConflictFinder::collect_table_box_conflicting
{ {
// Top edge from column group or table. Left and right edges of the column group are handled in collect_column_group_conflicting_edges. // Top edge from column group or table. Left and right edges of the column group are handled in collect_column_group_conflicting_edges.
if (cell.row_index == 0 && edge == ConflictingSide::Top) { if (cell.row_index == 0 && edge == ConflictingSide::Top) {
if (m_col_elements_by_index[cell.column_index]) { if (auto col_element = get_col_element(cell.column_index); col_element) {
result.append({ m_col_elements_by_index[cell.column_index], Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Top, {}, cell.column_index }); result.append({ col_element, Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Top, {}, cell.column_index });
} }
result.append({ &m_context->table_box(), Painting::PaintableBox::ConflictingElementKind::Table, ConflictingSide::Top, {}, {} }); result.append({ &m_context->table_box(), Painting::PaintableBox::ConflictingElementKind::Table, ConflictingSide::Top, {}, {} });
} }
// Bottom edge from column group or table. Left and right edges of the column group are handled in collect_column_group_conflicting_edges. // Bottom edge from column group or table. Left and right edges of the column group are handled in collect_column_group_conflicting_edges.
if (cell.row_index + cell.row_span == m_context->m_rows.size() && edge == ConflictingSide::Bottom) { if (cell.row_index + cell.row_span == m_context->m_rows.size() && edge == ConflictingSide::Bottom) {
if (m_col_elements_by_index[cell.column_index]) { if (auto col_element = get_col_element(cell.column_index); col_element) {
result.append({ m_col_elements_by_index[cell.column_index], Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Bottom, {}, cell.column_index }); result.append({ col_element, Painting::PaintableBox::ConflictingElementKind::ColumnGroup, ConflictingSide::Bottom, {}, cell.column_index });
} }
result.append({ &m_context->table_box(), Painting::PaintableBox::ConflictingElementKind::Table, ConflictingSide::Bottom, {}, {} }); result.append({ &m_context->table_box(), Painting::PaintableBox::ConflictingElementKind::Table, ConflictingSide::Bottom, {}, {} });
} }

View file

@ -168,6 +168,13 @@ private:
void collect_column_group_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const; void collect_column_group_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
void collect_table_box_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const; void collect_table_box_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
JS::GCPtr<Node const> get_col_element(size_t index) const
{
if (index >= m_col_elements_by_index.size())
return {};
return m_col_elements_by_index[index];
}
struct RowGroupInfo { struct RowGroupInfo {
JS::GCPtr<Node const> row_group; JS::GCPtr<Node const> row_group;
size_t start_index; size_t start_index;