Skip to content

Commit af259c6

Browse files
committed
Fix unsafe references to errno within error messaging logic.
Various places were supposing that errno could be expected to hold still within an ereport() nest or similar contexts. This isn't true necessarily, though in some cases it accidentally failed to fail depending on how the compiler chanced to order the subexpressions. This class of thinko explains recent reports of odd failures on clang-built versions, typically missing or inappropriate HINT fields in messages. Problem identified by Christian Kruse, who also submitted the patch this commit is based on. (I fixed a few issues in his patch and found a couple of additional places with the same disease.) Back-patch as appropriate to all supported branches.
1 parent 1b384af commit af259c6

File tree

3 files changed

+24
-15
lines changed

3 files changed

+24
-15
lines changed

src/backend/commands/tablespace.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,10 +769,14 @@ destroy_tablespace_directories(Oid tablespaceoid, bool redo)
769769
else
770770
{
771771
if (unlink(linkloc) < 0)
772-
ereport(redo ? LOG : (errno == ENOENT ? WARNING : ERROR),
772+
{
773+
int saved_errno = errno;
774+
775+
ereport(redo ? LOG : (saved_errno == ENOENT ? WARNING : ERROR),
773776
(errcode_for_file_access(),
774777
errmsg("could not remove symbolic link \"%s\": %m",
775778
linkloc)));
779+
}
776780
}
777781

778782
pfree(linkloc_with_version_dir);

src/backend/port/sysv_sema.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,17 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey, int numSems)
9494

9595
if (semId < 0)
9696
{
97+
int saved_errno = errno;
98+
9799
/*
98100
* Fail quietly if error indicates a collision with existing set. One
99101
* would expect EEXIST, given that we said IPC_EXCL, but perhaps we
100102
* could get a permission violation instead? Also, EIDRM might occur
101103
* if an old set is slated for destruction but not gone yet.
102104
*/
103-
if (errno == EEXIST || errno == EACCES
105+
if (saved_errno == EEXIST || saved_errno == EACCES
104106
#ifdef EIDRM
105-
|| errno == EIDRM
107+
|| saved_errno == EIDRM
106108
#endif
107109
)
108110
return -1;
@@ -115,7 +117,7 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey, int numSems)
115117
errdetail("Failed system call was semget(%lu, %d, 0%o).",
116118
(unsigned long) semKey, numSems,
117119
IPC_CREAT | IPC_EXCL | IPCProtection),
118-
(errno == ENOSPC) ?
120+
(saved_errno == ENOSPC) ?
119121
errhint("This error does *not* mean that you have run out of disk space. "
120122
"It occurs when either the system limit for the maximum number of "
121123
"semaphore sets (SEMMNI), or the system wide maximum number of "
@@ -139,13 +141,17 @@ IpcSemaphoreInitialize(IpcSemaphoreId semId, int semNum, int value)
139141

140142
semun.val = value;
141143
if (semctl(semId, semNum, SETVAL, semun) < 0)
144+
{
145+
int saved_errno = errno;
146+
142147
ereport(FATAL,
143148
(errmsg_internal("semctl(%d, %d, SETVAL, %d) failed: %m",
144149
semId, semNum, value),
145-
(errno == ERANGE) ?
150+
(saved_errno == ERANGE) ?
146151
errhint("You possibly need to raise your kernel's SEMVMX value to be at least "
147152
"%d. Look into the PostgreSQL documentation for details.",
148153
value) : 0));
154+
}
149155
}
150156

151157
/*

src/backend/port/sysv_shmem.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,17 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
7979

8080
if (shmid < 0)
8181
{
82+
int shmget_errno = errno;
83+
8284
/*
8385
* Fail quietly if error indicates a collision with existing segment.
8486
* One would expect EEXIST, given that we said IPC_EXCL, but perhaps
8587
* we could get a permission violation instead? Also, EIDRM might
8688
* occur if an old seg is slated for destruction but not gone yet.
8789
*/
88-
if (errno == EEXIST || errno == EACCES
90+
if (shmget_errno == EEXIST || shmget_errno == EACCES
8991
#ifdef EIDRM
90-
|| errno == EIDRM
92+
|| shmget_errno == EIDRM
9193
#endif
9294
)
9395
return NULL;
@@ -101,10 +103,8 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
101103
* against SHMMIN in the preexisting-segment case, so we will not get
102104
* EINVAL a second time if there is such a segment.
103105
*/
104-
if (errno == EINVAL)
106+
if (shmget_errno == EINVAL)
105107
{
106-
int save_errno = errno;
107-
108108
shmid = shmget(memKey, 0, IPC_CREAT | IPC_EXCL | IPCProtection);
109109

110110
if (shmid < 0)
@@ -130,8 +130,6 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
130130
elog(LOG, "shmctl(%d, %d, 0) failed: %m",
131131
(int) shmid, IPC_RMID);
132132
}
133-
134-
errno = save_errno;
135133
}
136134

137135
/*
@@ -143,12 +141,13 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
143141
* it should be. SHMMNI violation is ENOSPC, per spec. Just plain
144142
* not-enough-RAM is ENOMEM.
145143
*/
144+
errno = shmget_errno;
146145
ereport(FATAL,
147146
(errmsg("could not create shared memory segment: %m"),
148147
errdetail("Failed system call was shmget(key=%lu, size=%lu, 0%o).",
149148
(unsigned long) memKey, (unsigned long) size,
150149
IPC_CREAT | IPC_EXCL | IPCProtection),
151-
(errno == EINVAL) ?
150+
(shmget_errno == EINVAL) ?
152151
errhint("This error usually means that PostgreSQL's request for a shared memory "
153152
"segment exceeded your kernel's SHMMAX parameter. You can either "
154153
"reduce the request size or reconfigure the kernel with larger SHMMAX. "
@@ -161,7 +160,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
161160
"The PostgreSQL documentation contains more information about shared "
162161
"memory configuration.",
163162
(unsigned long) size) : 0,
164-
(errno == ENOMEM) ?
163+
(shmget_errno == ENOMEM) ?
165164
errhint("This error usually means that PostgreSQL's request for a shared "
166165
"memory segment exceeded available memory or swap space, "
167166
"or exceeded your kernel's SHMALL parameter. You can either "
@@ -172,7 +171,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
172171
"The PostgreSQL documentation contains more information about shared "
173172
"memory configuration.",
174173
(unsigned long) size) : 0,
175-
(errno == ENOSPC) ?
174+
(shmget_errno == ENOSPC) ?
176175
errhint("This error does *not* mean that you have run out of disk space. "
177176
"It occurs either if all available shared memory IDs have been taken, "
178177
"in which case you need to raise the SHMMNI parameter in your kernel, "

0 commit comments

Comments
 (0)