mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-10-29 05:40:16 -04:00 
			
		
		
		
	util: Avoid undefined behaviour in for_each_helper
for_each_helper tries to calculate a one-past-the-end pointer for its wl_array input. This is fine when the array has one or more entries, but we initialize arrays by setting wl_array.data to NULL. Pointer arithmetic is only defined when both the pointer operand and the result point to the same allocation, or one-past-the-end of that allocation. As NULL points to no allocation, no pointer arithmetic can be performed on it, not even adding 0, even if the result is never dereferenced. This is caught by clang's ubsan from version 10. Many tests already hit this case, but I added an explicit test for iterating over an empty wl_map. Signed-off-by: Fergus Dall <sidereal@google.com>
This commit is contained in:
		
							parent
							
								
									ada25fbd52
								
							
						
					
					
						commit
						80164ef300
					
				
					 2 changed files with 25 additions and 6 deletions
				
			
		|  | @ -363,18 +363,21 @@ wl_map_lookup_flags(struct wl_map *map, uint32_t i) | ||||||
| static enum wl_iterator_result | static enum wl_iterator_result | ||||||
| for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) | for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) | ||||||
| { | { | ||||||
| 	union map_entry *start, *end, *p; |  | ||||||
| 	enum wl_iterator_result ret = WL_ITERATOR_CONTINUE; | 	enum wl_iterator_result ret = WL_ITERATOR_CONTINUE; | ||||||
|  | 	union map_entry entry, *start; | ||||||
|  | 	size_t count; | ||||||
| 
 | 
 | ||||||
| 	start = entries->data; | 	start = (union map_entry *) entries->data; | ||||||
| 	end = (union map_entry *) ((char *) entries->data + entries->size); | 	count = entries->size / sizeof(union map_entry); | ||||||
| 
 | 
 | ||||||
| 	for (p = start; p < end; p++) | 	for (size_t idx = 0; idx < count; idx++) { | ||||||
| 		if (p->data && !map_entry_is_free(*p)) { | 		entry = start[idx]; | ||||||
| 			ret = func(map_entry_get_data(*p), data, map_entry_get_flags(*p)); | 		if (entry.data && !map_entry_is_free(entry)) { | ||||||
|  | 			ret = func(map_entry_get_data(entry), data, map_entry_get_flags(entry)); | ||||||
| 			if (ret != WL_ITERATOR_CONTINUE) | 			if (ret != WL_ITERATOR_CONTINUE) | ||||||
| 				break; | 				break; | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -119,3 +119,19 @@ TEST(map_flags) | ||||||
| 
 | 
 | ||||||
| 	wl_map_release(&map); | 	wl_map_release(&map); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static enum wl_iterator_result never_run(void *element, void *data, uint32_t flags) | ||||||
|  | { | ||||||
|  | 	assert(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TEST(map_iter_empty) | ||||||
|  | { | ||||||
|  | 	struct wl_map map; | ||||||
|  | 
 | ||||||
|  | 	wl_map_init(&map, WL_MAP_SERVER_SIDE); | ||||||
|  | 
 | ||||||
|  | 	wl_map_for_each(&map, never_run, NULL); | ||||||
|  | 
 | ||||||
|  | 	wl_map_release(&map); | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Fergus Dall
						Fergus Dall