1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-28 11:44:57 +03:00

Add pg_add_size_overflow() and friends

Commit 600086f47 added (several bespoke copies of) size_t addition with
overflow checks to libpq. Move this to common/int.h, along with
its subtraction and multiplication counterparts.

pg_neg_size_overflow() is intentionally omitted; I'm not sure we should
add SSIZE_MAX to win32_port.h for the sake of a function with no
callers.

Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAOYmi%2B%3D%2BpqUd2MUitvgW1pAJuXgG_TKCVc3_Ek7pe8z9nkf%2BAg%40mail.gmail.com
This commit is contained in:
Jacob Champion
2025-11-24 09:59:38 -08:00
parent f1881c7dd3
commit 8934f2136c
4 changed files with 91 additions and 83 deletions

View File

@@ -601,6 +601,73 @@ pg_neg_u64_overflow(uint64 a, int64 *result)
#endif #endif
} }
/*
* size_t
*/
static inline bool
pg_add_size_overflow(size_t a, size_t b, size_t *result)
{
#if defined(HAVE__BUILTIN_OP_OVERFLOW)
return __builtin_add_overflow(a, b, result);
#else
size_t res = a + b;
if (res < a)
{
*result = 0x5EED; /* to avoid spurious warnings */
return true;
}
*result = res;
return false;
#endif
}
static inline bool
pg_sub_size_overflow(size_t a, size_t b, size_t *result)
{
#if defined(HAVE__BUILTIN_OP_OVERFLOW)
return __builtin_sub_overflow(a, b, result);
#else
if (b > a)
{
*result = 0x5EED; /* to avoid spurious warnings */
return true;
}
*result = a - b;
return false;
#endif
}
static inline bool
pg_mul_size_overflow(size_t a, size_t b, size_t *result)
{
#if defined(HAVE__BUILTIN_OP_OVERFLOW)
return __builtin_mul_overflow(a, b, result);
#else
size_t res = a * b;
if (a != 0 && b != res / a)
{
*result = 0x5EED; /* to avoid spurious warnings */
return true;
}
*result = res;
return false;
#endif
}
/*
* pg_neg_size_overflow is currently omitted, to avoid having to reason about
* the portability of SSIZE_MIN/_MAX before a use case exists.
*/
/*
* static inline bool
* pg_neg_size_overflow(size_t a, ssize_t *result)
* {
* ...
* }
*/
/*------------------------------------------------------------------------ /*------------------------------------------------------------------------
* *
* Comparison routines for integer types. * Comparison routines for integer types.

View File

@@ -24,6 +24,7 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "common/int.h"
#include "libpq-fe.h" #include "libpq-fe.h"
#include "libpq-int.h" #include "libpq-int.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
@@ -4220,27 +4221,6 @@ PQescapeString(char *to, const char *from, size_t length)
} }
/*
* Frontend version of the backend's add_size(), intended to be API-compatible
* with the pg_add_*_overflow() helpers. Stores the result into *dst on success.
* Returns true instead if the addition overflows.
*
* TODO: move to common/int.h
*/
static bool
add_size_overflow(size_t s1, size_t s2, size_t *dst)
{
size_t result;
result = s1 + s2;
if (result < s1 || result < s2)
return true;
*dst = result;
return false;
}
/* /*
* Escape arbitrary strings. If as_ident is true, we escape the result * Escape arbitrary strings. If as_ident is true, we escape the result
* as an identifier; if false, as a literal. The result is returned in * as an identifier; if false, as a literal. The result is returned in
@@ -4324,14 +4304,14 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
* Allocate output buffer. Protect against overflow, in case the caller * Allocate output buffer. Protect against overflow, in case the caller
* has allocated a large fraction of the available size_t. * has allocated a large fraction of the available size_t.
*/ */
if (add_size_overflow(input_len, num_quotes, &result_size) || if (pg_add_size_overflow(input_len, num_quotes, &result_size) ||
add_size_overflow(result_size, 3, &result_size)) /* two quotes plus a NUL */ pg_add_size_overflow(result_size, 3, &result_size)) /* two quotes plus a NUL */
goto overflow; goto overflow;
if (!as_ident && num_backslashes > 0) if (!as_ident && num_backslashes > 0)
{ {
if (add_size_overflow(result_size, num_backslashes, &result_size) || if (pg_add_size_overflow(result_size, num_backslashes, &result_size) ||
add_size_overflow(result_size, 2, &result_size)) /* for " E" prefix */ pg_add_size_overflow(result_size, 2, &result_size)) /* for " E" prefix */
goto overflow; goto overflow;
} }
@@ -4493,9 +4473,9 @@ PQescapeByteaInternal(PGconn *conn,
if (use_hex) if (use_hex)
{ {
/* We prepend "\x" and double each input character. */ /* We prepend "\x" and double each input character. */
if (add_size_overflow(len, bslash_len + 1, &len) || if (pg_add_size_overflow(len, bslash_len + 1, &len) ||
add_size_overflow(len, from_length, &len) || pg_add_size_overflow(len, from_length, &len) ||
add_size_overflow(len, from_length, &len)) pg_add_size_overflow(len, from_length, &len))
goto overflow; goto overflow;
} }
else else
@@ -4505,22 +4485,22 @@ PQescapeByteaInternal(PGconn *conn,
{ {
if (*vp < 0x20 || *vp > 0x7e) if (*vp < 0x20 || *vp > 0x7e)
{ {
if (add_size_overflow(len, bslash_len + 3, &len)) /* octal "\ooo" */ if (pg_add_size_overflow(len, bslash_len + 3, &len)) /* octal "\ooo" */
goto overflow; goto overflow;
} }
else if (*vp == '\'') else if (*vp == '\'')
{ {
if (add_size_overflow(len, 2, &len)) /* double each quote */ if (pg_add_size_overflow(len, 2, &len)) /* double each quote */
goto overflow; goto overflow;
} }
else if (*vp == '\\') else if (*vp == '\\')
{ {
if (add_size_overflow(len, bslash_len * 2, &len)) /* double each backslash */ if (pg_add_size_overflow(len, bslash_len * 2, &len)) /* double each backslash */
goto overflow; goto overflow;
} }
else else
{ {
if (add_size_overflow(len, 1, &len)) if (pg_add_size_overflow(len, 1, &len))
goto overflow; goto overflow;
} }
} }

View File

@@ -33,6 +33,7 @@
#endif #endif
#endif #endif
#include "common/int.h"
#include "libpq-fe.h" #include "libpq-fe.h"
#include "libpq-int.h" #include "libpq-int.h"
@@ -451,27 +452,6 @@ do_field(const PQprintOpt *po, const PGresult *res,
} }
/*
* Frontend version of the backend's add_size(), intended to be API-compatible
* with the pg_add_*_overflow() helpers. Stores the result into *dst on success.
* Returns true instead if the addition overflows.
*
* TODO: move to common/int.h
*/
static bool
add_size_overflow(size_t s1, size_t s2, size_t *dst)
{
size_t result;
result = s1 + s2;
if (result < s1 || result < s2)
return true;
*dst = result;
return false;
}
static char * static char *
do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax, do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
const char **fieldNames, unsigned char *fieldNotNum, const char **fieldNames, unsigned char *fieldNotNum,
@@ -492,20 +472,20 @@ do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
for (; n < nFields; n++) for (; n < nFields; n++)
{ {
/* Field plus separator, plus 2 extra '-' in standard format. */ /* Field plus separator, plus 2 extra '-' in standard format. */
if (add_size_overflow(tot, fieldMax[n], &tot) || if (pg_add_size_overflow(tot, fieldMax[n], &tot) ||
add_size_overflow(tot, fs_len, &tot) || pg_add_size_overflow(tot, fs_len, &tot) ||
(po->standard && add_size_overflow(tot, 2, &tot))) (po->standard && pg_add_size_overflow(tot, 2, &tot)))
goto overflow; goto overflow;
} }
if (po->standard) if (po->standard)
{ {
/* An extra separator at the front and back. */ /* An extra separator at the front and back. */
if (add_size_overflow(tot, fs_len, &tot) || if (pg_add_size_overflow(tot, fs_len, &tot) ||
add_size_overflow(tot, fs_len, &tot) || pg_add_size_overflow(tot, fs_len, &tot) ||
add_size_overflow(tot, 2, &tot)) pg_add_size_overflow(tot, 2, &tot))
goto overflow; goto overflow;
} }
if (add_size_overflow(tot, 1, &tot)) /* terminator */ if (pg_add_size_overflow(tot, 1, &tot)) /* terminator */
goto overflow; goto overflow;
border = malloc(tot); border = malloc(tot);

View File

@@ -25,6 +25,7 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#endif #endif
#include "common/int.h"
#include "libpq-fe.h" #include "libpq-fe.h"
#include "libpq-int.h" #include "libpq-int.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
@@ -2404,26 +2405,6 @@ pqBuildStartupPacket3(PGconn *conn, int *packetlen,
return startpacket; return startpacket;
} }
/*
* Frontend version of the backend's add_size(), intended to be API-compatible
* with the pg_add_*_overflow() helpers. Stores the result into *dst on success.
* Returns true instead if the addition overflows.
*
* TODO: move to common/int.h
*/
static bool
add_size_overflow(size_t s1, size_t s2, size_t *dst)
{
size_t result;
result = s1 + s2;
if (result < s1 || result < s2)
return true;
*dst = result;
return false;
}
/* /*
* Build a startup packet given a filled-in PGconn structure. * Build a startup packet given a filled-in PGconn structure.
* *
@@ -2456,11 +2437,11 @@ build_startup_packet(const PGconn *conn, char *packet,
do { \ do { \
if (packet) \ if (packet) \
strcpy(packet + packet_len, optname); \ strcpy(packet + packet_len, optname); \
if (add_size_overflow(packet_len, strlen(optname) + 1, &packet_len)) \ if (pg_add_size_overflow(packet_len, strlen(optname) + 1, &packet_len)) \
return 0; \ return 0; \
if (packet) \ if (packet) \
strcpy(packet + packet_len, optval); \ strcpy(packet + packet_len, optval); \
if (add_size_overflow(packet_len, strlen(optval) + 1, &packet_len)) \ if (pg_add_size_overflow(packet_len, strlen(optval) + 1, &packet_len)) \
return 0; \ return 0; \
} while(0) } while(0)
@@ -2496,7 +2477,7 @@ build_startup_packet(const PGconn *conn, char *packet,
/* Add trailing terminator */ /* Add trailing terminator */
if (packet) if (packet)
packet[packet_len] = '\0'; packet[packet_len] = '\0';
if (add_size_overflow(packet_len, 1, &packet_len)) if (pg_add_size_overflow(packet_len, 1, &packet_len))
return 0; return 0;
return packet_len; return packet_len;