v1-0001-Harden-internal_load_library-against-transient-er.patch
application/octet-stream
Filename: v1-0001-Harden-internal_load_library-against-transient-er.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v1-0001
Subject: Harden internal_load_library() against transient errors
| File | + | − |
|---|---|---|
| src/backend/utils/fmgr/dfmgr.c | 61 | 10 |
From e7b6802367686f72cba7b1a43a07302add963ca6 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Thu, 26 Feb 2026 11:08:17 -0800
Subject: [PATCH v1] Harden internal_load_library() against transient errors
MacOS can fail to find a shared library during rapid crash/restart
cycles, owing to well known filesystem flakiness. When the library
is loaded in response to the postgresql.conf entry
shared_preload_library = 'mylib'
the library name gets expanded to the full path /path/to/mylib.dylib
and that gets stored. Later, the same library can by called using
"$libdir/mylib". The $libdir/ prefix gets stripped in
load_external_function(), resulting in a search for just "mylib".
The call to expand_dynamic_library_name("mylib") tries to find it,
but pg_file_exists() can get a spurious failure from macOS despite
the file existing. In that case, pg_file_exists() fails and
internal_load_libary("mylib") gets called without the full path,
leading to a strcmp for "mylib" to fail, because it doesn't match
"/path/to/mylib.dylib". Then stat("mylib") gets called, which fails
with ENOENT.
Modify internal_load_library() in dfmgr.c to have a fallback when
the matching fails to check whether the library was already loaded
during server startup.
---
src/backend/utils/fmgr/dfmgr.c | 71 +++++++++++++++++++++++++++++-----
1 file changed, 61 insertions(+), 10 deletions(-)
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 1366521f471..ef4a27ac838 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -193,6 +193,7 @@ internal_load_library(const char *libname)
char *load_error;
struct stat stat_buf;
PG_init_t PG_init;
+ int stat_errno = 0;
/*
* Scan the list of loaded FILES to see if the file has been loaded.
@@ -209,16 +210,66 @@ internal_load_library(const char *libname)
* Check for same files - different paths (ie, symlink or link)
*/
if (stat(libname, &stat_buf) == -1)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not access file \"%s\": %m",
- libname)));
-
- for (file_scanner = file_list;
- file_scanner != NULL &&
- !SAME_INODE(stat_buf, *file_scanner);
- file_scanner = file_scanner->next)
- ;
+ {
+ /*
+ * Save errno for later, but don't error out yet. We might still
+ * find this library already loaded under a different path. This
+ * can happen if the library was preloaded with its full path but
+ * we're now trying to load it with a bare name.
+ */
+ stat_errno = errno;
+ }
+
+ if (stat_errno == 0)
+ {
+ for (file_scanner = file_list;
+ file_scanner != NULL &&
+ !SAME_INODE(stat_buf, *file_scanner);
+ file_scanner = file_scanner->next)
+ ;
+ }
+
+ /*
+ * If we couldn't stat() the file, check if any loaded library's
+ * filename ends with the basename we're looking for. This handles
+ * the case where a library was preloaded with its full path but
+ * we're trying to load it again with just the basename.
+ */
+ if (stat_errno != 0 && file_scanner == NULL)
+ {
+ size_t libname_len = strlen(libname);
+
+ for (file_scanner = file_list;
+ file_scanner != NULL;
+ file_scanner = file_scanner->next)
+ {
+ size_t scanner_len = strlen(file_scanner->filename);
+ const char *scanner_base;
+
+ /* Check if the loaded filename ends with our libname */
+ if (scanner_len >= libname_len)
+ {
+ scanner_base = file_scanner->filename + scanner_len - libname_len;
+ if ((scanner_base == file_scanner->filename ||
+ IS_DIR_SEP(scanner_base[-1])) &&
+ strcmp(scanner_base, libname) == 0)
+ {
+ /* Found a match by basename */
+ break;
+ }
+ }
+ }
+
+ /* If still not found, now we can error out */
+ if (file_scanner == NULL)
+ {
+ errno = stat_errno;
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not access file \"%s\": %m",
+ libname)));
+ }
+ }
}
if (file_scanner == NULL)
--
2.39.5 (Apple Git-154)