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.
This commit is contained in:
1 parent
4003202ccf
commit
a8ce2ff09a
6 files changed
+28
-7
No files matched your search
+4
-1
@@ -734,9 +734,12 @@ static jv f_format(jq_state *jq, jv input, jv fmt) {
|
|||||||
input = f_tostring(jq, input);
|
input = f_tostring(jq, input);
|
||||||
const unsigned char* data = (const unsigned char*)jv_string_value(input);
|
const unsigned char* data = (const unsigned char*)jv_string_value(input);
|
||||||
int len = jv_string_length_bytes(jv_copy(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
|
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));
|
char *result = jv_mem_calloc(decoded_len, sizeof(char));
|
||||||
memset(result, 0, decoded_len * sizeof(char));
|
|
||||||
uint32_t ri = 0;
|
uint32_t ri = 0;
|
||||||
int input_bytes_read=0;
|
int input_bytes_read=0;
|
||||||
uint32_t code = 0;
|
uint32_t code = 0;
|
||||||
|
|||||||
+1
-3
@@ -1,5 +1,4 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -7,7 +6,6 @@
|
|||||||
#include "bytecode.h"
|
#include "bytecode.h"
|
||||||
#include "locfile.h"
|
#include "locfile.h"
|
||||||
#include "jv_alloc.h"
|
#include "jv_alloc.h"
|
||||||
#include "linker.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The intermediate representation for jq filters is as a sequence of
|
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));
|
bc->globals = jv_mem_alloc(sizeof(struct symbol_table));
|
||||||
int ncfunc = count_cfunctions(b);
|
int ncfunc = count_cfunctions(b);
|
||||||
bc->globals->ncfunctions = 0;
|
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->globals->cfunc_names = jv_array();
|
||||||
bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null());
|
bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null());
|
||||||
jv env = jv_invalid();
|
jv env = jv_invalid();
|
||||||
|
|||||||
+5
-2
@@ -1,7 +1,8 @@
|
|||||||
#include <stdlib.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "jv_alloc.h"
|
#include "jv.h"
|
||||||
|
|
||||||
struct nomem_handler {
|
struct nomem_handler {
|
||||||
jv_nomem_handler_f 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) {
|
void* jv_mem_calloc(size_t nemb, size_t sz) {
|
||||||
|
assert(nemb > 0 && sz > 0);
|
||||||
void* p = calloc(nemb, sz);
|
void* p = calloc(nemb, sz);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
memory_exhausted();
|
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) {
|
void* jv_mem_calloc_unguarded(size_t nemb, size_t sz) {
|
||||||
|
assert(nemb > 0 && sz > 0);
|
||||||
return calloc(nemb, sz);
|
return calloc(nemb, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define JV_ALLOC_H
|
#define JV_ALLOC_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "jv.h"
|
|
||||||
|
|
||||||
void* jv_mem_alloc(size_t);
|
void* jv_mem_alloc(size_t);
|
||||||
void* jv_mem_alloc_unguarded(size_t);
|
void* jv_mem_alloc_unguarded(size_t);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "jv.h"
|
||||||
#include "jv_alloc.h"
|
#include "jv_alloc.h"
|
||||||
#include "jv_private.h"
|
#include "jv_private.h"
|
||||||
|
|
||||||
@@ -552,6 +553,10 @@ jv jv_keys_unsorted(jv x) {
|
|||||||
jv jv_keys(jv x) {
|
jv jv_keys(jv x) {
|
||||||
if (jv_get_kind(x) == JV_KIND_OBJECT) {
|
if (jv_get_kind(x) == JV_KIND_OBJECT) {
|
||||||
int nkeys = jv_object_length(jv_copy(x));
|
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));
|
jv* keys = jv_mem_calloc(nkeys, sizeof(jv));
|
||||||
int kidx = 0;
|
int kidx = 0;
|
||||||
jv_object_foreach(x, key, value) {
|
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_get_kind(keys) == JV_KIND_ARRAY);
|
||||||
assert(jv_array_length(jv_copy(objects)) == jv_array_length(jv_copy(keys)));
|
assert(jv_array_length(jv_copy(objects)) == jv_array_length(jv_copy(keys)));
|
||||||
int n = jv_array_length(jv_copy(objects));
|
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));
|
struct sort_entry* entries = jv_mem_calloc(n, sizeof(struct sort_entry));
|
||||||
for (int i=0; i<n; i++) {
|
for (int i=0; i<n; i++) {
|
||||||
entries[i].object = jv_array_get(jv_copy(objects), 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
|
# Tests are groups of three lines: program, input, expected output
|
||||||
# Blank lines and lines starting with # are ignored
|
# Blank lines and lines starting with # are ignored
|
||||||
|
|
||||||
|
@base64
|
||||||
|
""
|
||||||
|
""
|
||||||
|
|
||||||
@base64
|
@base64
|
||||||
"<>&'\"\t"
|
"<>&'\"\t"
|
||||||
"PD4mJyIJ"
|
"PD4mJyIJ"
|
||||||
@@ -15,6 +19,10 @@
|
|||||||
"foóbar\n"
|
"foóbar\n"
|
||||||
"Zm/Ds2Jhcgo="
|
"Zm/Ds2Jhcgo="
|
||||||
|
|
||||||
|
@base64d
|
||||||
|
""
|
||||||
|
""
|
||||||
|
|
||||||
@base64d
|
@base64d
|
||||||
"Zm/Ds2Jhcgo="
|
"Zm/Ds2Jhcgo="
|
||||||
"foóbar\n"
|
"foóbar\n"
|
||||||
|
|||||||
Reference in new issue
Block a user