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 18, 2024
1 parent 6c0a4b5 commit 27aba5b
Show file tree
Hide file tree
Showing 3 changed files with 381 additions and 148 deletions.
13 changes: 11 additions & 2 deletions changelog/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@ 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, and the result is:
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 several nice improvements.

- A new event-based parser engine is now in place, enabling the improvements described below. This engine uses a templated event handler, where each event is a function call, which spares branches on the event handler. The parsing code was fully rewritten, and is now much more simple (albeit longer), and much easier to work with and fix.
- YAML standard-conformance was improved significantly. Along with many smaller fixes and additions, (too many to list here), the main changes are the following:
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 27aba5b

Please sign in to comment.