250304.8 · a8ce2ff09af51b39be0d76091e6117caccd1b5c0
Avoid zero-length `calloc` (#3280)
Using `calloc` function with a count of zero elements is implementation defined and it may cause allocation errors on some platforms (ref #3277). This commit fixes `jv_mem_calloc` callers to avoid undefined behavior.
reading declarations
@@ -734,9 +734,12 @@ static jv f_format(jq_state *jq, jv input, jv fmt) { input = f_tostring(jq, input); const unsigned char* data = (const unsigned char*)jv_string_value(input); int len = jv_string_length_bytes(jv_copy(input));+ if (len == 0) {+ jv_free(input);+ return jv_string("");+ } size_t decoded_len = (3 * (size_t)len) / 4; // 3 usable bytes for every 4 bytes of input char *result = jv_mem_calloc(decoded_len, sizeof(char));- memset(result, 0, decoded_len * sizeof(char)); uint32_t ri = 0; int input_bytes_read=0; uint32_t code = 0;
@@ -1,5 +1,4 @@ #include <assert.h>-#include <math.h> #include <string.h> #include <stdlib.h> #include <unistd.h>@@ -7,7 +6,6 @@ #include "bytecode.h" #include "locfile.h" #include "jv_alloc.h"-#include "linker.h" /* The intermediate representation for jq filters is as a sequence of@@ -1374,7 +1372,7 @@ int block_compile(block b, struct bytecode** out, struct locfile* lf, jv args) { bc->globals = jv_mem_alloc(sizeof(struct symbol_table)); int ncfunc = count_cfunctions(b); bc->globals->ncfunctions = 0;- bc->globals->cfunctions = jv_mem_calloc(ncfunc, sizeof(struct cfunction));+ bc->globals->cfunctions = jv_mem_calloc(ncfunc ? ncfunc : 1, sizeof(struct cfunction)); bc->globals->cfunc_names = jv_array(); bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null()); jv env = jv_invalid();
@@ -1,7 +1,8 @@-#include <stdlib.h>+#include <assert.h> #include <stdio.h>+#include <stdlib.h> #include <string.h>-#include "jv_alloc.h"+#include "jv.h" struct nomem_handler { jv_nomem_handler_f handler;@@ -150,6 +151,7 @@ void* jv_mem_alloc_unguarded(size_t sz) { } void* jv_mem_calloc(size_t nemb, size_t sz) {+ assert(nemb > 0 && sz > 0); void* p = calloc(nemb, sz); if (!p) { memory_exhausted();@@ -158,6 +160,7 @@ void* jv_mem_calloc(size_t nemb, size_t sz) { } void* jv_mem_calloc_unguarded(size_t nemb, size_t sz) {+ assert(nemb > 0 && sz > 0); return calloc(nemb, sz); }
@@ -2,7 +2,6 @@ #define JV_ALLOC_H #include <stddef.h>-#include "jv.h" void* jv_mem_alloc(size_t); void* jv_mem_alloc_unguarded(size_t);
@@ -3,6 +3,7 @@ #include <math.h> #include <string.h> #include <stdlib.h>+#include "jv.h" #include "jv_alloc.h" #include "jv_private.h" @@ -552,6 +553,10 @@ jv jv_keys_unsorted(jv x) { jv jv_keys(jv x) { if (jv_get_kind(x) == JV_KIND_OBJECT) { int nkeys = jv_object_length(jv_copy(x));+ if (nkeys == 0) {+ jv_free(x);+ return jv_array();+ } jv* keys = jv_mem_calloc(nkeys, sizeof(jv)); int kidx = 0; jv_object_foreach(x, key, value) {@@ -673,6 +678,11 @@ static struct sort_entry* sort_items(jv objects, jv keys) { assert(jv_get_kind(keys) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(objects)) == jv_array_length(jv_copy(keys))); int n = jv_array_length(jv_copy(objects));+ if (n == 0) {+ jv_free(objects);+ jv_free(keys);+ return NULL;+ } struct sort_entry* entries = jv_mem_calloc(n, sizeof(struct sort_entry)); for (int i=0; i<n; i++) { entries[i].object = jv_array_get(jv_copy(objects), i);
@@ -1,6 +1,10 @@ # Tests are groups of three lines: program, input, expected output # Blank lines and lines starting with # are ignored +@base64+""+""+ @base64 "<>&'\"\t" "PD4mJyIJ"@@ -15,6 +19,10 @@ "foóbar\n" "Zm/Ds2Jhcgo=" +@base64d+""+""+ @base64d "Zm/Ds2Jhcgo=" "foóbar\n"