]> granicus.if.org Git - postgresql/commitdiff
Make get_controlfile not leak file descriptors
authorJoe Conway <mail@joeconway.com>
Thu, 28 Feb 2019 20:57:40 +0000 (15:57 -0500)
committerJoe Conway <mail@joeconway.com>
Thu, 28 Feb 2019 20:57:40 +0000 (15:57 -0500)
When backend functions were added to expose controldata via SQL,
reading of pg_control was consolidated under src/common so that
both frontend and backend could share the same code. That move
from frontend-only to shared frontend-backend failed to recognize
the risk (and coding standards violation) of using a bare open().
In particular, it risked leaking file descriptors if transient
errors occurred while reading the file. Fix that by using
OpenTransientFile() instead in the backend case, which is
purpose-built for this type of usage.

Since there have been no complaints from the field, and an intermittent
failure low risk, no backpatch. Hard failure would of course be bad, but
in that case these functions are probably the least of your worries.

Author: Joe Conway
Reviewed-By: Michael Paquier
Reported by: Michael Paquier
Discussion: https://postgr.es/m/20190227074728.GA15710@paquier.xyz

src/common/controldata_utils.c

index abfe7065f55154328cbbe6820078447095b6e499..000f3c66d626e31a8d043e5a5b8774e0fc333d5b 100644 (file)
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
 #include "port/pg_crc32c.h"
+#ifndef FRONTEND
+#include "storage/fd.h"
+#endif
 
 /*
- * get_controlfile(char *DataDir, const char *progname, bool *crc_ok_p)
+ * get_controlfile()
  *
  * Get controlfile values.  The result is returned as a palloc'd copy of the
  * control file data.
@@ -51,13 +54,14 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
        ControlFile = palloc(sizeof(ControlFileData));
        snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
 
-       if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
 #ifndef FRONTEND
+       if ((fd = OpenTransientFile(ControlFilePath, O_RDONLY | PG_BINARY)) == -1)
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not open file \"%s\" for reading: %m",
                                                ControlFilePath)));
 #else
+       if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
        {
                fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
                                progname, ControlFilePath, strerror(errno));
@@ -95,7 +99,11 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 #endif
        }
 
+#ifndef FRONTEND
+       CloseTransientFile(fd);
+#else
        close(fd);
+#endif
 
        /* Check the CRC. */
        INIT_CRC32C(crc);