public inbox for [email protected]
help / color / mirror / Atom feedBUG #19458: OOM killer in jsonb_path_exists_opr (@?) with malformed JSONPath containing non-existent variables
5+ messages / 4 participants
[nested] [flat]
* BUG #19458: OOM killer in jsonb_path_exists_opr (@?) with malformed JSONPath containing non-existent variables
@ 2026-04-17 11:20 PG Bug reporting form <[email protected]>
0 siblings, 1 reply; 5+ messages in thread
From: PG Bug reporting form @ 2026-04-17 11:20 UTC (permalink / raw)
To: [email protected]; +Cc: [email protected]
The following bug has been logged on the website:
Bug reference: 19458
Logged by: Andrey Rachitskiy
Email address: [email protected]
PostgreSQL version: 14.22
Operating system: Debian GNU/Linux 12 (bookworm)
Description:
Description:
During fuzzing of the jsonb_path_exists_opr (operator jsonb @? jsonpath, a
two-argument version of jsonb_path_exists()), a pathological query was
discovered that causes uncontrolled memory consumption, leading to OOM
Killer on PostgreSQL versions REL_14/15/16_STABLE.
On versions 17 and 18, the same query returns a proper error instead of
crashing the server.
This bug was found using AFL++ as a fuzzer and LibBlobStamper as a tool for
creating syntactically correct arguments.
Reproduction:
Execute the following query:
```sql
select '[3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
13558284848669739, 3472328296227668016, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328295419228208, 3472328296227680304,
3528904766546522246, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296328343600,
3472328296227680304, 3472328296227680299, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3470920921344127024, 3906362710315511856,
3472328296228075062, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472334893297446960, 3472328090069248816,
13511005849006128, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
3472328296227680304, 3472328296227680304, 3472328296227680304,
13563782407139376, 4337019423877509168]'::jsonb @? '(-$?(0 <
($"〰〭〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰" - $?(0 < $"〰〰〰〰〰〰〰〰〰〰〰〰〰〰" - $?(0 + $ <
$"㘰〰㘶〰")."〰〰〰〰")."〰〰〰〰〰〰〰〰") - 0?(+$ < $"〰
〰〰〰")."ほ〰〰㘰")."〰〰〰〶〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰")'::jsonpath;
```
Expected result:
The query should return an error, as happens on versions 17 and 18:
ERROR: could not find jsonpath variable "〰〭〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰"
Actual result (14, 15, 16):
- Memory consumption grows until the kernel kills the postgres process via
OOM Killer
- Client loses connection:
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
Kernel log:
516294.487767] Out of memory: Killed process 1135405 (postgres)
total-vm:13521932kB, anon-rss:9170792kB, file-rss:92kB, shmem-rss:1848kB,
UID:1002 pgtables:26176kB oom_score_adj:0
--
Regards,
Andrey Rachitskiy
Postgres Professional
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: BUG #19458: OOM killer in jsonb_path_exists_opr (@?) with malformed JSONPath containing non-existent variables
@ 2026-04-20 13:38 Andrey Rachitskiy <[email protected]>
parent: PG Bug reporting form <[email protected]>
0 siblings, 1 reply; 5+ messages in thread
From: Andrey Rachitskiy @ 2026-04-20 13:38 UTC (permalink / raw)
To: [email protected]; [email protected]; +Cc: [email protected]
I propose a targeted backpatch for REL_14/15/16 in jsonpath_exec.c to align
missing variable handling with newer branches and prevent pathological
memory growth on malformed/hostile jsonpath expressions.
Why this is not a full backport
This is intentionally not a full backport of the REL_17 jsonpath executor
refactoring (callbacks for variable access, broader executor integration,
etc.).
Why this still fixes the reported issue
On REL_14/15/16, with current behavior (missing vars -> null), some crafted
jsonpath expressions continue deep evaluation and can consume very large
memory, leading to OOM.
With this patch, execution fails early on undefined variable, matching
REL_17 behavior for this case and avoiding runaway memory use.
—
Regards,
Andrey Rachitskiy
Postgres Professional
пт, 17 апр. 2026 г. в 16:21, PG Bug reporting form <[email protected]>:
> The following bug has been logged on the website:
>
> Bug reference: 19458
> Logged by: Andrey Rachitskiy
> Email address: [email protected]
> PostgreSQL version: 14.22
> Operating system: Debian GNU/Linux 12 (bookworm)
> Description:
>
> Description:
> During fuzzing of the jsonb_path_exists_opr (operator jsonb @? jsonpath, a
> two-argument version of jsonb_path_exists()), a pathological query was
> discovered that causes uncontrolled memory consumption, leading to OOM
> Killer on PostgreSQL versions REL_14/15/16_STABLE.
> On versions 17 and 18, the same query returns a proper error instead of
> crashing the server.
> This bug was found using AFL++ as a fuzzer and LibBlobStamper as a tool for
> creating syntactically correct arguments.
>
> Reproduction:
> Execute the following query:
> ```sql
> select '[3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 13558284848669739, 3472328296227668016, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328295419228208, 3472328296227680304,
> 3528904766546522246, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296328343600,
> 3472328296227680304, 3472328296227680299, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3470920921344127024, 3906362710315511856,
> 3472328296228075062, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472334893297446960, 3472328090069248816,
> 13511005849006128, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 3472328296227680304, 3472328296227680304, 3472328296227680304,
> 13563782407139376, 4337019423877509168]'::jsonb @? '(-$?(0 <
> ($"〰〭〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰" - $?(0 < $"〰〰〰〰〰〰〰〰〰〰〰〰〰〰" - $?(0 + $ <
> $"㘰〰㘶〰")."〰〰〰〰")."〰〰〰〰〰〰〰〰") - 0?(+$ < $"〰
>
> 〰〰〰")."ほ〰〰㘰")."〰〰〰〶〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰")'::jsonpath;
> ```
>
> Expected result:
> The query should return an error, as happens on versions 17 and 18:
> ERROR: could not find jsonpath variable "〰〭〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰〰"
>
> Actual result (14, 15, 16):
> - Memory consumption grows until the kernel kills the postgres process
> via
> OOM Killer
> - Client loses connection:
> server closed the connection unexpectedly
> This probably means the server terminated abnormally
> before or while processing the request.
>
> Kernel log:
> 516294.487767] Out of memory: Killed process 1135405 (postgres)
> total-vm:13521932kB, anon-rss:9170792kB, file-rss:92kB, shmem-rss:1848kB,
> UID:1002 pgtables:26176kB oom_score_adj:0
>
> --
> Regards,
> Andrey Rachitskiy
> Postgres Professional
>
>
>
Attachments:
[application/octet-stream] jsonpath-fix-null-comparison.patch (768B, 3-jsonpath-fix-null-comparison.patch)
download | inline diff:
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 10ec66c6293..34420849eac 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -2128,14 +2128,15 @@ getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
JsonbValue tmp;
JsonbValue *v;
- if (!vars)
- {
- value->type = jbvNull;
- return;
- }
-
Assert(variable->type == jpiVariable);
varName = jspGetString(variable, &varNameLength);
+
+ if (!vars)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find jsonpath variable \"%s\"",
+ pnstrdup(varName, varNameLength))));
+
tmp.type = jbvString;
tmp.val.string.val = varName;
tmp.val.string.len = varNameLength;
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: BUG #19458: OOM killer in jsonb_path_exists_opr (@?) with malformed JSONPath containing non-existent variables
@ 2026-04-23 18:55 Andrey Borodin <[email protected]>
parent: Andrey Rachitskiy <[email protected]>
0 siblings, 1 reply; 5+ messages in thread
From: Andrey Borodin @ 2026-04-23 18:55 UTC (permalink / raw)
To: Andrey Rachitskiy <[email protected]>; +Cc: [email protected]; [email protected]
> On 20 Apr 2026, at 18:38, Andrey Rachitskiy <[email protected]> wrote:
>
> I propose a targeted backpatch for REL_14/15/16 in jsonpath_exec.c to align missing variable handling with newer branches and prevent pathological memory growth on malformed/hostile jsonpath expressions.
Hi! Thank you for the report and proposed fix. I've took a look into the
patch.
So we can use vars like this:
# SELECT jsonb_path_exists(
'{"x": 42}'::jsonb,
'$ ? ($"threshold" < 50)'::jsonpath,
'{"threshold": 10}'::jsonb -- HERE go vars
);
Operator @? is doing the same, but without supplied vars. And this thread
essentially points to buggy handling of vars:
# SELECT j @? '$"no_such_var"'
FROM (VALUES
('{"important": "data"}'::jsonb),
('42'::jsonb),
('null'::jsonb),
('false'::jsonb)
) AS t(j);
?column?
----------
t
t
t
t
(4 rows)
It basically says that path with value of var "no_such_var" exists everywhere.
I think it's a bug, but we would need a JSON Path expert here.
17+ throws an error, which seems suspicious to me too. @? is expected to
operate in silent mode. Perhaps, we should just return NULL instead of t.
By using RETURN_ERROR macro. But it might sound overly invasive for back
branches.
Even if we are going to throw an error, we can give mode details. I'd suggest
instead of "could not find jsonpath variable \"%s\"" throwing something like
"no variables supplied to reference by variable \"%s\"" or something along
those lines.
Besides this, the direction of the fix looks good to me. Thank you!
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: BUG #19458: OOM killer in jsonb_path_exists_opr (@?) with malformed JSONPath containing non-existent variables
@ 2026-04-28 20:19 Nikita Malakhov <[email protected]>
parent: Andrey Borodin <[email protected]>
0 siblings, 1 reply; 5+ messages in thread
From: Nikita Malakhov @ 2026-04-28 20:19 UTC (permalink / raw)
To: Andrey Borodin <[email protected]>; Amit Langote <[email protected]>; +Cc: Andrey Rachitskiy <[email protected]>; [email protected]; [email protected]
Hi!
According to the Jsonpath standard, malformed expression should return an
error,
but not all cases of malformation are thoroughly described.
When this functionality was developed (Jsonpath and SQL/JSON) the absence
of the variable was considered as malformation and was decided to throw an
error
in threads long time ago. In case this behavior to be a subject for change
it surely
should not be backported, but the error-throwing code has to.
I agree that sometimes Json (-path) functionality provides very little info
on errors,
and it could be extended.
Changing this behavior is subject for Hackers and should be approved by Tom
Lane,
Adres Freund and other people responsible for including Jsonpath and
SQL/JSON
into Postgres.
On Tue, Apr 28, 2026 at 7:51 PM Andrey Borodin <[email protected]> wrote:
>
>
> > On 20 Apr 2026, at 18:38, Andrey Rachitskiy <[email protected]> wrote:
> >
> > I propose a targeted backpatch for REL_14/15/16 in jsonpath_exec.c to
> align missing variable handling with newer branches and prevent
> pathological memory growth on malformed/hostile jsonpath expressions.
>
> Hi! Thank you for the report and proposed fix. I've took a look into the
> patch.
>
> So we can use vars like this:
>
> # SELECT jsonb_path_exists(
> '{"x": 42}'::jsonb,
> '$ ? ($"threshold" < 50)'::jsonpath,
> '{"threshold": 10}'::jsonb -- HERE go vars
> );
>
> Operator @? is doing the same, but without supplied vars. And this thread
> essentially points to buggy handling of vars:
>
> # SELECT j @? '$"no_such_var"'
> FROM (VALUES
> ('{"important": "data"}'::jsonb),
> ('42'::jsonb),
> ('null'::jsonb),
> ('false'::jsonb)
> ) AS t(j);
> ?column?
> ----------
> t
> t
> t
> t
> (4 rows)
>
> It basically says that path with value of var "no_such_var" exists
> everywhere.
>
> I think it's a bug, but we would need a JSON Path expert here.
>
> 17+ throws an error, which seems suspicious to me too. @? is expected to
> operate in silent mode. Perhaps, we should just return NULL instead of t.
> By using RETURN_ERROR macro. But it might sound overly invasive for back
> branches.
>
> Even if we are going to throw an error, we can give mode details. I'd
> suggest
> instead of "could not find jsonpath variable \"%s\"" throwing something
> like
> "no variables supplied to reference by variable \"%s\"" or something along
> those lines.
>
>
> Besides this, the direction of the fix looks good to me. Thank you!
>
>
> Best regards, Andrey Borodin.
>
>
>
>
--
Regards,
Nikita Malakhov
Postgres Professional
The Russian Postgres Company
https://postgrespro.ru/
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: BUG #19458: OOM killer in jsonb_path_exists_opr (@?) with malformed JSONPath containing non-existent variables
@ 2026-04-30 12:03 Andrey Borodin <[email protected]>
parent: Nikita Malakhov <[email protected]>
0 siblings, 0 replies; 5+ messages in thread
From: Andrey Borodin @ 2026-04-30 12:03 UTC (permalink / raw)
To: Nikita Malakhov <[email protected]>; +Cc: Amit Langote <[email protected]>; Andrey Rachitskiy <[email protected]>; [email protected]; [email protected]
> On 29 Apr 2026, at 01:19, Nikita Malakhov <[email protected]> wrote:
>
> According to the Jsonpath standard, malformed expression should return an error,
> but not all cases of malformation are thoroughly described.
>
> When this functionality was developed (Jsonpath and SQL/JSON) the absence
> of the variable was considered as malformation and was decided to throw an error
> in threads long time ago. In case this behavior to be a subject for change it surely
> should not be backported, but the error-throwing code has to.
I think you just explained very well why we throw an error. Your arguments against
silent mode are valid and we don't need to consider RETURN_ERROR any further.
Current master behavior throws an error, in this thread author propose to backport it.
This might be behavior change for some users. But it seems to me we have to backport,
because
SELECT '42'::jsonb @? '$"no_such_var"';
should not return true. What do you think?
Best regards, Andrey Borodin.
^ permalink raw reply [nested|flat] 5+ messages in thread
end of thread, other threads:[~2026-04-30 12:03 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-04-17 11:20 BUG #19458: OOM killer in jsonb_path_exists_opr (@?) with malformed JSONPath containing non-existent variables PG Bug reporting form <[email protected]>
2026-04-20 13:38 ` Andrey Rachitskiy <[email protected]>
2026-04-23 18:55 ` Andrey Borodin <[email protected]>
2026-04-28 20:19 ` Nikita Malakhov <[email protected]>
2026-04-30 12:03 ` Andrey Borodin <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox