summaryrefslogtreecommitdiff
path: root/cursor/parse_cursor_file.c
diff options
context:
space:
mode:
authorMichael Stapelberg <michael@stapelberg.de>2013-11-07 22:00:21 +0100
committerMichael Stapelberg <michael@stapelberg.de>2013-11-07 22:00:21 +0100
commitc453d4baceaead514c814b825cdd9b517c6bcd8c (patch)
tree1ecc56849e154cffcf93d7351cbead29d4c16470 /cursor/parse_cursor_file.c
parent0bde33d9a11e73c1e798b40c453fa0593f8f706b (diff)
handle read() errors (Thanks psychon)
Diffstat (limited to 'cursor/parse_cursor_file.c')
-rw-r--r--cursor/parse_cursor_file.c70
1 files changed, 44 insertions, 26 deletions
diff --git a/cursor/parse_cursor_file.c b/cursor/parse_cursor_file.c
index 30f7df5..b944c4a 100644
--- a/cursor/parse_cursor_file.c
+++ b/cursor/parse_cursor_file.c
@@ -35,6 +35,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <stdbool.h>
#ifdef HAVE_ENDIAN_H
#include <endian.h>
@@ -82,14 +83,24 @@ static uint32_t find_best_size(xcint_cursor_file_t *cf, const uint32_t target, u
return best;
}
+/* Returns true if and only if the read() call read the entirety of the data it
+ * was supposed to read. */
+static bool read_entirely(int fd, void *buf, size_t count) {
+ return read(fd, buf, count) == count;
+}
+
int parse_cursor_file(xcb_cursor_context_t *c, const int fd, xcint_image_t **images, int *nimg) {
/* Read the header, verify the magic value. */
xcint_cursor_file_t cf;
uint32_t nsizes = 0;
uint32_t best = 0;
uint32_t skip = 0;
+ /* The amount of images stored in 'images', used when cleaning up. */
+ int cnt = 0;
+
+ if (!read_entirely(fd, &(cf.header), sizeof(xcint_file_header_t)))
+ return -EINVAL;
- read(fd, &(cf.header), sizeof(xcint_file_header_t));
cf.header.magic = le32toh(cf.header.magic);
cf.header.header = le32toh(cf.header.header);
cf.header.version = le32toh(cf.header.version);
@@ -107,7 +118,9 @@ int parse_cursor_file(xcb_cursor_context_t *c, const int fd, xcint_image_t **ima
/* Read the table of contents */
cf.tocs = malloc(cf.header.ntoc * sizeof(xcint_file_toc_t));
- read(fd, cf.tocs, cf.header.ntoc * sizeof(xcint_file_toc_t));
+ if (!read_entirely(fd, cf.tocs, cf.header.ntoc * sizeof(xcint_file_toc_t)))
+ goto error;
+
for (int n = 0; n < cf.header.ntoc; n++) {
cf.tocs[n].type = le32toh(cf.tocs[n].type);
cf.tocs[n].subtype = le32toh(cf.tocs[n].subtype);
@@ -115,23 +128,17 @@ int parse_cursor_file(xcb_cursor_context_t *c, const int fd, xcint_image_t **ima
}
/* No images? Invalid file. */
- if ((best = find_best_size(&cf, c->size, &nsizes)) == 0 || nsizes == 0) {
- free(cf.tocs);
- return -EINVAL;
- }
+ if ((best = find_best_size(&cf, c->size, &nsizes)) == 0 || nsizes == 0)
+ goto error;
*nimg = nsizes;
- if ((*images = calloc(nsizes, sizeof(xcint_image_t))) == NULL) {
- free(cf.tocs);
- return -errno;
- }
+ if ((*images = calloc(nsizes, sizeof(xcint_image_t))) == NULL)
+ goto error;
- for (int n = 0, cnt = 0;
- n < cf.header.ntoc;
- n++) {
+ for (int n = 0; n < cf.header.ntoc; n++) {
xcint_chunk_header_t chunk;
/* for convenience */
- xcint_image_t *i = &((*images)[cnt++]);
+ xcint_image_t *i = &((*images)[n]);
uint32_t numpixels = 0;
uint32_t *p = NULL;
@@ -140,18 +147,18 @@ int parse_cursor_file(xcb_cursor_context_t *c, const int fd, xcint_image_t **ima
continue;
lseek(fd, cf.tocs[n].position, SEEK_SET);
- read(fd, &chunk, sizeof(xcint_chunk_header_t));
+ if (!read_entirely(fd, &chunk, sizeof(xcint_chunk_header_t)))
+ goto error2;
chunk.header = le32toh(chunk.header);
chunk.type = le32toh(chunk.type);
chunk.subtype = le32toh(chunk.subtype);
chunk.version = le32toh(chunk.version);
/* Sanity check, as libxcursor does it. */
if (chunk.type != cf.tocs[n].type ||
- chunk.subtype != cf.tocs[n].subtype) {
- free(cf.tocs);
- return -EINVAL;
- }
- read(fd, i, sizeof(xcint_image_t) - sizeof(uint32_t*)); // TODO: better type
+ chunk.subtype != cf.tocs[n].subtype)
+ goto error2;
+ if (!read_entirely(fd, i, sizeof(xcint_image_t) - sizeof(uint32_t*))) // TODO: better type
+ goto error2;
i->width = le32toh(i->width);
i->height = le32toh(i->height);
i->xhot = le32toh(i->xhot);
@@ -159,14 +166,15 @@ int parse_cursor_file(xcb_cursor_context_t *c, const int fd, xcint_image_t **ima
i->delay = le32toh(i->delay);
/* Read the actual image data and convert it to host byte order */
- if (((uint64_t)i->width) * i->height > UINT32_MAX) {
- /* Catch integer overflows */
- free(cf.tocs);
- return -EINVAL;
- }
+ /* Catch integer overflows */
+ if (((uint64_t)i->width) * i->height > UINT32_MAX)
+ goto error2;
numpixels = i->width * i->height;
i->pixels = malloc(numpixels * sizeof(uint32_t));
- read(fd, i->pixels, numpixels * sizeof(uint32_t));
+ /* With the malloc, one more image is eligible for cleanup later. */
+ cnt++;
+ if (!read_entirely(fd, i->pixels, numpixels * sizeof(uint32_t)))
+ goto error2;
p = i->pixels;
for (int j = 0; j < numpixels; j++, p++)
*p = le32toh(*p);
@@ -174,4 +182,14 @@ int parse_cursor_file(xcb_cursor_context_t *c, const int fd, xcint_image_t **ima
free(cf.tocs);
return 0;
+
+error2:
+ /* Free the memory for all images that were read so far. */
+ for (int n = 0; n < cnt; n++)
+ free((*images)[n].pixels);
+ free(*images);
+error:
+ *images = NULL;
+ free(cf.tocs);
+ return -EINVAL;
}