diff options
author | Robin Watts <robin.watts@artifex.com> | 2012-05-15 19:44:50 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2012-05-15 19:44:50 +0100 |
commit | a846030605e04c09265241853ed5ac3442c258e9 (patch) | |
tree | 62220da6aabc0658a3c51ee4ee70b6309e7a1b2b | |
parent | b549f7df132df28783e34ef6839812b691c9eed5 (diff) |
Leak checking tweaks; memory finalisation and param handling
When Ghostscript shuts down, it closes its malloc handler, which frees
all the outstanding blocks it knows about. This is unhelpful behaviour
when checking for leaks, so we disable this freeing in MEMENTO builds.
Also, the Ghostscript arg handling code is quite keen on 'arg_copy'ing
args only to pass them into routines that immediate copy them again
into heap allocated buffers. These copies are then allowed to leak.
Where it is obviously safe, avoid these copies. Where it's not so clear
free them (using a new arg_free function).
-rw-r--r-- | gs/base/gsargs.c | 7 | ||||
-rw-r--r-- | gs/base/gsargs.h | 3 | ||||
-rw-r--r-- | gs/base/gsmalloc.c | 4 | ||||
-rw-r--r-- | gs/psi/imainarg.c | 57 |
4 files changed, 37 insertions, 34 deletions
diff --git a/gs/base/gsargs.c b/gs/base/gsargs.c index 93641ed77..a7436cde4 100644 --- a/gs/base/gsargs.c +++ b/gs/base/gsargs.c @@ -237,3 +237,10 @@ arg_copy(const char *str, gs_memory_t * mem) strcpy(sstr, str); return sstr; } + +/* Free a previously arg_copy'd string */ +void +arg_free(char *str, gs_memory_t * mem) +{ + gs_free_object(mem, str, "arg_copy"); +} diff --git a/gs/base/gsargs.h b/gs/base/gsargs.h index 4d5ef1aa7..e27f3a80a 100644 --- a/gs/base/gsargs.h +++ b/gs/base/gsargs.h @@ -76,4 +76,7 @@ const char *arg_next(arg_list * pal, int *code); /* Copy an argument string to the heap. */ char *arg_copy(const char *str, gs_memory_t * mem); +/* Free an argument string previously copied to the heap. */ +void arg_free(char *str, gs_memory_t * mem); + #endif /* gsargs_INCLUDED */ diff --git a/gs/base/gsmalloc.c b/gs/base/gsmalloc.c index 5514cc205..ef831c257 100644 --- a/gs/base/gsmalloc.c +++ b/gs/base/gsmalloc.c @@ -467,6 +467,9 @@ gs_heap_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname) */ mmem->monitor = NULL; /* delete reference to this monitor */ gx_monitor_free(mon); /* free the monitor */ +#ifndef MEMENTO + /* Normally gs calls this on closedown, and it frees every block that + * has ever been allocated. This is not helpful for leak checking. */ if (free_mask & FREE_ALL_DATA) { gs_malloc_block_t *bp = mmem->allocated; gs_malloc_block_t *np; @@ -480,6 +483,7 @@ gs_heap_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname) free(bp); } } +#endif if (free_mask & FREE_ALL_ALLOCATOR) free(mem); } diff --git a/gs/psi/imainarg.c b/gs/psi/imainarg.c index 258594bfb..7dc7cd2ac 100644 --- a/gs/psi/imainarg.c +++ b/gs/psi/imainarg.c @@ -316,27 +316,24 @@ run_stdin: } psarg = arg_copy(psarg, minst->heap); if (psarg == NULL) - return e_Fatal; - code = gs_main_init2(minst); - if (code < 0) - return code; - code = run_string(minst, "userdict/ARGUMENTS[", 0); - if (code < 0) - return code; - while ((arg = arg_next(pal, &code)) != 0) { - char *fname = arg_copy(arg, minst->heap); - if (fname == NULL) - return e_Fatal; - code = runarg(minst, "", fname, "", runInit); - if (code < 0) - return code; - } - if (code < 0) - return e_Fatal; - code = runarg(minst, "]put", psarg, ".runfile", runInit | runFlush); - if (code < 0) - return code; - return e_Quit; + code = e_Fatal; + else + code = gs_main_init2(minst); + if (code >= 0) + code = run_string(minst, "userdict/ARGUMENTS[", 0); + if (code >= 0) + while ((arg = arg_next(pal, &code)) != 0) { + code = runarg(minst, "", arg, "", runInit); + if (code < 0) + break; + } + if (code >= 0) + code = runarg(minst, "]put", psarg, ".runfile", runInit | runFlush); + arg_free(psarg, minst->heap); + if (code >= 0) + code = e_Quit; + + return code; } case 'A': /* trace allocator */ switch (*arg) { @@ -377,16 +374,11 @@ run_stdin: return code; pal->expand_ats = false; while ((arg = arg_next(pal, &code)) != 0) { - char *sarg; - if (arg[0] == '@' || (arg[0] == '-' && !isdigit((unsigned char)arg[1])) ) break; - sarg = arg_copy(arg, minst->heap); - if (sarg == NULL) - return e_Fatal; - code = runarg(minst, "", sarg, ".runstring", 0); + code = runarg(minst, "", arg, ".runstring", 0); if (code < 0) return code; } @@ -752,19 +744,15 @@ static int argproc(gs_main_instance * minst, const char *arg) { int code = gs_main_init1(minst); /* need i_ctx_p to proceed */ - char *filearg; if (code < 0) return code; - filearg = arg_copy(arg, minst->heap); - if (filearg == NULL) - return e_Fatal; if (minst->run_buffer_size) { /* Run file with run_string. */ - return run_buffered(minst, filearg); + return run_buffered(minst, arg); } else { /* Run file directly in the normal way. */ - return runarg(minst, "", filearg, ".runfile", runInit | runFlush); + return runarg(minst, "", arg, ".runfile", runInit | runFlush); } } static int @@ -822,7 +810,7 @@ runarg(gs_main_instance * minst, const char *pre, const char *arg, if (code < 0) return code; } - line = (char *)gs_alloc_bytes(minst->heap, len, "argproc"); + line = (char *)gs_alloc_bytes(minst->heap, len, "runarg"); if (line == 0) { lprintf("Out of memory!\n"); return_error(e_VMerror); @@ -833,6 +821,7 @@ runarg(gs_main_instance * minst, const char *pre, const char *arg, minst->i_ctx_p->starting_arg_file = true; code = run_string(minst, line, options); minst->i_ctx_p->starting_arg_file = false; + gs_free_object(minst->heap, line, "runarg"); return code; } static int |