Hello Michael and Matthias,

Could you please look at other similar anomalies I have discovered?:

(Assuming the attached OOM injection patch applied.)
1) An issue in generate_partition_qual():
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -419,3 +419,5 @@ generate_partition_qual(Relation rel)
         oldcxt = MemoryContextSwitchTo(rel->rd_partcheckcxt);
+oom_prob = 0.1;
         rel->rd_partcheck = copyObject(result);
+oom_prob = 0;
         MemoryContextSwitchTo(oldcxt);

for i in {1..100}; do
echo "
CREATE TABLE t1(a INT PRIMARY KEY) PARTITION BY RANGE (a);
CREATE TABLE t1p1 PARTITION OF t1 FOR VALUES FROM (1) TO (2) PARTITION BY LIST 
(a);
CREATE TABLE t2 (a INT, CONSTRAINT fkey FOREIGN KEY(a) REFERENCES t1(a));
INSERT INTO t2 VALUES (1);
INSERT INTO t2 VALUES (1);
DROP TABLE t1, t2 CASCADE;
" | psql

grep 'TRAP' server.log && break;
done

triggers
TRAP: failed Assert("cache->cc_tupdesc != NULL"), File: "catcache.c", Line: 
1112, PID: 43932


2) lookup_type_cache():
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -463,8 +463,10 @@ lookup_type_cache(Oid type_id, int flags)
     in_progress_list[in_progress_offset] = type_id;

+oom_prob = 0.1;
     /* Try to look up an existing entry */
     typentry = (TypeCacheEntry *) hash_search(TypeCacheHash,
                                               &type_id,
                                               HASH_FIND, NULL);
+oom_prob = 0;
     if (typentry == NULL)
     {

for i in {1..10}; do
echo "
CREATE TABLE t(a int);
\c
SELECT * FROM t ORDER BY a;

DROP TABLE t;
" | psql

grep 'TRAP' server.log && break;
done

triggers
TRAP: failed Assert("cache->cc_tupdesc != NULL"), File: "catcache.c", Line: 
1112, PID: 43932


3) pgstat_prep_pending_entry() / pgstat_write_statsfiles():
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -1333,3 +1333,5 @@ pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, 
uint64 objid, bool *creat

+oom_prob = 0.005;
         entry_ref->pending = MemoryContextAllocZero(pgStatPendingContext, 
entrysize);
+oom_prob = 0;
         dlist_push_tail(&pgStatPending, &entry_ref->pending_node);

for i in {1..100}; do
pg_ctl -l server.log start
echo "
CREATE TABLE t (a int);
ALTER TABLE t SET (parallel_workers = 20);
SET parallel_setup_cost = 0;
SELECT SUM(a) FROM t;
DROP TABLE t;
" | psql
pg_ctl -l server.log stop

grep 'TRAP' server.log && break;
done

triggers
TRAP: failed Assert("!ps->dropped"), File: "pgstat.c", Line: 1730, PID: 844901
maybe this Assert can be removed, because there is no corresponding
assert in pgstat_build_snapshot(), but I saw also:
TRAP: failed Assert("rel->pgstat_info->relation == NULL"), File: 
"pgstat_relation.c", Line: 142, PID: 157820
TRAP: failed Assert("ent->entry_ref != NULL"), File: "pgstat_shmem.c", Line: 
827, PID: 190431


4) make_new_heap():
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -1255,3 +1255,5 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid 
NewAccessMethod,
      */
+oom_prob = 0.01;
     CommandCounterIncrement();
+oom_prob = 0;

for i in {1..100}; do
echo "
CREATE TABLE t1(i int PRIMARY KEY);
CLUSTER t1 USING t1_pkey;
CREATE TABLE t2(i int PRIMARY KEY);
CLUSTER t2 USING t2_pkey;
DROP TABLE t2;
DROP TABLE t1;
" | psql

grep 'TRAP' server.log && break;
done

triggers:
TRAP: failed Assert("ItemIdIsNormal(lp)"), File: "heapam.c", Line: 2813, PID: 
943626
also:
ERROR:  attempted to delete invisible tuple

(similar to [1], which can also be triggered with OOM inside
CommandCounterIncrement(), but this one is even more interesting, IMO)

[1] 
https://www.postgresql.org/message-id/21363eb7-606c-468d-88f4-c14162ddafc8%40gmail.com

Best regards,
Alexander
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 6a9ea367107..af4d55f9b4c 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -51,6 +51,7 @@
 #include "utils/memutils.h"
 #include "utils/memutils_internal.h"
 #include "utils/memutils_memorychunk.h"
+#include "common/pg_prng.h"
 
 /*--------------------
  * Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
@@ -946,6 +947,7 @@ AllocSetAllocFromNewBlock(MemoryContext context, Size size, int flags,
 	while (blksize < required_size)
 		blksize <<= 1;
 
+if (pg_prng_double(&pg_global_prng_state) < oom_prob) { oom_prob = 0; return MemoryContextAllocationFailure(context, size, flags); }
 	/* Try to allocate it */
 	block = (AllocBlock) malloc(blksize);
 
@@ -1023,6 +1025,7 @@ AllocSetAlloc(MemoryContext context, Size size, int flags)
 	/* due to the keeper block set->blocks should never be NULL */
 	Assert(set->blocks != NULL);
 
+if (pg_prng_double(&pg_global_prng_state) < oom_prob) { oom_prob = 0; return MemoryContextAllocationFailure(context, size, flags); }
 	/*
 	 * If requested size exceeds maximum for chunks we hand the request off to
 	 * AllocSetAllocLarge().
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 930fc457328..af050ed870d 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -46,6 +46,7 @@
 #include "utils/memutils_internal.h"
 #include "utils/memutils_memorychunk.h"
 
+double oom_prob = 0;
 
 static void BogusFree(void *pointer);
 static void *BogusRealloc(void *pointer, Size size, int flags);
diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h
index 0e934158b60..90033ddc5a3 100644
--- a/src/include/utils/palloc.h
+++ b/src/include/utils/palloc.h
@@ -163,5 +163,6 @@ extern char *pchomp(const char *in);
 /* sprintf into a palloc'd buffer --- these are in psprintf.c */
 extern char *psprintf(const char *fmt, ...) pg_attribute_printf(1, 2);
 extern size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) pg_attribute_printf(3, 0);
+extern double oom_prob;
 
 #endif							/* PALLOC_H */

Reply via email to