DSM segment handle generation in background workers
Hello,
I noticed that every parallel worker generates the same sequence of
handles here:
/*
* Loop until we find an unused identifier for the new control
segment. We
* sometimes use 0 as a sentinel value indicating that no
control segment
* is known to exist, so avoid using that value for a real control
* segment.
*/
for (;;)
{
Assert(dsm_control_address == NULL);
Assert(dsm_control_mapped_size == 0);
dsm_control_handle = random();
if (dsm_control_handle == DSM_HANDLE_INVALID)
continue;
if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize,
&dsm_control_impl_private, &dsm_control_address,
&dsm_control_mapped_size, ERROR))
break;
}
It's harmless AFAICS, but it produces sequences of syscalls like this
when Parallel Hash is building the hash table:
shm_open("/PostgreSQL.240477264",O_RDWR|O_CREAT|O_EXCL,0600) ERR#17
'File exists'
shm_open("/PostgreSQL.638747851",O_RDWR|O_CREAT|O_EXCL,0600) ERR#17
'File exists'
shm_open("/PostgreSQL.1551053007",O_RDWR|O_CREAT|O_EXCL,0600) = 5 (0x5)
That's because the bgworker startup path doesn't contain a call to
srandom(...distinguishing stuff...), unlike BackendRun(). I suppose
do_start_bgworker() could gain a similar call... or perhaps that call
should be moved into InitPostmasterChild(). If we put it in there
right after MyStartTime is assigned a new value, we could use the same
incantation that PostmasterMain() uses.
I noticed that the comment in PostmasterMain() refers to
PostmasterRandom(), which is gone.
--
Thomas Munro
http://www.enterprisedb.com
On Mon, Oct 8, 2018 at 1:17 AM Thomas Munro
<thomas.munro@enterprisedb.com> wrote:
That's because the bgworker startup path doesn't contain a call to
srandom(...distinguishing stuff...), unlike BackendRun(). I suppose
do_start_bgworker() could gain a similar call... or perhaps that call
should be moved into InitPostmasterChild(). If we put it in there
right after MyStartTime is assigned a new value, we could use the same
incantation that PostmasterMain() uses.I noticed that the comment in PostmasterMain() refers to
PostmasterRandom(), which is gone.
Maybe something like this?
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
move-srandom.patchapplication/octet-stream; name=move-srandom.patchDownload
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 41de140ae01..b50776678f7 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -602,8 +602,8 @@ PostmasterMain(int argc, char *argv[])
*
* Note: the seed is pretty predictable from externally-visible facts such
* as postmaster start time, so avoid using random() for security-critical
- * random values during postmaster startup. At the time of first
- * connection, PostmasterRandom will select a hopefully-more-random seed.
+ * random values during postmaster startup. InitPostmasterChild() will
+ * set a new seed in child processes.
*/
srandom((unsigned int) (MyProcPid ^ MyStartTime));
@@ -4315,22 +4315,16 @@ BackendRun(Port *port)
char **av;
int maxac;
int ac;
- long secs;
- int usecs;
int i;
/*
* Don't want backend to be able to see the postmaster random number
- * generator state. We have to clobber the static random_seed *and* start
- * a new random sequence in the random() library function.
+ * generator state. We have to clobber the static random_seed.
*/
#ifndef HAVE_STRONG_RANDOM
random_seed = 0;
random_start_time.tv_usec = 0;
#endif
- /* slightly hacky way to convert timestamptz into integers */
- TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
- srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
/*
* Now, build the argv vector that will be given to PostgresMain.
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index f590ecb25e8..d907226ada4 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -278,6 +278,9 @@ InitPostmasterChild(void)
MyStartTime = time(NULL); /* set our start time in case we call elog */
+ /* Set a different seed for libc's random() in every backend. */
+ srandom((unsigned int) (MyProcPid ^ MyStartTime));
+
/*
* make sure stderr is in binary mode before anything can possibly be
* written to it, in case it's actually the syslogger pipe, so the pipe
Thomas Munro <thomas.munro@enterprisedb.com> writes:
On Mon, Oct 8, 2018 at 1:17 AM Thomas Munro
<thomas.munro@enterprisedb.com> wrote:That's because the bgworker startup path doesn't contain a call to
srandom(...distinguishing stuff...), unlike BackendRun(). I suppose
do_start_bgworker() could gain a similar call... or perhaps that call
should be moved into InitPostmasterChild(). If we put it in there
right after MyStartTime is assigned a new value, we could use the same
incantation that PostmasterMain() uses.
Maybe something like this?
I think the bit with
#ifndef HAVE_STRONG_RANDOM
random_seed = 0;
random_start_time.tv_usec = 0;
#endif
should also be done in every postmaster child, no? If we want to hide the
postmaster's state from child processes, we ought to hide it from all.
regards, tom lane
On Tue, Oct 9, 2018 at 1:53 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
On Mon, Oct 8, 2018 at 1:17 AM Thomas Munro
<thomas.munro@enterprisedb.com> wrote:That's because the bgworker startup path doesn't contain a call to
srandom(...distinguishing stuff...), unlike BackendRun(). I suppose
do_start_bgworker() could gain a similar call... or perhaps that call
should be moved into InitPostmasterChild(). If we put it in there
right after MyStartTime is assigned a new value, we could use the same
incantation that PostmasterMain() uses.Maybe something like this?
I think the bit with
#ifndef HAVE_STRONG_RANDOM
random_seed = 0;
random_start_time.tv_usec = 0;
#endifshould also be done in every postmaster child, no? If we want to hide the
postmaster's state from child processes, we ought to hide it from all.
Ok, here is a sketch patch with a new function InitRandomSeeds() to do
that. It is called from PostmasterMain(), InitPostmasterChild() and
InitStandaloneProcess() for consistency.
It seems a bit strange to me that internal infrastructure shares a
random number generator with SQL-callable functions random() and
setseed(), though I'm not saying it's harmful.
While wondering if something like this should be back-patched, I
noticed that SQL random() is declared as parallel-restricted, which is
good: it means we aren't exposing a random() function that generates
the same values in every parallel worker. So I think this is probably
just a minor nuisance and should probably only be pushed to master, or
at most to 11 (since Parallel Hash likes to create DSM segments in
workers), unless someone can think of a more serious way this can hurt
you.
(Tangentially: I suppose it might be useful to have a different SQL
random number function that is parallel safe, that isn't associated
with a user-controllable seed, and whose seed is different in each
backend.)
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Make-sure-we-initialize-random-seeds-per-backend.patchapplication/octet-stream; name=0001-Make-sure-we-initialize-random-seeds-per-backend.patchDownload
From 921c474e2c117535392b1287454bb44e9c550afb Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Tue, 9 Oct 2018 14:32:47 +1300
Subject: [PATCH] Make sure we initialize random seeds per backend.
Background workers, including parallel workers, were generating
the same sequence of numbers in various code paths that use
random(). The case noticed as DSM handle generation, where many
collisions can occur during Parallal Hash execution, but there
are probably other ways to see this.
Repair by refactoring the seed initialization code such that all
backends run it. Use the same function for the postmaster, its
children and also standalone processes, for consistency.
Author: Thomas Munro
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/CAEepm%3D2eJj_6%3DB%2B2tEpGu2nf1BjthCf9nXXUouYvJJ4C5WSwhg%40mail.gmail.com
---
src/backend/postmaster/postmaster.c | 43 +++++++++++++++++------------
src/backend/utils/init/miscinit.c | 4 ++-
src/include/postmaster/postmaster.h | 1 +
3 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 41de140ae01..9e90306f411 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -602,10 +602,10 @@ PostmasterMain(int argc, char *argv[])
*
* Note: the seed is pretty predictable from externally-visible facts such
* as postmaster start time, so avoid using random() for security-critical
- * random values during postmaster startup. At the time of first
- * connection, PostmasterRandom will select a hopefully-more-random seed.
+ * random values during postmaster startup. InitPostmasterChild() will
+ * do this again to set a new seed in child processes.
*/
- srandom((unsigned int) (MyProcPid ^ MyStartTime));
+ InitRandomSeeds();
/*
* By default, palloc() requests in the postmaster will be allocated in
@@ -2513,6 +2513,28 @@ ClosePostmasterPorts(bool am_syslogger)
}
+/*
+ * InitRandomSeeds -- initialize seeds for random number generators
+ *
+ * Called in every backend after MyProcPid and MyStartTime have been assigned.
+ */
+void
+InitRandomSeeds(void)
+{
+ /*
+ * Don't want backend to be able to see the postmaster random number
+ * generator state. We have to clobber the static random_seed.
+ */
+#ifndef HAVE_STRONG_RANDOM
+ random_seed = 0;
+ random_start_time.tv_usec = 0;
+#endif
+
+ /* Set a different seed for random() in every backend. */
+ srandom((unsigned int) (MyProcPid ^ MyStartTime));
+}
+
+
/*
* reset_shared -- reset shared memory and semaphores
*/
@@ -4315,23 +4337,8 @@ BackendRun(Port *port)
char **av;
int maxac;
int ac;
- long secs;
- int usecs;
int i;
- /*
- * Don't want backend to be able to see the postmaster random number
- * generator state. We have to clobber the static random_seed *and* start
- * a new random sequence in the random() library function.
- */
-#ifndef HAVE_STRONG_RANDOM
- random_seed = 0;
- random_start_time.tv_usec = 0;
-#endif
- /* slightly hacky way to convert timestamptz into integers */
- TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
- srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
-
/*
* Now, build the argv vector that will be given to PostgresMain.
*
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index f590ecb25e8..f35bfe813f9 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -278,6 +278,8 @@ InitPostmasterChild(void)
MyStartTime = time(NULL); /* set our start time in case we call elog */
+ InitRandomSeeds(); /* set up per-backend random seeds */
+
/*
* make sure stderr is in binary mode before anything can possibly be
* written to it, in case it's actually the syslogger pipe, so the pipe
@@ -331,7 +333,7 @@ InitStandaloneProcess(const char *argv0)
* high-entropy seed before any user query. Fewer distinct initial seeds
* can occur here.
*/
- srandom((unsigned int) (MyProcPid ^ MyStartTime));
+ InitRandomSeeds();
/* Initialize process-local latch support */
InitializeLatchSupport();
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 1877eef2391..217ef4490f4 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -48,6 +48,7 @@ extern PGDLLIMPORT const char *progname;
extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
extern void ClosePostmasterPorts(bool am_syslogger);
+extern void InitRandomSeeds(void);
extern int MaxLivePostmasterChildren(void);
--
2.17.1 (Apple Git-112)
On Tue, Oct 9, 2018 at 3:21 PM Thomas Munro
<thomas.munro@enterprisedb.com> wrote:
On Tue, Oct 9, 2018 at 1:53 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
On Mon, Oct 8, 2018 at 1:17 AM Thomas Munro
<thomas.munro@enterprisedb.com> wrote:That's because the bgworker startup path doesn't contain a call to
srandom(...distinguishing stuff...), unlike BackendRun(). I suppose
do_start_bgworker() could gain a similar call... or perhaps that call
should be moved into InitPostmasterChild(). If we put it in there
right after MyStartTime is assigned a new value, we could use the same
incantation that PostmasterMain() uses.Maybe something like this?
I think the bit with
#ifndef HAVE_STRONG_RANDOM
random_seed = 0;
random_start_time.tv_usec = 0;
#endifshould also be done in every postmaster child, no? If we want to hide the
postmaster's state from child processes, we ought to hide it from all.Ok, here is a sketch patch with a new function InitRandomSeeds() to do
that. It is called from PostmasterMain(), InitPostmasterChild() and
InitStandaloneProcess() for consistency.
Here's a version I propose to push to master and 11 tomorrow, if there
are no objections.
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Use-different-random-seeds-in-all-backends.patchapplication/octet-stream; name=0001-Use-different-random-seeds-in-all-backends.patchDownload
From 76efc715ade5c35e7b618d370b7a9e0045ae3dc0 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Tue, 9 Oct 2018 14:32:47 +1300
Subject: [PATCH] Use different random() seeds in all backends.
Background workers, including parallel workers, were generating
the same sequence of numbers in various code paths that use
random(). This was noticed by harmless DSM handle collisions
during execution of Parallel Hash, but any code that calls
random() in background workers could be affected if it cares
about different backends generating different numbers.
Repair by refactoring the seed initialization code so that all
backends run it. Use the same function for the postmaster, its
children and also standalone processes, for consistency.
Back-patch only to 11, because that's where Parallel Hash landed,
making this obvious to anyone tracing syscalls.
Author: Thomas Munro
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/CAEepm%3D2eJj_6%3DB%2B2tEpGu2nf1BjthCf9nXXUouYvJJ4C5WSwhg%40mail.gmail.com
---
src/backend/postmaster/postmaster.c | 43 +++++++++++++++++------------
src/backend/utils/init/miscinit.c | 4 ++-
src/include/postmaster/postmaster.h | 1 +
3 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 41de140ae01..9e90306f411 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -602,10 +602,10 @@ PostmasterMain(int argc, char *argv[])
*
* Note: the seed is pretty predictable from externally-visible facts such
* as postmaster start time, so avoid using random() for security-critical
- * random values during postmaster startup. At the time of first
- * connection, PostmasterRandom will select a hopefully-more-random seed.
+ * random values during postmaster startup. InitPostmasterChild() will
+ * do this again to set a new seed in child processes.
*/
- srandom((unsigned int) (MyProcPid ^ MyStartTime));
+ InitRandomSeeds();
/*
* By default, palloc() requests in the postmaster will be allocated in
@@ -2513,6 +2513,28 @@ ClosePostmasterPorts(bool am_syslogger)
}
+/*
+ * InitRandomSeeds -- initialize seeds for random number generators
+ *
+ * Called in every backend after MyProcPid and MyStartTime have been assigned.
+ */
+void
+InitRandomSeeds(void)
+{
+ /*
+ * Don't want backend to be able to see the postmaster random number
+ * generator state. We have to clobber the static random_seed.
+ */
+#ifndef HAVE_STRONG_RANDOM
+ random_seed = 0;
+ random_start_time.tv_usec = 0;
+#endif
+
+ /* Set a different seed for random() in every backend. */
+ srandom((unsigned int) (MyProcPid ^ MyStartTime));
+}
+
+
/*
* reset_shared -- reset shared memory and semaphores
*/
@@ -4315,23 +4337,8 @@ BackendRun(Port *port)
char **av;
int maxac;
int ac;
- long secs;
- int usecs;
int i;
- /*
- * Don't want backend to be able to see the postmaster random number
- * generator state. We have to clobber the static random_seed *and* start
- * a new random sequence in the random() library function.
- */
-#ifndef HAVE_STRONG_RANDOM
- random_seed = 0;
- random_start_time.tv_usec = 0;
-#endif
- /* slightly hacky way to convert timestamptz into integers */
- TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
- srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
-
/*
* Now, build the argv vector that will be given to PostgresMain.
*
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index f590ecb25e8..f35bfe813f9 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -278,6 +278,8 @@ InitPostmasterChild(void)
MyStartTime = time(NULL); /* set our start time in case we call elog */
+ InitRandomSeeds(); /* set up per-backend random seeds */
+
/*
* make sure stderr is in binary mode before anything can possibly be
* written to it, in case it's actually the syslogger pipe, so the pipe
@@ -331,7 +333,7 @@ InitStandaloneProcess(const char *argv0)
* high-entropy seed before any user query. Fewer distinct initial seeds
* can occur here.
*/
- srandom((unsigned int) (MyProcPid ^ MyStartTime));
+ InitRandomSeeds();
/* Initialize process-local latch support */
InitializeLatchSupport();
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 1877eef2391..217ef4490f4 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -48,6 +48,7 @@ extern PGDLLIMPORT const char *progname;
extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
extern void ClosePostmasterPorts(bool am_syslogger);
+extern void InitRandomSeeds(void);
extern int MaxLivePostmasterChildren(void);
--
2.17.1 (Apple Git-112)
Thomas Munro <thomas.munro@enterprisedb.com> writes:
Ok, here is a sketch patch with a new function InitRandomSeeds() to do
that. It is called from PostmasterMain(), InitPostmasterChild() and
InitStandaloneProcess() for consistency.
Here's a version I propose to push to master and 11 tomorrow, if there
are no objections.
The comment adjacent to the change in InitStandaloneProcess bothers me.
In particular, it points out that what BackendRun() is currently doing
creates more entropy in the process's random seed than what you have
here: MyStartTime is only good to the nearest second, whereas the code
you removed from BackendRun() factors in fractional seconds to whatever
the precision of GetCurrentTimestamp is. This does not seem like an
improvement.
I'm inclined to think we should refactor a bit more aggressively so
that, rather than dumbing backends down to the standard of other
processes, we make them all use the better method. A reasonable way
to approach this would be to invent a global variable MyStartTimestamp
beside MyStartTime, and initialize both of them in the places that
currently initialize the latter, using code like that in
BackendInitialize:
/* save process start time */
port->SessionStartTime = GetCurrentTimestamp();
MyStartTime = timestamptz_to_time_t(port->SessionStartTime);
and then this new InitRandomSeeds function could adopt BackendRun's
seed initialization method instead of the stupider way.
Possibly it'd be sane to merge the MyStartTime* initializations
and the srandom resets into one function, not sure.
regards, tom lane
On Thu, Oct 11, 2018 at 5:51 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
The comment adjacent to the change in InitStandaloneProcess bothers me.
In particular, it points out that what BackendRun() is currently doing
creates more entropy in the process's random seed than what you have
here: MyStartTime is only good to the nearest second, whereas the code
you removed from BackendRun() factors in fractional seconds to whatever
the precision of GetCurrentTimestamp is. This does not seem like an
improvement.
True.
I'm inclined to think we should refactor a bit more aggressively so
that, rather than dumbing backends down to the standard of other
processes, we make them all use the better method. A reasonable way
to approach this would be to invent a global variable MyStartTimestamp
beside MyStartTime, and initialize both of them in the places that
currently initialize the latter, using code like that in
BackendInitialize:/* save process start time */
port->SessionStartTime = GetCurrentTimestamp();
MyStartTime = timestamptz_to_time_t(port->SessionStartTime);and then this new InitRandomSeeds function could adopt BackendRun's
seed initialization method instead of the stupider way.
Ok, done.
With MyStartTimestamp in the picture, port->SessionStartTime is
probably redundant... <looks around> and in fact the comment in struct
Port says it shouldn't even be there. So... I removed it, and used
the new MyStartTimestamp in the couple of places that wanted it.
Thoughts?
Possibly it'd be sane to merge the MyStartTime* initializations
and the srandom resets into one function, not sure.
+1
The main difficulty was coming up with a name for the function that
does those things. I went with InitProcessGlobals(). Better
suggestions welcome.
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Refactor-random-seed-and-start-time-initialization.patchapplication/octet-stream; name=0001-Refactor-random-seed-and-start-time-initialization.patchDownload
From 4896c92548026c79d0637a47938520ca9454c93d Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Tue, 9 Oct 2018 14:32:47 +1300
Subject: [PATCH] Refactor random seed and start time initialization.
Background workers, including parallel workers, were generating
the same sequence of numbers in random(). This showed up as DSM
handle collisions when Parallel Hash created multiple segments,
but any code that calls random() in background workers could be
affected if it cares about different backends generating different
numbers.
Repair by making sure that all new processes initialize the seed
at the same time as they set MyProcPid and MyStartTime in a new
function InitProcessGlobals(), called by the postmaster, its
children and also standalone processes. Also Add a new high
resolution MyStartTimestamp as a potentially useful by-product,
and remove SessionStartTime from struct Port as it is now
redundant.
Back-patch only to 11, because that's where Parallel Hash landed,
making the problem obvious to anyone tracing DSM-related syscalls.
Author: Thomas Munro
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/CAEepm%3D2eJj_6%3DB%2B2tEpGu2nf1BjthCf9nXXUouYvJJ4C5WSwhg%40mail.gmail.com
---
src/backend/postmaster/pgstat.c | 10 +----
src/backend/postmaster/postmaster.c | 60 ++++++++++++++---------------
src/backend/tcop/postgres.c | 2 +-
src/backend/utils/init/globals.c | 1 +
src/backend/utils/init/miscinit.c | 16 +-------
src/include/libpq/libpq-be.h | 7 ----
src/include/miscadmin.h | 2 +
src/include/postmaster/postmaster.h | 1 +
8 files changed, 37 insertions(+), 62 deletions(-)
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 8a5b2b3b420..8de603d1933 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2784,21 +2784,13 @@ pgstat_initialize(void)
void
pgstat_bestart(void)
{
- TimestampTz proc_start_timestamp;
SockAddr clientaddr;
volatile PgBackendStatus *beentry;
/*
* To minimize the time spent modifying the PgBackendStatus entry, fetch
* all the needed data first.
- *
- * If we have a MyProcPort, use its session start time (for consistency,
- * and to save a kernel call).
*/
- if (MyProcPort)
- proc_start_timestamp = MyProcPort->SessionStartTime;
- else
- proc_start_timestamp = GetCurrentTimestamp();
/*
* We may not have a MyProcPort (eg, if this is the autovacuum process).
@@ -2883,7 +2875,7 @@ pgstat_bestart(void)
} while ((beentry->st_changecount & 1) == 0);
beentry->st_procpid = MyProcPid;
- beentry->st_proc_start_timestamp = proc_start_timestamp;
+ beentry->st_proc_start_timestamp = MyStartTimestamp;
beentry->st_activity_start_timestamp = 0;
beentry->st_state_start_timestamp = 0;
beentry->st_xact_start_timestamp = 0;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 41de140ae01..688f462e7d0 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -129,6 +129,7 @@
#include "utils/pidfile.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
+#include "utils/timestamp.h"
#include "utils/varlena.h"
#ifdef EXEC_BACKEND
@@ -581,9 +582,9 @@ PostmasterMain(int argc, char *argv[])
int i;
char *output_config_variable = NULL;
- MyProcPid = PostmasterPid = getpid();
+ InitProcessGlobals();
- MyStartTime = time(NULL);
+ PostmasterPid = MyProcPid;
IsPostmasterEnvironment = true;
@@ -597,16 +598,6 @@ PostmasterMain(int argc, char *argv[])
*/
umask(PG_MODE_MASK_OWNER);
- /*
- * Initialize random(3) so we don't get the same values in every run.
- *
- * Note: the seed is pretty predictable from externally-visible facts such
- * as postmaster start time, so avoid using random() for security-critical
- * random values during postmaster startup. At the time of first
- * connection, PostmasterRandom will select a hopefully-more-random seed.
- */
- srandom((unsigned int) (MyProcPid ^ MyStartTime));
-
/*
* By default, palloc() requests in the postmaster will be allocated in
* the PostmasterContext, which is space that can be recycled by backends.
@@ -2513,6 +2504,32 @@ ClosePostmasterPorts(bool am_syslogger)
}
+/*
+ * InitProcessGlobals -- set MyProcPid, MyStartTime[stamp], random seeds
+ *
+ * Called early in every backend.
+ */
+void
+InitProcessGlobals(void)
+{
+ MyProcPid = getpid();
+ MyStartTimestamp = GetCurrentTimestamp();
+ MyStartTime = timestamptz_to_time_t(MyStartTimestamp);
+
+ /*
+ * Don't want backend to be able to see the postmaster random number
+ * generator state. We have to clobber the static random_seed.
+ */
+#ifndef HAVE_STRONG_RANDOM
+ random_seed = 0;
+ random_start_time.tv_usec = 0;
+#endif
+
+ /* Set a different seed for random() in every backend. */
+ srandom((unsigned int) MyProcPid ^ (unsigned int) MyStartTimestamp);
+}
+
+
/*
* reset_shared -- reset shared memory and semaphores
*/
@@ -4154,10 +4171,6 @@ BackendInitialize(Port *port)
/* This flag will remain set until InitPostgres finishes authentication */
ClientAuthInProgress = true; /* limit visibility of log messages */
- /* save process start time */
- port->SessionStartTime = GetCurrentTimestamp();
- MyStartTime = timestamptz_to_time_t(port->SessionStartTime);
-
/* set these to empty in case they are needed before we set them up */
port->remote_host = "";
port->remote_port = "";
@@ -4315,23 +4328,8 @@ BackendRun(Port *port)
char **av;
int maxac;
int ac;
- long secs;
- int usecs;
int i;
- /*
- * Don't want backend to be able to see the postmaster random number
- * generator state. We have to clobber the static random_seed *and* start
- * a new random sequence in the random() library function.
- */
-#ifndef HAVE_STRONG_RANDOM
- random_seed = 0;
- random_start_time.tv_usec = 0;
-#endif
- /* slightly hacky way to convert timestamptz into integers */
- TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
- srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
-
/*
* Now, build the argv vector that will be given to PostgresMain.
*
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index e4c6e3d406e..6e13d14fcd0 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4632,7 +4632,7 @@ log_disconnections(int code, Datum arg)
minutes,
seconds;
- TimestampDifference(port->SessionStartTime,
+ TimestampDifference(MyStartTimestamp,
GetCurrentTimestamp(),
&secs, &usecs);
msecs = usecs / 1000;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 5971310aabb..c6939779b98 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -39,6 +39,7 @@ volatile uint32 CritSectionCount = 0;
int MyProcPid;
pg_time_t MyStartTime;
+TimestampTz MyStartTimestamp;
struct Port *MyProcPort;
int32 MyCancelKey;
int MyPMChildSlot;
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index f590ecb25e8..238fe1deec8 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -274,9 +274,7 @@ InitPostmasterChild(void)
{
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
- MyProcPid = getpid(); /* reset MyProcPid */
-
- MyStartTime = time(NULL); /* set our start time in case we call elog */
+ InitProcessGlobals();
/*
* make sure stderr is in binary mode before anything can possibly be
@@ -321,17 +319,7 @@ InitStandaloneProcess(const char *argv0)
{
Assert(!IsPostmasterEnvironment);
- MyProcPid = getpid(); /* reset MyProcPid */
-
- MyStartTime = time(NULL); /* set our start time in case we call elog */
-
- /*
- * Initialize random() for the first time, like PostmasterMain() would.
- * In a regular IsUnderPostmaster backend, BackendRun() computes a
- * high-entropy seed before any user query. Fewer distinct initial seeds
- * can occur here.
- */
- srandom((unsigned int) (MyProcPid ^ MyStartTime));
+ InitProcessGlobals();
/* Initialize process-local latch support */
InitializeLatchSupport();
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index eb8bba4ed88..b2c59df54e4 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -150,13 +150,6 @@ typedef struct Port
*/
HbaLine *hba;
- /*
- * Information that really has no business at all being in struct Port,
- * but since it gets used by elog.c in the same way as database_name and
- * other members of this struct, we may as well keep it here.
- */
- TimestampTz SessionStartTime; /* backend start time */
-
/*
* TCP keepalive settings.
*
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 69f356f8cdb..d6b32c070c2 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -25,6 +25,7 @@
#include <signal.h>
+#include "datatype/timestamp.h" /* for TimestampTZ */
#include "pgtime.h" /* for pg_time_t */
@@ -163,6 +164,7 @@ extern PGDLLIMPORT int max_parallel_workers;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;
+extern PGDLLIMPORT TimestampTz MyStartTimestamp;
extern PGDLLIMPORT struct Port *MyProcPort;
extern PGDLLIMPORT struct Latch *MyLatch;
extern int32 MyCancelKey;
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 1877eef2391..a40d66e8906 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -48,6 +48,7 @@ extern PGDLLIMPORT const char *progname;
extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
extern void ClosePostmasterPorts(bool am_syslogger);
+extern void InitProcessGlobals(void);
extern int MaxLivePostmasterChildren(void);
--
2.17.1 (Apple Git-112)
On Sat, Oct 13, 2018 at 11:45 PM Thomas Munro
<thomas.munro@enterprisedb.com> wrote:
On Thu, Oct 11, 2018 at 5:51 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
The comment adjacent to the change in InitStandaloneProcess bothers me.
In particular, it points out that what BackendRun() is currently doing
creates more entropy in the process's random seed than what you have
here: MyStartTime is only good to the nearest second, whereas the code
you removed from BackendRun() factors in fractional seconds to whatever
the precision of GetCurrentTimestamp is. This does not seem like an
improvement.True.
I'm inclined to think we should refactor a bit more aggressively so
that, rather than dumbing backends down to the standard of other
processes, we make them all use the better method. A reasonable way
to approach this would be to invent a global variable MyStartTimestamp
beside MyStartTime, and initialize both of them in the places that
currently initialize the latter, using code like that in
BackendInitialize:/* save process start time */
port->SessionStartTime = GetCurrentTimestamp();
MyStartTime = timestamptz_to_time_t(port->SessionStartTime);and then this new InitRandomSeeds function could adopt BackendRun's
seed initialization method instead of the stupider way.Ok, done.
With MyStartTimestamp in the picture, port->SessionStartTime is
probably redundant... <looks around> and in fact the comment in struct
Port says it shouldn't even be there. So... I removed it, and used
the new MyStartTimestamp in the couple of places that wanted it.
Thoughts?Possibly it'd be sane to merge the MyStartTime* initializations
and the srandom resets into one function, not sure.+1
The main difficulty was coming up with a name for the function that
does those things. I went with InitProcessGlobals(). Better
suggestions welcome.
Pushed to master only.
--
Thomas Munro
http://www.enterprisedb.com
On Sat, Oct 13, 2018 at 11:45:17PM +1300, Thomas Munro wrote:
+ /* Set a different seed for random() in every backend. */ + srandom((unsigned int) MyProcPid ^ (unsigned int) MyStartTimestamp);
- TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
- srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
Compared to the old code, the new code requires more wall time to visit every
possible seed value. New code xor's the PID bits into the fastest-changing
timestamp bits, so only about twenty bits can vary within any given one-second
period. (That assumes a PID space of twenty or fewer bits; fifteen bits is
the Linux default.) Is that aspect of the change justified?
On Mon, Nov 12, 2018 at 9:34 PM Noah Misch <noah@leadboat.com> wrote:
On Sat, Oct 13, 2018 at 11:45:17PM +1300, Thomas Munro wrote:
+ /* Set a different seed for random() in every backend. */ + srandom((unsigned int) MyProcPid ^ (unsigned int) MyStartTimestamp);- TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
- srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));Compared to the old code, the new code requires more wall time to visit every
possible seed value. New code xor's the PID bits into the fastest-changing
timestamp bits, so only about twenty bits can vary within any given one-second
period. (That assumes a PID space of twenty or fewer bits; fifteen bits is
the Linux default.) Is that aspect of the change justified?
Hmm, right. How about applying pg_bswap32() to one of the terms, as
an easy approximation of reversing the bits?
--
Thomas Munro
http://www.enterprisedb.com
Thomas Munro <thomas.munro@enterprisedb.com> writes:
On Mon, Nov 12, 2018 at 9:34 PM Noah Misch <noah@leadboat.com> wrote:
Compared to the old code, the new code requires more wall time to visit every
possible seed value. New code xor's the PID bits into the fastest-changing
timestamp bits, so only about twenty bits can vary within any given one-second
period. (That assumes a PID space of twenty or fewer bits; fifteen bits is
the Linux default.) Is that aspect of the change justified?
Hmm, right. How about applying pg_bswap32() to one of the terms, as
an easy approximation of reversing the bits?
I doubt that's a good idea; to a first approximation, it would mean that
half the seed depends only on the PID and the other half only on the
timestamp. Maybe we could improve matters a little by left-shifting the
PID four bits or so, but I think we still want it to mix with some
rapidly-changing time bits.
I'm not really sure that we need to do anything though. Basically,
what we've got here is a tradeoff between how many bits change over
a given timespan and how unpredictable those bits are. I don't see
that one of those is necessarily more important than the other.
regards, tom lane
On Mon, Nov 12, 2018 at 09:39:01AM -0500, Tom Lane wrote:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
On Mon, Nov 12, 2018 at 9:34 PM Noah Misch <noah@leadboat.com> wrote:
Compared to the old code, the new code requires more wall time to visit every
possible seed value. New code xor's the PID bits into the fastest-changing
timestamp bits, so only about twenty bits can vary within any given one-second
period. (That assumes a PID space of twenty or fewer bits; fifteen bits is
the Linux default.) Is that aspect of the change justified?Hmm, right. How about applying pg_bswap32() to one of the terms, as
an easy approximation of reversing the bits?
That seems adequate, yes. But why not just restore the old algorithm in the
new function? (I'm not opposed to revising the algorithm, but I think a
revision should have explicit goals. The ease of pg_bswap32() is not itself a
worthy goal, because the old BackendRun() algorithm was also quite easy.)
I doubt that's a good idea; to a first approximation, it would mean that
half the seed depends only on the PID and the other half only on the
timestamp. Maybe we could improve matters a little by left-shifting the
PID four bits or so, but I think we still want it to mix with some
rapidly-changing time bits.I'm not really sure that we need to do anything though. Basically,
what we've got here is a tradeoff between how many bits change over
a given timespan and how unpredictable those bits are. I don't see
that one of those is necessarily more important than the other.
What counts is the ease of predicting a complete seed. HEAD's algorithm has
~13 trivially-predictable bits, and the algorithm that stood in BackendRun()
from 98c5065 until 197e4af had no such bits. You're right that the other 19
bits are harder to predict than any given 19 bits under the old algorithm, but
the complete seed remains more predictable than it was before 197e4af.
Goal I recommend: if connections arrive in a Poisson distribution of unknown
lambda, maximize the number of distinct seeds.
nm
On Wed, Nov 14, 2018 at 3:24 PM Noah Misch <noah@leadboat.com> wrote:
On Mon, Nov 12, 2018 at 09:39:01AM -0500, Tom Lane wrote:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
On Mon, Nov 12, 2018 at 9:34 PM Noah Misch <noah@leadboat.com> wrote:
Compared to the old code, the new code requires more wall time to visit every
possible seed value. New code xor's the PID bits into the fastest-changing
timestamp bits, so only about twenty bits can vary within any given one-second
period. (That assumes a PID space of twenty or fewer bits; fifteen bits is
the Linux default.) Is that aspect of the change justified?Hmm, right. How about applying pg_bswap32() to one of the terms, as
an easy approximation of reversing the bits?That seems adequate, yes. But why not just restore the old algorithm in the
new function? (I'm not opposed to revising the algorithm, but I think a
revision should have explicit goals. The ease of pg_bswap32() is not itself a
worthy goal, because the old BackendRun() algorithm was also quite easy.)
Ok. I rewrote it only because in the new coding I had a TimestampTz
rather than the separate sec and usec components of the old code. I
didn't intend to revise the algorithm fundamentally, but I missed the
significance of the bit shifting from commit 98c50656c that moved the
faster moving bits up. I'll change it back.
I doubt that's a good idea; to a first approximation, it would mean that
half the seed depends only on the PID and the other half only on the
timestamp. Maybe we could improve matters a little by left-shifting the
PID four bits or so, but I think we still want it to mix with some
rapidly-changing time bits.I'm not really sure that we need to do anything though. Basically,
what we've got here is a tradeoff between how many bits change over
a given timespan and how unpredictable those bits are. I don't see
that one of those is necessarily more important than the other.What counts is the ease of predicting a complete seed. HEAD's algorithm has
~13 trivially-predictable bits, and the algorithm that stood in BackendRun()
from 98c5065 until 197e4af had no such bits. You're right that the other 19
bits are harder to predict than any given 19 bits under the old algorithm, but
the complete seed remains more predictable than it was before 197e4af.
However we mix them, given that the source code is well known, isn't
an attacker's job really to predict the time and pid, two not
especially well guarded secrets? I don't see how the mixing matters
in that respect. (You can also just clobber the seed from SQL, but
that'd be cheating.)
Goal I recommend: if connections arrive in a Poisson distribution of unknown
lambda, maximize the number of distinct seeds.
Yeah. I think bit reversing one of them achieves the maximum number
of distinct seeds by putting the busy ends far apart, but the original
bit shifting is similar.
--
Thomas Munro
http://www.enterprisedb.com
On Wed, Nov 14, 2018 at 05:50:26PM +1300, Thomas Munro wrote:
On Wed, Nov 14, 2018 at 3:24 PM Noah Misch <noah@leadboat.com> wrote:
On Mon, Nov 12, 2018 at 09:39:01AM -0500, Tom Lane wrote:
I doubt that's a good idea; to a first approximation, it would mean that
half the seed depends only on the PID and the other half only on the
timestamp. Maybe we could improve matters a little by left-shifting the
PID four bits or so, but I think we still want it to mix with some
rapidly-changing time bits.I'm not really sure that we need to do anything though. Basically,
what we've got here is a tradeoff between how many bits change over
a given timespan and how unpredictable those bits are. I don't see
that one of those is necessarily more important than the other.What counts is the ease of predicting a complete seed. HEAD's algorithm has
~13 trivially-predictable bits, and the algorithm that stood in BackendRun()
from 98c5065 until 197e4af had no such bits. You're right that the other 19
bits are harder to predict than any given 19 bits under the old algorithm, but
the complete seed remains more predictable than it was before 197e4af.However we mix them, given that the source code is well known, isn't
an attacker's job really to predict the time and pid, two not
especially well guarded secrets?
True. Better to frame the issue as uniform distribution of seed, not
unpredictability of seed selection.
Incidentally, possible future work may be to use pg_strong_random() when
available, like pgbench set_random_seed() does. That would achieve both
unpredictability and uniform distribution. It would be mere defense in depth;
if unpredictability matters, one still needs a CSPRNG (e.g. pgcrypto).
On Wed, Nov 14, 2018 at 6:34 PM Noah Misch <noah@leadboat.com> wrote:
On Wed, Nov 14, 2018 at 05:50:26PM +1300, Thomas Munro wrote:
On Wed, Nov 14, 2018 at 3:24 PM Noah Misch <noah@leadboat.com> wrote:
What counts is the ease of predicting a complete seed. HEAD's algorithm has
~13 trivially-predictable bits, and the algorithm that stood in BackendRun()
from 98c5065 until 197e4af had no such bits. You're right that the other 19
bits are harder to predict than any given 19 bits under the old algorithm, but
the complete seed remains more predictable than it was before 197e4af.However we mix them, given that the source code is well known, isn't
an attacker's job really to predict the time and pid, two not
especially well guarded secrets?True. Better to frame the issue as uniform distribution of seed, not
unpredictability of seed selection.
What do you think about the attached?
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Increase-the-number-of-possible-random-seeds-per-tim.patchapplication/octet-stream; name=0001-Increase-the-number-of-possible-random-seeds-per-tim.patchDownload
From 7518c2b42afd21e7fcedcefb3e4dda65b9e9920d Mon Sep 17 00:00:00 2001
From: Thomas Munro <tmunro@postgresql.org>
Date: Wed, 14 Nov 2018 19:36:14 +1300
Subject: [PATCH] Increase the number of possible random seeds per time period.
Commit 197e4af9 refactored the initialization of the libc random()
seed, but reduced the number of possible seeds values that could be
chosen in a given time period. This negation of the effects of
commit 98c50656c was unintentional. Replace with code that
shifts the fast moving timestamp bits left, like the earlier code.
Author: Thomas Munro
Reported-by: Noah Misch
Reviewed-by:
Discussion: https://postgr.es/m/20181112083358.GA1073796%40rfd.leadboat.com
---
src/backend/postmaster/postmaster.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 688f462e7d..d64d554022 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -2525,8 +2525,14 @@ InitProcessGlobals(void)
random_start_time.tv_usec = 0;
#endif
- /* Set a different seed for random() in every backend. */
- srandom((unsigned int) MyProcPid ^ (unsigned int) MyStartTimestamp);
+ /*
+ * Set a different seed for random() in every backend. Since PIDs and
+ * timestamps tend to change more frequently in their least significant
+ * bits, shift the timestamp left to allow a larger total number of seeds
+ * in a given time period. Since that would leave only 20 bits of the
+ * timestamp that cycle every ~1 second, also mix in some higher bits.
+ */
+ srandom(MyProcPid ^ (MyStartTimestamp << 12) ^ (MyStartTimestamp >> 20));
}
--
2.19.1
On Wed, Nov 14, 2018 at 08:22:42PM +1300, Thomas Munro wrote:
On Wed, Nov 14, 2018 at 6:34 PM Noah Misch <noah@leadboat.com> wrote:
On Wed, Nov 14, 2018 at 05:50:26PM +1300, Thomas Munro wrote:
On Wed, Nov 14, 2018 at 3:24 PM Noah Misch <noah@leadboat.com> wrote:
What counts is the ease of predicting a complete seed. HEAD's algorithm has
~13 trivially-predictable bits, and the algorithm that stood in BackendRun()
from 98c5065 until 197e4af had no such bits. You're right that the other 19
bits are harder to predict than any given 19 bits under the old algorithm, but
the complete seed remains more predictable than it was before 197e4af.However we mix them, given that the source code is well known, isn't
an attacker's job really to predict the time and pid, two not
especially well guarded secrets?True. Better to frame the issue as uniform distribution of seed, not
unpredictability of seed selection.What do you think about the attached?
You mentioned that you rewrote the algorithm because the new function had a
TimestampTz. But the BackendRun() code, which it replaced, also had a
TimestampTz. You can reuse the exact algorithm. Is there a reason to change?
On Wed, Nov 14, 2018 at 8:52 PM Noah Misch <noah@leadboat.com> wrote:
On Wed, Nov 14, 2018 at 08:22:42PM +1300, Thomas Munro wrote:
On Wed, Nov 14, 2018 at 6:34 PM Noah Misch <noah@leadboat.com> wrote:
On Wed, Nov 14, 2018 at 05:50:26PM +1300, Thomas Munro wrote:
On Wed, Nov 14, 2018 at 3:24 PM Noah Misch <noah@leadboat.com> wrote:
What counts is the ease of predicting a complete seed. HEAD's algorithm has
~13 trivially-predictable bits, and the algorithm that stood in BackendRun()
from 98c5065 until 197e4af had no such bits. You're right that the other 19
bits are harder to predict than any given 19 bits under the old algorithm, but
the complete seed remains more predictable than it was before 197e4af.However we mix them, given that the source code is well known, isn't
an attacker's job really to predict the time and pid, two not
especially well guarded secrets?True. Better to frame the issue as uniform distribution of seed, not
unpredictability of seed selection.What do you think about the attached?
You mentioned that you rewrote the algorithm because the new function had a
TimestampTz. But the BackendRun() code, which it replaced, also had a
TimestampTz. You can reuse the exact algorithm. Is there a reason to change?
The old code used a "slightly hacky way to convert timestamptz into
integers" because TimestampTz might have been floating point back in
the day. Now that TimestampTz is always an integer, we might as well
use it directly and shuffle its bits for the same general effect, no?
The difference between x >> 20 and x / USECS_PER_SEC doesn't seem to
be material.
--
Thomas Munro
http://www.enterprisedb.com
Thomas Munro <thomas.munro@enterprisedb.com> writes:
What do you think about the attached?
I think you need to cast MyStartTimestamp to uint64 before shifting
to ensure portable behavior of the shifts. In principle it wouldn't
matter because the int64 sign bit is nowhere near the part we care
about, but I've heard some pretty wild claims about what compiler
writers are entitled to do with "undefined" cases.
regards, tom lane
On Thu, Nov 15, 2018 at 4:25 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
What do you think about the attached?
I think you need to cast MyStartTimestamp to uint64 before shifting
to ensure portable behavior of the shifts. In principle it wouldn't
matter because the int64 sign bit is nowhere near the part we care
about, but I've heard some pretty wild claims about what compiler
writers are entitled to do with "undefined" cases.
Thanks. Pushed.
--
Thomas Munro
http://www.enterprisedb.com