aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/serd/reader.h3
-rw-r--r--include/serd/world.h29
-rw-r--r--src/reader.c4
-rw-r--r--src/serdi.c5
-rw-r--r--src/world.c19
-rw-r--r--src/world.h1
-rw-r--r--test/test_overflow.c6
-rw-r--r--test/test_reader_writer.c22
8 files changed, 74 insertions, 15 deletions
diff --git a/include/serd/reader.h b/include/serd/reader.h
index cc19a9b8..a2b2698d 100644
--- a/include/serd/reader.h
+++ b/include/serd/reader.h
@@ -31,8 +31,7 @@ typedef struct SerdReaderImpl SerdReader;
SERD_API SerdReader* SERD_ALLOCATED
serd_reader_new(SerdWorld* SERD_NONNULL world,
SerdSyntax syntax,
- const SerdSink* SERD_NONNULL sink,
- size_t stack_size);
+ const SerdSink* SERD_NONNULL sink);
/**
Enable or disable strict parsing.
diff --git a/include/serd/world.h b/include/serd/world.h
index abf2999c..fe381628 100644
--- a/include/serd/world.h
+++ b/include/serd/world.h
@@ -7,6 +7,9 @@
#include "serd/attributes.h"
#include "serd/error.h"
#include "serd/node.h"
+#include "serd/status.h"
+
+#include <stddef.h>
SERD_BEGIN_DECLS
@@ -19,6 +22,11 @@ SERD_BEGIN_DECLS
/// Global library state
typedef struct SerdWorldImpl SerdWorld;
+/// Resource limits to control allocation
+typedef struct {
+ size_t reader_stack_size;
+} SerdLimits;
+
/**
Create a new Serd World.
@@ -33,6 +41,27 @@ SERD_API void
serd_world_free(SerdWorld* SERD_NULLABLE world);
/**
+ Return the current resource limits.
+
+ These determine how much memory is allocated for reading and writing (where
+ the required stack space depends on the input data. The defaults use about
+ a megabyte and over 100 levels of nesting, which is more than enough for
+ most data.
+*/
+SERD_API SerdLimits
+serd_world_limits(const SerdWorld* SERD_NONNULL world);
+
+/**
+ Set the current resource limits.
+
+ This updates the "current" limits, that is, those that will be used after
+ this call. It can be used to configure allocation sizes before calling some
+ other function like serd_reader_new() that uses the current limits.
+*/
+SERD_API SerdStatus
+serd_world_set_limits(SerdWorld* SERD_NONNULL world, SerdLimits limits);
+
+/**
Return a unique blank node.
The returned node is valid only until the next time serd_world_get_blank()
diff --git a/src/reader.c b/src/reader.c
index 61da89ff..4702131e 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -146,9 +146,9 @@ serd_reader_read_document(SerdReader* const reader)
SerdReader*
serd_reader_new(SerdWorld* const world,
const SerdSyntax syntax,
- const SerdSink* const sink,
- const size_t stack_size)
+ const SerdSink* const sink)
{
+ const size_t stack_size = world->limits.reader_stack_size;
if (stack_size < 3 * sizeof(SerdNode) + 192 + serd_node_align) {
return NULL;
}
diff --git a/src/serdi.c b/src/serdi.c
index 0610069d..105bda46 100644
--- a/src/serdi.c
+++ b/src/serdi.c
@@ -245,8 +245,11 @@ main(int argc, char** argv)
SerdWriter* const writer = serd_writer_new(
world, output_syntax, writer_flags, env, (SerdWriteFunc)fwrite, out_fd);
+ const SerdLimits limits = {stack_size};
+ serd_world_set_limits(world, limits);
+
SerdReader* const reader =
- serd_reader_new(world, input_syntax, serd_writer_sink(writer), stack_size);
+ serd_reader_new(world, input_syntax, serd_writer_sink(writer));
serd_reader_set_strict(reader, !lax);
if (quiet) {
diff --git a/src/world.c b/src/world.c
index 21cdffab..7fb5eea2 100644
--- a/src/world.c
+++ b/src/world.c
@@ -16,6 +16,7 @@
# include <fcntl.h>
#endif
+#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
@@ -102,7 +103,8 @@ serd_world_new(void)
return NULL;
}
- world->blank_node = blank_node;
+ world->limits.reader_stack_size = 1048576U;
+ world->blank_node = blank_node;
return world;
}
@@ -116,6 +118,21 @@ serd_world_free(SerdWorld* const world)
}
}
+SerdLimits
+serd_world_limits(const SerdWorld* const world)
+{
+ assert(world);
+ return world->limits;
+}
+
+SerdStatus
+serd_world_set_limits(SerdWorld* const world, const SerdLimits limits)
+{
+ assert(world);
+ world->limits = limits;
+ return SERD_SUCCESS;
+}
+
const SerdNode*
serd_world_get_blank(SerdWorld* const world)
{
diff --git a/src/world.h b/src/world.h
index b330d4e4..96252a7a 100644
--- a/src/world.h
+++ b/src/world.h
@@ -13,6 +13,7 @@
#include <stdio.h>
struct SerdWorldImpl {
+ SerdLimits limits;
SerdErrorFunc error_func;
void* error_handle;
uint32_t next_blank_id;
diff --git a/test/test_overflow.c b/test/test_overflow.c
index 62154958..ac47d239 100644
--- a/test/test_overflow.c
+++ b/test/test_overflow.c
@@ -17,8 +17,12 @@ test_size(SerdWorld* const world,
const SerdSyntax syntax,
const size_t stack_size)
{
+ SerdLimits limits = serd_world_limits(world);
+ limits.reader_stack_size = stack_size;
+ serd_world_set_limits(world, limits);
+
SerdSink* sink = serd_sink_new(NULL, NULL, NULL);
- SerdReader* const reader = serd_reader_new(world, syntax, sink, stack_size);
+ SerdReader* const reader = serd_reader_new(world, syntax, sink);
if (!reader) {
return SERD_BAD_STACK;
}
diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c
index 3cacd4be..fd9c0d28 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -162,7 +162,7 @@ test_read_nquads_chunks(const char* const path)
SerdSink* const sink = serd_sink_new(&rt, test_sink, NULL);
assert(sink);
- SerdReader* const reader = serd_reader_new(world, SERD_NQUADS, sink, 4096);
+ SerdReader* const reader = serd_reader_new(world, SERD_NQUADS, sink);
assert(reader);
SerdStatus st = serd_reader_start_stream(
@@ -241,7 +241,7 @@ test_read_turtle_chunks(const char* const path)
SerdSink* sink = serd_sink_new(&rt, test_sink, NULL);
assert(sink);
- SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
+ SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink);
assert(reader);
SerdStatus st = serd_reader_start_stream(
@@ -321,7 +321,7 @@ test_read_string(void)
SerdSink* sink = serd_sink_new(&rt, test_sink, NULL);
assert(sink);
- SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
+ SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink);
assert(reader);
// Test reading a string that ends exactly at the end of input (no newline)
@@ -386,8 +386,8 @@ test_write_errors(void)
SerdWriter* const writer =
serd_writer_new(world, syntax, 0U, env, faulty_sink, &ctx);
- const SerdSink* const sink = serd_writer_sink(writer);
- SerdReader* const reader = serd_reader_new(world, SERD_TRIG, sink, 4096U);
+ const SerdSink* const sink = serd_writer_sink(writer);
+ SerdReader* const reader = serd_reader_new(world, SERD_TRIG, sink);
SerdStatus st = serd_reader_start_string(reader, doc_string, NULL);
assert(!st);
@@ -513,9 +513,15 @@ test_reader(const char* path)
assert(sink);
// Test that too little stack space fails gracefully
- assert(!serd_reader_new(world, SERD_TURTLE, sink, 32));
-
- SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
+ const SerdLimits old_limits = serd_world_limits(world);
+ SerdLimits limits = old_limits;
+ limits.reader_stack_size = 32U;
+ serd_world_set_limits(world, limits);
+ assert(!serd_reader_new(world, SERD_TURTLE, sink));
+
+ // Restore original limits and successfully create reader
+ serd_world_set_limits(world, old_limits);
+ SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink);
assert(reader);
assert(serd_reader_read_chunk(reader) == SERD_FAILURE);