summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdrian Thurston <thurston@colm.net>2020-12-08 00:12:36 +0000
committerAdrian Thurston <thurston@colm.net>2020-12-08 00:12:36 +0000
commitfe0e546c65accd2e9ca0fa5410fd88a9b64b36a4 (patch)
tree19335864620e514d73d62b38c76c773c1bf8e227 /src
parent5f310c57af176d7a9a113cbe7fc5b0ff4e4b75f5 (diff)
downloadcolm-fe0e546c65accd2e9ca0fa5410fd88a9b64b36a4.tar.gz
use fopencookie to avoid leaking FILE structs
If we use fdopen for stdin/out/err we cannot close it to free the file struct without also closing the file descriptor. If fopencookie is available, use that to wrap the file descriptor, but allow closing without closing the fd. This is useful when embedding in long running programs.
Diffstat (limited to 'src')
-rw-r--r--src/input.h6
-rw-r--r--src/stream.c78
2 files changed, 76 insertions, 8 deletions
diff --git a/src/input.h b/src/input.h
index 8cb20088..1d86a11b 100644
--- a/src/input.h
+++ b/src/input.h
@@ -193,6 +193,12 @@ struct stream_impl_data
char *name;
FILE *file;
+ // There is one condition when we don't want to close the FILE struct. If
+ // there is no fopencookie available, we need to use fdopen to wrap FD 0, 1
+ // and 2. However, closing those also closes the file descriptor, and when
+ // a colm program is embedded in a bigger program, we don't want that.
+ int no_file_close;
+
struct colm_str_collect *collect;
int consumed;
diff --git a/src/stream.c b/src/stream.c
index 69cbd0ad..0afde365 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -20,6 +20,13 @@
* SOFTWARE.
*/
+#include "config.h"
+
+#ifdef HAVE_FOPENCOOKIE
+#define _GNU_SOURCE
+#include <sys/types.h>
+#endif
+
#include <colm/input.h>
#include <stdio.h>
@@ -42,6 +49,57 @@ DEF_STREAM_FUNCS( stream_funcs_data, stream_impl_data );
extern struct stream_funcs_data file_funcs;
extern struct stream_funcs_data accum_funcs;
+#ifdef HAVE_FOPENCOOKIE
+
+struct colm_file_cookie
+{
+ int fd;
+};
+
+static ssize_t cfc_read(void *cookie, char *buf, size_t size)
+{
+ return read( ((struct colm_file_cookie*)cookie)->fd, buf, size );
+}
+
+static ssize_t cfc_write(void *cookie, const char *buf, size_t size)
+{
+ return write( ((struct colm_file_cookie*)cookie)->fd, buf, size );
+}
+
+static int cfc_seek(void *cookie, off_t *offset, int whence)
+{
+ return -1;
+}
+
+static int cfc_close(void *cookie)
+{
+ free(cookie);
+ return 0;
+}
+
+FILE *colm_fd_open( int fd, const char *mode )
+{
+ cookie_io_functions_t cf = {
+ cfc_read,
+ cfc_write,
+ cfc_seek,
+ cfc_close,
+ };
+
+ struct colm_file_cookie *cfc = malloc(sizeof(struct colm_file_cookie));
+ cfc->fd = fd;
+ return fopencookie( cfc, mode, cf );
+}
+
+#else
+
+FILE *colm_fd_open( int fd, const char *mode )
+{
+ return fdopen( fd, mode );
+}
+
+#endif
+
void stream_impl_push_line( struct stream_impl_data *ss, int ll )
{
if ( ss->line_len == 0 ) {
@@ -94,9 +152,7 @@ static bool loc_set( location_t *loc )
static void close_stream_file( FILE *file )
{
- if ( file != stdin && file != stdout && file != stderr &&
- fileno(file) != 0 && fileno( file) != 1 && fileno(file) != 2 )
- {
+ if ( file != stdin && file != stdout && file != stderr ) {
fclose( file );
}
}
@@ -349,7 +405,7 @@ int data_undo_append_data( struct colm_program *prg, struct stream_impl_data *si
static void data_destructor( program_t *prg, tree_t **sp, struct stream_impl_data *si )
{
- if ( si->file != 0 )
+ if ( si->file != 0 && !si->no_file_close )
close_stream_file( si->file );
if ( si->collect != 0 ) {
@@ -394,10 +450,10 @@ static void data_flush_stream( struct colm_program *prg, struct stream_impl_data
static void data_close_stream( struct colm_program *prg, struct stream_impl_data *si )
{
- if ( si->file != 0 ) {
+ if ( si->file != 0 && !si->no_file_close )
close_stream_file( si->file );
- si->file = 0;
- }
+
+ si->file = 0;
}
static int data_get_option( struct colm_program *prg, struct stream_impl_data *si, int option )
@@ -696,7 +752,13 @@ static struct stream_impl *colm_impl_new_fd( char *name, long fd )
malloc(sizeof(struct stream_impl_data));
si_data_init( si, name );
si->funcs = (struct stream_funcs*)&file_funcs;
- si->file = fdopen( fd, ( fd == 0 ) ? "r" : "w" );
+
+ const char *mode = ( fd == 0 ) ? "r" : "w";
+ si->file = colm_fd_open( fd, mode );
+#ifndef HAVE_FOPENCOOKIE
+ if ( fd == 0 || fd == 1 || fd == 2 )
+ si->no_file_close = 1;
+#endif
return (struct stream_impl*)si;
}