Plug memory leaks introduced by dynamic-search-path changes.

From Teodor Sigaev.
This commit is contained in:
Tom Lane 2001-10-04 19:13:55 +00:00
parent 38633cf891
commit 3f8a50c013
1 changed files with 47 additions and 29 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.51 2001/09/16 16:11:11 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.52 2001/10/04 19:13:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -24,7 +24,7 @@
/* /*
* List of dynamically loaded files. * List of dynamically loaded files (kept in malloc'd memory).
*/ */
typedef struct df_files typedef struct df_files
@ -71,25 +71,25 @@ load_external_function(char *filename, char *funcname,
char *fullname; char *fullname;
fullname = expand_dynamic_library_name(filename); fullname = expand_dynamic_library_name(filename);
if (fullname) if (!fullname)
filename = fullname; fullname = pstrdup(filename);
/* at this point fullname is always freshly palloc'd */
/* /*
* Scan the list of loaded FILES to see if the file has been loaded. * Scan the list of loaded FILES to see if the file has been loaded.
*/ */
for (file_scanner = file_list; for (file_scanner = file_list;
file_scanner != (DynamicFileList *) NULL && file_scanner != (DynamicFileList *) NULL &&
strcmp(filename, file_scanner->filename) != 0; strcmp(fullname, file_scanner->filename) != 0;
file_scanner = file_scanner->next) file_scanner = file_scanner->next)
; ;
if (file_scanner == (DynamicFileList *) NULL) if (file_scanner == (DynamicFileList *) NULL)
{ {
/* /*
* Check for same files - different paths (ie, symlink or link) * Check for same files - different paths (ie, symlink or link)
*/ */
if (stat(filename, &stat_buf) == -1) if (stat(fullname, &stat_buf) == -1)
elog(ERROR, "stat failed on file '%s': %m", filename); elog(ERROR, "stat failed on file '%s': %m", fullname);
for (file_scanner = file_list; for (file_scanner = file_list;
file_scanner != (DynamicFileList *) NULL && file_scanner != (DynamicFileList *) NULL &&
@ -100,27 +100,26 @@ load_external_function(char *filename, char *funcname,
if (file_scanner == (DynamicFileList *) NULL) if (file_scanner == (DynamicFileList *) NULL)
{ {
/* /*
* File not loaded yet. * File not loaded yet.
*/ */
file_scanner = (DynamicFileList *) file_scanner = (DynamicFileList *)
malloc(sizeof(DynamicFileList) + strlen(filename)); malloc(sizeof(DynamicFileList) + strlen(fullname));
if (file_scanner == NULL) if (file_scanner == NULL)
elog(ERROR, "Out of memory in load_external_function"); elog(ERROR, "Out of memory in load_external_function");
MemSet((char *) file_scanner, 0, sizeof(DynamicFileList)); MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
strcpy(file_scanner->filename, filename); strcpy(file_scanner->filename, fullname);
file_scanner->device = stat_buf.st_dev; file_scanner->device = stat_buf.st_dev;
file_scanner->inode = stat_buf.st_ino; file_scanner->inode = stat_buf.st_ino;
file_scanner->next = (DynamicFileList *) NULL; file_scanner->next = (DynamicFileList *) NULL;
file_scanner->handle = pg_dlopen(filename); file_scanner->handle = pg_dlopen(fullname);
if (file_scanner->handle == (void *) NULL) if (file_scanner->handle == (void *) NULL)
{ {
load_error = (char *) pg_dlerror(); load_error = (char *) pg_dlerror();
free((char *) file_scanner); free((char *) file_scanner);
elog(ERROR, "Load of file %s failed: %s", filename, load_error); elog(ERROR, "Load of file %s failed: %s", fullname, load_error);
} }
/* OK to link it into list */ /* OK to link it into list */
@ -135,13 +134,17 @@ load_external_function(char *filename, char *funcname,
* If funcname is NULL, we only wanted to load the file. * If funcname is NULL, we only wanted to load the file.
*/ */
if (funcname == (char *) NULL) if (funcname == (char *) NULL)
{
pfree(fullname);
return (PGFunction) NULL; return (PGFunction) NULL;
}
retval = pg_dlsym(file_scanner->handle, funcname); retval = pg_dlsym(file_scanner->handle, funcname);
if (retval == (PGFunction) NULL && signalNotFound) if (retval == (PGFunction) NULL && signalNotFound)
elog(ERROR, "Can't find function %s in file %s", funcname, filename); elog(ERROR, "Can't find function %s in file %s", funcname, fullname);
pfree(fullname);
return retval; return retval;
} }
@ -159,16 +162,17 @@ load_file(char *filename)
char *fullname; char *fullname;
fullname = expand_dynamic_library_name(filename); fullname = expand_dynamic_library_name(filename);
if (fullname) if (!fullname)
filename = fullname; fullname = pstrdup(filename);
/* at this point fullname is always freshly palloc'd */
/* /*
* We need to do stat() in order to determine whether this is the same * We need to do stat() in order to determine whether this is the same
* file as a previously loaded file; it's also handy so as to give a * file as a previously loaded file; it's also handy so as to give a
* good error message if bogus file name given. * good error message if bogus file name given.
*/ */
if (stat(filename, &stat_buf) == -1) if (stat(fullname, &stat_buf) == -1)
elog(ERROR, "LOAD: could not open file '%s': %m", filename); elog(ERROR, "LOAD: could not open file '%s': %m", fullname);
if (file_list != (DynamicFileList *) NULL) if (file_list != (DynamicFileList *) NULL)
{ {
@ -197,7 +201,9 @@ load_file(char *filename)
} }
} }
load_external_function(filename, (char *) NULL, false); load_external_function(fullname, (char *) NULL, false);
pfree(fullname);
} }
@ -235,6 +241,8 @@ file_exists(const char *name)
* find_in_dynamic_libpath below); if that works, return the fully * find_in_dynamic_libpath below); if that works, return the fully
* expanded file name. If the previous failed, append DLSUFFIX and * expanded file name. If the previous failed, append DLSUFFIX and
* try again. If all fails, return NULL. * try again. If all fails, return NULL.
*
* A non-NULL result will always be freshly palloc'd.
*/ */
static char * static char *
expand_dynamic_library_name(const char *name) expand_dynamic_library_name(const char *name)
@ -258,6 +266,7 @@ expand_dynamic_library_name(const char *name)
full = substitute_libpath_macro(name); full = substitute_libpath_macro(name);
if (file_exists(full)) if (file_exists(full))
return full; return full;
pfree(full);
} }
new = palloc(strlen(name)+ strlen(DLSUFFIX) + 1); new = palloc(strlen(name)+ strlen(DLSUFFIX) + 1);
@ -274,15 +283,20 @@ expand_dynamic_library_name(const char *name)
else else
{ {
full = substitute_libpath_macro(new); full = substitute_libpath_macro(new);
pfree(new);
if (file_exists(full)) if (file_exists(full))
return full; return full;
pfree(full);
} }
return NULL; return NULL;
} }
/*
* Substitute for any macros appearing in the given string.
* Result is always freshly palloc'd.
*/
static char * static char *
substitute_libpath_macro(const char * name) substitute_libpath_macro(const char * name)
{ {
@ -302,7 +316,7 @@ substitute_libpath_macro(const char * name)
elog(ERROR, "invalid macro name in dynamic library path"); elog(ERROR, "invalid macro name in dynamic library path");
if (name[macroname_len] == '\0') if (name[macroname_len] == '\0')
return replacement; return pstrdup(replacement);
else else
{ {
char * new; char * new;
@ -319,15 +333,14 @@ substitute_libpath_macro(const char * name)
/* /*
* Search for a file called 'basename' in the colon-separated search * Search for a file called 'basename' in the colon-separated search
* path 'path'. If the file is found, the full file name is returned * path Dynamic_library_path. If the file is found, the full file name
* in palloced memory. The the file is not found, return NULL. * is returned in freshly palloc'd memory. If the file is not found,
* return NULL.
*/ */
static char * static char *
find_in_dynamic_libpath(const char * basename) find_in_dynamic_libpath(const char * basename)
{ {
const char *p; const char *p;
char *full;
size_t len;
size_t baselen; size_t baselen;
AssertArg(basename != NULL); AssertArg(basename != NULL);
@ -340,9 +353,12 @@ find_in_dynamic_libpath(const char * basename)
baselen = strlen(basename); baselen = strlen(basename);
do { for (;;)
{
size_t len;
char * piece; char * piece;
const char * mangled; char * mangled;
char *full;
len = strcspn(p, ":"); len = strcspn(p, ":");
@ -354,6 +370,7 @@ find_in_dynamic_libpath(const char * basename)
piece[len] = '\0'; piece[len] = '\0';
mangled = substitute_libpath_macro(piece); mangled = substitute_libpath_macro(piece);
pfree(piece);
/* only absolute paths */ /* only absolute paths */
if (mangled[0] != '/') if (mangled[0] != '/')
@ -361,6 +378,7 @@ find_in_dynamic_libpath(const char * basename)
full = palloc(strlen(mangled) + 1 + baselen + 1); full = palloc(strlen(mangled) + 1 + baselen + 1);
sprintf(full, "%s/%s", mangled, basename); sprintf(full, "%s/%s", mangled, basename);
pfree(mangled);
if (DebugLvl > 1) if (DebugLvl > 1)
elog(DEBUG, "find_in_dynamic_libpath: trying %s", full); elog(DEBUG, "find_in_dynamic_libpath: trying %s", full);
@ -368,13 +386,13 @@ find_in_dynamic_libpath(const char * basename)
if (file_exists(full)) if (file_exists(full))
return full; return full;
pfree(piece);
pfree(full); pfree(full);
if (p[len] == '\0') if (p[len] == '\0')
break; break;
else else
p += len + 1; p += len + 1;
} while(1); }
return NULL; return NULL;
} }