From f58b1eb469d981d65659c901b7348899b2d82cf5 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Wed, 27 Jan 2016 18:30:37 -0700 Subject: [PATCH] Fixed handling of shared memory left over by Squid crashes or bugs. A Squid instance may inherit an old shared memory segment from the previous instance as the result of either a Squid crash or an at-exit cleanup bug. This change fixes two problems triggered by old segments: 1. After an earlier OS X fix (bug 3805; trunk r13947), Squid stopped initializing previously used shared memory. Uninitialzed memory resulted in subtle bugs and crashes. 2. When called for an old Squid shared memory segment, OS X ftruncate() fails with EINVAL, preventing Squid from starting when the old segment is still around. More specifically: Darwin ftruncate() calls pshm_truncate(). pshm_truncate() checks if the PSHM_ALLOCATED flag is already set on the memory region. If the flag is set, the call fails with EINVAL. Otherwise, pshm_truncate() sets PSHM_ALLOCATED for the region. Since Squid must call ftruncate() to size every new segment, all old Squid segments have that flag set, preventing ftruncate() calls for old segments in newer Sqid instances from succeeding. [1] http://www.opensource.apple.com/source/xnu/xnu-3248.20.55/bsd/kern/posix_shm.c To fix both problems, Squid now uses shm_open(O_EXCL) to detect the existence of an old segment and remove/recreate it as needed. --- src/ipc/mem/Segment.cc | 23 ++++++++++++++++++++--- src/ipc/mem/Segment.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/ipc/mem/Segment.cc b/src/ipc/mem/Segment.cc index 8498ac51ea..dfc363d7de 100644 --- a/src/ipc/mem/Segment.cc +++ b/src/ipc/mem/Segment.cc @@ -88,9 +88,15 @@ Ipc::Mem::Segment::create(const off_t aSize) assert(aSize > 0); assert(theFD < 0); - // OS X does not allow using O_TRUNC here. - theFD = shm_open(theName.termedBuf(), O_CREAT | O_RDWR, - S_IRUSR | S_IWUSR); + // Why a brand new segment? A Squid crash may leave a reusable segment, but + // our placement-new code requires an all-0s segment. We could truncate and + // resize the old segment, but OS X does not allow using O_TRUNC with + // shm_open() and does not support ftruncate() for old segments. + if (!createFresh() && errno == EEXIST) { + unlink(); + createFresh(); + } + if (theFD < 0) { debugs(54, 5, HERE << "shm_open " << theName << ": " << xstrerror()); fatalf("Ipc::Mem::Segment::create failed to shm_open(%s): %s\n", @@ -138,6 +144,17 @@ Ipc::Mem::Segment::open() attach(); } +/// Creates a brand new shared memory segment and returns true. +/// Fails and returns false if there exist an old segment with the same name. +bool +Ipc::Mem::Segment::createFresh() +{ + theFD = shm_open(theName.termedBuf(), + O_EXCL | O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR); + return theFD >= 0; +} + /// Map the shared memory segment to the process memory space. void Ipc::Mem::Segment::attach() diff --git a/src/ipc/mem/Segment.h b/src/ipc/mem/Segment.h index f622613322..e62171ca33 100644 --- a/src/ipc/mem/Segment.h +++ b/src/ipc/mem/Segment.h @@ -54,6 +54,7 @@ private: #if HAVE_SHM + bool createFresh(); void attach(); void detach(); void unlink(); ///< unlink the segment -- 2.39.5