Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w3H2F-0014ET-2N for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Mar 2026 17:19:51 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w3H2D-001Qoj-2h for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Mar 2026 17:19:50 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w3H2D-001QoD-1P for pgsql-hackers@lists.postgresql.org; Thu, 19 Mar 2026 17:19:49 +0000 Received: from mail-ej1-x632.google.com ([2a00:1450:4864:20::632]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w3H2C-000000002Av-0PPL for pgsql-hackers@lists.postgresql.org; Thu, 19 Mar 2026 17:19:48 +0000 Received: by mail-ej1-x632.google.com with SMTP id a640c23a62f3a-b98069e41b0so202418366b.1 for ; Thu, 19 Mar 2026 10:19:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1773940787; cv=none; d=google.com; s=arc-20240605; b=kjo5G4NqDT1klPNGKOjCuijGZa3yZ9cdaFQr7X8LZ4G+FY9O+2TknBS2K6eLfLpiUz HUKzW3ucZqE8MbllJjyYnsVuD4Gi4TKFjCW9r6uwVah++6dWtGr5QfX2fcmBulPhA/NG IBqSGyPo9j5QN2wEOFiynFRaZV4jVdcYqUkP2sjXDBv4u/QY1qi4hAGRk9ilrGmt0z99 6PpjU6GwRUkLqqJw8qWLpn7T17+gKkHNLsg5K0JStPNTPcj8R0HgbtM9ZRxLsFt05DOs 5YRxnIlOZI5yCU5gD/fI+d0Wu/TZ0x38bgKBVcASdtXktrsrD04dLLhZAq/KaNQJXI7d XCKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=SZPK+RlatPLZxJo7As6iNw9Z5BNk9+Xs9mlIQVHn1to=; fh=vmkx8SKDdth5ZOzSdK1j5Xj+EMWosfLlVGvDtAvQRcQ=; b=lvi1qth7A+t0fIjmtlcovcQNBkQ6RvN0Yhroff52lbPaOKxklsFsA4oRteE25odkAm Skoeg150FG8kYYXYGJcSIda1MQNjFoabXwwoQ/e/Gu2gMjQx6b8vajL1VQ75d1lxtxIB cgjYSvY+gkT/Ea+hSNUtDSpPOHp+4Lvd+okDvgAWqune9XRhf8tJF0PUAYCXE3vqFssi 1m2hIarqGUw2FXeWR7fUgm5ic0benevlaZeqGaZck8O6SIXz+7S7LnFEPNkowaa5m3Zx YU2bWbMr4FRku1AMiXuRFYH6Zuaj3K2zd97prmbFDCXKboVljaYg6GwvCsNpDrlEMRRD lVjA==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773940787; x=1774545587; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=SZPK+RlatPLZxJo7As6iNw9Z5BNk9+Xs9mlIQVHn1to=; b=KCC5X0+phJtPEvQ+U5WWwlPnOX8Lt9Uu53b6gLr2M/yQsi/GBSXBtirV1xAexqD9ey SkczYH99Q9TIcdngbTet7ze0S4vnyjFsZ3RQ/AVdDs3Ds+rvbMrJs623EC7dPMy99n/Y zed9Ul1jCMU6eTU1ofI/scxm2DzleIBjUPKWAWmf0NC+zs+xHSl9FlVK/sC6eLix6X2u ETeJcU57WYRHDs3q/8JcPQ4DSzOBkQnhJPX3woAApFsCZfPI5I1K4qL+bE2rI4UgdTuY 0Go2KWqyGBYMk3RB2N86PiKiYispDIDGgZqCpkp5tWPq1JCCVxArirp0tZjGsIcqqCdo Jzsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773940787; x=1774545587; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=SZPK+RlatPLZxJo7As6iNw9Z5BNk9+Xs9mlIQVHn1to=; b=ch8mAy06YtMKHpFLoQdEm94twi/s0p2y6IuNG76j6kh2Fm1DwWBA+zeLt3NicyncKO Ifq67nPgO3snCQArzSXAZAEerbuWgsqa6fHTuFhryZkwd1cPxgJF9ItR7vtdIJbbYxSm lEo7N1xx/3TtAVRgFY9351iEx8luLR+TW2RVYZm8FG4NWGeTUV6Cd285ej3hgZBvfjkr q3GhpqW0TquP6XtUT0P7UH88vUBFcIM27A/vUFVRrnMBvzpN1NDhUnKBRDU2+by7lcqA sSvgkCzlPFeE9Xe9S0Jcs9Dcx9i0z2uEplIrRlRReASmTigsW2ibN5FFa+QPVtTitDv/ WgCQ== X-Gm-Message-State: AOJu0YzxncoWAQxJvFdNzetvSSFkd4H9V+OytQcf9Q9TYNC/rYXTu9S9 E9nT9+xKXrZevfeG0nERKzG9Nwi1Mpv58O77fLjCUaet6u7w5qWdC3vapn2ARneP81IdpLHNb1h Ptn5jWwTAQZzfv9NSigS1yhpeBJHHlkj7tkkV9kc= X-Gm-Gg: ATEYQzy4vLbwY0wyS8x9xTNyJDRbiex485SHolorWOOyJrawF03RLHgVOZbl93CwSL6 aiNfb1nEAmOa70gPGfsvKail7iNbFSVxGc29Mkwb6ZQ2cPeYsF+zH139d4lBKtrv+wOsj1pTqaL +ZdSbbv7aF+tQnE657E+arxcEBhR/0BxR2rHaacUyNflGwlxUMYLrw2zEXe4scjACKqMjX3VIZT 7cWqvR5FmjMAPWcV944/E7JUbVstfVXrhyC/musvMAF5Vv6b1bcRUbQ5B+2Dx91xxFIgdxnqY6d f+kdVMzNfhSeAPDyhlBh2LAMBgeSOghKwfnek290 X-Received: by 2002:a17:907:9625:b0:b97:b149:4e72 with SMTP id a640c23a62f3a-b980fac0a12mr299860966b.28.1773940786430; Thu, 19 Mar 2026 10:19:46 -0700 (PDT) MIME-Version: 1.0 References: <62bbe34d-2315-4b42-b768-56d901aa83e1@gmail.com> <1302471.1773940095@sss.pgh.pa.us> In-Reply-To: <1302471.1773940095@sss.pgh.pa.us> From: Jianghua Yang Date: Thu, 19 Mar 2026 10:19:10 -0700 X-Gm-Features: AaiRm52cZCFqh9Gc40Zkem4FFjWZciGFUskVJDonK0QD1eHJLOy9W8SN3-TYFMI Message-ID: Subject: Re: [PATCH] Fix fd leak in pg_dump compression backends when dup()+fdopen() fails To: Tom Lane Cc: pgsql-hackers@lists.postgresql.org Content-Type: multipart/alternative; boundary="0000000000006d85aa064d63c6a3" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000006d85aa064d63c6a3 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable You're correct. All callers invoke pg_fatal() on failure, so the process exits immediately and the OS reclaims the fd. There is no live bug worth back-patching on those grounds. That said, the patch does fix a real diagnostic problem. In the original code, when dup() fails with EMFILE, the -1 return value is passed directly to fdopen(), which fails with EBADF. The user sees: pg_dump: error: could not open output file: Bad file descriptor which is misleading -- the actual cause is fd exhaustion, not a bad descriptor. With the patch, errno is preserved correctly, so the message becomes: pg_dump: error: could not open output file: Too many open files which gives the user actionable information. I'm happy to limit this to HEAD only if back-patching is not warranted. Regards, Jianghua Yang Tom Lane =E4=BA=8E2026=E5=B9=B43=E6=9C=8819=E6=97=A5=E5= =91=A8=E5=9B=9B 10:08=E5=86=99=E9=81=93=EF=BC=9A > Jianghua Yang writes: > > =3D=3D The Bug =3D=3D > > > All four compression open functions use this pattern when an existin= g > > file descriptor is passed in: > > > if (fd >=3D 0) > > fp =3D fdopen(dup(fd), mode); /* or gzdopen() */ > > > if (fp =3D=3D NULL) > > return false; /* dup'd fd is leaked here */ > > > The problem is that dup(fd) and fdopen()/gzdopen() are two separate > > steps, and their failure modes must be handled independently: > > Hmm. You're right that we could leak the dup'd FD, but would it matter? > I'm pretty sure all these programs will just exit immediately on > failure. > > I'm not averse to improving the code, but I'm not sure there is > a live bug worth back-patching. > > regards, tom lane > --0000000000006d85aa064d63c6a3 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
You're correct.=C2=A0 All callers invoke pg_fatal() on= failure, so the
=C2=A0 process exits immediately and the OS reclaims th= e fd.=C2=A0 There is no
=C2=A0 live bug worth back-patching on those gro= unds.

=C2=A0 That said, the patch does fix a real diagnostic problem= .=C2=A0 In the
=C2=A0 original code, when dup() fails with EMFILE, the -= 1 return value is
=C2=A0 passed directly to fdopen(), which fails with E= BADF.=C2=A0 The user sees:

=C2=A0 =C2=A0 pg_dump: error: could not o= pen output file: Bad file descriptor

=C2=A0 which is misleading -- t= he actual cause is fd exhaustion, not a bad
=C2=A0 descriptor.=C2=A0 Wit= h the patch, errno is preserved correctly, so the
=C2=A0 message becomes= :

=C2=A0 =C2=A0 pg_dump: error: could not open output file: Too many= open files

=C2=A0 which gives the user actionable information.
<= br>=C2=A0 I'm happy to limit this to HEAD only if back-patching is not<= br>=C2=A0 warranted.

=C2=A0 Regards,
=C2=A0 Jianghua Yang
Tom Lane <tgl@sss.p= gh.pa.us> =E4=BA=8E2026=E5=B9=B43=E6=9C=8819=E6=97=A5=E5=91=A8=E5=9B= =9B 10:08=E5=86=99=E9=81=93=EF=BC=9A
Jianghua Yang <yjhjstz@gmail.com> writes:
>=C2=A0 =C2=A0 =3D=3D The Bug =3D=3D

>=C2=A0 =C2=A0 All four compression open functions use this pattern when= an existing
>=C2=A0 =C2=A0 file descriptor is passed in:

>=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (fd >=3D 0)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 fp =3D fdopen(dup(fd), mode);= =C2=A0 =C2=A0/* or gzdopen() */

>=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (fp =3D=3D NULL)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return false;=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* dup'd fd is leaked h= ere */

>=C2=A0 =C2=A0 The problem is that dup(fd) and fdopen()/gzdopen() are tw= o separate
>=C2=A0 =C2=A0 steps, and their failure modes must be handled independen= tly:

Hmm.=C2=A0 You're right that we could leak the dup'd FD, but would = it matter?
I'm pretty sure all these programs will just exit immediately on
failure.

I'm not averse to improving the code, but I'm not sure there is
a live bug worth back-patching.

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 regards, tom lane
--0000000000006d85aa064d63c6a3--