From 4a600d76b7e4ec50d0e91da291da4fc9e00deeaf Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@tigerdata.com>
Date: Tue, 16 Jun 2026 15:54:08 +0300
Subject: [PATCH v1 2/2] jsonb_plperl: Replace reference-unwinding loop with
 recursion

SV_to_JsonbValue() used a while loop to dereference chains of Perl
references before processing the underlying value.  This loop had no
protection against circular reference chains (e.g. $x = \$x), causing
the backend to spin indefinitely.

Replace the loop with a small recursive helper SV_deref() that calls
check_stack_depth() on each step.  This makes circular and pathologically
deep reference chains raise "stack depth limit exceeded" instead of
hanging the backend, consistent with how jsonb_plpython handles circular
Python object references.

Author: Aleksander Alekseev <aleksander@tigerdata.com>
Reviewed-by: TODO FIXME
Discussion: TODO FIXME
---
 contrib/jsonb_plperl/jsonb_plperl.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/contrib/jsonb_plperl/jsonb_plperl.c b/contrib/jsonb_plperl/jsonb_plperl.c
index fdcec7760da..40c283d3132 100644
--- a/contrib/jsonb_plperl/jsonb_plperl.c
+++ b/contrib/jsonb_plperl/jsonb_plperl.c
@@ -176,6 +176,20 @@ HV_to_JsonbValue(HV *obj, JsonbInState *jsonb_state)
 	pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
 }
 
+/*
+ * Recursively dereference a Perl reference to reach the underlying value.
+ * Using recursion rather than a loop lets check_stack_depth() detect
+ * circular reference chains.
+ */
+static SV *
+SV_deref(SV *in)
+{
+	check_stack_depth();
+	if (SvROK(in))
+		return SV_deref(SvRV(in));
+	return in;
+}
+
 static void
 SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem)
 {
@@ -184,9 +198,7 @@ SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem)
 
 	check_stack_depth();
 
-	/* Dereference references recursively. */
-	while (SvROK(in))
-		in = SvRV(in);
+	in = SV_deref(in);
 
 	switch (SvTYPE(in))
 	{
-- 
2.43.0

