diff options
-rw-r--r-- | include/serd/reader.h | 3 | ||||
-rw-r--r-- | include/serd/world.h | 29 | ||||
-rw-r--r-- | src/reader.c | 4 | ||||
-rw-r--r-- | src/serdi.c | 5 | ||||
-rw-r--r-- | src/world.c | 19 | ||||
-rw-r--r-- | src/world.h | 1 | ||||
-rw-r--r-- | test/test_overflow.c | 6 | ||||
-rw-r--r-- | test/test_reader_writer.c | 22 |
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); |