fix memory-management problem in putenv
Problem reported by Sergey Pinaev: free(oldbuffer) should be called AFTER putenv(buffer). Also, respond correctly to an (unlikely) putenv() failure.
This commit is contained in:
parent
f43096b123
commit
6cf28d55cd
|
@ -2367,12 +2367,12 @@ static Scheme_Object *sch_getenv(int argc, Scheme_Object *argv[])
|
||||||
#ifndef DOS_FILE_SYSTEM
|
#ifndef DOS_FILE_SYSTEM
|
||||||
static int sch_unix_putenv(const char *var, const char *val, const intptr_t varlen, const intptr_t vallen) {
|
static int sch_unix_putenv(const char *var, const char *val, const intptr_t varlen, const intptr_t vallen) {
|
||||||
char *buffer;
|
char *buffer;
|
||||||
intptr_t total_length;
|
intptr_t total_length, r;
|
||||||
total_length = varlen + vallen + 2;
|
total_length = varlen + vallen + 2;
|
||||||
|
|
||||||
if (val) {
|
if (val) {
|
||||||
#ifdef MZ_PRECISE_GC
|
#ifdef MZ_PRECISE_GC
|
||||||
/* Can't put moveable string into array. */
|
/* Can't put movable string into environ array */
|
||||||
buffer = malloc(total_length);
|
buffer = malloc(total_length);
|
||||||
#else
|
#else
|
||||||
buffer = (char *)scheme_malloc_atomic(total_length);
|
buffer = (char *)scheme_malloc_atomic(total_length);
|
||||||
|
@ -2385,27 +2385,38 @@ static int sch_unix_putenv(const char *var, const char *val, const intptr_t varl
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MZ_PRECISE_GC
|
|
||||||
{
|
|
||||||
/* Free old, if in table: */
|
|
||||||
char *oldbuffer;
|
|
||||||
oldbuffer = (char *)putenv_str_table_get(var);
|
|
||||||
if (oldbuffer)
|
|
||||||
free(oldbuffer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* if precise the buffer needs to be remembered so it can be freed */
|
|
||||||
/* if not precise the buffer needs to be rooted so it doesn't get collected prematurely */
|
|
||||||
putenv_str_table_put_name(var, buffer);
|
|
||||||
|
|
||||||
if (buffer)
|
if (buffer)
|
||||||
return putenv(buffer);
|
r = putenv(buffer);
|
||||||
else {
|
else {
|
||||||
/* on some platforms, unsetenv() returns void */
|
/* on some platforms, unsetenv() returns void */
|
||||||
unsetenv(var);
|
unsetenv(var);
|
||||||
return 0;
|
r = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!r) {
|
||||||
|
#ifdef MZ_PRECISE_GC
|
||||||
|
char *oldbuffer;
|
||||||
|
|
||||||
|
/* Will free old, if in table: */
|
||||||
|
oldbuffer = (char *)putenv_str_table_get(var);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If precise GC, the buffer needs to be remembered so it can be freed;
|
||||||
|
otherwise, the buffer needs to be referenced so it doesn't get GCed */
|
||||||
|
putenv_str_table_put_name(var, buffer);
|
||||||
|
|
||||||
|
#ifdef MZ_PRECISE_GC
|
||||||
|
if (oldbuffer)
|
||||||
|
free(oldbuffer);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef MZ_PRECISE_GC
|
||||||
|
if (buffer)
|
||||||
|
free(buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user