From 901c14c409e6e8143ade06a7478241e558cfb79c Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Wed, 16 Aug 2017 09:23:21 +0200 Subject: [PATCH] Prevent alloc errors from crashing in `list_t` This commit changes the `list_t` api so that alloc errors can be detected and worked around. Also fixes errors not found in 5cc7342 --- backend/drm/drm.c | 17 +++++++++++++++-- backend/libinput/events.c | 5 ++++- backend/multi/backend.c | 8 ++++++-- backend/wayland/output.c | 12 +++++++++--- backend/wayland/wl_seat.c | 8 ++++++-- examples/touch.c | 4 +++- include/wlr/util/list.h | 37 +++++++++++++++++++++++++++++++++---- util/list.c | 37 +++++++++++++++++++++++++++---------- 8 files changed, 103 insertions(+), 25 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 424c7685..9b4cee2f 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -748,8 +748,13 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) { parse_edid(&output->output, edid_len, edid); free(edid); + if (list_add(backend->outputs, output) == -1) { + wlr_log_errno(L_ERROR, "Allocation failed"); + drmModeFreeConnector(conn); + free(output); + continue; + } wlr_output_create_global(&output->output, backend->display); - list_add(backend->outputs, output); wlr_log(L_INFO, "Found display '%s'", output->output.name); } else { output = backend->outputs->items[index]; @@ -764,6 +769,10 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) { for (int i = 0; i < conn->count_modes; ++i) { struct wlr_drm_output_mode *mode = calloc(1, sizeof(struct wlr_drm_output_mode)); + if (!mode) { + wlr_log_errno(L_ERROR, "Allocation failed"); + continue; + } mode->mode = conn->modes[i]; mode->wlr_mode.width = mode->mode.hdisplay; mode->wlr_mode.height = mode->mode.vdisplay; @@ -773,7 +782,11 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) { mode->wlr_mode.width, mode->wlr_mode.height, mode->wlr_mode.refresh); - list_add(output->output.modes, mode); + if (list_add(backend->outputs, output) == -1) { + wlr_log_errno(L_ERROR, "Allocation failed"); + free(mode); + continue; + } } output->state = WLR_DRM_OUTPUT_NEEDS_MODESET; diff --git a/backend/libinput/events.c b/backend/libinput/events.c index dc5e4cb1..2a396536 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -44,11 +44,14 @@ static struct wlr_input_device *allocate_device( return NULL; } struct wlr_input_device *wlr_dev = &wlr_libinput_dev->wlr_input_device; + if (list_add(wlr_devices, wlr_dev) == -1) { + free(wlr_libinput_dev); + return NULL; + } wlr_libinput_dev->handle = libinput_dev; libinput_device_ref(libinput_dev); wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor, product); - list_add(wlr_devices, wlr_dev); return wlr_dev; } diff --git a/backend/multi/backend.c b/backend/multi/backend.c index 290b9678..33b26a0a 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -120,6 +120,12 @@ void wlr_multi_backend_add(struct wlr_backend *_multi, wlr_log(L_ERROR, "Could not add backend: allocation failed"); return; } + if (list_add(multi->backends, sub) == -1) { + wlr_log(L_ERROR, "Could not add backend: allocation failed"); + free(sub); + return; + } + sub->backend = backend; sub->container = &multi->backend; @@ -137,8 +143,6 @@ void wlr_multi_backend_add(struct wlr_backend *_multi, wl_signal_add(&backend->events.input_remove, &sub->input_remove); wl_signal_add(&backend->events.output_add, &sub->output_add); wl_signal_add(&backend->events.output_remove, &sub->output_remove); - - list_add(multi->backends, sub); } struct wlr_session *wlr_multi_get_session(struct wlr_backend *_backend) { diff --git a/backend/wayland/output.c b/backend/wayland/output.c index cb286316..786dc46e 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -236,7 +236,8 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { output->egl_surface, output->egl_surface, output->backend->egl.context)) { wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); - return false; + free(output); + return NULL; } glViewport(0, 0, wlr_output->width, wlr_output->height); @@ -248,11 +249,16 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); - return false; + free(output); + return NULL; } + if (list_add(backend->outputs, wlr_output) == -1) { + wlr_log(L_ERROR, "Allocation failed"); + free(output); + return NULL; + } wlr_output_create_global(wlr_output, backend->local_display); - list_add(backend->outputs, wlr_output); wl_signal_emit(&backend->backend.events.output_add, wlr_output); return wlr_output; } diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index 4668a72b..a4cc0ba5 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -188,7 +188,7 @@ static struct wlr_input_device *allocate_device(struct wlr_wl_backend *backend, enum wlr_input_device_type type) { struct wlr_wl_input_device *wlr_wl_dev; if (!(wlr_wl_dev = calloc(1, sizeof(struct wlr_wl_input_device)))) { - wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + wlr_log_errno(L_ERROR, "Allocation failed"); return NULL; } @@ -200,7 +200,11 @@ static struct wlr_input_device *allocate_device(struct wlr_wl_backend *backend, struct wlr_input_device *wlr_device = &wlr_wl_dev->wlr_input_device; wlr_input_device_init(wlr_device, type, &input_device_impl, name, vendor, product); - list_add(backend->devices, wlr_device); + if (list_add(backend->devices, wlr_device) == -1) { + wlr_log_errno(L_ERROR, "Allocation failed"); + free(wlr_wl_dev); + return NULL; + } return wlr_device; } diff --git a/examples/touch.c b/examples/touch.c index a32c76ba..7e01a6c2 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -65,7 +65,9 @@ static void handle_touch_down(struct touch_state *tstate, int32_t slot, point->slot = slot; point->x = x / width; point->y = y / height; - list_add(sample->touch_points, point); + if (list_add(sample->touch_points, point) == -1) { + free(point); + } } static void handle_touch_up(struct touch_state *tstate, int32_t slot) { diff --git a/include/wlr/util/list.h b/include/wlr/util/list.h index 0c175132..6e746ec4 100644 --- a/include/wlr/util/list.h +++ b/include/wlr/util/list.h @@ -9,16 +9,45 @@ typedef struct { void **items; } list_t; +/** + * Creates a new list, may return `NULL` on failure + */ list_t *list_create(void); void list_free(list_t *list); void list_foreach(list_t *list, void (*callback)(void *item)); -void list_add(list_t *list, void *item); -void list_push(list_t *list, void *item); -void list_insert(list_t *list, size_t index, void *item); +/** + * Add `item` to the end of a list. + * Returns: new list length or `-1` on failure + */ +int list_add(list_t *list, void *item); +/** + * Add `item` to the end of a list. + * Returns: new list length or `-1` on failure + */ +int list_push(list_t *list, void *item); +/** + * Place `item` into index `index` in the list + * Returns: new list length or `-1` on failure + */ +int list_insert(list_t *list, size_t index, void *item); +/** + * Remove an item from the list + */ void list_del(list_t *list, size_t index); +/** + * Remove and return an item from the end of the list + */ void *list_pop(list_t *list); +/** + * Get a reference to the last item of a list without removal + */ void *list_peek(list_t *list); -void list_cat(list_t *list, list_t *source); +/** + * Append each item in `source` to `list` + * Does not modify `source` + * Returns: new list length or `-1` on failure + */ +int list_cat(list_t *list, list_t *source); // See qsort. Remember to use *_qsort functions as compare functions, // because they dereference the left and right arguments first! void list_qsort(list_t *list, int compare(const void *left, const void *right)); diff --git a/util/list.c b/util/list.c index 44fba4db..4abd689b 100644 --- a/util/list.c +++ b/util/list.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -19,11 +20,16 @@ list_t *list_create(void) { return list; } -static void list_resize(list_t *list) { +static bool list_resize(list_t *list) { if (list->length == list->capacity) { + void *new_items = realloc(list->items, sizeof(void*) * (list->capacity + 10)); + if (!new_items) { + return false; + } list->capacity += 10; - list->items = realloc(list->items, sizeof(void*) * list->capacity); + list->items = new_items; } + return true; } void list_free(list_t *list) { @@ -43,20 +49,26 @@ void list_foreach(list_t *list, void (*callback)(void *item)) { } } -void list_add(list_t *list, void *item) { - list_resize(list); +int list_add(list_t *list, void *item) { + if (!list_resize(list)) { + return -1; + } list->items[list->length++] = item; + return list->length; } -void list_push(list_t *list, void *item) { - list_add(list, item); +int list_push(list_t *list, void *item) { + return list_add(list, item); } -void list_insert(list_t *list, size_t index, void *item) { - list_resize(list); +int list_insert(list_t *list, size_t index, void *item) { + if (!list_resize(list)) { + return -1; + } memmove(&list->items[index + 1], &list->items[index], sizeof(void*) * (list->length - index)); list->length++; list->items[index] = item; + return list->length; } void list_del(list_t *list, size_t index) { @@ -74,11 +86,16 @@ void *list_peek(list_t *list) { return list->items[list->length - 1]; } -void list_cat(list_t *list, list_t *source) { +int list_cat(list_t *list, list_t *source) { + size_t old_len = list->length; size_t i; for (i = 0; i < source->length; ++i) { - list_add(list, source->items[i]); + if (list_add(list, source->items[i]) == -1) { + list->length = old_len; + return -1; + } } + return list->length; } void list_qsort(list_t *list, int compare(const void *left, const void *right)) {