From 7d037b0b440e1913776650dbe35dbac6d5cfb5d5 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Thu, 4 Nov 2010 23:34:33 +0100 Subject: [PATCH] file_write: Fix NULL pointer dereference. register_writer_node() is the only caller of the ->open method for paraslash writers. It does not check its return value, which is OK for alsa, oss and osx as these writer's ->open method always succeeds. However, the ->open() method of the file writer may fail, for example because the output file could not be opened. This error will be ignored and the writer node task is registered as usual with ->fd being initialized to zero. Fix this bug by splitting the ->open method of the file writer into the part which merely allocates the private_file_write_data structure, hence always succeeds, and the part which actually opens the output file. This second part is called later from ->post_select as soon as there is data available to be written. After this patch the ->open methods of all writers always succeed and we may change its return value to void which is done in the next patch. --- file_write.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/file_write.c b/file_write.c index 4a4dc66e..7497dfaa 100644 --- a/file_write.c +++ b/file_write.c @@ -52,9 +52,17 @@ __must_check __malloc static char *random_filename(void) static int file_write_open(struct writer_node *wn) { - struct private_file_write_data *pfwd = para_calloc( - sizeof(struct private_file_write_data)); + struct private_file_write_data *pfwd = para_calloc(sizeof(*pfwd)); + + wn->private_data = pfwd; + pfwd->fd = -1; + return 0; +} + +static int prepare_output_file(struct writer_node *wn) +{ struct file_write_args_info *conf = wn->conf; + struct private_file_write_data *pfwd = wn->private_data; char *filename; int ret; @@ -62,7 +70,6 @@ static int file_write_open(struct writer_node *wn) filename = conf->filename_arg; else filename = random_filename(); - wn->private_data = pfwd; ret = para_open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (!conf->filename_given) free(filename); @@ -86,9 +93,9 @@ static void file_write_pre_select(struct sched *s, struct task *t) t->error = 0; ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); - if (ret > 0) + if (ret > 0 && pfwd->fd >= 0) para_fd_set(pfwd->fd, &s->wfds, &s->max_fileno); - else if (ret < 0) + else if (ret != 0) /* error or bos and fd not yet open */ sched_min_delay(s); } @@ -96,7 +103,8 @@ static void file_write_close(struct writer_node *wn) { struct private_file_write_data *pfwd = wn->private_data; - close(pfwd->fd); + if (pfwd->fd >= 0) + close(pfwd->fd); free(pfwd); } @@ -114,6 +122,11 @@ static void file_write_post_select(__a_unused struct sched *s, ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); if (ret <= 0) goto out; + if (pfwd->fd < 0) { + ret = prepare_output_file(wn); + if (ret < 0) + goto out; + } if (!FD_ISSET(pfwd->fd, &s->wfds)) return; bytes = btr_next_buffer(btrn, &buf); -- 2.39.5