aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/writer.c25
-rw-r--r--test/test_writer.c56
2 files changed, 74 insertions, 7 deletions
diff --git a/src/writer.c b/src/writer.c
index a2ba0482..b132dc83 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -501,11 +501,11 @@ reset_context(SerdWriter* writer, bool graph)
}
static SerdStatus
-free_context(SerdWriter* writer)
+free_context(const WriteContext* const ctx)
{
- serd_node_free(writer->context.graph);
- serd_node_free(writer->context.subject);
- serd_node_free(writer->context.predicate);
+ serd_node_free(ctx->graph);
+ serd_node_free(ctx->subject);
+ serd_node_free(ctx->predicate);
return SERD_SUCCESS;
}
@@ -888,6 +888,10 @@ serd_writer_write_statement(SerdWriter* const writer,
if (flags & (SERD_ANON_S_BEGIN | SERD_ANON_O_BEGIN)) {
WriteContext* ctx =
(WriteContext*)serd_stack_push(&writer->anon_stack, sizeof(WriteContext));
+ if (!ctx) {
+ return SERD_ERR_OVERFLOW;
+ }
+
*ctx = writer->context;
WriteContext new_context = {
serd_node_copy(graph), serd_node_copy(subject), NULL};
@@ -916,7 +920,7 @@ serd_writer_end_anon(SerdWriter* writer, const SerdNode* node)
}
--writer->indent;
write_sep(writer, SEP_ANON_END);
- free_context(writer);
+ free_context(&writer->context);
writer->context = *anon_stack_top(writer);
serd_stack_pop(&writer->anon_stack, sizeof(WriteContext));
const bool is_subject = serd_node_equals(node, writer->context.subject);
@@ -937,7 +941,7 @@ serd_writer_finish(SerdWriter* writer)
write_sep(writer, SEP_GRAPH_END);
}
serd_byte_sink_flush(&writer->byte_sink);
- free_context(writer);
+ free_context(&writer->context);
writer->indent = 0;
writer->context = WRITE_CONTEXT_NULL;
return SERD_SUCCESS;
@@ -958,7 +962,7 @@ serd_writer_new(SerdSyntax syntax,
writer->env = env;
writer->root_node = NULL;
writer->root_uri = SERD_URI_NULL;
- writer->anon_stack = serd_stack_new(4 * sizeof(WriteContext));
+ writer->anon_stack = serd_stack_new(SERD_PAGE_SIZE);
writer->context = context;
writer->list_subj = NULL;
writer->empty = true;
@@ -1077,6 +1081,13 @@ serd_writer_free(SerdWriter* writer)
}
serd_writer_finish(writer);
+
+ // Free any leaked entries in the anonymous context stack
+ while (!serd_stack_is_empty(&writer->anon_stack)) {
+ free_context(anon_stack_top(writer));
+ serd_stack_pop(&writer->anon_stack, sizeof(WriteContext));
+ }
+
serd_stack_free(&writer->anon_stack);
free(writer->bprefix);
serd_byte_sink_free(&writer->byte_sink);
diff --git a/test/test_writer.c b/test/test_writer.c
index 190995b6..19aaf4b3 100644
--- a/test/test_writer.c
+++ b/test/test_writer.c
@@ -19,6 +19,7 @@
#include "serd/serd.h"
#include <assert.h>
+#include <stdio.h>
#include <string.h>
static void
@@ -82,11 +83,66 @@ test_write_long_literal(void)
serd_free(out);
}
+static size_t
+null_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
+{
+ (void)buf;
+ (void)stream;
+
+ return size * nmemb;
+}
+
+static void
+test_writer_stack_overflow(void)
+{
+ SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
+ SerdWriter* writer = serd_writer_new(SERD_TURTLE, 0u, env, null_sink, NULL);
+
+ const SerdSink* sink = serd_writer_sink(writer);
+
+ SerdNode* const s = serd_new_uri(SERD_STRING("http://example.org/s"));
+ SerdNode* const p = serd_new_uri(SERD_STRING("http://example.org/p"));
+
+ SerdNode* o = serd_new_blank(SERD_STRING("http://example.org/o"));
+ SerdStatus st = serd_sink_write(sink, SERD_ANON_O_BEGIN, s, p, o, NULL);
+ assert(!st);
+
+ // Repeatedly write nested anonymous objects until the writer stack overflows
+ for (unsigned i = 0u; i < 512u; ++i) {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "b%u", i);
+
+ SerdNode* next_o = serd_new_blank(SERD_STRING(buf));
+
+ st = serd_sink_write(sink, SERD_ANON_O_BEGIN, o, p, next_o, NULL);
+
+ serd_node_free(o);
+ o = next_o;
+
+ if (st) {
+ assert(st == SERD_ERR_OVERFLOW);
+ break;
+ }
+ }
+
+ assert(st == SERD_ERR_OVERFLOW);
+
+ serd_node_free(o);
+ serd_node_free(p);
+ serd_node_free(s);
+ serd_writer_free(writer);
+ serd_env_free(env);
+}
+
int
main(void)
{
test_write_bad_prefix();
test_write_long_literal();
+ test_writer_stack_overflow();
return 0;
}