Skip to content

Commit beac793

Browse files
committed
Avoid testing tuple visibility without buffer lock.
INSERT ... ON CONFLICT (specifically ExecCheckHeapTupleVisible) contains another example of this unsafe coding practice. It is much harder to get a failure out of it than the case fixed in commit 6292c23, because in most scenarios any hint bits that could be set would have already been set earlier in the command. However, Konstantin Knizhnik reported a failure with a custom transaction manager, and it's clearly possible to get a failure via a race condition in async-commit mode. For lack of a reproducible example, no regression test case in this commit. I did some testing with Asserts added to tqual.c's functions, and can say that running "make check-world" exposed these two bugs and no others. The Asserts are messy enough that I've not added them to the code for now. Report: <57EE93C8.8080504@postgrespro.ru> Related-Discussion: <CAO3NbwOycQjt2Oqy2VW-eLTq2M5uGMyHnGm=RNga4mjqcYD7gQ@mail.gmail.com>
1 parent 65d85b8 commit beac793

File tree

1 file changed

+6
-0
lines changed

1 file changed

+6
-0
lines changed

src/backend/executor/nodeModifyTable.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ ExecCheckHeapTupleVisible(EState *estate,
177177
if (!IsolationUsesXactSnapshot())
178178
return;
179179

180+
/*
181+
* We need buffer pin and lock to call HeapTupleSatisfiesVisibility.
182+
* Caller should be holding pin, but not lock.
183+
*/
184+
LockBuffer(buffer, BUFFER_LOCK_SHARE);
180185
if (!HeapTupleSatisfiesVisibility(tuple, estate->es_snapshot, buffer))
181186
{
182187
/*
@@ -190,6 +195,7 @@ ExecCheckHeapTupleVisible(EState *estate,
190195
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
191196
errmsg("could not serialize access due to concurrent update")));
192197
}
198+
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
193199
}
194200

195201
/*

0 commit comments

Comments
 (0)