Fix a bug in extension_file_exists()

Started by Chao Liabout 2 months ago4 messageshackers
Jump to latest
#1Chao Li
li.evan.chao@gmail.com

Hi,

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.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Attachments:

v1-0001-Fix-incorrect-iteration-type-in-extension_file_ex.patchapplication/octet-stream; name=v1-0001-Fix-incorrect-iteration-type-in-extension_file_ex.patch; x-unix-mode=0644Download+3-4
#2Heikki Linnakangas
heikki.linnakangas@enterprisedb.com
In reply to: Chao Li (#1)
Re: Fix a bug in extension_file_exists()

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

#3Matheus Alcantara
matheusssilv97@gmail.com
In reply to: Heikki Linnakangas (#2)
Re: Fix a bug in extension_file_exists()

On 09/02/26 07:02, Heikki Linnakangas wrote:

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!

Sorry, I miss this change.

Thanks for the patch Chao and Heikki for committing.

--
Matheus Alcantara
EDB: https://www.enterprisedb.com

#4Chao Li
li.evan.chao@gmail.com
In reply to: Heikki Linnakangas (#2)
Re: Fix a bug in extension_file_exists()

On Feb 9, 2026, at 18:02, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

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

Thanks for pushing.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/