Skip to content

Commit 3e71ce1

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 ea311bf commit 3e71ce1

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
@@ -774,10 +774,14 @@ destroy_tablespace_directories(Oid tablespaceoid, bool redo)
774774
else
775775
{
776776
if (unlink(linkloc) < 0)
777-
ereport(redo ? LOG : (errno == ENOENT ? WARNING : ERROR),
777+
{
778+
int saved_errno = errno;
779+
780+
ereport(redo ? LOG : (saved_errno == ENOENT ? WARNING : ERROR),
778781
(errcode_for_file_access(),
779782
errmsg("could not remove symbolic link \"%s\": %m",
780783
linkloc)));
784+
}
781785
}
782786

783787
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
@@ -91,15 +91,17 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey, int numSems)
9191

9292
if (semId < 0)
9393
{
94+
int saved_errno = errno;
95+
9496
/*
9597
* Fail quietly if error indicates a collision with existing set. One
9698
* would expect EEXIST, given that we said IPC_EXCL, but perhaps we
9799
* could get a permission violation instead? Also, EIDRM might occur
98100
* if an old set is slated for destruction but not gone yet.
99101
*/
100-
if (errno == EEXIST || errno == EACCES
102+
if (saved_errno == EEXIST || saved_errno == EACCES
101103
#ifdef EIDRM
102-
|| errno == EIDRM
104+
|| saved_errno == EIDRM
103105
#endif
104106
)
105107
return -1;
@@ -112,7 +114,7 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey, int numSems)
112114
errdetail("Failed system call was semget(%lu, %d, 0%o).",
113115
(unsigned long) semKey, numSems,
114116
IPC_CREAT | IPC_EXCL | IPCProtection),
115-
(errno == ENOSPC) ?
117+
(saved_errno == ENOSPC) ?
116118
errhint("This error does *not* mean that you have run out of disk space. "
117119
"It occurs when either the system limit for the maximum number of "
118120
"semaphore sets (SEMMNI), or the system wide maximum number of "
@@ -136,13 +138,17 @@ IpcSemaphoreInitialize(IpcSemaphoreId semId, int semNum, int value)
136138

137139
semun.val = value;
138140
if (semctl(semId, semNum, SETVAL, semun) < 0)
141+
{
142+
int saved_errno = errno;
143+
139144
ereport(FATAL,
140145
(errmsg_internal("semctl(%d, %d, SETVAL, %d) failed: %m",
141146
semId, semNum, value),
142-
(errno == ERANGE) ?
147+
(saved_errno == ERANGE) ?
143148
errhint("You possibly need to raise your kernel's SEMVMX value to be at least "
144149
"%d. Look into the PostgreSQL documentation for details.",
145150
value) : 0));
151+
}
146152
}
147153

148154
/*

src/backend/port/sysv_shmem.c

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

7777
if (shmid < 0)
7878
{
79+
int shmget_errno = errno;
80+
7981
/*
8082
* Fail quietly if error indicates a collision with existing segment.
8183
* One would expect EEXIST, given that we said IPC_EXCL, but perhaps
8284
* we could get a permission violation instead? Also, EIDRM might
8385
* occur if an old seg is slated for destruction but not gone yet.
8486
*/
85-
if (errno == EEXIST || errno == EACCES
87+
if (shmget_errno == EEXIST || shmget_errno == EACCES
8688
#ifdef EIDRM
87-
|| errno == EIDRM
89+
|| shmget_errno == EIDRM
8890
#endif
8991
)
9092
return NULL;
@@ -98,10 +100,8 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
98100
* against SHMMIN in the preexisting-segment case, so we will not get
99101
* EINVAL a second time if there is such a segment.
100102
*/
101-
if (errno == EINVAL)
103+
if (shmget_errno == EINVAL)
102104
{
103-
int save_errno = errno;
104-
105105
shmid = shmget(memKey, 0, IPC_CREAT | IPC_EXCL | IPCProtection);
106106

107107
if (shmid < 0)
@@ -127,8 +127,6 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
127127
elog(LOG, "shmctl(%d, %d, 0) failed: %m",
128128
(int) shmid, IPC_RMID);
129129
}
130-
131-
errno = save_errno;
132130
}
133131

134132
/*
@@ -140,12 +138,13 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
140138
* it should be. SHMMNI violation is ENOSPC, per spec. Just plain
141139
* not-enough-RAM is ENOMEM.
142140
*/
141+
errno = shmget_errno;
143142
ereport(FATAL,
144143
(errmsg("could not create shared memory segment: %m"),
145144
errdetail("Failed system call was shmget(key=%lu, size=%lu, 0%o).",
146145
(unsigned long) memKey, (unsigned long) size,
147146
IPC_CREAT | IPC_EXCL | IPCProtection),
148-
(errno == EINVAL) ?
147+
(shmget_errno == EINVAL) ?
149148
errhint("This error usually means that PostgreSQL's request for a shared memory "
150149
"segment exceeded your kernel's SHMMAX parameter. You can either "
151150
"reduce the request size or reconfigure the kernel with larger SHMMAX. "
@@ -158,7 +157,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
158157
"The PostgreSQL documentation contains more information about shared "
159158
"memory configuration.",
160159
(unsigned long) size) : 0,
161-
(errno == ENOMEM) ?
160+
(shmget_errno == ENOMEM) ?
162161
errhint("This error usually means that PostgreSQL's request for a shared "
163162
"memory segment exceeded available memory or swap space, "
164163
"or exceeded your kernel's SHMALL parameter. You can either "
@@ -169,7 +168,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
169168
"The PostgreSQL documentation contains more information about shared "
170169
"memory configuration.",
171170
(unsigned long) size) : 0,
172-
(errno == ENOSPC) ?
171+
(shmget_errno == ENOSPC) ?
173172
errhint("This error does *not* mean that you have run out of disk space. "
174173
"It occurs either if all available shared memory IDs have been taken, "
175174
"in which case you need to raise the SHMMNI parameter in your kernel, "

0 commit comments

Comments
 (0)