diff --git a/include/prism/internal/oom.h b/include/prism/internal/oom.h new file mode 100644 index 0000000000..11ccd2ce77 --- /dev/null +++ b/include/prism/internal/oom.h @@ -0,0 +1,15 @@ +#ifndef PRISM_INTERNAL_OOM_H +#define PRISM_INTERNAL_OOM_H + +/** + * Called when an allocation that prism cannot recover from fails. By default + * it writes a message to stderr and aborts. A consumer can define PRISM_OOM + * before building prism to handle the failure itself. + */ +#ifndef PRISM_OOM +#include +#include +#define PRISM_OOM() do { fputs("prism out of memory; aborting\n", stderr); abort(); } while (0) +#endif + +#endif diff --git a/prism.gemspec b/prism.gemspec index f9a06c73a1..b63078626f 100644 --- a/prism.gemspec +++ b/prism.gemspec @@ -83,6 +83,7 @@ Gem::Specification.new do |spec| "include/prism/internal/magic_comments.h", "include/prism/internal/memchr.h", "include/prism/internal/node.h", + "include/prism/internal/oom.h", "include/prism/internal/options.h", "include/prism/internal/parser.h", "include/prism/internal/regexp.h", diff --git a/src/arena.c b/src/arena.c index 323c5bdc7d..8c9ce13556 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1,9 +1,9 @@ #include "prism/internal/arena.h" #include "prism/internal/allocator.h" +#include "prism/internal/oom.h" #include -#include #include /** @@ -48,11 +48,7 @@ static pm_arena_block_t * pm_arena_block_new(pm_arena_t *arena, size_t data_size, size_t initial_used) { assert(initial_used <= data_size); pm_arena_block_t *block = (pm_arena_block_t *) xmalloc(PM_ARENA_BLOCK_SIZE(data_size)); - - if (block == NULL) { - fprintf(stderr, "prism: out of memory; aborting\n"); - abort(); - } + if (block == NULL) PRISM_OOM(); block->capacity = data_size; block->used = initial_used; @@ -92,7 +88,7 @@ pm_arena_alloc_slow(pm_arena_t *arena, size_t size) { pm_arena_t * pm_arena_new(void) { pm_arena_t *arena = (pm_arena_t *) xcalloc(1, sizeof(pm_arena_t)); - if (arena == NULL) abort(); + if (arena == NULL) PRISM_OOM(); return arena; } diff --git a/src/buffer.c b/src/buffer.c index b5904355b7..849d3f2eaa 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2,12 +2,12 @@ #include "prism/compiler/inline.h" -#include "prism/internal/char.h" #include "prism/internal/allocator.h" +#include "prism/internal/char.h" +#include "prism/internal/oom.h" #include #include -#include #include #include @@ -20,7 +20,7 @@ pm_buffer_init(pm_buffer_t *buffer, size_t capacity) { buffer->capacity = capacity; buffer->value = (char *) xmalloc(capacity); - if (buffer->value == NULL) abort(); + if (buffer->value == NULL) PRISM_OOM(); } /** @@ -29,7 +29,7 @@ pm_buffer_init(pm_buffer_t *buffer, size_t capacity) { pm_buffer_t * pm_buffer_new(void) { pm_buffer_t *buffer = (pm_buffer_t *) xmalloc(sizeof(pm_buffer_t)); - if (buffer == NULL) abort(); + if (buffer == NULL) PRISM_OOM(); pm_buffer_init(buffer, 1024); return buffer; diff --git a/src/errors_format.c b/src/errors_format.c index 32956a613a..cdde17162b 100644 --- a/src/errors_format.c +++ b/src/errors_format.c @@ -5,6 +5,7 @@ #include "prism/internal/diagnostic.h" #include "prism/internal/encoding.h" #include "prism/internal/line_offset_list.h" +#include "prism/internal/oom.h" #include "prism/internal/parser.h" #include @@ -420,7 +421,7 @@ pm_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, pm_errors_forma if (rich_errors_size / sizeof(pm_rich_error_t) != nerrors) abort(); pm_rich_error_t *rich_errors = xmalloc(rich_errors_size); - if (rich_errors == NULL) abort(); + if (rich_errors == NULL) PRISM_OOM(); bool is_utf8 = true; size_t rich_errors_idx = 0; diff --git a/src/integer.c b/src/integer.c index 25dbf2d7e3..a415f6e3d3 100644 --- a/src/integer.c +++ b/src/integer.c @@ -2,6 +2,7 @@ #include "prism/internal/allocator.h" #include "prism/internal/buffer.h" +#include "prism/internal/oom.h" /* Include sys/types.h before inttypes.h to work around an issue with certain * versions of GCC and newlib which causes omission of PRIu64 and the other @@ -55,7 +56,7 @@ big_add(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint size_t length = left_length < right_length ? right_length : left_length; uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * (length + 1)); - if (values == NULL) return; + if (values == NULL) PRISM_OOM(); uint64_t carry = 0; for (size_t index = 0; index < length; index++) { @@ -92,8 +93,9 @@ big_sub2(pm_integer_t *destination, pm_integer_t *a, pm_integer_t *b, pm_integer INTEGER_EXTRACT(c, c_length, c_values) uint32_t *values = (uint32_t*) xmalloc(sizeof(uint32_t) * a_length); - int64_t carry = 0; + if (values == NULL) PRISM_OOM(); + int64_t carry = 0; for (size_t index = 0; index < a_length; index++) { int64_t sub = ( carry + @@ -143,7 +145,7 @@ karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t * if (left_length <= 10) { size_t length = left_length + right_length; uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t)); - if (values == NULL) return; + if (values == NULL) PRISM_OOM(); for (size_t left_index = 0; left_index < left_length; left_index++) { uint32_t carry = 0; @@ -162,6 +164,7 @@ karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t * if (left_length * 2 <= right_length) { uint32_t *values = (uint32_t *) xcalloc(left_length + right_length, sizeof(uint32_t)); + if (values == NULL) PRISM_OOM(); for (size_t start_offset = 0; start_offset < right_length; start_offset += left_length) { size_t end_offset = start_offset + left_length; @@ -227,6 +230,7 @@ karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t * size_t length = left_length + right_length; uint32_t *values = (uint32_t*) xcalloc(length, sizeof(uint32_t)); + if (values == NULL) PRISM_OOM(); assert(z0.values != NULL); memcpy(values, z0.values, sizeof(uint32_t) * z0.length); @@ -315,7 +319,7 @@ pm_integer_from_uint64(pm_integer_t *integer, uint64_t value, uint64_t base) { } uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * length); - if (values == NULL) return; + if (values == NULL) PRISM_OOM(); for (size_t value_index = 0; value_index < length; value_index++) { values[value_index] = (uint32_t) (value % base); @@ -366,7 +370,7 @@ pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, u assert(bigints_length > 0); pm_integer_t *bigints = (pm_integer_t *) xcalloc(bigints_length, sizeof(pm_integer_t)); - if (bigints == NULL) return; + if (bigints == NULL) PRISM_OOM(); for (size_t index = 0; index < source_length; index += 2) { uint64_t value = source_values[index] + base_from * (index + 1 < source_length ? source_values[index + 1] : 0); @@ -385,6 +389,7 @@ pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, u size_t next_length = (bigints_length + 1) / 2; pm_integer_t *next_bigints = (pm_integer_t *) xcalloc(next_length, sizeof(pm_integer_t)); + if (next_bigints == NULL) PRISM_OOM(); for (size_t bigints_index = 0; bigints_index < bigints_length; bigints_index += 2) { if (bigints_index + 1 == bigints_length) { @@ -425,6 +430,7 @@ pm_integer_parse_powof2(pm_integer_t *integer, uint32_t base, const uint8_t *dig size_t length = (digits_length * bit + 31) / 32; uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t)); + if (values == NULL) PRISM_OOM(); for (size_t digit_index = 0; digit_index < digits_length; digit_index++) { size_t bit_position = bit * (digits_length - digit_index - 1); @@ -451,8 +457,9 @@ pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t di const size_t length = (digits_length + batch - 1) / batch; uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t)); - uint32_t value = 0; + if (values == NULL) PRISM_OOM(); + uint32_t value = 0; for (size_t digits_index = 0; digits_index < digits_length; digits_index++) { value = value * 10 + digits[digits_index]; @@ -476,8 +483,9 @@ pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t * // Allocate an array to store digits. const size_t digits_capa = sizeof(uint8_t) * (size_t) (end - start); uint8_t *digits = xmalloc(digits_capa); - size_t digits_length = 0; + if (digits == NULL) PRISM_OOM(); + size_t digits_length = 0; for (; start < end; start++) { if (*start == '_') continue; digits[digits_length++] = pm_integer_parse_digit(*start); @@ -664,7 +672,7 @@ pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) { // Allocate a buffer that we'll copy the decimal digits into. const size_t digits_length = converted.length * 9; char *digits = xcalloc(digits_length, sizeof(char)); - if (digits == NULL) return; + if (digits == NULL) PRISM_OOM(); // Pack bigdecimal to digits. for (size_t value_index = 0; value_index < converted.length; value_index++) { diff --git a/src/options.c b/src/options.c index 09c6db8d8f..4bd3f03b40 100644 --- a/src/options.c +++ b/src/options.c @@ -4,6 +4,7 @@ #include "prism/internal/allocator.h" #include "prism/internal/char.h" +#include "prism/internal/oom.h" #include "prism/internal/stringy.h" #include @@ -16,7 +17,7 @@ pm_options_t * pm_options_new(void) { pm_options_t *options = xcalloc(1, sizeof(pm_options_t)); - if (options == NULL) abort(); + if (options == NULL) PRISM_OOM(); options->line = 1; return options; @@ -312,7 +313,7 @@ pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) { scope->locals_count = locals_count; scope->locals = xcalloc(locals_count, sizeof(pm_string_t)); scope->forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE; - if (scope->locals == NULL) abort(); + if (scope->locals == NULL) PRISM_OOM(); } /** diff --git a/src/prism.c b/src/prism.c index da849e0839..1ee3d75083 100644 --- a/src/prism.c +++ b/src/prism.c @@ -19,6 +19,7 @@ #include "prism/internal/magic_comments.h" #include "prism/internal/memchr.h" #include "prism/internal/node.h" +#include "prism/internal/oom.h" #include "prism/internal/options.h" #include "prism/internal/parser.h" #include "prism/internal/regexp.h" @@ -4122,6 +4123,8 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) { size_t length = (size_t) diff; const size_t buffer_size = sizeof(char) * (length + 1); char *buffer = xmalloc(buffer_size); + if (buffer == NULL) PRISM_OOM(); + memcpy((void *) buffer, token->start, length); // Next, determine if we need to replace the decimal point because of @@ -4255,10 +4258,7 @@ pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) { assert(point && "should have a decimal point"); uint8_t *digits = xmalloc(length); - if (digits == NULL) { - fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr); - abort(); - } + if (digits == NULL) PRISM_OOM(); memcpy(digits, start, (unsigned long) (point - start)); memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1)); @@ -23527,7 +23527,7 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si pm_parser_t * pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) { pm_parser_t *parser = (pm_parser_t *) xmalloc(sizeof(pm_parser_t)); - if (parser == NULL) abort(); + if (parser == NULL) PRISM_OOM(); pm_parser_init(arena, parser, source, size, options); return parser; diff --git a/src/source.c b/src/source.c index 9118a44a5a..00fea4bdd5 100644 --- a/src/source.c +++ b/src/source.c @@ -2,6 +2,7 @@ #include "prism/internal/allocator.h" #include "prism/internal/buffer.h" +#include "prism/internal/oom.h" #include #include @@ -26,7 +27,7 @@ static const uint8_t empty_source[] = ""; static pm_source_t * pm_source_alloc(const uint8_t *source, size_t length, pm_source_type_t type) { pm_source_t *result = xmalloc(sizeof(pm_source_t)); - if (result == NULL) abort(); + if (result == NULL) PRISM_OOM(); *result = (struct pm_source_t) { .source = source, diff --git a/src/static_literals.c b/src/static_literals.c index d29a71288f..9ba092ef08 100644 --- a/src/static_literals.c +++ b/src/static_literals.c @@ -7,6 +7,7 @@ #include "prism/internal/buffer.h" #include "prism/internal/integer.h" #include "prism/internal/isinf.h" +#include "prism/internal/oom.h" #include "prism/internal/parser.h" #include "prism/internal/stringy.h" #include "prism/internal/xxh3.h" @@ -14,7 +15,6 @@ #include #include #include -#include #include #include @@ -309,7 +309,7 @@ pm_static_literals_place(pm_static_literals_entry_t *entries, uint32_t mask, pm_ static void pm_static_literals_resize(const pm_parser_t *parser, pm_static_literals_t *literals, uint32_t capacity) { pm_static_literals_entry_t *entries = xcalloc(capacity, sizeof(pm_static_literals_entry_t)); - if (entries == NULL) abort(); + if (entries == NULL) PRISM_OOM(); /* It turns out to be more efficient to mask the hash value than to use the * modulo operator. Because our capacities are always powers of two, we can