Thread
-
Is this non-volatile pointer access OK?
Daniel Farina <daniel@heroku.com> — 2012-09-03T07:10:58Z
http://doxygen.postgresql.org/xlog_8c_source.html#l08197 On line 8197 of xlog.c: 08194 /* Get a local copy of the last safe checkpoint record. */ 08195 SpinLockAcquire(&xlogctl->info_lck); 08196 lastCheckPointRecPtr = xlogctl->lastCheckPointRecPtr; 08197 memcpy(&lastCheckPoint, &XLogCtl->lastCheckPoint, sizeof(CheckPoint)); 08198 SpinLockRelease(&xlogctl->info_lck); Note the use of capital XLogCtl->lastCheckPoint, which is not the volatile pointer. I found this while scouring the code trying to figure out Bug #6291, which is the (to my latest knowledge) is when the epoch is not incremented (sometimes) when passing wraparound. -- fdr
-
Re: Is this non-volatile pointer access OK?
Peter Geoghegan <peter@2ndquadrant.com> — 2012-09-03T10:14:58Z
On 3 September 2012 08:10, Daniel Farina <daniel@heroku.com> wrote: > http://doxygen.postgresql.org/xlog_8c_source.html#l08197 > > On line 8197 of xlog.c: > > 08194 /* Get a local copy of the last safe checkpoint record. */ > 08195 SpinLockAcquire(&xlogctl->info_lck); > 08196 lastCheckPointRecPtr = xlogctl->lastCheckPointRecPtr; > 08197 memcpy(&lastCheckPoint, &XLogCtl->lastCheckPoint, sizeof(CheckPoint)); > 08198 SpinLockRelease(&xlogctl->info_lck); > > Note the use of capital XLogCtl->lastCheckPoint, which is not the > volatile pointer. That looks like a bug to me. Come to think of it, the whole convention of using a lower-case variant of the original pointer variable name seems like a foot-gun, given the harmful and indeed very subtle consequences of making this error. I count 98 SpinLockAcquire() call sites (of which only a minority use this convention, which is mostly within xlog.c, I think). Is it worth instituting an alternative convention to make this kind of misuse more obvious? This went unnoticed since February 2009. -- Peter Geoghegan http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training and Services
-
Re: Is this non-volatile pointer access OK?
Tom Lane <tgl@sss.pgh.pa.us> — 2012-09-03T15:45:54Z
Peter Geoghegan <peter@2ndquadrant.com> writes: > On 3 September 2012 08:10, Daniel Farina <daniel@heroku.com> wrote: >> On line 8197 of xlog.c: >> >> 08194 /* Get a local copy of the last safe checkpoint record. */ >> 08195 SpinLockAcquire(&xlogctl->info_lck); >> 08196 lastCheckPointRecPtr = xlogctl->lastCheckPointRecPtr; >> 08197 memcpy(&lastCheckPoint, &XLogCtl->lastCheckPoint, sizeof(CheckPoint)); >> 08198 SpinLockRelease(&xlogctl->info_lck); >> >> Note the use of capital XLogCtl->lastCheckPoint, which is not the >> volatile pointer. > That looks like a bug to me. The problem with s/XLogCtl/xlogctl/ there is that then the compiler warns about passing a volatile pointer to memcpy. I seem to recall we discussed this once before and decided to leave it alone. I experimented just now with replacing the memcpy with struct assignment, here and in the other place where xlog.c does this (see attached patch). I don't get a complaint from my versions of gcc, although it's not entirely clear why not, since I doubt the assembly code for struct assignment is any more atomic than memcpy would be. According to http://archives.postgresql.org/pgsql-patches/2007-07/msg00025.php g++ *does* complain about that. Anyway, since we're already depending on struct assignment for XLogRecPtr (in the back branches anyway), I don't see any very good reason not to depend on it for struct CheckPoint as well, and so propose that we apply the attached. > Come to think of it, the whole convention of using a lower-case > variant of the original pointer variable name seems like a foot-gun, > given the harmful and indeed very subtle consequences of making this > error. Yes. The right way to fix this would be for the compiler to not ever move assignments across a SpinLockAcquire or SpinLockRelease. Do you have a bulletproof method for guaranteeing that? regards, tom lane
-
Re: Is this non-volatile pointer access OK?
Peter Eisentraut <peter_e@gmx.net> — 2012-09-04T01:21:11Z
On Mon, 2012-09-03 at 11:14 +0100, Peter Geoghegan wrote: > Come to think of it, the whole convention of using a lower-case > variant of the original pointer variable name seems like a foot-gun, > given the harmful and indeed very subtle consequences of making this > error. With some inventive macro magic, you could probably make this safer. I'm thinking something along the lines of replacing SpinLockAcquire(&xlogctl->info_lck); with SpinLockAcquire(XLogCtl, info_lck); which expands to { volatile typeof(XLogCtl) *XLogCtl_volatile = XLogCtl; void *XLogCtl = NULL; // compiler error or crash at run time if used OldSpinLockAcquire(XLogCtl_volatile->info_lock); ... and then something corresponding for SpinLockRelease. This will likely only work with modern compilers, but it could give you some amount of static checking against this problem.