v1-0001-Fix-refint-cascade-UPDATE-crash-with-NULL-keys.patch

application/octet-stream

Filename: v1-0001-Fix-refint-cascade-UPDATE-crash-with-NULL-keys.patch
Type: application/octet-stream
Part: 0
Message: Re: BUG #19476: Segmentation fault in contrib/spi

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: Fix refint cascade UPDATE crash with NULL keys
File+
contrib/spi/refint.c 15 5
From dd97dd1e196aa8dd0a12afb957b046d984ed491e Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Tue, 12 May 2026 17:43:12 +0000
Subject: [PATCH v1 1/2] Fix refint cascade UPDATE crash with NULL keys

check_foreign_key() builds cascade UPDATE queries using the new key
value retrieved by SPI_getvalue().  When that value is NULL,
SPI_getvalue() returns a NULL pointer, which the code then passed to
snprintf("%s").  That is undefined behavior; on most builds it happens
to print "(null)", which SQL then parses as the NULL keyword, but on
builds with _FORTIFY_SOURCE the snprintf formatter crashes when
computing the string length, matching the backtrace in the report.

Emit the SQL NULL keyword directly when SPI_getvalue() returns NULL.

No regression test is added because triggering the crash requires a
hardened libc; without that, the existing code already happens to
produce the correct result via the "(null)" substitution above.

Reported-by: Nikita Kalinin <n.kalinin@postgrespro.ru>
Discussion: https://postgr.es/m/19476-bd04ea6241345303@postgresql.org
---
 contrib/spi/refint.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c
index fbbd558ca1e..0063410f27e 100644
--- a/contrib/spi/refint.c
+++ b/contrib/spi/refint.c
@@ -496,12 +496,22 @@ check_foreign_key(PG_FUNCTION_ARGS)
 #endif
 
 						/*
-						 * is_char_type =1 i set ' ' for define a new value
+						 * is_char_type =1 i set ' ' for define a new value.
+						 *
+						 * SPI_getvalue() returns NULL for SQL NULL values, so
+						 * emit the NULL keyword rather than passing a NULL
+						 * pointer to snprintf("%s"), which is undefined
+						 * behavior.
 						 */
-						snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql),
-								 " %s = %s%s%s %s ",
-								 args2[k], (is_char_type > 0) ? "'" : "",
-								 nv, (is_char_type > 0) ? "'" : "", (k < nkeys) ? ", " : "");
+						if (nv == NULL)
+							snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql),
+									 " %s = NULL %s ",
+									 args2[k], (k < nkeys) ? ", " : "");
+						else
+							snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql),
+									 " %s = %s%s%s %s ",
+									 args2[k], (is_char_type > 0) ? "'" : "",
+									 nv, (is_char_type > 0) ? "'" : "", (k < nkeys) ? ", " : "");
 					}
 					strcat(sql, " where ");
 				}
-- 
2.43.0