auto-closing gc'ed string ports to prevent memory leaks (issue #41).

also using a separate port field no_closep to indicate ports whose
underlying streams shouldn't be closed (stdin/stdout/stderr).
This commit is contained in:
Alex Shinn 2010-03-10 21:39:20 +09:00
parent d6c3b04e06
commit e15c49389c
3 changed files with 26 additions and 20 deletions

24
eval.c
View file

@ -2058,14 +2058,7 @@ static sexp sexp_close_port (sexp ctx, sexp port) {
return sexp_type_exception(ctx, "not a port", port);
if (! sexp_port_openp(port))
return sexp_user_exception(ctx, SEXP_FALSE, "port already closed", port);
if (sexp_port_stream(port))
fclose(sexp_port_stream(port));
#if ! SEXP_USE_STRING_STREAMS
if (sexp_port_buf(port) && sexp_oportp(port))
free(sexp_port_buf(port));
#endif
sexp_port_openp(port) = 0;
return SEXP_VOID;
return sexp_finalize_port(ctx, port);
}
void sexp_warn_undefs (sexp ctx, sexp from, sexp to, sexp out) {
@ -2588,12 +2581,15 @@ sexp sexp_add_module_directory (sexp ctx, sexp dir, sexp appendp) {
sexp sexp_load_standard_parameters (sexp ctx, sexp e) {
/* add io port and interaction env parameters */
sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_IN_SYMBOL),
sexp_make_input_port(ctx, stdin, SEXP_FALSE));
sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_OUT_SYMBOL),
sexp_make_output_port(ctx, stdout, SEXP_FALSE));
sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_ERR_SYMBOL),
sexp_make_output_port(ctx, stderr, SEXP_FALSE));
sexp p = sexp_make_input_port(ctx, stdin, SEXP_FALSE);
sexp_port_no_closep(p) = 1;
sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_IN_SYMBOL), p);
p = sexp_make_output_port(ctx, stdout, SEXP_FALSE);
sexp_port_no_closep(p) = 1;
sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_OUT_SYMBOL), p);
p = sexp_make_output_port(ctx, stderr, SEXP_FALSE);
sexp_port_no_closep(p) = 1;
sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_ERR_SYMBOL), p);
sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_INTERACTION_ENV_SYMBOL), e);
return SEXP_VOID;
}

View file

@ -190,7 +190,7 @@ struct sexp_struct {
struct {
FILE *stream;
char *buf;
char openp, sourcep;
char openp, no_closep, sourcep;
sexp_uint_t offset, line;
size_t size;
sexp name;
@ -544,6 +544,7 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_port_name(p) ((p)->value.port.name)
#define sexp_port_line(p) ((p)->value.port.line)
#define sexp_port_openp(p) ((p)->value.port.openp)
#define sexp_port_no_closep(p) ((p)->value.port.no_closep)
#define sexp_port_sourcep(p) ((p)->value.port.sourcep)
#define sexp_port_cookie(p) ((p)->value.port.cookie)
#define sexp_port_buf(p) ((p)->value.port.buf)
@ -848,6 +849,7 @@ SEXP_API sexp sexp_read_raw(sexp ctx, sexp in);
SEXP_API sexp sexp_read(sexp ctx, sexp in);
SEXP_API sexp sexp_read_from_string(sexp ctx, char *str);
SEXP_API sexp sexp_write_to_string(sexp ctx, sexp obj);
SEXP_API sexp sexp_finalize_port (sexp ctx, sexp port);
SEXP_API sexp sexp_make_input_port(sexp ctx, FILE* in, sexp name);
SEXP_API sexp sexp_make_output_port(sexp ctx, FILE* out, sexp name);
SEXP_API sexp sexp_make_input_string_port(sexp ctx, sexp str);

18
sexp.c
View file

@ -53,13 +53,20 @@ sexp sexp_alloc_tagged(sexp ctx, size_t size, sexp_uint_t tag) {
return res;
}
#if SEXP_USE_AUTOCLOSE_PORTS
static sexp sexp_finalize_port (sexp ctx, sexp port) {
if (sexp_port_openp(port) && sexp_port_stream(port)
&& sexp_stringp(sexp_port_name(port)))
fclose(sexp_port_stream(port));
sexp sexp_finalize_port (sexp ctx, sexp port) {
if (sexp_port_openp(port)) {
sexp_port_openp(port) = 0;
if (sexp_port_stream(port) && ! sexp_port_no_closep(port))
fclose(sexp_port_stream(port));
#if ! SEXP_USE_STRING_STREAMS
if (sexp_port_buf(port) && sexp_oportp(port))
free(sexp_port_buf(port));
#endif
}
return SEXP_VOID;
}
#if SEXP_USE_AUTOCLOSE_PORTS
#define SEXP_FINALIZE_PORT sexp_finalize_port
#else
#define SEXP_FINALIZE_PORT NULL
@ -1032,6 +1039,7 @@ sexp sexp_make_input_port (sexp ctx, FILE* in, sexp name) {
sexp_port_line(p) = 1;
sexp_port_buf(p) = NULL;
sexp_port_openp(p) = 1;
sexp_port_no_closep(p) = 0;
sexp_port_sourcep(p) = 1;
sexp_port_cookie(p) = SEXP_VOID;
return p;