Pavel Stehule <[email protected]> writes:
> attached patch allows raising exception from _PG_init function as was
> discussed before.

I fooled around with this and came up with the attached improved
version, which allows reporting the full error status.  However,
after thinking some more I feel that this is probably a cure worse
than the disease.  If we simply leave the code as it stands, an
elog(ERROR) in an init function doesn't corrupt dfmgr.c's internal list,
which is what I had been fearing when I complained about the issue.
The worst that happens is that we leave the library loaded and leak
a little bit of memory.  Unloading the library, as the patch does,
could easily make things worse not better.  Consider the not-unlikely
case that the library installs itself in a few callback hooks and
then fails.  If we unload the library, those hooks represent
*guaranteed* core dumps on next use.  If we don't unload, the hook
functions might or might not work too well --- presumably not everything
they need has been initialized --- but it's hard to imagine an outcome
that's worse than a guaranteed core dump.

So I'm thinking this is really unnecessary and we should leave well
enough alone.

                        regards, tom lane

Index: dfmgr.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v
retrieving revision 1.98
diff -c -r1.98 dfmgr.c
*** dfmgr.c     1 Jan 2009 17:23:51 -0000       1.98
--- dfmgr.c     1 Apr 2009 23:41:37 -0000
***************
*** 178,184 ****
  static void *
  internal_load_library(const char *libname)
  {
!       DynamicFileList *file_scanner;
        PGModuleMagicFunction magic_func;
        char       *load_error;
        struct stat stat_buf;
--- 178,184 ----
  static void *
  internal_load_library(const char *libname)
  {
!       DynamicFileList * volatile file_scanner;
        PGModuleMagicFunction magic_func;
        char       *load_error;
        struct stat stat_buf;
***************
*** 277,287 ****
                }
  
                /*
!                * If the library has a _PG_init() function, call it.
                 */
                PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, 
"_PG_init");
                if (PG_init)
!                       (*PG_init) ();
  
                /* OK to link it into list */
                if (file_list == NULL)
--- 277,329 ----
                }
  
                /*
!                * If the library has a _PG_init() function, call it.  Guard 
against
!                * the function possibly throwing elog(ERROR).
                 */
                PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, 
"_PG_init");
                if (PG_init)
!               {
!                       MemoryContext   oldcontext = CurrentMemoryContext;
! 
!                       PG_TRY();
!                       {
!                               (*PG_init) ();
!                       }
!                       PG_CATCH();
!                       {
!                               ErrorData  *edata;
! 
!                               /* fetch the error status so we can change it */
!                               MemoryContextSwitchTo(oldcontext);
!                               edata = CopyErrorData();
!                               FlushErrorState();
! 
!                               /*
!                                * The const pointers in the error status very 
likely point
!                                * at constant strings in the library, which we 
are about to
!                                * unload.  Copy them so we don't dump core 
while reporting
!                                * the error.  This might leak a bit of memory 
but it
!                                * beats the alternatives.
!                                */
!                               if (edata->filename)
!                                       edata->filename = 
pstrdup(edata->filename);
!                               if (edata->funcname)
!                                       edata->funcname = 
pstrdup(edata->funcname);
!                               if (edata->domain)
!                                       edata->domain = pstrdup(edata->domain);
! 
!                               /* library might have already called some of 
its functions */
!                               
clear_external_function_hash(file_scanner->handle);
! 
!                               /* try to unlink library */
!                               pg_dlclose(file_scanner->handle);
!                               free((char *) file_scanner);
! 
!                               /* complain */
!                               ReThrowError(edata);
!                       }
!                       PG_END_TRY();
!               }
  
                /* OK to link it into list */
                if (file_list == NULL)
-- 
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to