LCOV - code coverage report
Current view: top level - src/backend/utils/fmgr - dfmgr.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 67.9 % 277 188
Test Date: 2026-01-26 10:56:24 Functions: 68.8 % 16 11
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 42.8 % 187 80

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * dfmgr.c
       4                 :             :  *        Dynamic function manager code.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/utils/fmgr/dfmgr.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include <sys/stat.h>
      18                 :             : 
      19                 :             : #ifndef WIN32
      20                 :             : #include <dlfcn.h>
      21                 :             : #endif                                                  /* !WIN32 */
      22                 :             : 
      23                 :             : #include "fmgr.h"
      24                 :             : #include "lib/stringinfo.h"
      25                 :             : #include "miscadmin.h"
      26                 :             : #include "storage/fd.h"
      27                 :             : #include "storage/shmem.h"
      28                 :             : #include "utils/hsearch.h"
      29                 :             : 
      30                 :             : 
      31                 :             : /* signature for PostgreSQL-specific library init function */
      32                 :             : typedef void (*PG_init_t) (void);
      33                 :             : 
      34                 :             : /* hashtable entry for rendezvous variables */
      35                 :             : typedef struct
      36                 :             : {
      37                 :             :         char            varName[NAMEDATALEN];   /* hash key (must be first) */
      38                 :             :         void       *varValue;
      39                 :             : } rendezvousHashEntry;
      40                 :             : 
      41                 :             : /*
      42                 :             :  * List of dynamically loaded files (kept in malloc'd memory).
      43                 :             :  *
      44                 :             :  * Note: "typedef struct DynamicFileList DynamicFileList" appears in fmgr.h.
      45                 :             :  */
      46                 :             : struct DynamicFileList
      47                 :             : {
      48                 :             :         DynamicFileList *next;          /* List link */
      49                 :             :         dev_t           device;                 /* Device file is on */
      50                 :             : #ifndef WIN32                                   /* ensures we never again depend on this under
      51                 :             :                                                                  * win32 */
      52                 :             :         ino_t           inode;                  /* Inode number of file */
      53                 :             : #endif
      54                 :             :         void       *handle;                     /* a handle for pg_dl* functions */
      55                 :             :         const Pg_magic_struct *magic;   /* Location of module's magic block */
      56                 :             :         char            filename[FLEXIBLE_ARRAY_MEMBER];        /* Full pathname of file */
      57                 :             : };
      58                 :             : 
      59                 :             : static DynamicFileList *file_list = NULL;
      60                 :             : static DynamicFileList *file_tail = NULL;
      61                 :             : 
      62                 :             : /* stat() call under Win32 returns an st_ino field, but it has no meaning */
      63                 :             : #ifndef WIN32
      64                 :             : #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device)
      65                 :             : #else
      66                 :             : #define SAME_INODE(A,B) false
      67                 :             : #endif
      68                 :             : 
      69                 :             : char       *Dynamic_library_path;
      70                 :             : 
      71                 :             : static void *internal_load_library(const char *libname);
      72                 :             : pg_noreturn static void incompatible_module_error(const char *libname,
      73                 :             :                                                                                                   const Pg_abi_values *module_magic_data);
      74                 :             : static char *expand_dynamic_library_name(const char *name);
      75                 :             : static void check_restricted_library_name(const char *name);
      76                 :             : 
      77                 :             : /* ABI values that module needs to match to be accepted */
      78                 :             : static const Pg_abi_values magic_data = PG_MODULE_ABI_DATA;
      79                 :             : 
      80                 :             : 
      81                 :             : /*
      82                 :             :  * Load the specified dynamic-link library file, and look for a function
      83                 :             :  * named funcname in it.
      84                 :             :  *
      85                 :             :  * If the function is not found, we raise an error if signalNotFound is true,
      86                 :             :  * else return NULL.  Note that errors in loading the library
      87                 :             :  * will provoke ereport() regardless of signalNotFound.
      88                 :             :  *
      89                 :             :  * If filehandle is not NULL, then *filehandle will be set to a handle
      90                 :             :  * identifying the library file.  The filehandle can be used with
      91                 :             :  * lookup_external_function to lookup additional functions in the same file
      92                 :             :  * at less cost than repeating load_external_function.
      93                 :             :  */
      94                 :             : void *
      95                 :         381 : load_external_function(const char *filename, const char *funcname,
      96                 :             :                                            bool signalNotFound, void **filehandle)
      97                 :             : {
      98                 :         381 :         char       *fullname;
      99                 :         381 :         void       *lib_handle;
     100                 :         381 :         void       *retval;
     101                 :             : 
     102                 :             :         /*
     103                 :             :          * For extensions with hardcoded '$libdir/' library names, we strip the
     104                 :             :          * prefix to allow the library search path to be used. This is done only
     105                 :             :          * for simple names (e.g., "$libdir/foo"), not for nested paths (e.g.,
     106                 :             :          * "$libdir/foo/bar").
     107                 :             :          *
     108                 :             :          * For nested paths, 'expand_dynamic_library_name' directly expands the
     109                 :             :          * '$libdir' macro, so we leave them untouched.
     110                 :             :          */
     111         [ +  + ]:         381 :         if (strncmp(filename, "$libdir/", 8) == 0)
     112                 :             :         {
     113         [ -  + ]:         336 :                 if (first_dir_separator(filename + 8) == NULL)
     114                 :         336 :                         filename += 8;
     115                 :         336 :         }
     116                 :             : 
     117                 :             :         /* Expand the possibly-abbreviated filename to an exact path name */
     118                 :         381 :         fullname = expand_dynamic_library_name(filename);
     119                 :             : 
     120                 :             :         /* Load the shared library, unless we already did */
     121                 :         381 :         lib_handle = internal_load_library(fullname);
     122                 :             : 
     123                 :             :         /* Return handle if caller wants it */
     124         [ +  + ]:         381 :         if (filehandle)
     125                 :         380 :                 *filehandle = lib_handle;
     126                 :             : 
     127                 :             :         /* Look up the function within the library. */
     128                 :         381 :         retval = dlsym(lib_handle, funcname);
     129                 :             : 
     130   [ +  +  -  + ]:         381 :         if (retval == NULL && signalNotFound)
     131   [ +  -  +  - ]:           1 :                 ereport(ERROR,
     132                 :             :                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     133                 :             :                                  errmsg("could not find function \"%s\" in file \"%s\"",
     134                 :             :                                                 funcname, fullname)));
     135                 :             : 
     136                 :         380 :         pfree(fullname);
     137                 :         760 :         return retval;
     138                 :         380 : }
     139                 :             : 
     140                 :             : /*
     141                 :             :  * This function loads a shlib file without looking up any particular
     142                 :             :  * function in it.  If the same shlib has previously been loaded,
     143                 :             :  * we do not load it again.
     144                 :             :  *
     145                 :             :  * When 'restricted' is true, only libraries in the presumed-secure
     146                 :             :  * directory $libdir/plugins may be referenced.
     147                 :             :  */
     148                 :             : void
     149                 :          32 : load_file(const char *filename, bool restricted)
     150                 :             : {
     151                 :          32 :         char       *fullname;
     152                 :             : 
     153                 :             :         /* Apply security restriction if requested */
     154         [ +  - ]:          32 :         if (restricted)
     155                 :           0 :                 check_restricted_library_name(filename);
     156                 :             : 
     157                 :             :         /* Expand the possibly-abbreviated filename to an exact path name */
     158                 :          32 :         fullname = expand_dynamic_library_name(filename);
     159                 :             : 
     160                 :             :         /* Load the shared library, unless we already did */
     161                 :          32 :         (void) internal_load_library(fullname);
     162                 :             : 
     163                 :          32 :         pfree(fullname);
     164                 :          32 : }
     165                 :             : 
     166                 :             : /*
     167                 :             :  * Lookup a function whose library file is already loaded.
     168                 :             :  * Return NULL if not found.
     169                 :             :  */
     170                 :             : void *
     171                 :         379 : lookup_external_function(void *filehandle, const char *funcname)
     172                 :             : {
     173                 :         379 :         return dlsym(filehandle, funcname);
     174                 :             : }
     175                 :             : 
     176                 :             : 
     177                 :             : /*
     178                 :             :  * Load the specified dynamic-link library file, unless it already is
     179                 :             :  * loaded.  Return the pg_dl* handle for the file.
     180                 :             :  *
     181                 :             :  * Note: libname is expected to be an exact name for the library file.
     182                 :             :  *
     183                 :             :  * NB: There is presently no way to unload a dynamically loaded file.  We might
     184                 :             :  * add one someday if we can convince ourselves we have safe protocols for un-
     185                 :             :  * hooking from hook function pointers, releasing custom GUC variables, and
     186                 :             :  * perhaps other things that are definitely unsafe currently.
     187                 :             :  */
     188                 :             : static void *
     189                 :        1263 : internal_load_library(const char *libname)
     190                 :             : {
     191                 :        1263 :         DynamicFileList *file_scanner;
     192                 :        1263 :         PGModuleMagicFunction magic_func;
     193                 :        1263 :         char       *load_error;
     194                 :        1263 :         struct stat stat_buf;
     195                 :        1263 :         PG_init_t       PG_init;
     196                 :             : 
     197                 :             :         /*
     198                 :             :          * Scan the list of loaded FILES to see if the file has been loaded.
     199                 :             :          */
     200         [ +  + ]:        4160 :         for (file_scanner = file_list;
     201         [ +  + ]:        2897 :                  file_scanner != NULL &&
     202                 :        2345 :                  strcmp(libname, file_scanner->filename) != 0;
     203                 :        1634 :                  file_scanner = file_scanner->next)
     204                 :             :                 ;
     205                 :             : 
     206         [ +  + ]:        1263 :         if (file_scanner == NULL)
     207                 :             :         {
     208                 :             :                 /*
     209                 :             :                  * Check for same files - different paths (ie, symlink or link)
     210                 :             :                  */
     211         [ +  + ]:         552 :                 if (stat(libname, &stat_buf) == -1)
     212   [ +  -  +  - ]:           1 :                         ereport(ERROR,
     213                 :             :                                         (errcode_for_file_access(),
     214                 :             :                                          errmsg("could not access file \"%s\": %m",
     215                 :             :                                                         libname)));
     216                 :             : 
     217         [ +  + ]:        2030 :                 for (file_scanner = file_list;
     218         [ +  + ]:        1479 :                          file_scanner != NULL &&
     219         [ +  - ]:         928 :                          !SAME_INODE(stat_buf, *file_scanner);
     220                 :         928 :                          file_scanner = file_scanner->next)
     221                 :             :                         ;
     222                 :         551 :         }
     223                 :             : 
     224         [ +  + ]:        1262 :         if (file_scanner == NULL)
     225                 :             :         {
     226                 :             :                 /*
     227                 :             :                  * File not loaded yet.
     228                 :             :                  */
     229                 :         551 :                 file_scanner = (DynamicFileList *)
     230                 :         551 :                         malloc(offsetof(DynamicFileList, filename) + strlen(libname) + 1);
     231         [ +  - ]:         551 :                 if (file_scanner == NULL)
     232   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     233                 :             :                                         (errcode(ERRCODE_OUT_OF_MEMORY),
     234                 :             :                                          errmsg("out of memory")));
     235                 :             : 
     236   [ +  -  +  -  :        3306 :                 MemSet(file_scanner, 0, offsetof(DynamicFileList, filename));
          +  -  -  +  +  
                      + ]
     237                 :         551 :                 strcpy(file_scanner->filename, libname);
     238                 :         551 :                 file_scanner->device = stat_buf.st_dev;
     239                 :             : #ifndef WIN32
     240                 :         551 :                 file_scanner->inode = stat_buf.st_ino;
     241                 :             : #endif
     242                 :         551 :                 file_scanner->next = NULL;
     243                 :             : 
     244                 :         551 :                 file_scanner->handle = dlopen(file_scanner->filename, RTLD_NOW | RTLD_GLOBAL);
     245         [ +  - ]:         551 :                 if (file_scanner->handle == NULL)
     246                 :             :                 {
     247                 :           0 :                         load_error = dlerror();
     248                 :           0 :                         free(file_scanner);
     249                 :             :                         /* errcode_for_file_access might not be appropriate here? */
     250   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     251                 :             :                                         (errcode_for_file_access(),
     252                 :             :                                          errmsg("could not load library \"%s\": %s",
     253                 :             :                                                         libname, load_error)));
     254                 :           0 :                 }
     255                 :             : 
     256                 :             :                 /* Check the magic function to determine compatibility */
     257                 :         551 :                 magic_func = (PGModuleMagicFunction)
     258                 :         551 :                         dlsym(file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING);
     259         [ +  - ]:         551 :                 if (magic_func)
     260                 :             :                 {
     261                 :         551 :                         const Pg_magic_struct *magic_data_ptr = (*magic_func) ();
     262                 :             : 
     263                 :             :                         /* Check ABI compatibility fields */
     264         [ +  - ]:         551 :                         if (magic_data_ptr->len != sizeof(Pg_magic_struct) ||
     265                 :         551 :                                 memcmp(&magic_data_ptr->abi_fields, &magic_data,
     266                 :         551 :                                            sizeof(Pg_abi_values)) != 0)
     267                 :             :                         {
     268                 :             :                                 /* copy data block before unlinking library */
     269                 :           0 :                                 Pg_magic_struct module_magic_data = *magic_data_ptr;
     270                 :             : 
     271                 :             :                                 /* try to close library */
     272                 :           0 :                                 dlclose(file_scanner->handle);
     273                 :           0 :                                 free(file_scanner);
     274                 :             : 
     275                 :             :                                 /* issue suitable complaint */
     276                 :           0 :                                 incompatible_module_error(libname, &module_magic_data.abi_fields);
     277                 :             :                         }
     278                 :             : 
     279                 :             :                         /* Remember the magic block's location for future use */
     280                 :         551 :                         file_scanner->magic = magic_data_ptr;
     281                 :         551 :                 }
     282                 :             :                 else
     283                 :             :                 {
     284                 :             :                         /* try to close library */
     285                 :           0 :                         dlclose(file_scanner->handle);
     286                 :           0 :                         free(file_scanner);
     287                 :             :                         /* complain */
     288   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     289                 :             :                                         (errmsg("incompatible library \"%s\": missing magic block",
     290                 :             :                                                         libname),
     291                 :             :                                          errhint("Extension libraries are required to use the PG_MODULE_MAGIC macro.")));
     292                 :             :                 }
     293                 :             : 
     294                 :             :                 /*
     295                 :             :                  * If the library has a _PG_init() function, call it.
     296                 :             :                  */
     297                 :         551 :                 PG_init = (PG_init_t) dlsym(file_scanner->handle, "_PG_init");
     298         [ +  + ]:         551 :                 if (PG_init)
     299                 :         488 :                         (*PG_init) ();
     300                 :             : 
     301                 :             :                 /* OK to link it into list */
     302         [ +  + ]:         551 :                 if (file_list == NULL)
     303                 :          14 :                         file_list = file_scanner;
     304                 :             :                 else
     305                 :         537 :                         file_tail->next = file_scanner;
     306                 :         551 :                 file_tail = file_scanner;
     307                 :         551 :         }
     308                 :             : 
     309                 :        2524 :         return file_scanner->handle;
     310                 :        1262 : }
     311                 :             : 
     312                 :             : /*
     313                 :             :  * Report a suitable error for an incompatible magic block.
     314                 :             :  */
     315                 :             : static void
     316                 :           0 : incompatible_module_error(const char *libname,
     317                 :             :                                                   const Pg_abi_values *module_magic_data)
     318                 :             : {
     319                 :           0 :         StringInfoData details;
     320                 :             : 
     321                 :             :         /*
     322                 :             :          * If the version doesn't match, just report that, because the rest of the
     323                 :             :          * block might not even have the fields we expect.
     324                 :             :          */
     325         [ #  # ]:           0 :         if (magic_data.version != module_magic_data->version)
     326                 :             :         {
     327                 :           0 :                 char            library_version[32];
     328                 :             : 
     329         [ #  # ]:           0 :                 if (module_magic_data->version >= 1000)
     330                 :           0 :                         snprintf(library_version, sizeof(library_version), "%d",
     331                 :           0 :                                          module_magic_data->version / 100);
     332                 :             :                 else
     333                 :           0 :                         snprintf(library_version, sizeof(library_version), "%d.%d",
     334                 :           0 :                                          module_magic_data->version / 100,
     335                 :           0 :                                          module_magic_data->version % 100);
     336   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     337                 :             :                                 (errmsg("incompatible library \"%s\": version mismatch",
     338                 :             :                                                 libname),
     339                 :             :                                  errdetail("Server is version %d, library is version %s.",
     340                 :             :                                                    magic_data.version / 100, library_version)));
     341                 :           0 :         }
     342                 :             : 
     343                 :             :         /*
     344                 :             :          * Similarly, if the ABI extra field doesn't match, error out.  Other
     345                 :             :          * fields below might also mismatch, but that isn't useful information if
     346                 :             :          * you're using the wrong product altogether.
     347                 :             :          */
     348         [ #  # ]:           0 :         if (strcmp(module_magic_data->abi_extra, magic_data.abi_extra) != 0)
     349                 :             :         {
     350   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     351                 :             :                                 (errmsg("incompatible library \"%s\": ABI mismatch",
     352                 :             :                                                 libname),
     353                 :             :                                  errdetail("Server has ABI \"%s\", library has \"%s\".",
     354                 :             :                                                    magic_data.abi_extra,
     355                 :             :                                                    module_magic_data->abi_extra)));
     356                 :           0 :         }
     357                 :             : 
     358                 :             :         /*
     359                 :             :          * Otherwise, spell out which fields don't agree.
     360                 :             :          *
     361                 :             :          * XXX this code has to be adjusted any time the set of fields in a magic
     362                 :             :          * block change!
     363                 :             :          */
     364                 :           0 :         initStringInfo(&details);
     365                 :             : 
     366         [ #  # ]:           0 :         if (module_magic_data->funcmaxargs != magic_data.funcmaxargs)
     367                 :             :         {
     368         [ #  # ]:           0 :                 if (details.len)
     369                 :           0 :                         appendStringInfoChar(&details, '\n');
     370                 :           0 :                 appendStringInfo(&details,
     371                 :             :                 /* translator: %s is a variable name and %d its values */
     372                 :           0 :                                                  _("Server has %s = %d, library has %d."),
     373                 :             :                                                  "FUNC_MAX_ARGS", magic_data.funcmaxargs,
     374                 :           0 :                                                  module_magic_data->funcmaxargs);
     375                 :           0 :         }
     376         [ #  # ]:           0 :         if (module_magic_data->indexmaxkeys != magic_data.indexmaxkeys)
     377                 :             :         {
     378         [ #  # ]:           0 :                 if (details.len)
     379                 :           0 :                         appendStringInfoChar(&details, '\n');
     380                 :           0 :                 appendStringInfo(&details,
     381                 :             :                 /* translator: %s is a variable name and %d its values */
     382                 :           0 :                                                  _("Server has %s = %d, library has %d."),
     383                 :             :                                                  "INDEX_MAX_KEYS", magic_data.indexmaxkeys,
     384                 :           0 :                                                  module_magic_data->indexmaxkeys);
     385                 :           0 :         }
     386         [ #  # ]:           0 :         if (module_magic_data->namedatalen != magic_data.namedatalen)
     387                 :             :         {
     388         [ #  # ]:           0 :                 if (details.len)
     389                 :           0 :                         appendStringInfoChar(&details, '\n');
     390                 :           0 :                 appendStringInfo(&details,
     391                 :             :                 /* translator: %s is a variable name and %d its values */
     392                 :           0 :                                                  _("Server has %s = %d, library has %d."),
     393                 :             :                                                  "NAMEDATALEN", magic_data.namedatalen,
     394                 :           0 :                                                  module_magic_data->namedatalen);
     395                 :           0 :         }
     396         [ #  # ]:           0 :         if (module_magic_data->float8byval != magic_data.float8byval)
     397                 :             :         {
     398         [ #  # ]:           0 :                 if (details.len)
     399                 :           0 :                         appendStringInfoChar(&details, '\n');
     400                 :           0 :                 appendStringInfo(&details,
     401                 :             :                 /* translator: %s is a variable name and %d its values */
     402                 :           0 :                                                  _("Server has %s = %s, library has %s."),
     403                 :             :                                                  "FLOAT8PASSBYVAL", magic_data.float8byval ? "true" : "false",
     404                 :           0 :                                                  module_magic_data->float8byval ? "true" : "false");
     405                 :           0 :         }
     406                 :             : 
     407         [ #  # ]:           0 :         if (details.len == 0)
     408                 :           0 :                 appendStringInfoString(&details,
     409                 :           0 :                                                            _("Magic block has unexpected length or padding difference."));
     410                 :             : 
     411   [ #  #  #  # ]:           0 :         ereport(ERROR,
     412                 :             :                         (errmsg("incompatible library \"%s\": magic block mismatch",
     413                 :             :                                         libname),
     414                 :             :                          errdetail_internal("%s", details.data)));
     415                 :           0 : }
     416                 :             : 
     417                 :             : 
     418                 :             : /*
     419                 :             :  * Iterator functions to allow callers to scan the list of loaded modules.
     420                 :             :  *
     421                 :             :  * Note: currently, there is no special provision for dealing with changes
     422                 :             :  * in the list while a scan is happening.  Current callers don't need it.
     423                 :             :  */
     424                 :             : DynamicFileList *
     425                 :           0 : get_first_loaded_module(void)
     426                 :             : {
     427                 :           0 :         return file_list;
     428                 :             : }
     429                 :             : 
     430                 :             : DynamicFileList *
     431                 :           0 : get_next_loaded_module(DynamicFileList *dfptr)
     432                 :             : {
     433                 :           0 :         return dfptr->next;
     434                 :             : }
     435                 :             : 
     436                 :             : /*
     437                 :             :  * Return some details about the specified module.
     438                 :             :  *
     439                 :             :  * Note that module_name and module_version could be returned as NULL.
     440                 :             :  *
     441                 :             :  * We could dispense with this function by exposing struct DynamicFileList
     442                 :             :  * globally, but this way seems preferable.
     443                 :             :  */
     444                 :             : void
     445                 :           0 : get_loaded_module_details(DynamicFileList *dfptr,
     446                 :             :                                                   const char **library_path,
     447                 :             :                                                   const char **module_name,
     448                 :             :                                                   const char **module_version)
     449                 :             : {
     450                 :           0 :         *library_path = dfptr->filename;
     451                 :           0 :         *module_name = dfptr->magic->name;
     452                 :           0 :         *module_version = dfptr->magic->version;
     453                 :           0 : }
     454                 :             : 
     455                 :             : 
     456                 :             : /*
     457                 :             :  * If name contains a slash, check if the file exists, if so return
     458                 :             :  * the name.  Else (no slash) try to expand using search path (see
     459                 :             :  * find_in_path below); if that works, return the fully
     460                 :             :  * expanded file name.  If the previous failed, append DLSUFFIX and
     461                 :             :  * try again.  If all fails, just return the original name.
     462                 :             :  *
     463                 :             :  * The result will always be freshly palloc'd.
     464                 :             :  */
     465                 :             : static char *
     466                 :         413 : expand_dynamic_library_name(const char *name)
     467                 :             : {
     468                 :         413 :         bool            have_slash;
     469                 :         413 :         char       *new;
     470                 :         413 :         char       *full;
     471                 :             : 
     472         [ +  - ]:         413 :         Assert(name);
     473                 :             : 
     474                 :         413 :         have_slash = (first_dir_separator(name) != NULL);
     475                 :             : 
     476         [ +  + ]:         413 :         if (!have_slash)
     477                 :             :         {
     478                 :         368 :                 full = find_in_path(name, Dynamic_library_path, "dynamic_library_path", "$libdir", pkglib_path);
     479         [ -  + ]:         368 :                 if (full)
     480                 :           0 :                         return full;
     481                 :         368 :         }
     482                 :             :         else
     483                 :             :         {
     484                 :          45 :                 full = substitute_path_macro(name, "$libdir", pkglib_path);
     485         [ +  - ]:          45 :                 if (pg_file_exists(full))
     486                 :          45 :                         return full;
     487                 :           0 :                 pfree(full);
     488                 :             :         }
     489                 :             : 
     490                 :         368 :         new = psprintf("%s%s", name, DLSUFFIX);
     491                 :             : 
     492         [ -  + ]:         368 :         if (!have_slash)
     493                 :             :         {
     494                 :         368 :                 full = find_in_path(new, Dynamic_library_path, "dynamic_library_path", "$libdir", pkglib_path);
     495                 :         368 :                 pfree(new);
     496         [ +  + ]:         368 :                 if (full)
     497                 :         367 :                         return full;
     498                 :           1 :         }
     499                 :             :         else
     500                 :             :         {
     501                 :           0 :                 full = substitute_path_macro(new, "$libdir", pkglib_path);
     502                 :           0 :                 pfree(new);
     503         [ #  # ]:           0 :                 if (pg_file_exists(full))
     504                 :           0 :                         return full;
     505                 :           0 :                 pfree(full);
     506                 :             :         }
     507                 :             : 
     508                 :             :         /*
     509                 :             :          * If we can't find the file, just return the string as-is. The ensuing
     510                 :             :          * load attempt will fail and report a suitable message.
     511                 :             :          */
     512                 :           1 :         return pstrdup(name);
     513                 :         413 : }
     514                 :             : 
     515                 :             : /*
     516                 :             :  * Check a restricted library name.  It must begin with "$libdir/plugins/"
     517                 :             :  * and there must not be any directory separators after that (this is
     518                 :             :  * sufficient to prevent ".." style attacks).
     519                 :             :  */
     520                 :             : static void
     521                 :           0 : check_restricted_library_name(const char *name)
     522                 :             : {
     523         [ #  # ]:           0 :         if (strncmp(name, "$libdir/plugins/", 16) != 0 ||
     524                 :           0 :                 first_dir_separator(name + 16) != NULL)
     525   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     526                 :             :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     527                 :             :                                  errmsg("access to library \"%s\" is not allowed",
     528                 :             :                                                 name)));
     529                 :           0 : }
     530                 :             : 
     531                 :             : /*
     532                 :             :  * Substitute for any macros appearing in the given string.
     533                 :             :  * Result is always freshly palloc'd.
     534                 :             :  */
     535                 :             : char *
     536                 :         786 : substitute_path_macro(const char *str, const char *macro, const char *value)
     537                 :             : {
     538                 :         786 :         const char *sep_ptr;
     539                 :             : 
     540         [ +  - ]:         786 :         Assert(str != NULL);
     541         [ +  - ]:         786 :         Assert(macro[0] == '$');
     542                 :             : 
     543                 :             :         /* Currently, we only recognize $macro at the start of the string */
     544         [ +  + ]:         786 :         if (str[0] != '$')
     545                 :          45 :                 return pstrdup(str);
     546                 :             : 
     547         [ -  + ]:         741 :         if ((sep_ptr = first_dir_separator(str)) == NULL)
     548                 :         741 :                 sep_ptr = str + strlen(str);
     549                 :             : 
     550         [ +  - ]:         741 :         if (strlen(macro) != sep_ptr - str ||
     551                 :         741 :                 strncmp(str, macro, strlen(macro)) != 0)
     552   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     553                 :             :                                 (errcode(ERRCODE_INVALID_NAME),
     554                 :             :                                  errmsg("invalid macro name in path: %s",
     555                 :             :                                                 str)));
     556                 :             : 
     557                 :         741 :         return psprintf("%s%s", value, sep_ptr);
     558                 :         786 : }
     559                 :             : 
     560                 :             : 
     561                 :             : /*
     562                 :             :  * Search for a file called 'basename' in the colon-separated search
     563                 :             :  * path given.  If the file is found, the full file name
     564                 :             :  * is returned in freshly palloc'd memory.  If the file is not found,
     565                 :             :  * return NULL.
     566                 :             :  *
     567                 :             :  * path_param is the name of the parameter that path came from, for error
     568                 :             :  * messages.
     569                 :             :  *
     570                 :             :  * macro and macro_val allow substituting a macro; see
     571                 :             :  * substitute_path_macro().
     572                 :             :  */
     573                 :             : char *
     574                 :         736 : find_in_path(const char *basename, const char *path, const char *path_param,
     575                 :             :                          const char *macro, const char *macro_val)
     576                 :             : {
     577                 :         736 :         const char *p;
     578                 :         736 :         size_t          baselen;
     579                 :             : 
     580         [ +  - ]:         736 :         Assert(basename != NULL);
     581         [ +  - ]:         736 :         Assert(first_dir_separator(basename) == NULL);
     582         [ +  - ]:         736 :         Assert(path != NULL);
     583         [ +  - ]:         736 :         Assert(path_param != NULL);
     584                 :             : 
     585                 :         736 :         p = path;
     586                 :             : 
     587                 :             :         /*
     588                 :             :          * If the path variable is empty, don't do a path search.
     589                 :             :          */
     590         [ +  - ]:         736 :         if (strlen(p) == 0)
     591                 :           0 :                 return NULL;
     592                 :             : 
     593                 :         736 :         baselen = strlen(basename);
     594                 :             : 
     595                 :         736 :         for (;;)
     596                 :             :         {
     597                 :         736 :                 size_t          len;
     598                 :         736 :                 char       *piece;
     599                 :         736 :                 char       *mangled;
     600                 :         736 :                 char       *full;
     601                 :             : 
     602                 :         736 :                 piece = first_path_var_separator(p);
     603         [ +  - ]:         736 :                 if (piece == p)
     604   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     605                 :             :                                         (errcode(ERRCODE_INVALID_NAME),
     606                 :             :                                          errmsg("zero-length component in parameter \"%s\"", path_param)));
     607                 :             : 
     608         [ -  + ]:         736 :                 if (piece == NULL)
     609                 :         736 :                         len = strlen(p);
     610                 :             :                 else
     611                 :           0 :                         len = piece - p;
     612                 :             : 
     613                 :         736 :                 piece = palloc(len + 1);
     614                 :         736 :                 strlcpy(piece, p, len + 1);
     615                 :             : 
     616                 :         736 :                 mangled = substitute_path_macro(piece, macro, macro_val);
     617                 :         736 :                 pfree(piece);
     618                 :             : 
     619                 :         736 :                 canonicalize_path(mangled);
     620                 :             : 
     621                 :             :                 /* only absolute paths */
     622         [ +  - ]:         736 :                 if (!is_absolute_path(mangled))
     623   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     624                 :             :                                         (errcode(ERRCODE_INVALID_NAME),
     625                 :             :                                          errmsg("component in parameter \"%s\" is not an absolute path", path_param)));
     626                 :             : 
     627                 :         736 :                 full = palloc(strlen(mangled) + 1 + baselen + 1);
     628                 :         736 :                 sprintf(full, "%s/%s", mangled, basename);
     629                 :         736 :                 pfree(mangled);
     630                 :             : 
     631   [ -  +  -  + ]:         736 :                 elog(DEBUG3, "%s: trying \"%s\"", __func__, full);
     632                 :             : 
     633         [ +  + ]:         736 :                 if (pg_file_exists(full))
     634                 :         367 :                         return full;
     635                 :             : 
     636                 :         369 :                 pfree(full);
     637                 :             : 
     638         [ -  + ]:         369 :                 if (p[len] == '\0')
     639                 :         369 :                         break;
     640                 :             :                 else
     641                 :           0 :                         p += len + 1;
     642      [ +  +  - ]:         736 :         }
     643                 :             : 
     644                 :         369 :         return NULL;
     645                 :         736 : }
     646                 :             : 
     647                 :             : 
     648                 :             : /*
     649                 :             :  * Find (or create) a rendezvous variable that one dynamically
     650                 :             :  * loaded library can use to meet up with another.
     651                 :             :  *
     652                 :             :  * On the first call of this function for a particular varName,
     653                 :             :  * a "rendezvous variable" is created with the given name.
     654                 :             :  * The value of the variable is a void pointer (initially set to NULL).
     655                 :             :  * Subsequent calls with the same varName just return the address of
     656                 :             :  * the existing variable.  Once created, a rendezvous variable lasts
     657                 :             :  * for the life of the process.
     658                 :             :  *
     659                 :             :  * Dynamically loaded libraries can use rendezvous variables
     660                 :             :  * to find each other and share information: they just need to agree
     661                 :             :  * on the variable name and the data it will point to.
     662                 :             :  */
     663                 :             : void      **
     664                 :         472 : find_rendezvous_variable(const char *varName)
     665                 :             : {
     666                 :             :         static HTAB *rendezvousHash = NULL;
     667                 :             : 
     668                 :         472 :         rendezvousHashEntry *hentry;
     669                 :         472 :         bool            found;
     670                 :             : 
     671                 :             :         /* Create a hashtable if we haven't already done so in this process */
     672         [ -  + ]:         472 :         if (rendezvousHash == NULL)
     673                 :             :         {
     674                 :         472 :                 HASHCTL         ctl;
     675                 :             : 
     676                 :         472 :                 ctl.keysize = NAMEDATALEN;
     677                 :         472 :                 ctl.entrysize = sizeof(rendezvousHashEntry);
     678                 :         472 :                 rendezvousHash = hash_create("Rendezvous variable hash",
     679                 :             :                                                                          16,
     680                 :             :                                                                          &ctl,
     681                 :             :                                                                          HASH_ELEM | HASH_STRINGS);
     682                 :         472 :         }
     683                 :             : 
     684                 :             :         /* Find or create the hashtable entry for this varName */
     685                 :         944 :         hentry = (rendezvousHashEntry *) hash_search(rendezvousHash,
     686                 :         472 :                                                                                                  varName,
     687                 :             :                                                                                                  HASH_ENTER,
     688                 :             :                                                                                                  &found);
     689                 :             : 
     690                 :             :         /* Initialize to NULL if first time */
     691         [ -  + ]:         472 :         if (!found)
     692                 :         472 :                 hentry->varValue = NULL;
     693                 :             : 
     694                 :         944 :         return &hentry->varValue;
     695                 :         472 : }
     696                 :             : 
     697                 :             : /*
     698                 :             :  * Estimate the amount of space needed to serialize the list of libraries
     699                 :             :  * we have loaded.
     700                 :             :  */
     701                 :             : Size
     702                 :         155 : EstimateLibraryStateSpace(void)
     703                 :             : {
     704                 :         155 :         DynamicFileList *file_scanner;
     705                 :         155 :         Size            size = 1;
     706                 :             : 
     707         [ +  + ]:         421 :         for (file_scanner = file_list;
     708                 :         421 :                  file_scanner != NULL;
     709                 :         266 :                  file_scanner = file_scanner->next)
     710                 :         266 :                 size = add_size(size, strlen(file_scanner->filename) + 1);
     711                 :             : 
     712                 :         310 :         return size;
     713                 :         155 : }
     714                 :             : 
     715                 :             : /*
     716                 :             :  * Serialize the list of libraries we have loaded to a chunk of memory.
     717                 :             :  */
     718                 :             : void
     719                 :         155 : SerializeLibraryState(Size maxsize, char *start_address)
     720                 :             : {
     721                 :         155 :         DynamicFileList *file_scanner;
     722                 :             : 
     723         [ +  + ]:         421 :         for (file_scanner = file_list;
     724                 :         421 :                  file_scanner != NULL;
     725                 :         266 :                  file_scanner = file_scanner->next)
     726                 :             :         {
     727                 :         266 :                 Size            len;
     728                 :             : 
     729                 :         266 :                 len = strlcpy(start_address, file_scanner->filename, maxsize) + 1;
     730         [ +  - ]:         266 :                 Assert(len < maxsize);
     731                 :         266 :                 maxsize -= len;
     732                 :         266 :                 start_address += len;
     733                 :         266 :         }
     734                 :         155 :         start_address[0] = '\0';
     735                 :         155 : }
     736                 :             : 
     737                 :             : /*
     738                 :             :  * Load every library the serializing backend had loaded.
     739                 :             :  */
     740                 :             : void
     741                 :         477 : RestoreLibraryState(char *start_address)
     742                 :             : {
     743         [ +  + ]:        1327 :         while (*start_address != '\0')
     744                 :             :         {
     745                 :         850 :                 internal_load_library(start_address);
     746                 :         850 :                 start_address += strlen(start_address) + 1;
     747                 :             :         }
     748                 :         477 : }
        

Generated by: LCOV version 2.3.2-1