On 09/02/2026 11:21, Chao Li wrote:
I just noticed a bug in extension_file_exists():``` bool extension_file_exists(const char *extensionName) { bool result = false; List *locations; DIR *dir; struct dirent *de; locations = get_extension_control_directories(); foreach_ptr(char, location, locations) // <== Here type char is wrong { dir = AllocateDir(location); ``` get_extension_control_directories() returns a list of ExtensionLocation, but the loop iterates it as if it contained char *, which is incorrect. As a result, AllocateDir() and ReadDir() are called with the wrong type. This bug is only triggered on an error path, when PostgreSQL is deciding whether to emit a hint. For example: ``` evantest=# create function f() returns int LANGUAGE plpython3u as $$return 1$$; ERROR: language "plpython3u" does not exist ``` No hint is printed. With this patch applied: ``` evantest=# create function f() returns int LANGUAGE plpython3u as $$return 1$$; ERROR: language "plpython3u" does not exist HINT: Use CREATE EXTENSION to load the language into the database. ``` So the hint is shown as intended. Attached is a patch fixing the iteration to use ExtensionLocation and location->loc consistently.
Yep, good catch. This went wrong in commit f3c9e341cd, which changed the type of objects in the list from "char *" to "ExtensionLocation *". So this is master only, stable branches are not affected.
I will push the fix shortly, thanks! - Heikki
