This commit is a squashed backport of the following commits on the master branch: *pull/608/head099016b7e8*77d935b7ae*d07b910149*519dfe1591*a59d5acfab*26f080997d
| @@ -136,6 +136,9 @@ int array_list_del_idx(struct array_list *arr, size_t idx, size_t count) | |||||
| { | { | ||||
| size_t i, stop; | size_t i, stop; | ||||
| /* Avoid overflow in calculation with large indices. */ | |||||
| if (idx > SIZE_T_MAX - count) | |||||
| return -1; | |||||
| stop = idx + count; | stop = idx + count; | ||||
| if (idx >= arr->length || stop > arr->length) | if (idx >= arr->length || stop > arr->length) | ||||
| return -1; | return -1; | ||||
| @@ -12,6 +12,7 @@ | |||||
| #include "config.h" | #include "config.h" | ||||
| #include <assert.h> | |||||
| #include <limits.h> | #include <limits.h> | ||||
| #include <stdarg.h> | #include <stdarg.h> | ||||
| #include <stddef.h> | #include <stddef.h> | ||||
| @@ -499,6 +500,8 @@ struct lh_table *lh_table_new(int size, lh_entry_free_fn *free_fn, lh_hash_fn *h | |||||
| int i; | int i; | ||||
| struct lh_table *t; | struct lh_table *t; | ||||
| /* Allocate space for elements to avoid divisions by zero. */ | |||||
| assert(size > 0); | |||||
| t = (struct lh_table *)calloc(1, sizeof(struct lh_table)); | t = (struct lh_table *)calloc(1, sizeof(struct lh_table)); | ||||
| if (!t) | if (!t) | ||||
| return NULL; | return NULL; | ||||
| @@ -578,8 +581,12 @@ int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, con | |||||
| unsigned long n; | unsigned long n; | ||||
| if (t->count >= t->size * LH_LOAD_FACTOR) | if (t->count >= t->size * LH_LOAD_FACTOR) | ||||
| if (lh_table_resize(t, t->size * 2) != 0) | |||||
| { | |||||
| /* Avoid signed integer overflow with large tables. */ | |||||
| int new_size = (t->size > INT_MAX / 2) ? INT_MAX : (t->size * 2); | |||||
| if (t->size == INT_MAX || lh_table_resize(t, new_size) != 0) | |||||
| return -1; | return -1; | ||||
| } | |||||
| n = h % t->size; | n = h % t->size; | ||||
| @@ -15,6 +15,7 @@ | |||||
| #include "config.h" | #include "config.h" | ||||
| #include <limits.h> | |||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| @@ -66,9 +67,16 @@ static int printbuf_extend(struct printbuf *p, int min_size) | |||||
| if (p->size >= min_size) | if (p->size >= min_size) | ||||
| return 0; | return 0; | ||||
| new_size = p->size * 2; | |||||
| if (new_size < min_size + 8) | |||||
| /* Prevent signed integer overflows with large buffers. */ | |||||
| if (min_size > INT_MAX - 8) | |||||
| return -1; | |||||
| if (p->size > INT_MAX / 2) | |||||
| new_size = min_size + 8; | new_size = min_size + 8; | ||||
| else { | |||||
| new_size = p->size * 2; | |||||
| if (new_size < min_size + 8) | |||||
| new_size = min_size + 8; | |||||
| } | |||||
| #ifdef PRINTBUF_DEBUG | #ifdef PRINTBUF_DEBUG | ||||
| MC_DEBUG("printbuf_memappend: realloc " | MC_DEBUG("printbuf_memappend: realloc " | ||||
| "bpos=%d min_size=%d old_size=%d new_size=%d\n", | "bpos=%d min_size=%d old_size=%d new_size=%d\n", | ||||
| @@ -83,6 +91,9 @@ static int printbuf_extend(struct printbuf *p, int min_size) | |||||
| int printbuf_memappend(struct printbuf *p, const char *buf, int size) | int printbuf_memappend(struct printbuf *p, const char *buf, int size) | ||||
| { | { | ||||
| /* Prevent signed integer overflows with large buffers. */ | |||||
| if (size > INT_MAX - p->bpos - 1) | |||||
| return -1; | |||||
| if (p->size <= p->bpos + size + 1) | if (p->size <= p->bpos + size + 1) | ||||
| { | { | ||||
| if (printbuf_extend(p, p->bpos + size + 1) < 0) | if (printbuf_extend(p, p->bpos + size + 1) < 0) | ||||
| @@ -100,6 +111,9 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) | |||||
| if (offset == -1) | if (offset == -1) | ||||
| offset = pb->bpos; | offset = pb->bpos; | ||||
| /* Prevent signed integer overflows with large buffers. */ | |||||
| if (len > INT_MAX - offset) | |||||
| return -1; | |||||
| size_needed = offset + len; | size_needed = offset + len; | ||||
| if (pb->size < size_needed) | if (pb->size < size_needed) | ||||
| { | { | ||||
| @@ -3,12 +3,15 @@ | |||||
| */ | */ | ||||
| #include "config.h" | #include "config.h" | ||||
| #include <assert.h> | |||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | |||||
| #include <string.h> | #include <string.h> | ||||
| #include "json_inttypes.h" | #include "json_inttypes.h" | ||||
| #include "json_object.h" | #include "json_object.h" | ||||
| #include "json_tokener.h" | #include "json_tokener.h" | ||||
| #include "snprintf_compat.h" | |||||
| void print_hex(const char *s) | void print_hex(const char *s) | ||||
| { | { | ||||
| @@ -24,6 +27,29 @@ void print_hex(const char *s) | |||||
| putchar('\n'); | putchar('\n'); | ||||
| } | } | ||||
| static void test_lot_of_adds(void); | |||||
| static void test_lot_of_adds() | |||||
| { | |||||
| int ii; | |||||
| char key[50]; | |||||
| json_object *jobj = json_object_new_object(); | |||||
| assert(jobj != NULL); | |||||
| for (ii = 0; ii < 500; ii++) | |||||
| { | |||||
| snprintf(key, sizeof(key), "k%d", ii); | |||||
| json_object *iobj = json_object_new_int(ii); | |||||
| assert(iobj != NULL); | |||||
| if (json_object_object_add(jobj, key, iobj)) | |||||
| { | |||||
| fprintf(stderr, "FAILED to add object #%d\n", ii); | |||||
| abort(); | |||||
| } | |||||
| } | |||||
| printf("%s\n", json_object_to_json_string(jobj)); | |||||
| assert(json_object_object_length(jobj) == 500); | |||||
| json_object_put(jobj); | |||||
| } | |||||
| int main(void) | int main(void) | ||||
| { | { | ||||
| const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\""; | const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\""; | ||||
| @@ -52,5 +78,8 @@ int main(void) | |||||
| retval = 1; | retval = 1; | ||||
| } | } | ||||
| json_object_put(parse_result); | json_object_put(parse_result); | ||||
| test_lot_of_adds(); | |||||
| return retval; | return retval; | ||||
| } | } | ||||