diff options
author | David Robillard <d@drobilla.net> | 2024-06-23 16:36:12 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2024-06-23 16:36:20 -0400 |
commit | d2663582ca9305a36f9107cf95b951393a1563dc (patch) | |
tree | 39bbc053c24a89f03399a4d5dfd2f63f85b74db2 | |
parent | 24c22074662711dbb6bac2eadca557f98f356a9a (diff) | |
download | serd-d2663582ca9305a36f9107cf95b951393a1563dc.tar.gz serd-d2663582ca9305a36f9107cf95b951393a1563dc.tar.bz2 serd-d2663582ca9305a36f9107cf95b951393a1563dc.zip |
Gracefully handle failure to terminate written anonymous nodes
This case shouldn't be reachable when driven directly from a reader, but can be
reached by invalid use of the writer in an application.
-rw-r--r-- | src/writer.c | 28 | ||||
-rw-r--r-- | test/test_writer.c | 30 |
2 files changed, 44 insertions, 14 deletions
diff --git a/src/writer.c b/src/writer.c index 96e6135d..58d7e64f 100644 --- a/src/writer.c +++ b/src/writer.c @@ -1041,24 +1041,24 @@ serd_writer_write_statement(SerdWriter* writer, } else { // No abbreviation - if (serd_stack_is_empty(&writer->anon_stack)) { - if (writer->context.subject.type) { - TRY(st, write_sep(writer, SEP_END_S)); - } - if (writer->last_sep == SEP_END_S || writer->last_sep == SEP_END_DIRECT) { - TRY(st, write_newline(writer)); - } + if (!serd_stack_is_empty(&writer->anon_stack)) { + return SERD_ERR_BAD_ARG; + } - TRY(st, write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags)); - if ((flags & (SERD_ANON_S_BEGIN | SERD_LIST_S_BEGIN))) { - TRY(st, write_sep(writer, SEP_ANON_S_P)); - } else { - TRY(st, write_sep(writer, SEP_S_P)); - } + if (writer->context.subject.type) { + TRY(st, write_sep(writer, SEP_END_S)); + } - } else { + if (writer->last_sep == SEP_END_S || writer->last_sep == SEP_END_DIRECT) { + TRY(st, write_newline(writer)); + } + + TRY(st, write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags)); + if ((flags & (SERD_ANON_S_BEGIN | SERD_LIST_S_BEGIN))) { TRY(st, write_sep(writer, SEP_ANON_S_P)); + } else { + TRY(st, write_sep(writer, SEP_S_P)); } reset_context(writer, 0U); diff --git a/test/test_writer.c b/test/test_writer.c index 75b311cf..b478f052 100644 --- a/test/test_writer.c +++ b/test/test_writer.c @@ -176,6 +176,35 @@ test_writer_cleanup(void) } static void +test_write_bad_anon_stack(void) +{ + SerdStatus st = SERD_SUCCESS; + SerdEnv* env = serd_env_new(NULL); + SerdWriter* writer = + serd_writer_new(SERD_TURTLE, (SerdStyle)0U, env, NULL, null_sink, NULL); + + SerdNode s = serd_node_from_string(SERD_URI, USTR("http://example.org/s")); + SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/p")); + SerdNode b0 = serd_node_from_string(SERD_BLANK, USTR("b0")); + SerdNode b1 = serd_node_from_string(SERD_BLANK, USTR("b1")); + SerdNode b2 = serd_node_from_string(SERD_BLANK, USTR("b2")); + + assert(!(st = serd_writer_write_statement( + writer, SERD_ANON_O_BEGIN, NULL, &s, &p, &b0, NULL, NULL))); + + // (missing call to end the anonymous node here) + + st = serd_writer_write_statement( + writer, SERD_ANON_O_BEGIN, NULL, &b1, &p, &b2, NULL, NULL); + + assert(st == SERD_ERR_BAD_ARG); + + assert(!(st = serd_writer_finish(writer))); + serd_writer_free(writer); + serd_env_free(env); +} + +static void test_strict_write(void) { const char* const path = "serd_strict_write_test.ttl"; @@ -243,6 +272,7 @@ main(void) test_write_long_literal(); test_write_nested_anon(); test_writer_cleanup(); + test_write_bad_anon_stack(); test_strict_write(); test_write_error(); |