diff options
| author | Tom Lane | 2017-04-15 03:50:16 +0000 |
|---|---|---|
| committer | Tom Lane | 2017-04-15 03:50:16 +0000 |
| commit | 32470825d36d99a81347ee36c181d609c952c061 (patch) | |
| tree | 0fe8bfc11dbb20ae8dfe943632674cd3bc859b79 /src/backend/postmaster | |
| parent | 5a617ab3e691aec56725960e6d28c98c8af6ddaa (diff) | |
Avoid passing function pointers across process boundaries.
We'd already recognized that we can't pass function pointers across process
boundaries for functions in loadable modules, since a shared library could
get loaded at different addresses in different processes. But actually the
practice doesn't work for functions in the core backend either, if we're
using EXEC_BACKEND. This is the cause of recent failures on buildfarm
member culicidae. Switch to passing a string function name in all cases.
Something like this needs to be back-patched into 9.6, but let's see
if the buildfarm likes it first.
Petr Jelinek, with a bunch of basically-cosmetic adjustments by me
Discussion: https://postgr.es/m/548f9c1d-eafa-e3fa-9da8-f0cc2f654e60@2ndquadrant.com
Diffstat (limited to 'src/backend/postmaster')
| -rw-r--r-- | src/backend/postmaster/bgworker.c | 105 |
1 files changed, 61 insertions, 44 deletions
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 9ad3e915db3..f1194891f50 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -111,25 +111,30 @@ struct BackgroundWorkerHandle static BackgroundWorkerArray *BackgroundWorkerData; /* - * List of internal background workers. These are used for mapping the - * function name to actual function when building with EXEC_BACKEND and also - * to allow these to be loaded outside of shared_preload_libraries. + * List of internal background worker entry points. We need this for + * reasons explained in LookupBackgroundWorkerFunction(), below. */ -typedef struct InternalBGWorkerMain +static const struct { - char *bgw_function_name; - bgworker_main_type bgw_main; -} InternalBGWorkerMain; - -static const InternalBGWorkerMain InternalBGWorkers[] = { - {"ParallelWorkerMain", ParallelWorkerMain}, - {"ApplyLauncherMain", ApplyLauncherMain}, - {"ApplyWorkerMain", ApplyWorkerMain}, - /* Dummy entry marking end of the array. */ - {NULL, NULL} + const char *fn_name; + bgworker_main_type fn_addr; +} InternalBGWorkers[] = + +{ + { + "ParallelWorkerMain", ParallelWorkerMain + }, + { + "ApplyLauncherMain", ApplyLauncherMain + }, + { + "ApplyWorkerMain", ApplyWorkerMain + } }; -static bgworker_main_type GetInternalBgWorkerMain(BackgroundWorker *worker); +/* Private functions. */ +static bgworker_main_type LookupBackgroundWorkerFunction(const char *libraryname, const char *funcname); + /* * Calculate shared memory needed. @@ -812,18 +817,10 @@ StartBackgroundWorker(void) } /* - * For internal workers set the entry point to known function address. - * Otherwise use the entry point specified by library name (which will - * be loaded, if necessary) and a function name (which will be looked up - * in the named library). + * Look up the entry point function, loading its library if necessary. */ - entrypt = GetInternalBgWorkerMain(worker); - - if (entrypt == NULL) - entrypt = (bgworker_main_type) - load_external_function(worker->bgw_library_name, - worker->bgw_function_name, - true, NULL); + entrypt = LookupBackgroundWorkerFunction(worker->bgw_library_name, + worker->bgw_function_name); /* * Note that in normal processes, we would call InitPostgres here. For a @@ -842,10 +839,11 @@ StartBackgroundWorker(void) } /* - * Register a new background worker while processing shared_preload_libraries. + * Register a new static background worker. * - * This can only be called in the _PG_init function of a module library - * that's loaded by shared_preload_libraries; otherwise it has no effect. + * This can only be called directly from postmaster or in the _PG_init + * function of a module library that's loaded by shared_preload_libraries; + * otherwise it will have no effect. */ void RegisterBackgroundWorker(BackgroundWorker *worker) @@ -858,7 +856,7 @@ RegisterBackgroundWorker(BackgroundWorker *worker) (errmsg("registering background worker \"%s\"", worker->bgw_name))); if (!process_shared_preload_libraries_in_progress && - GetInternalBgWorkerMain(worker) == NULL) + strcmp(worker->bgw_library_name, "postgres") != 0) { if (!IsUnderPostmaster) ereport(LOG, @@ -1193,26 +1191,45 @@ TerminateBackgroundWorker(BackgroundWorkerHandle *handle) } /* - * Search the known internal worker array and return its main function - * pointer if found. + * Look up (and possibly load) a bgworker entry point function. + * + * For functions contained in the core code, we use library name "postgres" + * and consult the InternalBGWorkers array. External functions are + * looked up, and loaded if necessary, using load_external_function(). * - * Returns NULL if not known internal worker. + * The point of this is to pass function names as strings across process + * boundaries. We can't pass actual function addresses because of the + * possibility that the function has been loaded at a different address + * in a different process. This is obviously a hazard for functions in + * loadable libraries, but it can happen even for functions in the core code + * on platforms using EXEC_BACKEND (e.g., Windows). + * + * At some point it might be worthwhile to get rid of InternalBGWorkers[] + * in favor of applying load_external_function() for core functions too; + * but that raises portability issues that are not worth addressing now. */ static bgworker_main_type -GetInternalBgWorkerMain(BackgroundWorker *worker) +LookupBackgroundWorkerFunction(const char *libraryname, const char *funcname) { - int i; + /* + * If the function is to be loaded from postgres itself, search the + * InternalBGWorkers array. + */ + if (strcmp(libraryname, "postgres") == 0) + { + int i; - /* Internal workers always have to use postgres as library name. */ - if (strncmp(worker->bgw_library_name, "postgres", BGW_MAXLEN) != 0) - return NULL; + for (i = 0; i < lengthof(InternalBGWorkers); i++) + { + if (strcmp(InternalBGWorkers[i].fn_name, funcname) == 0) + return InternalBGWorkers[i].fn_addr; + } - for (i = 0; InternalBGWorkers[i].bgw_function_name; i++) - { - if (strncmp(InternalBGWorkers[i].bgw_function_name, - worker->bgw_function_name, BGW_MAXLEN) == 0) - return InternalBGWorkers[i].bgw_main; + /* We can only reach this by programming error. */ + elog(ERROR, "internal function \"%s\" not found", funcname); } - return NULL; + /* Otherwise load from external library. */ + return (bgworker_main_type) + load_external_function(libraryname, funcname, true, NULL); } |
