diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2019-04-25 12:13:09 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2019-04-25 12:13:09 +0100 |
commit | 24d852704f94f74caf96ddb512ae2fc7e6129c4b (patch) | |
tree | d7d10174181db7bed5a786dc8f543ff3d6817851 /contrib/libucl | |
parent | 19026c7116f1e394049d063d50147f8a2458f351 (diff) | |
download | rspamd-24d852704f94f74caf96ddb512ae2fc7e6129c4b.tar.gz rspamd-24d852704f94f74caf96ddb512ae2fc7e6129c4b.zip |
[Minor] Merge OOM fixes from libucl
Diffstat (limited to 'contrib/libucl')
-rw-r--r-- | contrib/libucl/kvec.h | 80 | ||||
-rw-r--r-- | contrib/libucl/ucl.h | 25 | ||||
-rw-r--r-- | contrib/libucl/ucl_hash.c | 58 | ||||
-rw-r--r-- | contrib/libucl/ucl_hash.h | 14 | ||||
-rw-r--r-- | contrib/libucl/ucl_internal.h | 18 | ||||
-rw-r--r-- | contrib/libucl/ucl_parser.c | 126 | ||||
-rw-r--r-- | contrib/libucl/ucl_util.c | 48 |
7 files changed, 259 insertions, 110 deletions
diff --git a/contrib/libucl/kvec.h b/contrib/libucl/kvec.h index b5cce8508..ce6a53640 100644 --- a/contrib/libucl/kvec.h +++ b/contrib/libucl/kvec.h @@ -30,11 +30,13 @@ int main() { kvec_t(int) array; kv_init(array); - kv_push(int, array, 10); // append + kv_push_safe(int, array, 10, e0); // append kv_a(int, array, 20) = 5; // dynamic kv_A(array, 20) = 4; // static kv_destroy(array); return 0; +e0: + return 1; } */ @@ -60,8 +62,71 @@ int main() { #define kv_size(v) ((v).n) #define kv_max(v) ((v).m) -#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m)) +#define kv_resize_safe(type, v, s, el) do { \ + type *_tp = (type*)realloc((v).a, sizeof(type) * (s)); \ + if (_tp == NULL) { \ + goto el; \ + } else { \ + (v).a = _tp; \ + (v).m = (s); \ + } \ + } while (0) + #define kv_grow_factor 1.5 +#define kv_grow_safe(type, v, el) do { \ + size_t _ts = ((v).m > 1 ? (v).m * kv_grow_factor : 2); \ + type *_tp = (type*)realloc((v).a, sizeof(type) * _ts); \ + if (_tp == NULL) { \ + goto el; \ + } else { \ + (v).a = _tp; \ + (v).m = _ts; \ + } \ + } while (0) + +#define kv_copy_safe(type, v1, v0, el) do { \ + if ((v1).m < (v0).n) kv_resize_safe(type, v1, (v0).n, el); \ + (v1).n = (v0).n; \ + memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \ + } while (0) + +#define kv_push_safe(type, v, x, el) do { \ + if ((v).n == (v).m) { \ + kv_grow_safe(type, v, el); \ + } \ + (v).a[(v).n++] = (x); \ + } while (0) + +#define kv_prepend_safe(type, v, x, el) do { \ + if ((v).n == (v).m) { \ + kv_grow_safe(type, v, el); \ + } \ + memmove((v).a + 1, (v).a, sizeof(type) * (v).n); \ + (v).a[0] = (x); \ + (v).n ++; \ + } while (0) + +#define kv_concat_safe(type, v1, v0, el) do { \ + if ((v1).m < (v0).n + (v1).n) \ + kv_resize_safe(type, v1, (v0).n + (v1).n, el); \ + memcpy((v1).a + (v1).n, (v0).a, sizeof(type) * (v0).n); \ + (v1).n = (v0).n + (v1).n; \ + } while (0) + +#define kv_del(type, v, i) do { \ + if ((i) < (v).n) { \ + memmove((v).a + (i), (v).a + ((i) + 1), sizeof(type) * ((v).n - (i) - 1)); \ + (v).n --; \ + } \ +} while (0) + +/* + * Old (ENOMEM-unsafe) version of kv_xxx macros. Compat-only, not for use in + * the new library code. + */ + +#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m)) + #define kv_grow(type, v) ((v).m = ((v).m > 1 ? (v).m * kv_grow_factor : 2), \ (v).a = (type*)realloc((v).a, sizeof(type) * (v).m)) @@ -89,15 +154,8 @@ int main() { #define kv_concat(type, v1, v0) do { \ if ((v1).m < (v0).n + (v1).n) kv_resize(type, v1, (v0).n + (v1).n); \ - memcpy((v1).a + (v1).n, (v0).a, sizeof(type) * ((v0).n + (v1).n)); \ + memcpy((v1).a + (v1).n, (v0).a, sizeof(type) * (v0).n); \ (v1).n = (v0).n + (v1).n; \ } while (0) -#define kv_del(type, v, i) do { \ - if ((i) < (v).n) { \ - memmove((v).a + (i), (v).a + ((i) + 1), sizeof(type) * ((v).n - (i) - 1)); \ - (v).n --; \ - } \ -} while (0) - -#endif +#endif /* AC_KVEC_H */ diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h index 482812d46..01542d3c7 100644 --- a/contrib/libucl/ucl.h +++ b/contrib/libucl/ucl.h @@ -469,8 +469,9 @@ UCL_EXTERN bool ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *e * Reserve space in ucl array or object for `elt` elements * @param obj object to reserve * @param reserved size to reserve in an object + * @return 0 on success, -1 on failure (i.e. ENOMEM) */ -UCL_EXTERN void ucl_object_reserve (ucl_object_t *obj, size_t reserved); +UCL_EXTERN bool ucl_object_reserve (ucl_object_t *obj, size_t reserved); /** * Append an element to the end of array object @@ -825,11 +826,14 @@ typedef void* ucl_object_iter_t; * @param iter opaque iterator, must be set to NULL on the first call: * ucl_object_iter_t it = NULL; * while ((cur = ucl_iterate_object (obj, &it)) != NULL) ... + * @param ep pointer record exception (such as ENOMEM), could be NULL * @return the next object or NULL */ -UCL_EXTERN const ucl_object_t* ucl_object_iterate (const ucl_object_t *obj, - ucl_object_iter_t *iter, bool expand_values); +UCL_EXTERN const ucl_object_t* ucl_object_iterate_with_error (const ucl_object_t *obj, + ucl_object_iter_t *iter, bool expand_values, int *ep); + #define ucl_iterate_object ucl_object_iterate +#define ucl_object_iterate(ob, it, ev) ucl_object_iterate_with_error((ob), (it), (ev), NULL) /** * Create new safe iterator for the specified object @@ -839,6 +843,15 @@ UCL_EXTERN const ucl_object_t* ucl_object_iterate (const ucl_object_t *obj, UCL_EXTERN ucl_object_iter_t ucl_object_iterate_new (const ucl_object_t *obj) UCL_WARN_UNUSED_RESULT; /** + * Check safe iterator object after performing some operations on it + * (such as ucl_object_iterate_safe()) to see if operation has encountered + * fatal exception while performing that operation (e.g. ENOMEM). + * @param iter opaque iterator + * @return true if exception has occured, false otherwise + */ +UCL_EXTERN bool ucl_object_iter_chk_excpn(ucl_object_iter_t *it); + +/** * Reset initialized iterator to a new object * @param obj new object to iterate * @return modified iterator object @@ -951,8 +964,9 @@ UCL_EXTERN int ucl_parser_get_default_priority (struct ucl_parser *parser); * @param macro macro name (without leading dot) * @param handler handler (it is called immediately after macro is parsed) * @param ud opaque user data for a handler + * @return true on success, false on failure (i.e. ENOMEM) */ -UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser, +UCL_EXTERN bool ucl_parser_register_macro (struct ucl_parser *parser, const char *macro, ucl_macro_handler handler, void* ud); @@ -962,8 +976,9 @@ UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser, * @param macro macro name (without leading dot) * @param handler handler (it is called immediately after macro is parsed) * @param ud opaque user data for a handler + * @return true on success, false on failure (i.e. ENOMEM) */ -UCL_EXTERN void ucl_parser_register_context_macro (struct ucl_parser *parser, +UCL_EXTERN bool ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro, ucl_context_macro_handler handler, void* ud); diff --git a/contrib/libucl/ucl_hash.c b/contrib/libucl/ucl_hash.c index 628980d28..6594b2557 100644 --- a/contrib/libucl/ucl_hash.c +++ b/contrib/libucl/ucl_hash.c @@ -147,17 +147,21 @@ ucl_hash_create (bool ignore_case) new = UCL_ALLOC (sizeof (ucl_hash_t)); if (new != NULL) { + void *h; kv_init (new->ar); new->caseless = ignore_case; if (ignore_case) { - khash_t(ucl_hash_caseless_node) *h = kh_init (ucl_hash_caseless_node); - new->hash = (void *)h; + h = (void *)kh_init (ucl_hash_caseless_node); } else { - khash_t(ucl_hash_node) *h = kh_init (ucl_hash_node); - new->hash = (void *)h; + h = (void *)kh_init (ucl_hash_node); } + if (h == NULL) { + UCL_FREE (sizeof (ucl_hash_t), new); + return NULL; + } + new->hash = h; } return new; } @@ -190,12 +194,12 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func) if (hashlin->caseless) { khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *) - hashlin->hash; + hashlin->hash; kh_destroy (ucl_hash_caseless_node, h); } else { khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *) - hashlin->hash; + hashlin->hash; kh_destroy (ucl_hash_node, h); } @@ -203,16 +207,16 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func) UCL_FREE (sizeof (*hashlin), hashlin); } -void +bool ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, - const char *key, unsigned keylen) + const char *key, unsigned keylen) { khiter_t k; int ret; struct ucl_hash_elt *elt; if (hashlin == NULL) { - return; + return false; } if (hashlin->caseless) { @@ -221,7 +225,7 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, k = kh_put (ucl_hash_caseless_node, h, obj, &ret); if (ret > 0) { elt = &kh_value (h, k); - kv_push (const ucl_object_t *, hashlin->ar, obj); + kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0); elt->obj = obj; elt->ar_idx = kv_size (hashlin->ar) - 1; } @@ -232,15 +236,20 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, k = kh_put (ucl_hash_node, h, obj, &ret); if (ret > 0) { elt = &kh_value (h, k); - kv_push (const ucl_object_t *, hashlin->ar, obj); + kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0); elt->obj = obj; elt->ar_idx = kv_size (hashlin->ar) - 1; + } else if (ret < 0) { + goto e0; } } + return true; + e0: + return false; } void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old, - const ucl_object_t *new) + const ucl_object_t *new) { khiter_t k; int ret; @@ -285,13 +294,16 @@ struct ucl_hash_real_iter { const ucl_object_t **end; }; +#define UHI_SETERR(ep, ern) {if (ep != NULL) *ep = (ern);} + const void* -ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter) +ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep) { struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(*iter); const ucl_object_t *ret = NULL; if (hashlin == NULL) { + UHI_SETERR(ep, EINVAL); return NULL; } @@ -299,6 +311,7 @@ ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter) it = UCL_ALLOC (sizeof (*it)); if (it == NULL) { + UHI_SETERR(ep, ENOMEM); return NULL; } @@ -306,6 +319,7 @@ ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter) it->end = it->cur + hashlin->ar.n; } + UHI_SETERR(ep, 0); if (it->cur < it->end) { ret = *it->cur++; } @@ -346,7 +360,7 @@ ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen) if (hashlin->caseless) { khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *) - hashlin->hash; + hashlin->hash; k = kh_get (ucl_hash_caseless_node, h, &search); if (k != kh_end (h)) { @@ -356,7 +370,7 @@ ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen) } else { khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *) - hashlin->hash; + hashlin->hash; k = kh_get (ucl_hash_node, h, &search); if (k != kh_end (h)) { elt = &kh_value (h, k); @@ -380,7 +394,7 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj) if (hashlin->caseless) { khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *) - hashlin->hash; + hashlin->hash; k = kh_get (ucl_hash_caseless_node, h, obj); if (k != kh_end (h)) { @@ -398,7 +412,7 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj) } else { khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *) - hashlin->hash; + hashlin->hash; k = kh_get (ucl_hash_node, h, obj); if (k != kh_end (h)) { elt = &kh_value (h, k); @@ -415,14 +429,15 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj) } } -void ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz) +bool +ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz) { if (hashlin == NULL) { - return; + return false; } if (sz > hashlin->ar.m) { - kv_resize (const ucl_object_t *, hashlin->ar, sz); + kv_resize_safe (const ucl_object_t *, hashlin->ar, sz, e0); if (hashlin->caseless) { khash_t(ucl_hash_caseless_node) *h = (khash_t( @@ -435,4 +450,7 @@ void ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz) kh_resize (ucl_hash_node, h, sz * 2); } } + return true; + e0: + return false; }
\ No newline at end of file diff --git a/contrib/libucl/ucl_hash.h b/contrib/libucl/ucl_hash.h index f474b462a..805c8efb2 100644 --- a/contrib/libucl/ucl_hash.h +++ b/contrib/libucl/ucl_hash.h @@ -55,8 +55,9 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func); /** * Inserts an element in the the hashtable. + * @return true on success, false on failure (i.e. ENOMEM) */ -void ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key, +bool ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key, unsigned keylen); /** @@ -81,9 +82,15 @@ const ucl_object_t* ucl_hash_search (ucl_hash_t* hashlin, const char *key, * Iterate over hash table * @param hashlin hash * @param iter iterator (must be NULL on first iteration) + * @param ep pointer record exception (such as ENOMEM), could be NULL * @return the next object */ -const void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter); +const void* ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep); + +/** + * Helper macro to support older code + */ +#define ucl_hash_iterate(hl, ip) ucl_hash_iterate2((hl), (ip), NULL) /** * Check whether an iterator has next element @@ -92,8 +99,9 @@ bool ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter); /** * Reserves space in hash + * @return true on sucess, false on failure (e.g. ENOMEM) * @param hashlin */ -void ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz); +bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz); #endif diff --git a/contrib/libucl/ucl_internal.h b/contrib/libucl/ucl_internal.h index edf647827..a7dd6eeac 100644 --- a/contrib/libucl/ucl_internal.h +++ b/contrib/libucl/ucl_internal.h @@ -472,12 +472,24 @@ ucl_hash_insert_object (ucl_hash_t *hashlin, const ucl_object_t *obj, bool ignore_case) { + ucl_hash_t *nhp; + if (hashlin == NULL) { - hashlin = ucl_hash_create (ignore_case); + nhp = ucl_hash_create (ignore_case); + if (nhp == NULL) { + return NULL; + } + } else { + nhp = hashlin; + } + if (!ucl_hash_insert (nhp, obj, obj->key, obj->keylen)) { + if (nhp != hashlin) { + ucl_hash_destroy(nhp, NULL); + } + return NULL; } - ucl_hash_insert (hashlin, obj, obj->key, obj->keylen); - return hashlin; + return nhp; } /** diff --git a/contrib/libucl/ucl_parser.c b/contrib/libucl/ucl_parser.c index 7752f6661..6a53fe805 100644 --- a/contrib/libucl/ucl_parser.c +++ b/contrib/libucl/ucl_parser.c @@ -634,70 +634,51 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser, bool is_array, uint32_t level, bool has_obrace) { struct ucl_stack *st; - bool need_free = false; - - if (!is_array) { - if (obj == NULL) { - obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority); - need_free = true; - } - else { - if (obj->type == UCL_ARRAY) { - /* Bad combination for merge: array and object */ - ucl_set_err (parser, UCL_EMERGE, - "cannot merge an array with an object", - &parser->err); - - return NULL; - } + ucl_object_t *nobj; - obj->type = UCL_OBJECT; + if (obj == NULL) { + nobj = ucl_object_new_full (is_array ? UCL_ARRAY : UCL_OBJECT, parser->chunks->priority); + if (nobj == NULL) { + goto enomem0; } + } else { + if (obj->type == (is_array ? UCL_OBJECT : UCL_ARRAY)) { + /* Bad combination for merge: array and object */ + ucl_set_err (parser, UCL_EMERGE, + "cannot merge an object with an array", + &parser->err); - if (obj->value.ov == NULL) { - obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE); + return NULL; } - parser->state = UCL_STATE_KEY; + nobj = obj; + nobj->type = is_array ? UCL_ARRAY : UCL_OBJECT; } - else { - if (obj == NULL) { - obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority); - need_free = true; - } - else { - if (obj->type == UCL_OBJECT) { - /* Bad combination for merge: array and object */ - ucl_set_err (parser, UCL_EMERGE, - "cannot merge an object with an array", - &parser->err); - return NULL; + if (!is_array) { + if (nobj->value.ov == NULL) { + nobj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE); + if (nobj->value.ov == NULL) { + goto enomem1; } - - obj->type = UCL_ARRAY; } + parser->state = UCL_STATE_KEY; + } else { parser->state = UCL_STATE_VALUE; } st = UCL_ALLOC (sizeof (struct ucl_stack)); if (st == NULL) { - ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object", - &parser->err); - if (need_free) { - ucl_object_unref (obj); - } - - return NULL; + goto enomem1; } - st->obj = obj; + st->obj = nobj; if (level >= UINT16_MAX) { ucl_set_err (parser, UCL_ENESTED, "objects are nesting too deep (over 65535 limit)", &parser->err); - if (need_free) { + if (nobj != obj) { ucl_object_unref (obj); } @@ -717,9 +698,16 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser, } LL_PREPEND (parser->stack, st); - parser->cur_obj = obj; + parser->cur_obj = nobj; - return obj; + return nobj; +enomem1: + if (nobj != obj) + ucl_object_unref (nobj); +enomem0: + ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object", + &parser->err); + return NULL; } int @@ -1194,6 +1182,9 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj if (tobj == NULL) { container = ucl_hash_insert_object (container, nobj, parser->flags & UCL_PARSER_KEY_LOWERCASE); + if (container == NULL) { + return false; + } nobj->prev = nobj; nobj->next = NULL; parser->stack->obj->len ++; @@ -1477,6 +1468,9 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, /* Create a new object */ nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority); + if (nobj == NULL) { + return false; + } keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY], &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false, false); @@ -2672,6 +2666,11 @@ ucl_state_machine (struct ucl_parser *parser) return true; } +#define UPRM_SAFE(fn, a, b, c, el) do { \ + if (!fn(a, b, c, a)) \ + goto el; \ + } while (0) + struct ucl_parser* ucl_parser_new (int flags) { @@ -2684,12 +2683,12 @@ ucl_parser_new (int flags) memset (parser, 0, sizeof (struct ucl_parser)); - ucl_parser_register_macro (parser, "include", ucl_include_handler, parser); - ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser); - ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser); - ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser); - ucl_parser_register_macro (parser, "load", ucl_load_handler, parser); - ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser); + UPRM_SAFE(ucl_parser_register_macro, parser, "include", ucl_include_handler, e0); + UPRM_SAFE(ucl_parser_register_macro, parser, "try_include", ucl_try_include_handler, e0); + UPRM_SAFE(ucl_parser_register_macro, parser, "includes", ucl_includes_handler, e0); + UPRM_SAFE(ucl_parser_register_macro, parser, "priority", ucl_priority_handler, e0); + UPRM_SAFE(ucl_parser_register_macro, parser, "load", ucl_load_handler, e0); + UPRM_SAFE(ucl_parser_register_context_macro, parser, "inherit", ucl_inherit_handler, e0); parser->flags = flags; parser->includepaths = NULL; @@ -2704,6 +2703,9 @@ ucl_parser_new (int flags) } return parser; +e0: + ucl_parser_free(parser); + return NULL; } bool @@ -2728,49 +2730,59 @@ ucl_parser_get_default_priority (struct ucl_parser *parser) return parser->default_priority; } -void +bool ucl_parser_register_macro (struct ucl_parser *parser, const char *macro, ucl_macro_handler handler, void* ud) { struct ucl_macro *new; if (macro == NULL || handler == NULL) { - return; + return false; } new = UCL_ALLOC (sizeof (struct ucl_macro)); if (new == NULL) { - return; + return false; } memset (new, 0, sizeof (struct ucl_macro)); new->h.handler = handler; new->name = strdup (macro); + if (new->name == NULL) { + UCL_FREE (sizeof (struct ucl_macro), new); + return false; + } new->ud = ud; HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); + return true; } -void +bool ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro, ucl_context_macro_handler handler, void* ud) { struct ucl_macro *new; if (macro == NULL || handler == NULL) { - return; + return false; } new = UCL_ALLOC (sizeof (struct ucl_macro)); if (new == NULL) { - return; + return false; } memset (new, 0, sizeof (struct ucl_macro)); new->h.context_handler = handler; new->name = strdup (macro); + if (new->name == NULL) { + UCL_FREE (sizeof (struct ucl_macro), new); + return false; + } new->ud = ud; new->is_context = true; HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); + return true; } void diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c index 6f36e5e73..7400c2a5f 100644 --- a/contrib/libucl/ucl_util.c +++ b/contrib/libucl/ucl_util.c @@ -2688,7 +2688,8 @@ ucl_object_lookup_any (const ucl_object_t *obj, } const ucl_object_t* -ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) +ucl_object_iterate_with_error (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values, + int *ep) { const ucl_object_t *elt = NULL; @@ -2699,7 +2700,7 @@ ucl_object_iterate (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan if (expand_values) { switch (obj->type) { case UCL_OBJECT: - return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); + return (const ucl_object_t*)ucl_hash_iterate2 (obj->value.ov, iter, ep); break; case UCL_ARRAY: { unsigned int idx; @@ -2745,6 +2746,7 @@ enum ucl_safe_iter_flags { UCL_ITERATE_FLAG_INSIDE_ARRAY, UCL_ITERATE_FLAG_INSIDE_OBJECT, UCL_ITERATE_FLAG_IMPLICIT, + UCL_ITERATE_FLAG_EXCEPTION }; const char safe_iter_magic[4] = {'u', 'i', 't', 'e'}; @@ -2777,6 +2779,15 @@ ucl_object_iterate_new (const ucl_object_t *obj) return (ucl_object_iter_t)it; } +bool +ucl_object_iter_chk_excpn(ucl_object_iter_t *it) +{ + struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); + + UCL_SAFE_ITER_CHECK (rit); + + return (rit->flags == UCL_ITERATE_FLAG_EXCEPTION); +} ucl_object_iter_t ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj) @@ -2810,6 +2821,7 @@ ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type) { struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); const ucl_object_t *ret = NULL; + int ern; UCL_SAFE_ITER_CHECK (rit); @@ -2819,7 +2831,12 @@ ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type) if (rit->impl_it->type == UCL_OBJECT) { rit->flags = UCL_ITERATE_FLAG_INSIDE_OBJECT; - ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true); + ret = ucl_object_iterate_with_error (rit->impl_it, &rit->expl_it, true, &ern); + + if (ret == NULL && ern != 0) { + rit->flags = UCL_ITERATE_FLAG_EXCEPTION; + return NULL; + } if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) { /* Need to switch to another implicit object in chain */ @@ -2967,7 +2984,7 @@ ucl_object_new_full (ucl_type_t type, unsigned priority) UCL_ARRAY_GET (vec, new); /* Preallocate some space for arrays */ - kv_resize (ucl_object_t *, *vec, 8); + kv_resize_safe (ucl_object_t *, *vec, 8, enomem); } } } @@ -2976,23 +2993,26 @@ ucl_object_new_full (ucl_type_t type, unsigned priority) new = ucl_object_new_userdata (NULL, NULL, NULL); ucl_object_set_priority (new, priority); } - +enomem: return new; } -void ucl_object_reserve (ucl_object_t *obj, size_t reserved) +bool ucl_object_reserve (ucl_object_t *obj, size_t reserved) { if (obj->type == UCL_ARRAY) { UCL_ARRAY_GET (vec, obj); if (vec->m < reserved) { /* Preallocate some space for arrays */ - kv_resize (ucl_object_t *, *vec, reserved); + kv_resize_safe (ucl_object_t *, *vec, reserved, e0); } } else if (obj->type == UCL_OBJECT) { ucl_hash_reserve (obj->value.ov, reserved); } + return true; +e0: + return false; } ucl_object_t* @@ -3102,11 +3122,13 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt) top->value.av = (void *)vec; } - kv_push (ucl_object_t *, *vec, elt); + kv_push_safe (ucl_object_t *, *vec, elt, e0); top->len ++; return true; +e0: + return false; } bool @@ -3122,16 +3144,18 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) vec = UCL_ALLOC (sizeof (*vec)); kv_init (*vec); top->value.av = (void *)vec; - kv_push (ucl_object_t *, *vec, elt); + kv_push_safe (ucl_object_t *, *vec, elt, e0); } else { /* Slow O(n) algorithm */ - kv_prepend (ucl_object_t *, *vec, elt); + kv_prepend_safe (ucl_object_t *, *vec, elt, e0); } top->len ++; return true; +e0: + return false; } bool @@ -3156,7 +3180,7 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) UCL_ARRAY_GET (v2, cp); if (v1 && v2) { - kv_concat (ucl_object_t *, *v1, *v2); + kv_concat_safe (ucl_object_t *, *v1, *v2, e0); for (i = v2->n; i < v1->n; i ++) { obj = &kv_A (*v1, i); @@ -3168,6 +3192,8 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) } return true; +e0: + return false; } ucl_object_t * |