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
This commit is contained in:
Calvin Lee 2017-08-16 09:23:21 +02:00
parent 19d6442f52
commit 901c14c409
8 changed files with 103 additions and 25 deletions

View File

@ -748,8 +748,13 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) {
parse_edid(&output->output, edid_len, edid); parse_edid(&output->output, edid_len, edid);
free(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); wlr_output_create_global(&output->output, backend->display);
list_add(backend->outputs, output);
wlr_log(L_INFO, "Found display '%s'", output->output.name); wlr_log(L_INFO, "Found display '%s'", output->output.name);
} else { } else {
output = backend->outputs->items[index]; 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) { for (int i = 0; i < conn->count_modes; ++i) {
struct wlr_drm_output_mode *mode = calloc(1, struct wlr_drm_output_mode *mode = calloc(1,
sizeof(struct wlr_drm_output_mode)); sizeof(struct wlr_drm_output_mode));
if (!mode) {
wlr_log_errno(L_ERROR, "Allocation failed");
continue;
}
mode->mode = conn->modes[i]; mode->mode = conn->modes[i];
mode->wlr_mode.width = mode->mode.hdisplay; mode->wlr_mode.width = mode->mode.hdisplay;
mode->wlr_mode.height = mode->mode.vdisplay; 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.width, mode->wlr_mode.height,
mode->wlr_mode.refresh); 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; output->state = WLR_DRM_OUTPUT_NEEDS_MODESET;

View File

@ -44,11 +44,14 @@ static struct wlr_input_device *allocate_device(
return NULL; return NULL;
} }
struct wlr_input_device *wlr_dev = &wlr_libinput_dev->wlr_input_device; 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; wlr_libinput_dev->handle = libinput_dev;
libinput_device_ref(libinput_dev); libinput_device_ref(libinput_dev);
wlr_input_device_init(wlr_dev, type, &input_device_impl, wlr_input_device_init(wlr_dev, type, &input_device_impl,
name, vendor, product); name, vendor, product);
list_add(wlr_devices, wlr_dev);
return wlr_dev; return wlr_dev;
} }

View File

@ -120,6 +120,12 @@ void wlr_multi_backend_add(struct wlr_backend *_multi,
wlr_log(L_ERROR, "Could not add backend: allocation failed"); wlr_log(L_ERROR, "Could not add backend: allocation failed");
return; 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->backend = backend;
sub->container = &multi->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.input_remove, &sub->input_remove);
wl_signal_add(&backend->events.output_add, &sub->output_add); wl_signal_add(&backend->events.output_add, &sub->output_add);
wl_signal_add(&backend->events.output_remove, &sub->output_remove); 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) { struct wlr_session *wlr_multi_get_session(struct wlr_backend *_backend) {

View File

@ -236,7 +236,8 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) {
output->egl_surface, output->egl_surface, output->egl_surface, output->egl_surface,
output->backend->egl.context)) { output->backend->egl.context)) {
wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error());
return false; free(output);
return NULL;
} }
glViewport(0, 0, wlr_output->width, wlr_output->height); 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)) { if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) {
wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); 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); 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); wl_signal_emit(&backend->backend.events.output_add, wlr_output);
return wlr_output; return wlr_output;
} }

View File

@ -188,7 +188,7 @@ static struct wlr_input_device *allocate_device(struct wlr_wl_backend *backend,
enum wlr_input_device_type type) { enum wlr_input_device_type type) {
struct wlr_wl_input_device *wlr_wl_dev; struct wlr_wl_input_device *wlr_wl_dev;
if (!(wlr_wl_dev = calloc(1, sizeof(struct wlr_wl_input_device)))) { 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; 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; struct wlr_input_device *wlr_device = &wlr_wl_dev->wlr_input_device;
wlr_input_device_init(wlr_device, type, &input_device_impl, wlr_input_device_init(wlr_device, type, &input_device_impl,
name, vendor, product); 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; return wlr_device;
} }

View File

@ -65,7 +65,9 @@ static void handle_touch_down(struct touch_state *tstate, int32_t slot,
point->slot = slot; point->slot = slot;
point->x = x / width; point->x = x / width;
point->y = y / height; 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) { static void handle_touch_up(struct touch_state *tstate, int32_t slot) {

View File

@ -9,16 +9,45 @@ typedef struct {
void **items; void **items;
} list_t; } list_t;
/**
* Creates a new list, may return `NULL` on failure
*/
list_t *list_create(void); list_t *list_create(void);
void list_free(list_t *list); void list_free(list_t *list);
void list_foreach(list_t *list, void (*callback)(void *item)); 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); * Add `item` to the end of a list.
void list_insert(list_t *list, size_t index, void *item); * 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); 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); 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_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, // See qsort. Remember to use *_qsort functions as compare functions,
// because they dereference the left and right arguments first! // because they dereference the left and right arguments first!
void list_qsort(list_t *list, int compare(const void *left, const void *right)); void list_qsort(list_t *list, int compare(const void *left, const void *right));

View File

@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <stddef.h> #include <stddef.h>
#include <wlr/util/list.h> #include <wlr/util/list.h>
@ -19,11 +20,16 @@ list_t *list_create(void) {
return list; return list;
} }
static void list_resize(list_t *list) { static bool list_resize(list_t *list) {
if (list->length == list->capacity) { if (list->length == list->capacity) {
list->capacity += 10; void *new_items = realloc(list->items, sizeof(void*) * (list->capacity + 10));
list->items = realloc(list->items, sizeof(void*) * list->capacity); if (!new_items) {
return false;
} }
list->capacity += 10;
list->items = new_items;
}
return true;
} }
void list_free(list_t *list) { 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) { int list_add(list_t *list, void *item) {
list_resize(list); if (!list_resize(list)) {
return -1;
}
list->items[list->length++] = item; list->items[list->length++] = item;
return list->length;
} }
void list_push(list_t *list, void *item) { int list_push(list_t *list, void *item) {
list_add(list, item); return list_add(list, item);
} }
void list_insert(list_t *list, size_t index, void *item) { int list_insert(list_t *list, size_t index, void *item) {
list_resize(list); if (!list_resize(list)) {
return -1;
}
memmove(&list->items[index + 1], &list->items[index], sizeof(void*) * (list->length - index)); memmove(&list->items[index + 1], &list->items[index], sizeof(void*) * (list->length - index));
list->length++; list->length++;
list->items[index] = item; list->items[index] = item;
return list->length;
} }
void list_del(list_t *list, size_t index) { 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]; 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; size_t i;
for (i = 0; i < source->length; ++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)) { void list_qsort(list_t *list, int compare(const void *left, const void *right)) {