mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
Add nbtree Valgrind buffer lock checks.
Holding just a buffer pin (with no buffer lock) on an nbtree buffer/page provides very weak guarantees, especially compared to heapam, where it's often safe to read a page while only holding a buffer pin. This commit has Valgrind enforce the following rule: it is never okay to access an nbtree buffer without holding both a pin and a lock on the buffer. A draft version of this patch detected questionable code that was cleaned up by commitsfa7ff642
and7154aa16
. The code in question used to access an nbtree buffer page's special/opaque area with no buffer lock (only a buffer pin). This practice (which isn't obviously unsafe) is hereby formally disallowed in nbtree. There doesn't seem to be any reason to allow it, and banning it keeps things simple for Valgrind. The new checks are implemented by adding custom nbtree client requests (located in LockBuffer() wrapper functions); these requests are "superimposed" on top of the generic bufmgr.c Valgrind client requests added by commit1e0dfd16
. No custom resource management cleanup code is needed to undo the effects of marking buffers as non-accessible under this scheme. Author: Peter Geoghegan Reviewed-By: Anastasia Lubennikova, Georgios Kokolatos Discussion: https://postgr.es/m/CAH2-WzkLgyN3zBvRZ1pkNJThC=xi_0gpWRUb_45eexLH1+k2_Q@mail.gmail.com
This commit is contained in:
@ -1639,8 +1639,8 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy)
|
||||
* Assume that we acquired a buffer pin for the purposes of
|
||||
* Valgrind buffer client checks (even in !result case) to
|
||||
* keep things simple. Buffers that are unsafe to access are
|
||||
* not generally guaranteed to be marked undefined in any
|
||||
* case.
|
||||
* not generally guaranteed to be marked undefined or
|
||||
* non-accessible in any case.
|
||||
*/
|
||||
VALGRIND_MAKE_MEM_DEFINED(BufHdrGetBlock(buf), BLCKSZ);
|
||||
break;
|
||||
@ -1649,7 +1649,16 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we previously pinned the buffer, it must surely be valid */
|
||||
/*
|
||||
* If we previously pinned the buffer, it must surely be valid.
|
||||
*
|
||||
* Note: We deliberately avoid a Valgrind client request here.
|
||||
* Individual access methods can optionally superimpose buffer page
|
||||
* client requests on top of our client requests to enforce that
|
||||
* buffers are only accessed while locked (and pinned). It's possible
|
||||
* that the buffer page is legitimately non-accessible here. We
|
||||
* cannot meddle with that.
|
||||
*/
|
||||
result = true;
|
||||
}
|
||||
|
||||
@ -1745,7 +1754,13 @@ UnpinBuffer(BufferDesc *buf, bool fixOwner)
|
||||
uint32 buf_state;
|
||||
uint32 old_buf_state;
|
||||
|
||||
/* Mark undefined, now that no pins remain in backend */
|
||||
/*
|
||||
* Mark buffer non-accessible to Valgrind.
|
||||
*
|
||||
* Note that the buffer may have already been marked non-accessible
|
||||
* within access method code that enforces that buffers are only
|
||||
* accessed while a buffer lock is held.
|
||||
*/
|
||||
VALGRIND_MAKE_MEM_NOACCESS(BufHdrGetBlock(buf), BLCKSZ);
|
||||
|
||||
/* I'd better not still hold any locks on the buffer */
|
||||
|
Reference in New Issue
Block a user