Skip to content

Commit

Permalink
Emit: fix possible stack-overflow by adding maxdepth; add append
Browse files Browse the repository at this point in the history
  • Loading branch information
biojppm committed May 19, 2024
1 parent dce9afc commit 60baa16
Show file tree
Hide file tree
Showing 3 changed files with 380 additions and 147 deletions.
11 changes: 10 additions & 1 deletion changelog/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,18 @@ Most of the changes are from the giant Parser refactor described below. Before g

### Fixes

- Fix `_RYML_CB_ALLOC()` using `T` in parenthesis, making the macro unusable.
- [#PR431](https://github.com/biojppm/rapidyaml/pull/431) - Emitter: prevent stack overflows when emitting malicious trees by providing a max tree depth for the emit visitor. This was done by adding an `EmitOptions` structure as an argument both to the emitter and to the emit functions, which is then forwarded to the emitter. This `EmitOptions` structure has a max tree depth setting with a default value of 64.
- [#PR431](https://github.com/biojppm/rapidyaml/pull/431) - Fix `_RYML_CB_ALLOC()` using `(T)` in parenthesis, making the macro unusable.


### New features

- [#PR431](https://github.com/biojppm/rapidyaml/pull/431) - append-emitting to the `emitrs_` functions, suggested in [#345](https://github.com/biojppm/rapidyaml/issues/345). This was achieved by adding a `bool append=false` as the last parameter of these functions.


------
All other changes come from [#PR414](https://github.com/biojppm/rapidyaml/pull/414).

### Parser refactor

The parser was completely refactored ([#PR414](https://github.com/biojppm/rapidyaml/pull/414)). This was a large and hard job carried out over several months, but it brings important improvements.
Expand Down
21 changes: 6 additions & 15 deletions src/c4/yml/emit.def.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,6 @@ substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, id_type id, bool
return this->Writer::_get(error_on_excess);
}

template<class Writer>
substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, bool error_on_excess)
{
if(t.empty())
return {};
return this->emit_as(type, t, t.root_id(), error_on_excess);
}

template<class Writer>
substr Emitter<Writer>::emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess)
{
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return this->emit_as(type, *n.tree(), n.id(), error_on_excess);
}


//-----------------------------------------------------------------------------

Expand Down Expand Up @@ -263,6 +248,8 @@ void Emitter<Writer>::_do_visit_flow_sl(id_type node, id_type ilevel)
RYML_ASSERT(!m_tree->is_stream(node));
RYML_ASSERT(m_tree->is_container(node) || m_tree->is_doc(node));
RYML_ASSERT(m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
if(C4_UNLIKELY(ilevel > m_opts.max_depth()))
_RYML_CB_ERR(m_tree->callbacks(), "max depth exceeded");

if(m_tree->is_doc(node))
{
Expand Down Expand Up @@ -368,6 +355,8 @@ void Emitter<Writer>::_do_visit_flow_ml(id_type id, id_type ilevel, id_type do_i
C4_UNUSED(id);
C4_UNUSED(ilevel);
C4_UNUSED(do_indent);
if(C4_UNLIKELY(ilevel > m_opts.max_depth()))
_RYML_CB_ERR(m_tree->callbacks(), "max depth exceeded");
const bool prev_flow = m_flow;
m_flow = true;
c4::yml::error("not implemented");
Expand Down Expand Up @@ -461,6 +450,8 @@ void Emitter<Writer>::_do_visit_block(id_type node, id_type ilevel, id_type do_i
RYML_ASSERT(!m_tree->is_stream(node));
RYML_ASSERT(m_tree->is_container(node) || m_tree->is_doc(node));
RYML_ASSERT(m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
if(C4_UNLIKELY(ilevel > m_opts.max_depth()))
_RYML_CB_ERR(m_tree->callbacks(), "max depth exceeded");
if(m_tree->is_doc(node))
{
_write_doc(node);
Expand Down
Loading

0 comments on commit 60baa16

Please sign in to comment.