#include <unistd.h>
#include "access/slru.h"
-#include "common/int.h"
#include "fmgr.h"
#include "funcapi.h"
#include "miscadmin.h"
return ptr;
}
-/*
- * Add two Size values, checking for overflow
- */
-Size
-add_size(Size s1, Size s2)
-{
- Size result;
-
- if (pg_add_size_overflow(s1, s2, &result))
- ereport(ERROR,
- (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("requested shared memory size overflows size_t")));
- return result;
-}
-
-/*
- * Multiply two Size values, checking for overflow
- */
-Size
-mul_size(Size s1, Size s2)
-{
- Size result;
-
- if (pg_mul_size_overflow(s1, s2, &result))
- ereport(ERROR,
- (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("requested shared memory size overflows size_t")));
- return result;
-}
-
/* SQL SRF showing allocated shared memory */
Datum
pg_get_shmem_allocations(PG_FUNCTION_ARGS)
#include "postgres.h"
+#include "common/int.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "utils/memdebug.h"
static void MemoryContextStatsPrint(MemoryContext context, void *passthru,
const char *stats_string,
bool print_to_stderr);
+pg_noreturn static pg_noinline void add_size_error(Size s1, Size s2);
+pg_noreturn static pg_noinline void mul_size_error(Size s1, Size s2);
/*
* You should not do memory allocations within a critical section, because
return ret;
}
+/*
+ * Support for safe calculation of memory request sizes
+ *
+ * These functions perform the requested calculation, but throw error if the
+ * result overflows.
+ *
+ * An important property of these functions is that if an argument was a
+ * negative signed int before promotion (implying overflow in calculating it)
+ * we will detect that as an error. That happens because we reject results
+ * larger than SIZE_MAX / 2 later on, in the actual allocation step.
+ */
+Size
+add_size(Size s1, Size s2)
+{
+ Size result;
+
+ if (unlikely(pg_add_size_overflow(s1, s2, &result)))
+ add_size_error(s1, s2);
+ return result;
+}
+
+pg_noreturn static pg_noinline void
+add_size_error(Size s1, Size s2)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("invalid memory allocation request size %zu + %zu",
+ s1, s2)));
+}
+
+Size
+mul_size(Size s1, Size s2)
+{
+ Size result;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &result)))
+ mul_size_error(s1, s2);
+ return result;
+}
+
+pg_noreturn static pg_noinline void
+mul_size_error(Size s1, Size s2)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("invalid memory allocation request size %zu * %zu",
+ s1, s2)));
+}
+
+/*
+ * palloc_mul
+ * Equivalent to palloc(mul_size(s1, s2)).
+ */
+void *
+palloc_mul(Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+ mul_size_error(s1, s2);
+ return palloc(req);
+}
+
+/*
+ * palloc0_mul
+ * Equivalent to palloc0(mul_size(s1, s2)).
+ *
+ * This is comparable to standard calloc's behavior.
+ */
+void *
+palloc0_mul(Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+ mul_size_error(s1, s2);
+ return palloc0(req);
+}
+
+/*
+ * palloc_mul_extended
+ * Equivalent to palloc_extended(mul_size(s1, s2), flags).
+ */
+void *
+palloc_mul_extended(Size s1, Size s2, int flags)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+ mul_size_error(s1, s2);
+ return palloc_extended(req, flags);
+}
+
+/*
+ * repalloc_mul
+ * Equivalent to repalloc(p, mul_size(s1, s2)).
+ */
+void *
+repalloc_mul(void *p, Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+ mul_size_error(s1, s2);
+ return repalloc(p, req);
+}
+
+/*
+ * repalloc_mul_extended
+ * Equivalent to repalloc_extended(p, mul_size(s1, s2), flags).
+ */
+void *
+repalloc_mul_extended(void *p, Size s1, Size s2, int flags)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+ mul_size_error(s1, s2);
+ return repalloc_extended(p, req, flags);
+}
+
/*
* MemoryContextAllocHuge
* Allocate (possibly-expansive) space within the specified context.
#include "postgres_fe.h"
+#include "common/int.h"
+
+pg_noreturn static pg_noinline void add_size_error(Size s1, Size s2);
+pg_noreturn static pg_noinline void mul_size_error(Size s1, Size s2);
+
+
static inline void *
pg_malloc_internal(size_t size, int flags)
{
{
return pg_realloc(pointer, size);
}
+
+/*
+ * Support for safe calculation of memory request sizes
+ *
+ * These functions perform the requested calculation, but throw error if the
+ * result overflows.
+ *
+ * An important property of these functions is that if an argument was a
+ * negative signed int before promotion (implying overflow in calculating it)
+ * we will detect that as an error. That happens because we reject results
+ * larger than SIZE_MAX / 2. In the backend we rely on later checks to do
+ * that, but in frontend we must do it here.
+ */
+Size
+add_size(Size s1, Size s2)
+{
+ Size result;
+
+ if (unlikely(pg_add_size_overflow(s1, s2, &result) ||
+ result > (SIZE_MAX / 2)))
+ add_size_error(s1, s2);
+ return result;
+}
+
+pg_noreturn static pg_noinline void
+add_size_error(Size s1, Size s2)
+{
+ fprintf(stderr, _("invalid memory allocation request size %zu + %zu\n"),
+ s1, s2);
+ exit(EXIT_FAILURE);
+}
+
+Size
+mul_size(Size s1, Size s2)
+{
+ Size result;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &result) ||
+ result > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return result;
+}
+
+pg_noreturn static pg_noinline void
+mul_size_error(Size s1, Size s2)
+{
+ fprintf(stderr, _("invalid memory allocation request size %zu * %zu\n"),
+ s1, s2);
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * pg_malloc_mul
+ * Equivalent to pg_malloc(mul_size(s1, s2)).
+ */
+void *
+pg_malloc_mul(Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
+ req > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return pg_malloc(req);
+}
+
+/*
+ * pg_malloc0_mul
+ * Equivalent to pg_malloc0(mul_size(s1, s2)).
+ *
+ * This is comparable to standard calloc's behavior.
+ */
+void *
+pg_malloc0_mul(Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
+ req > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return pg_malloc0(req);
+}
+
+/*
+ * pg_malloc_mul_extended
+ * Equivalent to pg_malloc_extended(mul_size(s1, s2), flags).
+ */
+void *
+pg_malloc_mul_extended(Size s1, Size s2, int flags)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
+ req > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return pg_malloc_extended(req, flags);
+}
+
+/*
+ * pg_realloc_mul
+ * Equivalent to pg_realloc(p, mul_size(s1, s2)).
+ */
+void *
+pg_realloc_mul(void *p, Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
+ req > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return pg_realloc(p, req);
+}
+
+/*
+ * palloc_mul
+ * Equivalent to palloc(mul_size(s1, s2)).
+ */
+void *
+palloc_mul(Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
+ req > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return palloc(req);
+}
+
+/*
+ * palloc0_mul
+ * Equivalent to palloc0(mul_size(s1, s2)).
+ *
+ * This is comparable to standard calloc's behavior.
+ */
+void *
+palloc0_mul(Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
+ req > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return palloc0(req);
+}
+
+/*
+ * palloc_mul_extended
+ * Equivalent to palloc_extended(mul_size(s1, s2), flags).
+ */
+void *
+palloc_mul_extended(Size s1, Size s2, int flags)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
+ req > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return palloc_extended(req, flags);
+}
+
+/*
+ * repalloc_mul
+ * Equivalent to repalloc(p, mul_size(s1, s2)).
+ */
+void *
+repalloc_mul(void *p, Size s1, Size s2)
+{
+ /* inline mul_size() for efficiency */
+ Size req;
+
+ if (unlikely(pg_mul_size_overflow(s1, s2, &req) ||
+ req > (SIZE_MAX / 2)))
+ mul_size_error(s1, s2);
+ return repalloc(p, req);
+}
extern void *pg_realloc(void *ptr, size_t size);
extern void pg_free(void *ptr);
+/*
+ * Support for safe calculation of memory request sizes
+ */
+extern Size add_size(Size s1, Size s2);
+extern Size mul_size(Size s1, Size s2);
+extern void *pg_malloc_mul(Size s1, Size s2);
+extern void *pg_malloc0_mul(Size s1, Size s2);
+extern void *pg_malloc_mul_extended(Size s1, Size s2, int flags);
+extern void *pg_realloc_mul(void *p, Size s1, Size s2);
+
/*
* Variants with easier notation and more type safety
*/
/*
* Allocate space for "count" objects of type "type"
*/
-#define pg_malloc_array(type, count) ((type *) pg_malloc(sizeof(type) * (count)))
-#define pg_malloc0_array(type, count) ((type *) pg_malloc0(sizeof(type) * (count)))
+#define pg_malloc_array(type, count) ((type *) pg_malloc_mul(sizeof(type), count))
+#define pg_malloc0_array(type, count) ((type *) pg_malloc0_mul(sizeof(type), count))
+#define pg_malloc_array_extended(type, count, flags) ((type *) pg_malloc_mul_extended(sizeof(type), count, flags))
/*
* Change size of allocation pointed to by "pointer" to have space for "count"
* objects of type "type"
*/
-#define pg_realloc_array(pointer, type, count) ((type *) pg_realloc(pointer, sizeof(type) * (count)))
+#define pg_realloc_array(pointer, type, count) ((type *) pg_realloc_mul(pointer, sizeof(type), count))
/* Equivalent functions, deliberately named the same as backend functions */
extern char *pstrdup(const char *in);
extern void *palloc_extended(Size size, int flags);
extern void *repalloc(void *pointer, Size size);
extern void pfree(void *pointer);
+extern void *palloc_mul(Size s1, Size s2);
+extern void *palloc0_mul(Size s1, Size s2);
+extern void *palloc_mul_extended(Size s1, Size s2, int flags);
+extern void *repalloc_mul(void *p, Size s1, Size s2);
#define palloc_object(type) ((type *) palloc(sizeof(type)))
#define palloc0_object(type) ((type *) palloc0(sizeof(type)))
-#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count)))
-#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count)))
-#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count)))
+#define palloc_array(type, count) ((type *) palloc_mul(sizeof(type), count))
+#define palloc0_array(type, count) ((type *) palloc0_mul(sizeof(type), count))
+#define palloc_array_extended(type, count, flags) ((type *) palloc_mul_extended(sizeof(type), count, flags))
+#define repalloc_array(pointer, type, count) ((type *) repalloc_mul(pointer, sizeof(type), count))
/* sprintf into a palloc'd buffer --- these are in psprintf.c */
extern char *psprintf(const char *fmt,...) pg_attribute_printf(1, 2);
extern void *ShmemAlloc(Size size);
extern void *ShmemAllocNoError(Size size);
-extern Size add_size(Size s1, Size s2);
-extern Size mul_size(Size s1, Size s2);
-
extern PGDLLIMPORT Size pg_get_shmem_pagesize(void);
/* ipci.c */
#define AllocSizeIsValid(size) ((Size) (size) <= MaxAllocSize)
-/* Must be less than SIZE_MAX */
+/* Do not make this any bigger; see add_size() and mul_size() */
#define MaxAllocHugeSize (SIZE_MAX / 2)
#define InvalidAllocSize SIZE_MAX
pg_nodiscard extern void *repalloc0(void *pointer, Size oldsize, Size size);
extern void pfree(void *pointer);
+/*
+ * Support for safe calculation of memory request sizes
+ */
+extern Size add_size(Size s1, Size s2);
+extern Size mul_size(Size s1, Size s2);
+extern void *palloc_mul(Size s1, Size s2);
+extern void *palloc0_mul(Size s1, Size s2);
+extern void *palloc_mul_extended(Size s1, Size s2, int flags);
+pg_nodiscard extern void *repalloc_mul(void *p, Size s1, Size s2);
+pg_nodiscard extern void *repalloc_mul_extended(void *p, Size s1, Size s2,
+ int flags);
+
/*
* Variants with easier notation and more type safety
*/
/*
* Allocate space for "count" objects of type "type"
*/
-#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count)))
-#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count)))
+#define palloc_array(type, count) ((type *) palloc_mul(sizeof(type), count))
+#define palloc0_array(type, count) ((type *) palloc0_mul(sizeof(type), count))
+#define palloc_array_extended(type, count, flags) ((type *) palloc_mul_extended(sizeof(type), count, flags))
/*
* Change size of allocation pointed to by "pointer" to have space for "count"
* objects of type "type"
*/
-#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count)))
-#define repalloc0_array(pointer, type, oldcount, count) ((type *) repalloc0(pointer, sizeof(type) * (oldcount), sizeof(type) * (count)))
+#define repalloc_array(pointer, type, count) ((type *) repalloc_mul(pointer, sizeof(type), count))
+#define repalloc0_array(pointer, type, oldcount, count) ((type *) repalloc0(pointer, mul_size(sizeof(type), oldcount), mul_size(sizeof(type), count)))
+#define repalloc_array_extended(pointer, type, count, flags) ((type *) repalloc_mul_extended(pointer, sizeof(type), count, flags))
/* Higher-limit allocators. */
extern void *MemoryContextAllocHuge(MemoryContext context, Size size);