Change AutoRemoteSyscalls::infallible_mmap_syscall to infallible_mmap_syscall_if_alive
diff --git a/src/AddressSpace.cc b/src/AddressSpace.cc
index e3fea9e..b31fef5 100644
--- a/src/AddressSpace.cc
+++ b/src/AddressSpace.cc
@@ -314,11 +314,11 @@
     int child_fd = remote.infallible_send_fd_if_alive(page.get());
     if (child_fd >= 0) {
       if (t->session().is_recording()) {
-        remote.infallible_mmap_syscall(rr_page_start() - offset_bytes, offset_bytes, prot, flags,
-                                      child_fd, 0);
+        remote.infallible_mmap_syscall_if_alive(rr_page_start() - offset_bytes, offset_bytes, prot, flags,
+                                                child_fd, 0);
       }
-      remote.infallible_mmap_syscall(rr_page_start(), rr_page_size(), prot, flags,
-                                     child_fd, offset_pages);
+      remote.infallible_mmap_syscall_if_alive(rr_page_start(), rr_page_size(), prot, flags,
+                                              child_fd, offset_pages);
 
       struct stat fstat = t->stat_fd(child_fd);
       file_name = t->file_name_of_fd(child_fd);
@@ -1546,7 +1546,7 @@
       t->read_bytes_helper(mapping.map.start(), buffer.size(), buffer.data());
       {
         AutoRemoteSyscalls remote(t);
-        remote.infallible_mmap_syscall(mapping.map.start(), buffer.size(),
+        remote.infallible_mmap_syscall_if_alive(mapping.map.start(), buffer.size(),
             mapping.map.prot(), mapping.map.flags() | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
       }
       t->write_bytes_helper(mapping.map.start(), buffer.size(), buffer.data());
diff --git a/src/AutoRemoteSyscalls.cc b/src/AutoRemoteSyscalls.cc
index f9670d5..6d695b5 100644
--- a/src/AutoRemoteSyscalls.cc
+++ b/src/AutoRemoteSyscalls.cc
@@ -186,10 +186,12 @@
   if (found_stack.start().is_null()) {
     AutoRemoteSyscalls remote(t, DISABLE_MEMORY_PARAMS);
     found_stack =
-        MemoryRange(remote.infallible_mmap_syscall(
+        MemoryRange(remote.infallible_mmap_syscall_if_alive(
                         remote_ptr<void>(), 4096, PROT_READ | PROT_WRITE,
                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0),
                     4096);
+    ASSERT(t, !found_stack.start().is_null())
+      << "Tracee unexpectedly died here";
     scratch_mem_was_mapped = true;
   }
 
@@ -581,7 +583,7 @@
   }
 }
 
-remote_ptr<void> AutoRemoteSyscalls::infallible_mmap_syscall(
+remote_ptr<void> AutoRemoteSyscalls::infallible_mmap_syscall_if_alive(
     remote_ptr<void> addr, size_t length, int prot, int flags, int child_fd,
     uint64_t offset_pages) {
   // The first syscall argument is called "arg 1", so
@@ -589,13 +591,13 @@
   // with "1".
   remote_ptr<void> ret =
       has_mmap2_syscall(arch())
-          ? infallible_syscall_ptr(syscall_number_for_mmap2(arch()), addr,
-                                   length, prot, flags, child_fd,
-                                   (off_t)offset_pages)
-          : infallible_syscall_ptr(syscall_number_for_mmap(arch()), addr,
-                                   length, prot, flags, child_fd,
-                                   offset_pages * page_size());
-  if (flags & MAP_FIXED) {
+          ? infallible_syscall_ptr_if_alive(syscall_number_for_mmap2(arch()), addr,
+                                            length, prot, flags, child_fd,
+                                            (off_t)offset_pages)
+          : infallible_syscall_ptr_if_alive(syscall_number_for_mmap(arch()), addr,
+                                            length, prot, flags, child_fd,
+                                            offset_pages * page_size());
+  if (ret && (flags & MAP_FIXED)) {
     ASSERT(t, addr == ret) << "MAP_FIXED at " << addr << " but got " << ret;
   }
   return ret;
@@ -663,7 +665,7 @@
                             backing_file_open_flags);
   }
   /* And mmap that file. */
-  infallible_mmap_syscall(rec_addr, length,
+  infallible_mmap_syscall_if_alive(rec_addr, length,
                           /* (We let SHARED|WRITEABLE
                           * mappings go through while
                           * they're not handled properly,
diff --git a/src/AutoRemoteSyscalls.h b/src/AutoRemoteSyscalls.h
index 6560011..66f8edb 100644
--- a/src/AutoRemoteSyscalls.h
+++ b/src/AutoRemoteSyscalls.h
@@ -176,23 +176,23 @@
     return ret;
   }
 
-  /** TODO replace with infallible_syscall_ptr_if_alive */
+  /** Returns null if the tracee is dead */
   template <typename... Rest>
-  remote_ptr<void> infallible_syscall_ptr(int syscallno, Rest... args) {
+  remote_ptr<void> infallible_syscall_ptr_if_alive(int syscallno, Rest... args) {
     Registers callregs = regs();
     long ret = syscall_helper<1>(syscallno, callregs, args...);
-    check_syscall_result(ret, syscallno, false);
-    return ret;
+    check_syscall_result(ret, syscallno);
+    return ret == -ESRCH ? 0 : ret;
   }
 
   /**
    * Remote mmap syscalls are common and non-trivial due to the need to
    * select either mmap2 or mmap.
-   * TODO replace with infallble_mmap_syscall_if_alive
+   * Returns null if the process dies or has died.
    */
-  remote_ptr<void> infallible_mmap_syscall(remote_ptr<void> addr, size_t length,
-                                           int prot, int flags, int child_fd,
-                                           uint64_t offset_pages);
+  remote_ptr<void> infallible_mmap_syscall_if_alive(remote_ptr<void> addr, size_t length,
+                                                    int prot, int flags, int child_fd,
+                                                    uint64_t offset_pages);
 
   /** TODO replace with infallible_lseek_syscall_if_alive */
   int64_t infallible_lseek_syscall(int fd, int64_t offset, int whence);
diff --git a/src/Monkeypatcher.cc b/src/Monkeypatcher.cc
index f3214e0..4fcc92b 100644
--- a/src/Monkeypatcher.cc
+++ b/src/Monkeypatcher.cc
@@ -219,7 +219,11 @@
       AutoRemoteSyscalls remote(t);
       int prot = PROT_READ | PROT_EXEC;
       int flags = MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE;
-      remote.infallible_mmap_syscall(addr, page_size(), prot, flags, -1, 0);
+      auto ret = remote.infallible_mmap_syscall_if_alive(addr, page_size(), prot, flags, -1, 0);
+      if (!ret) {
+        /* Tracee died */
+        return nullptr;
+      }
       KernelMapping recorded(addr, addr + page_size(), string(),
                              KernelMapping::NO_DEVICE, KernelMapping::NO_INODE,
                              prot, flags);
diff --git a/src/ReplaySession.cc b/src/ReplaySession.cc
index dd0f61f..0a3cc87 100644
--- a/src/ReplaySession.cc
+++ b/src/ReplaySession.cc
@@ -138,7 +138,6 @@
   // Check that sizes and offsets of supported XSAVE areas area all identical.
   // An Intel employee promised this on a mailing list...
   // https://lists.xen.org/archives/html/xen-devel/2013-09/msg00484.html
-  // His promise isn't binding on AMD though.
   for (int feature = 2; feature <= 63; ++feature) {
     if (!(tracee_xcr0 & our_xcr0 & (uint64_t(1) << feature))) {
       continue;
@@ -150,10 +149,8 @@
         record->out.ebx != data.ebx ||
         (check_alignment && (record->out.ecx & 2) != (data.ecx & 2))) {
       CLEAN_FATAL()
-          << "XSAVE offset/size/alignment differs for feature " << feature << "\n"
-          << "Expected " << record->out.eax << " == " << data.eax << " && "
-          << record->out.ebx << " == " << data.ebx << " && (!" << check_alignment
-          << " || " << (record->out.ecx & 2) << " == " << (data.ecx & 2) << ")";
+          << "XSAVE offset/size/alignment differs for feature " << feature
+          << "; H. Peter Anvin said this would never happen!";
     }
   }
 }
@@ -1467,8 +1464,8 @@
     }
     AutoRemoteSyscalls remote(t);
     ASSERT(t, km.flags() & MAP_ANONYMOUS);
-    remote.infallible_mmap_syscall(km.start(), km.size(), km.prot(),
-                                   km.flags() | MAP_FIXED, -1, 0);
+    remote.infallible_mmap_syscall_if_alive(km.start(), km.size(), km.prot(),
+                                            km.flags() | MAP_FIXED, -1, 0);
     t->vm()->map(t, km.start(), km.size(), km.prot(), km.flags(), 0, string(),
                  KernelMapping::NO_DEVICE, KernelMapping::NO_INODE, nullptr,
                  &km);
diff --git a/src/Session.cc b/src/Session.cc
index b5f1680..59d4b42 100644
--- a/src/Session.cc
+++ b/src/Session.cc
@@ -411,14 +411,20 @@
   struct stat real_file = remote.task()->stat_fd(remote_fd);
   string real_file_name = remote.task()->file_name_of_fd(remote_fd);
   // XXX this condition is x86/x64-specific, I imagine.
-  remote.infallible_mmap_syscall(m.map.start(), m.map.size(), m.map.prot(),
-                                 // The remapped segment *must* be
-                                 // remapped at the same address,
-                                 // or else many things will go
-                                 // haywire.
-                                 (m.map.flags() & ~MAP_ANONYMOUS) | MAP_FIXED,
-                                 remote_fd,
-                                 m.map.file_offset_bytes() / page_size());
+  // The remapped segment *must* be remapped at the same address,
+  // or else many things will go haywire.
+  auto ret = remote.infallible_mmap_syscall_if_alive(m.map.start(), m.map.size(), m.map.prot(),
+                                                     (m.map.flags() & ~MAP_ANONYMOUS) | MAP_FIXED,
+                                                     remote_fd,
+                                                     m.map.file_offset_bytes() / page_size());
+  if (!ret) {
+    if (remote.task()->vm()->task_set().size() > remote.task()->thread_group()->task_set().size()) {
+      // XXX not sure how to handle the case where the tracee died after
+      // we unmapped the area
+      FATAL() << "Unexpected task death leaving this address space in a bad state";
+    }
+    return;
+  }
 
   // We update the AddressSpace mapping too, since that tracks the real file
   // name and we need to update that.
@@ -453,21 +459,26 @@
   if (child_shmem_fd < 0) {
     return km;
   }
-  resize_shmem_segment(shmem_fd, size);
   LOG(debug) << "created shmem segment " << path;
 
   // Map the segment in ours and the tracee's address spaces.
   void* map_addr;
   int flags = MAP_SHARED;
-  if ((void*)-1 == (map_addr = mmap(nullptr, size, PROT_READ | PROT_WRITE,
-                                    flags, shmem_fd, 0))) {
-    FATAL() << "Failed to mmap shmem region";
-  }
   if (!map_hint.is_null()) {
     flags |= MAP_FIXED;
   }
-  remote_ptr<void> child_map_addr = remote.infallible_mmap_syscall(
+  remote_ptr<void> child_map_addr = remote.infallible_mmap_syscall_if_alive(
       map_hint, size, tracee_prot, flags, child_shmem_fd, 0);
+  if (!child_map_addr) {
+    // tracee unexpectedly died
+    return km;
+  }
+
+  if ((void*)-1 == (map_addr = mmap(nullptr, size, PROT_READ | PROT_WRITE,
+                                    MAP_SHARED, shmem_fd, 0))) {
+    FATAL() << "Failed to mmap shmem region";
+  }
+  resize_shmem_segment(shmem_fd, size);
 
   struct stat st;
   ASSERT(remote.task(), 0 == ::fstat(shmem_fd, &st));
diff --git a/src/Task.cc b/src/Task.cc
index c8686c3..9ac8b63 100644
--- a/src/Task.cc
+++ b/src/Task.cc
@@ -3498,14 +3498,17 @@
   dev_t device = KernelMapping::NO_DEVICE;
   ino_t inode = KernelMapping::NO_INODE;
   if (km.is_real_device() && !file_was_deleted(km.fsname())) {
-    struct stat real_file; string real_file_name;
+    struct stat real_file;
+    string real_file_name;
     remote.finish_direct_mmap(km.start(), km.size(), km.prot(), km.flags(),
       km.fsname(), O_RDONLY, km.file_offset_bytes()/page_size(),
       real_file, real_file_name);
   } else {
-    remote.infallible_mmap_syscall(km.start(), km.size(), km.prot(),
-                                  km.flags() | MAP_FIXED | MAP_ANONYMOUS, -1,
-                                  0);
+    auto ret = remote.infallible_mmap_syscall_if_alive(km.start(), km.size(), km.prot(),
+                                                       km.flags() | MAP_FIXED | MAP_ANONYMOUS, -1,
+                                                       0);
+    ASSERT(t, ret || t->vm()->task_set().size() == t->thread_group()->task_set().size())
+      << "Not handling shared address spaces where one threadgroup unexpectedly dies";
   }
   t->vm()->map(t, km.start(), km.size(), km.prot(), km.flags(), km.file_offset_bytes(),
                real_file_name, device, inode, nullptr, &km);
diff --git a/src/record_signal.cc b/src/record_signal.cc
index edff7a3..0fdde53 100644
--- a/src/record_signal.cc
+++ b/src/record_signal.cc
@@ -203,7 +203,7 @@
 
   {
     AutoRemoteSyscalls remote(t, AutoRemoteSyscalls::DISABLE_MEMORY_PARAMS);
-    remote.infallible_mmap_syscall(
+    remote.infallible_mmap_syscall_if_alive(
         new_start, it->map.start() - new_start, it->map.prot(),
         (it->map.flags() & ~MAP_GROWSDOWN) | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
   }
diff --git a/src/record_syscall.cc b/src/record_syscall.cc
index 17867cb..5e43720 100644
--- a/src/record_syscall.cc
+++ b/src/record_syscall.cc
@@ -3137,12 +3137,12 @@
     AutoRemoteSyscalls remote(t);
 
     if (addr_type == DYNAMIC_ADDRESS) {
-      t->scratch_ptr = remote.infallible_mmap_syscall(remote_ptr<void>(), sz,
-                                                      prot, flags, -1, 0);
+      t->scratch_ptr = remote.infallible_mmap_syscall_if_alive(remote_ptr<void>(), sz,
+                                                               prot, flags, -1, 0);
     } else {
       t->scratch_ptr =
-          remote.infallible_mmap_syscall(remote_ptr<void>(FIXED_SCRATCH_PTR),
-                                         sz, prot, flags | MAP_FIXED, -1, 0);
+          remote.infallible_mmap_syscall_if_alive(remote_ptr<void>(FIXED_SCRATCH_PTR),
+                                                  sz, prot, flags | MAP_FIXED, -1, 0);
     }
     t->scratch_size = scratch_size;
   }
@@ -5406,8 +5406,8 @@
         remote.infallible_syscall(syscall_number_for_munmap(remote.arch()),
                                   km.start() - page_size(), page_size());
       }
-      remote.infallible_mmap_syscall(km.start(), km.size(), km.prot(), flags,
-                                     -1, 0);
+      remote.infallible_mmap_syscall_if_alive(km.start(), km.size(), km.prot(), flags,
+                                              -1, 0);
       t->write_mem(km.start().cast<uint8_t>(), buf.data(), buf.size());
     }
   }
diff --git a/src/replay_syscall.cc b/src/replay_syscall.cc
index f0202ce..33f73bd 100644
--- a/src/replay_syscall.cc
+++ b/src/replay_syscall.cc
@@ -87,8 +87,8 @@
 
   {
     AutoRemoteSyscalls remote(t);
-    remote.infallible_mmap_syscall(t->scratch_ptr, sz, km.prot(),
-                                   km.flags() | MAP_FIXED, -1, 0);
+    remote.infallible_mmap_syscall_if_alive(t->scratch_ptr, sz, km.prot(),
+                                            km.flags() | MAP_FIXED, -1, 0);
     t->vm()->map(t, t->scratch_ptr, sz, km.prot(), km.flags(), 0, string(),
                  KernelMapping::NO_DEVICE, KernelMapping::NO_INODE, nullptr,
                  &km);
@@ -342,9 +342,9 @@
     case TraceReader::SOURCE_TRACE:
     case TraceReader::SOURCE_ZERO:
       flags |= MAP_ANONYMOUS;
-      remote.infallible_mmap_syscall(km.start(), km.size(), km.prot(),
-                                     (flags & ~MAP_GROWSDOWN) | MAP_FIXED, -1,
-                                     0);
+      remote.infallible_mmap_syscall_if_alive(km.start(), km.size(), km.prot(),
+                                              (flags & ~MAP_GROWSDOWN) | MAP_FIXED, -1,
+                                              0);
       // The data, if any, will be written back by
       // ReplayTask::apply_all_data_records_from_trace
       break;
@@ -513,9 +513,9 @@
   if (km.flags()) {
     AutoRemoteSyscalls remote(t);
     ASSERT(t, data.source == TraceReader::SOURCE_ZERO);
-    remote.infallible_mmap_syscall(km.start(), km.size(), km.prot(),
-                                   MAP_ANONYMOUS | MAP_FIXED | km.flags(), -1,
-                                   0);
+    remote.infallible_mmap_syscall_if_alive(km.start(), km.size(), km.prot(),
+                                            MAP_ANONYMOUS | MAP_FIXED | km.flags(), -1,
+                                            0);
     t->vm()->map(t, km.start(), km.size(), km.prot(),
                  MAP_ANONYMOUS | km.flags(), 0, "[heap]",
                  KernelMapping::NO_DEVICE, KernelMapping::NO_INODE, nullptr,
@@ -538,10 +538,10 @@
   KernelMapping recorded_km = t->trace_reader().read_mapped_region(&data);
   EmuFile::shr_ptr emu_file;
   if (!(flags & MAP_SHARED)) {
-    remote.infallible_mmap_syscall(rec_addr, length, prot,
-                                   // Tell the kernel to take |rec_addr|
-                                   // seriously.
-                                   (flags & ~MAP_GROWSDOWN) | MAP_FIXED, -1, 0);
+    remote.infallible_mmap_syscall_if_alive(rec_addr, length, prot,
+                                            // Tell the kernel to take |rec_addr|
+                                            // seriously.
+                                            (flags & ~MAP_GROWSDOWN) | MAP_FIXED, -1, 0);
   } else {
     ASSERT(remote.task(), data.source == TraceReader::SOURCE_ZERO);
     emu_file = t->session().emufs().get_or_create(recorded_km);
@@ -636,7 +636,7 @@
                                 TraceReader::MappedData& data) {
   LOG(debug) << "  finishing private mmap of " << km.fsname();
 
-  remote.infallible_mmap_syscall(
+  remote.infallible_mmap_syscall_if_alive(
       rec_addr, length, prot,
       // Tell the kernel to take |rec_addr| seriously.
       (flags & ~MAP_GROWSDOWN) | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
@@ -835,15 +835,15 @@
     if (new_addr == old_addr) {
       // Non-moving mremap. Don't pass MREMAP_FIXED or MREMAP_MAYMOVE
       // since that triggers EINVAL when the new map overlaps the old map.
-      remote.infallible_syscall_ptr(trace_regs.original_syscallno(), new_addr,
-                                    old_size, new_size, 0);
+      remote.infallible_syscall_if_alive(trace_regs.original_syscallno(), new_addr,
+                                         old_size, new_size, 0);
     } else {
       // Force the mremap to use the destination address from recording.
       // XXX could the new mapping overlap the old, with different start
       // addresses? Hopefully the kernel doesn't do that to us!!!
-      remote.infallible_syscall_ptr(trace_regs.original_syscallno(), old_addr,
-                                    old_size, new_size,
-                                    MREMAP_MAYMOVE | MREMAP_FIXED, new_addr);
+      remote.infallible_syscall_if_alive(trace_regs.original_syscallno(), old_addr,
+                                         old_size, new_size,
+                                         MREMAP_MAYMOVE | MREMAP_FIXED, new_addr);
     }
 
     remote.regs().set_syscall_result(new_addr);
@@ -873,8 +873,8 @@
       // Shared non-EmuFs mappings must be of immutable files so it's OK to
       // just copy the file data into a private mapping here.
       int map_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
-      remote.infallible_mmap_syscall(new_addr, new_size, mapping.map.prot(),
-                                     map_flags, -1, 0);
+      remote.infallible_mmap_syscall_if_alive(new_addr, new_size, mapping.map.prot(),
+                                              map_flags, -1, 0);
       t->vm()->unmap(t, new_addr, new_size);
       t->vm()->map(t, new_addr, new_size, mapping.map.prot(), map_flags,
                    mapping.map.file_offset_bytes(), string(),