file: fix segfault in uci_parse_option
[project/uci.git] / ucimap.c
index 99b8829e194dab82a470a7f4f1badf49a5901394..7c2b0435d308358c83cfa89d7f14133ad4dca008 100644 (file)
--- a/ucimap.c
+++ b/ucimap.c
@@ -9,11 +9,11 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
  */
 
 /*
- * This file contains ucimap, an API for mapping UCI to C data structures 
+ * This file contains ucimap, an API for mapping UCI to C data structures
  */
 
 #include <strings.h>
@@ -59,23 +59,13 @@ struct ucimap_fixup {
 static inline bool
 ucimap_is_alloc(enum ucimap_type type)
 {
-       switch(type & UCIMAP_SUBTYPE) {
-       case UCIMAP_STRING:
-               return true;
-       default:
-               return false;
-       }
+       return (type & UCIMAP_SUBTYPE) == UCIMAP_STRING;
 }
 
 static inline bool
 ucimap_is_fixup(enum ucimap_type type)
 {
-       switch(type & UCIMAP_SUBTYPE) {
-       case UCIMAP_SECTION:
-               return true;
-       default:
-               return false;
-       }
+       return (type & UCIMAP_SUBTYPE) == UCIMAP_SECTION;
 }
 
 static inline bool
@@ -144,7 +134,7 @@ void
 ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd)
 {
        void *section;
-       int i;
+       unsigned int i;
 
        section = ucimap_section_ptr(sd);
        if (sd->ref)
@@ -172,9 +162,10 @@ ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd)
 void
 ucimap_cleanup(struct uci_map *map)
 {
-       struct ucimap_section_data *sd;
+       struct ucimap_section_data *sd, *sd_next;
 
-       for (sd = map->sdata; sd; sd = sd->next) {
+       for (sd = map->sdata; sd; sd = sd_next) {
+               sd_next = sd->next;
                ucimap_free_section(map, sd);
        }
 }
@@ -217,7 +208,6 @@ static bool
 ucimap_handle_fixup(struct uci_map *map, struct ucimap_fixup *f)
 {
        void *ptr = ucimap_find_section(map, f);
-       struct ucimap_list *list;
        union ucimap_data *data;
 
        if (!ptr)
@@ -228,7 +218,6 @@ ucimap_handle_fixup(struct uci_map *map, struct ucimap_fixup *f)
                f->data->ptr = ptr;
                break;
        case UCIMAP_LIST:
-               list = f->data->list;
                data = ucimap_list_append(f->data->list);
                if (!data)
                        return false;
@@ -245,7 +234,7 @@ ucimap_free_item(struct ucimap_section_data *sd, void *item)
        struct ucimap_alloc_custom *ac;
        struct ucimap_alloc *a;
        void *ptr = *((void **) item);
-       int i;
+       unsigned int i;
 
        if (!ptr)
                return;
@@ -281,11 +270,14 @@ ucimap_resize_list(struct ucimap_section_data *sd, struct ucimap_list **list, in
 {
        struct ucimap_list *new;
        struct ucimap_alloc *a;
-       int i, offset = 0;
+       unsigned int i;
+       int offset = 0;
        int size = sizeof(struct ucimap_list) + items * sizeof(union ucimap_data);
 
        if (!*list) {
                new = calloc(1, size);
+               if (!new)
+                       return -ENOMEM;
 
                ucimap_add_alloc(sd, new);
                goto set;
@@ -304,6 +296,9 @@ realloc:
                offset = (items - (*list)->size) * sizeof(union ucimap_data);
 
        a->ptr = realloc(a->ptr, size);
+       if (!a->ptr)
+               return -ENOMEM;
+
        if (offset)
                memset((char *) a->ptr + offset, 0, size - offset);
        new = a->ptr;
@@ -320,6 +315,7 @@ ucimap_add_fixup(struct ucimap_section_data *sd, union ucimap_data *data, struct
        struct ucimap_fixup *f, tmp;
        struct uci_map *map = sd->map;
 
+       tmp.next = NULL;
        tmp.sm = om->data.sm;
        tmp.name = str;
        tmp.type = om->type;
@@ -365,7 +361,7 @@ ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_s
        switch(om->type & UCIMAP_SUBTYPE) {
        case UCIMAP_STRING:
                if ((om->data.s.maxlen > 0) &&
-                       (strlen(str) > om->data.s.maxlen))
+                       (strlen(str) > (unsigned) om->data.s.maxlen))
                        return;
 
                s = strdup(str);
@@ -404,11 +400,10 @@ ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_s
                ucimap_add_fixup(sd, data, om, str);
                return;
        case UCIMAP_CUSTOM:
-               tdata.s = (char *) data;
                break;
        }
        if (om->parse) {
-               if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0)
+               if (om->parse(ucimap_section_ptr(sd), om, data, str) < 0)
                        return;
                if (ucimap_is_custom(om->type) && om->free) {
                        if (tdata.ptr != data->ptr)
@@ -495,16 +490,21 @@ ucimap_add_section_list(struct uci_map *map, struct ucimap_section_data *sd)
        map->sdata_tail = &sd->next;
 }
 
-static void
+static int
 ucimap_add_section(struct ucimap_section_data *sd)
 {
+       int r;
        struct uci_map *map = sd->map;
 
        sd->next = NULL;
-       if (sd->sm->add(map, ucimap_section_ptr(sd)) < 0)
+       r = sd->sm->add(map, ucimap_section_ptr(sd));
+       if (r < 0) {
                ucimap_free_section(map, sd);
-       else
+               return r;
+       } else
                ucimap_add_section_list(map, sd);
+
+       return 0;
 }
 
 #ifdef UCI_DEBUG
@@ -538,7 +538,7 @@ ucimap_get_type_name(int type)
 static bool
 ucimap_check_optmap_type(struct uci_sectionmap *sm, struct uci_optmap *om)
 {
-       unsigned int type;
+       int type;
 
        if (unlikely(sm->type_name != om->type_name) &&
            unlikely(strcmp(sm->type_name, om->type_name) != 0)) {
@@ -707,7 +707,9 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim
                goto error;
 
        if (map->parsed) {
-               ucimap_add_section(sd);
+               err = ucimap_add_section(sd);
+               if (err)
+                       return err;
        } else {
                ucimap_add_section_list(map, sd);
        }
@@ -719,8 +721,8 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim
        return 0;
 
 error_mem:
-       if (sd->allocmap)
-               free(sd->allocmap);
+       free(sd->alloc_custom);
+       free(sd->allocmap);
        free(sd);
        return UCI_ERR_MEM;
 
@@ -752,7 +754,7 @@ ucimap_set_changed(struct ucimap_section_data *sd, void *field)
        void *section = ucimap_section_ptr(sd);
        struct uci_sectionmap *sm = sd->sm;
        struct uci_optmap *om;
-       int ofs = (char *)field - (char *)section;
+       unsigned int ofs = (char *)field - (char *)section;
        int i = 0;
 
        ucimap_foreach_option(sm, om) {
@@ -795,13 +797,6 @@ ucimap_data_to_string(struct ucimap_section_data *sd, struct uci_optmap *om, uni
        }
 
        if (om->format) {
-               union ucimap_data tdata;
-
-               if (ucimap_is_custom(om->type)) {
-                       tdata.s = (char *)data;
-                       data = &tdata;
-               }
-
                if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
                        return NULL;
 
@@ -881,7 +876,7 @@ ucimap_parse(struct uci_map *map, struct uci_package *pkg)
        struct uci_element *e;
        struct ucimap_section_data *sd, **sd_tail;
        struct ucimap_fixup *f;
-       int i;
+       unsigned int i;
 
        sd_tail = map->sdata_tail;
        map->parsed = false;
@@ -902,6 +897,7 @@ ucimap_parse(struct uci_map *map, struct uci_package *pkg)
                        } else {
                                sd = malloc(sm->alloc_len);
                                memset(sd, 0, sm->alloc_len);
+                               sd = ucimap_ptr_section(sm, sd);
                        }
                        if (!sd)
                                continue;