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:
		
							parent
							
								
									19d6442f52
								
							
						
					
					
						commit
						901c14c409
					
				|  | @ -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; | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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)); | ||||
|  |  | |||
							
								
								
									
										37
									
								
								util/list.c
								
								
								
								
							
							
						
						
									
										37
									
								
								util/list.c
								
								
								
								
							|  | @ -1,5 +1,6 @@ | |||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <wlr/util/list.h> | ||||
|  | @ -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)) { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue