From b044556df29edfe1f8a9c28d8549887dc657738b Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Fri, 7 Sep 2018 11:20:13 +0200 Subject: [PATCH] Xml_generator: fix exception handling in Node(...) When the functor provided to the Node constructor throws an exception, do revert all changes in reverse order. Previously, the changes made to the parent node were not considered by the exception handler which caused unnecessary characters to remain in the out buffer for each reverted node. Issue #2967 --- repos/base/include/util/xml_generator.h | 30 +++++++++++++++++++++++-- repos/os/run/xml_generator.run | 5 +---- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/repos/base/include/util/xml_generator.h b/repos/base/include/util/xml_generator.h index 615e3118bcd..79f6851e0a1 100644 --- a/repos/base/include/util/xml_generator.h +++ b/repos/base/include/util/xml_generator.h @@ -60,6 +60,9 @@ class Genode::Xml_generator _used += len; } + void undo_append(size_t const len) { + _used = len < _used ? _used - len : 0; } + /** * Append character */ @@ -162,6 +165,8 @@ class Genode::Xml_generator unsigned const _indent_level; Node * const _parent_node = 0; + bool const _parent_was_indented; + bool const _parent_had_content; Out_buffer _out_buffer; @@ -197,6 +202,20 @@ class Genode::Xml_generator return _out_buffer.remainder(); } + void _undo_content_buffer(bool indented, + bool was_indented, + bool had_content) + { + _is_indented = was_indented; + _has_content = had_content; + + if (indented) + _out_buffer.undo_append(1); + + if (!_has_content) + _out_buffer.undo_append(1); + } + /** * Called by sub node */ @@ -217,7 +236,7 @@ class Genode::Xml_generator dst.append(name); dst.append("=\""); dst.append(value, strlen(value)); - dst.append("\""); + dst.append('\"'); _attr_offset += gap; } @@ -241,6 +260,8 @@ class Genode::Xml_generator : _indent_level(xml._curr_indent), _parent_node(xml._curr_node), + _parent_was_indented(_parent_node ? _parent_node->is_indented() : false), + _parent_had_content (_parent_node ? _parent_node->has_content() : false), _out_buffer(_parent_node ? _parent_node->_content_buffer(true) : xml._out_buffer) { @@ -259,8 +280,10 @@ class Genode::Xml_generator func(); } catch (...) { /* reset and drop changes by not committing it */ - xml._curr_node = _parent_node; xml._curr_indent--; + xml._curr_node = _parent_node; + if (_parent_node) { + _parent_node->_undo_content_buffer(true, _parent_was_indented, _parent_had_content); } throw; } @@ -286,6 +309,9 @@ class Genode::Xml_generator _out_buffer.append('\0'); } + + bool has_content() { return _has_content; } + bool is_indented() { return _is_indented; } }; Out_buffer _out_buffer; diff --git a/repos/os/run/xml_generator.run b/repos/os/run/xml_generator.run index 076d60b0f7c..1feb1f470c7 100644 --- a/repos/os/run/xml_generator.run +++ b/repos/os/run/xml_generator.run @@ -53,20 +53,17 @@ compare_output_to { [init -> test-xml_generator] exception on level3 (expected exception value=11) [init -> test-xml_generator] exception on level3 (expected exception value=12) [init -> test-xml_generator] - [init -> test-xml_generator] used 183 bytes, result: + [init -> test-xml_generator] used 180 bytes, result: [init -> test-xml_generator] [init -> test-xml_generator] [init -> test-xml_generator] [init -> test-xml_generator] - [init -> test-xml_generator] [init -> test-xml_generator] [init -> test-xml_generator] [init -> test-xml_generator] - [init -> test-xml_generator] [init -> test-xml_generator] [init -> test-xml_generator] [init -> test-xml_generator] - [init -> test-xml_generator] [init -> test-xml_generator] [init -> test-xml_generator] [init -> test-xml_generator]