pipewire-v4l2: only access globals.file_maps while holding globals.lock

`file_map` structures are allocated in a `pw_array`. When inserting into
a full `pw_array`, it is resized to accomodate the new elements. In that case,
all `file_map` pointers may be invalidated. Hence it is only safe to access
`file_map` structs while holding `globals.lock`, which prevents any modifications
to the file map array, thus keeping the references valid.
This commit is contained in:
Barnabás Pőcze 2021-10-14 21:27:22 +02:00 committed by Wim Taymans
parent 5e1a93d61d
commit d21a8caace

View file

@ -362,24 +362,34 @@ static int add_file_map(void *addr, struct file *file)
pthread_mutex_unlock(&globals.lock); pthread_mutex_unlock(&globals.lock);
return 0; return 0;
} }
static struct file_map *find_file_map(void *addr)
/* must be called with `globals.lock` held */
static struct file_map *find_file_map_unlocked(void *addr)
{ {
struct file_map *map, *res = NULL; struct file_map *map;
pthread_mutex_lock(&globals.lock);
pw_array_for_each(map, &globals.file_maps) { pw_array_for_each(map, &globals.file_maps) {
if (map->addr == addr) { if (map->addr == addr)
res = map; return map;
break;
}
} }
pthread_mutex_unlock(&globals.lock);
return res; return NULL;
} }
static void remove_file_map(struct file_map *map) static struct file *remove_file_map(void *addr)
{ {
pthread_mutex_lock(&globals.lock); pthread_mutex_lock(&globals.lock);
pw_array_remove(&globals.file_maps, map);
struct file_map *map = find_file_map_unlocked(addr);
struct file *file = NULL;
if (map != NULL) {
file = map->file;
pw_array_remove(&globals.file_maps, map);
}
pthread_mutex_unlock(&globals.lock); pthread_mutex_unlock(&globals.lock);
return file;
} }
static int add_buffer_map(struct file *file, void *addr, uint32_t id) static int add_buffer_map(struct file *file, void *addr, uint32_t id)
@ -729,9 +739,9 @@ static int v4l2_dup(int oldfd)
static int v4l2_close(int fd) static int v4l2_close(int fd)
{ {
struct file *file = remove_fd_map(fd); struct file *file;
if (file == NULL) if ((file = remove_fd_map(fd)) == NULL)
return globals.old_fops.close(fd); return globals.old_fops.close(fd);
unref_file(file); unref_file(file);
@ -1852,15 +1862,12 @@ error_unlock:
static int v4l2_munmap(void *addr, size_t length) static int v4l2_munmap(void *addr, size_t length)
{ {
int res; int res;
struct file_map *fmap;
struct buffer_map *bmap; struct buffer_map *bmap;
struct file *file; struct file *file;
if ((fmap = find_file_map(addr)) == NULL) if ((file = remove_file_map(addr)) == NULL)
return globals.old_fops.munmap(addr, length); return globals.old_fops.munmap(addr, length);
file = fmap->file;
pw_thread_loop_lock(file->loop); pw_thread_loop_lock(file->loop);
bmap = find_buffer_map(file, addr); bmap = find_buffer_map(file, addr);
@ -1879,8 +1886,6 @@ static int v4l2_munmap(void *addr, size_t length)
exit_unlock: exit_unlock:
pw_thread_loop_unlock(file->loop); pw_thread_loop_unlock(file->loop);
remove_file_map(fmap);
return res; return res;
} }