Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 571addd

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 120c5cc commit 571addd

File tree

5 files changed

+44
-27
lines changed

5 files changed

+44
-27
lines changed

src/backend/commands/tablespace.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,10 +782,14 @@ destroy_tablespace_directories(Oid tablespaceoid, bool redo)
782782
else
783783
{
784784
if (unlink(linkloc) < 0)
785-
ereport(redo ? LOG : (errno == ENOENT ? WARNING : ERROR),
785+
{
786+
int saved_errno = errno;
787+
788+
ereport(redo ? LOG : (saved_errno == ENOENT ? WARNING : ERROR),
786789
(errcode_for_file_access(),
787790
errmsg("could not remove symbolic link \"%s\": %m",
788791
linkloc)));
792+
}
789793
}
790794

791795
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: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,17 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
7373

7474
if (shmid < 0)
7575
{
76+
int shmget_errno = errno;
77+
7678
/*
7779
* Fail quietly if error indicates a collision with existing segment.
7880
* One would expect EEXIST, given that we said IPC_EXCL, but perhaps
7981
* we could get a permission violation instead? Also, EIDRM might
8082
* occur if an old seg is slated for destruction but not gone yet.
8183
*/
82-
if (errno == EEXIST || errno == EACCES
84+
if (shmget_errno == EEXIST || shmget_errno == EACCES
8385
#ifdef EIDRM
84-
|| errno == EIDRM
86+
|| shmget_errno == EIDRM
8587
#endif
8688
)
8789
return NULL;
@@ -95,10 +97,8 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
9597
* against SHMMIN in the preexisting-segment case, so we will not get
9698
* EINVAL a second time if there is such a segment.
9799
*/
98-
if (errno == EINVAL)
100+
if (shmget_errno == EINVAL)
99101
{
100-
int save_errno = errno;
101-
102102
shmid = shmget(memKey, 0, IPC_CREAT | IPC_EXCL | IPCProtection);
103103

104104
if (shmid < 0)
@@ -124,8 +124,6 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
124124
elog(LOG, "shmctl(%d, %d, 0) failed: %m",
125125
(int) shmid, IPC_RMID);
126126
}
127-
128-
errno = save_errno;
129127
}
130128

131129
/*
@@ -137,25 +135,26 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
137135
* it should be. SHMMNI violation is ENOSPC, per spec. Just plain
138136
* not-enough-RAM is ENOMEM.
139137
*/
138+
errno = shmget_errno;
140139
ereport(FATAL,
141140
(errmsg("could not create shared memory segment: %m"),
142141
errdetail("Failed system call was shmget(key=%lu, size=%zu, 0%o).",
143142
(unsigned long) memKey, size,
144143
IPC_CREAT | IPC_EXCL | IPCProtection),
145-
(errno == EINVAL) ?
144+
(shmget_errno == EINVAL) ?
146145
errhint("This error usually means that PostgreSQL's request for a shared memory "
147146
"segment exceeded your kernel's SHMMAX parameter, or possibly that "
148147
"it is less than "
149148
"your kernel's SHMMIN parameter.\n"
150149
"The PostgreSQL documentation contains more information about shared "
151150
"memory configuration.") : 0,
152-
(errno == ENOMEM) ?
151+
(shmget_errno == ENOMEM) ?
153152
errhint("This error usually means that PostgreSQL's request for a shared "
154153
"memory segment exceeded your kernel's SHMALL parameter. You might need "
155154
"to reconfigure the kernel with larger SHMALL.\n"
156155
"The PostgreSQL documentation contains more information about shared "
157156
"memory configuration.") : 0,
158-
(errno == ENOSPC) ?
157+
(shmget_errno == ENOSPC) ?
159158
errhint("This error does *not* mean that you have run out of disk space. "
160159
"It occurs either if all available shared memory IDs have been taken, "
161160
"in which case you need to raise the SHMMNI parameter in your kernel, "
@@ -331,6 +330,7 @@ CreateAnonymousSegment(Size *size)
331330
{
332331
Size allocsize = *size;
333332
void *ptr = MAP_FAILED;
333+
int mmap_errno = 0;
334334

335335
#ifndef MAP_HUGETLB
336336
if (huge_tlb_pages == HUGE_TLB_ON)
@@ -363,6 +363,7 @@ CreateAnonymousSegment(Size *size)
363363

364364
ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE,
365365
PG_MMAP_FLAGS | MAP_HUGETLB, -1, 0);
366+
mmap_errno = errno;
366367
if (huge_tlb_pages == HUGE_TLB_TRY && ptr == MAP_FAILED)
367368
elog(DEBUG1, "mmap with MAP_HUGETLB failed, huge pages disabled: %m");
368369
}
@@ -376,20 +377,25 @@ CreateAnonymousSegment(Size *size)
376377
* back to non-huge pages.
377378
*/
378379
allocsize = *size;
379-
ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE, PG_MMAP_FLAGS, -1, 0);
380+
ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE,
381+
PG_MMAP_FLAGS, -1, 0);
382+
mmap_errno = errno;
380383
}
381384

382385
if (ptr == MAP_FAILED)
386+
{
387+
errno = mmap_errno;
383388
ereport(FATAL,
384389
(errmsg("could not map anonymous shared memory: %m"),
385-
(errno == ENOMEM) ?
390+
(mmap_errno == ENOMEM) ?
386391
errhint("This error usually means that PostgreSQL's request "
387392
"for a shared memory segment exceeded available memory, "
388393
"swap space or huge pages. To reduce the request size "
389394
"(currently %zu bytes), reduce PostgreSQL's shared "
390395
"memory usage, perhaps by reducing shared_buffers or "
391396
"max_connections.",
392397
*size) : 0));
398+
}
393399

394400
*size = allocsize;
395401
return ptr;

src/bin/psql/command.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,14 +264,15 @@ exec_command(const char *cmd,
264264
{
265265
#ifndef WIN32
266266
struct passwd *pw;
267+
uid_t user_id = geteuid();
267268

268-
errno = 0; /* clear errno before call */
269-
pw = getpwuid(geteuid());
269+
errno = 0; /* clear errno before call */
270+
pw = getpwuid(user_id);
270271
if (!pw)
271272
{
272-
psql_error("could not get home directory for user id %d: %s\n",
273-
(int) geteuid(), errno ?
274-
strerror(errno) : "user does not exist");
273+
psql_error("could not get home directory for user id %ld: %s\n",
274+
(long) user_id,
275+
errno ? strerror(errno) : _("user does not exist"));
275276
exit(EXIT_FAILURE);
276277
}
277278
dir = pw->pw_dir;

src/common/username.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@ get_user_name(char **errstr)
3434
{
3535
#ifndef WIN32
3636
struct passwd *pw;
37-
uid_t user_id = geteuid();
37+
uid_t user_id = geteuid();
3838

3939
*errstr = NULL;
4040

41-
errno = 0; /* clear errno before call */
41+
errno = 0; /* clear errno before call */
4242
pw = getpwuid(user_id);
4343
if (!pw)
4444
{
45-
*errstr = psprintf(_("failed to look up effective user id %d: %s"),
46-
(int) user_id, errno ? strerror(errno) :
47-
_("user does not exist"));
45+
*errstr = psprintf(_("failed to look up effective user id %ld: %s"),
46+
(long) user_id,
47+
errno ? strerror(errno) : _("user does not exist"));
4848
return NULL;
4949
}
5050

0 commit comments

Comments
 (0)