summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-05-15 19:44:50 +0100
committerRobin Watts <robin.watts@artifex.com>2012-05-15 19:44:50 +0100
commita846030605e04c09265241853ed5ac3442c258e9 (patch)
tree62220da6aabc0658a3c51ee4ee70b6309e7a1b2b
parentb549f7df132df28783e34ef6839812b691c9eed5 (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.c7
-rw-r--r--gs/base/gsargs.h3
-rw-r--r--gs/base/gsmalloc.c4
-rw-r--r--gs/psi/imainarg.c57
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