If we get EOF earlier than expected, the current read loops will deadlock. This may easily happen if the disk cache gets corrupted. Fix it by using a helper function that handles EOF.
Steps to reproduce (on a build with asserts disabled): $ glxgears $ find ~/.cache/mesa/ -type f -exec truncate -s 0 '{}' \; $ glxgears # deadlock Signed-off-by: Grazvydas Ignotas <nota...@gmail.com> --- src/util/disk_cache.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/util/disk_cache.c b/src/util/disk_cache.c index 4f66aa9..9677f93 100644 --- a/src/util/disk_cache.c +++ b/src/util/disk_cache.c @@ -636,10 +636,25 @@ disk_cache_remove(struct disk_cache *cache, const cache_key key) if (sb.st_size) p_atomic_add(cache->size, - (uint64_t)sb.st_size); } static ssize_t +read_all(int fd, void *buf, size_t count) +{ + char *in = buf; + ssize_t read_ret; + size_t done; + + for (done = 0; done < count; done += read_ret) { + read_ret = read(fd, in + done, count - done); + if (read_ret == -1 || read_ret == 0) + return -1; + } + return done; +} + +static ssize_t write_all(int fd, const void *buf, size_t count) { const char *out = buf; ssize_t written; size_t done; @@ -932,11 +947,11 @@ inflate_cache_data(uint8_t *in_data, size_t in_data_size, } void * disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size) { - int fd = -1, ret, len; + int fd = -1, ret; struct stat sb; char *filename = NULL; uint8_t *data = NULL; uint8_t *uncompressed_data = NULL; @@ -963,16 +978,14 @@ disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size) uint8_t *file_header = malloc(ck_size); if (!file_header) goto fail; assert(sb.st_size > ck_size); - for (len = 0; len < ck_size; len += ret) { - ret = read(fd, ((uint8_t *) file_header) + len, ck_size - len); - if (ret == -1) { - free(file_header); - goto fail; - } + ret = read_all(fd, file_header, ck_size); + if (ret == -1) { + free(file_header); + goto fail; } assert(memcmp(cache->driver_keys_blob, file_header, ck_size) == 0); free(file_header); @@ -986,23 +999,19 @@ disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size) #endif /* Load the CRC that was created when the file was written. */ struct cache_entry_file_data cf_data; size_t cf_data_size = sizeof(cf_data); - for (len = 0; len < cf_data_size; len += ret) { - ret = read(fd, ((uint8_t *) &cf_data) + len, cf_data_size - len); - if (ret == -1) - goto fail; - } + ret = read_all(fd, &cf_data, cf_data_size); + if (ret == -1) + goto fail; /* Load the actual cache data. */ size_t cache_data_size = sb.st_size - cf_data_size - ck_size; - for (len = 0; len < cache_data_size; len += ret) { - ret = read(fd, data + len, cache_data_size - len); - if (ret == -1) - goto fail; - } + ret = read_all(fd, data, cache_data_size); + if (ret == -1) + goto fail; /* Uncompress the cache data */ uncompressed_data = malloc(cf_data.uncompressed_size); if (!inflate_cache_data(data, cache_data_size, uncompressed_data, cf_data.uncompressed_size)) -- 2.7.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev