diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 15d563eeb0021411574dd267935b0310c1aedfee..d4920d3747b9171938e5fe2a1a53d246770e28d8 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,18 @@ This document contains the ``fslpy`` release history in reverse chronological
 order.
 
 
+1.10.2 (Friday September 7th 2018)
+----------------------------------
+
+
+Fixed
+^^^^^
+
+
+* The :meth:`.Image.save` method was not handling memory-mapped images
+  correctly.
+
+
 1.10.1 (Friday August 3rd 2018)
 -------------------------------
 
@@ -16,7 +28,7 @@ Changed
 Fixed
 ^^^^^
 
-* The .mod:`.FEATImage.getCOPE` method was returning PE images.
+* The :mod:`.FEATImage.getCOPE` method was returning PE images.
 
 
 1.10.0 (Wednesday July 18th 2018)
diff --git a/fsl/data/image.py b/fsl/data/image.py
index 0a130dcaad1169a847f5900fb27ac8f7081ee065..7af1e696053f3c94648f66810134127b9120a11f 100644
--- a/fsl/data/image.py
+++ b/fsl/data/image.py
@@ -35,8 +35,10 @@ and file names:
 
 import                      os
 import os.path           as op
+import                      shutil
 import                      string
 import                      logging
+import                      tempfile
 
 import                      six
 import                      deprecation
@@ -1165,11 +1167,41 @@ class Image(Nifti):
         log.debug('Saving {} to {}'.format(self.name, filename))
 
         # If this Image is not managing its
-        # own file object, nibabel does all
-        # of the hard work.
-        if self.__fileobj is None:
+        # own file object, and the image is not
+        # memory-mapped, nibabel does all of
+        # the hard work.
+        newnibimage = False
+        ismmap      = isinstance(self[0, 0, :10], np.memmap)
+        if self.__fileobj is None and (not ismmap):
             nib.save(self.__nibImage, filename)
 
+        # If the image is memory-mapped, we need
+        # to close and re-open the image
+        elif self.__fileobj is None:
+
+            # We save the image out to a temp file,
+            # then close the old image, move the
+            # temp file to the real destination,
+            # then re-open the file.
+            newnibimage     = True
+            tmphd, tmpfname = tempfile.mkstemp(suffix=op.splitext(filename)[1])
+            os.close(tmphd)
+
+            try:
+                nib.save(self.__nibImage, tmpfname)
+
+                self.__nibImage = None
+                self.header     = None
+
+                shutil.copy(tmpfname, filename)
+
+                self.__nibImage = nib.load(filename)
+                self.header     = self.__nibImage.header
+
+            except Exception:
+                os.remove(tmpfname)
+                raise
+
         # Otherwise we've got our own file
         # handle to an IndexedGzipFile
         else:
@@ -1190,15 +1222,19 @@ class Image(Nifti):
             # compressed data. And then be able to
             # transfer the index generated from the
             # write to a new read-only file handle.
+            newnibimage = True
             nib.save(self.__nibImage, filename)
             self.__fileobj.close()
             self.__nibImage, self.__fileobj = loadIndexedImageFile(filename)
             self.header = self.__nibImage.header
 
-            # We have to create a new ImageWrapper
-            # instance too, as we have just destroyed
-            # the nibabel image we gave to the last
-            # one.
+        # If we've created a new nibabel image,
+        # we have to create a new ImageWrapper
+        # instance too, as we have just destroyed
+        # the nibabel image we gave to the last
+        # one.
+        if newnibimage:
+
             self.__imageWrapper.deregister(self.__lName)
             self.__imageWrapper = imagewrapper.ImageWrapper(
                 self.nibImage,
diff --git a/fsl/data/imagewrapper.py b/fsl/data/imagewrapper.py
index d2b4fb9169a862dbb102807a06abba44036bb546..559c0d974f5563edbafef459870cbbb5b504ddac 100644
--- a/fsl/data/imagewrapper.py
+++ b/fsl/data/imagewrapper.py
@@ -825,6 +825,8 @@ def expectedShape(sliceobj, shape):
         if start is None: start = 0
         if stop  is None: stop  = shape[i]
 
+        stop = min(stop, shape[i])
+
         expShape.append(stop - start)
 
     return len(expShape), expShape
diff --git a/tests/test_image.py b/tests/test_image.py
index da6263912057ddd902624a89c6999d2bd805760c..84a3d244542163e7c164a26a0408c336447af250 100644
--- a/tests/test_image.py
+++ b/tests/test_image.py
@@ -994,29 +994,29 @@ def _test_Image_save(imgtype):
 
         make_image(filename, imgtype)
 
-        # Using mmap can cause a "Bus error"
-        # under docker. No idea why.
-        img = fslimage.Image(filename, mmap=False)
+        # Save to original location, and
+        # to a different location. And
+        # test both with and without mmap
+        targets = [None, filename, filename2]
+        mmaps   = [False, True]
 
-        randvoxes = randvoxes(5)
-        randvals  = [np.random.random() for i in range(5)]
+        for target, mmap in it.product(targets, mmaps):
 
-        for (x, y, z), v in zip(randvoxes, randvals):
-            img[x, y, z] = v
+            img = fslimage.Image(filename, mmap=mmap)
 
-        if imgtype > 0:
-            img.voxToWorldMat = xform
+            rvoxs = randvoxes(5)
+            rvals = [np.random.random() for i in range(5)]
 
-        # Save to original location, and
-        # to a different location
-        targets = [None, filename, filename2]
+            for (x, y, z), v in zip(rvoxs, rvals):
+                img[x, y, z] = v
 
-        for t in targets:
+            if imgtype > 0:
+                img.voxToWorldMat = xform
 
-            img.save(t)
+            img.save(target)
 
-            if t is None: expDataSource = filename
-            else:         expDataSource = t
+            if target is None: expDataSource = filename
+            else:              expDataSource = target
 
             assert img.saveState
             assert img.dataSource == expDataSource
@@ -1024,7 +1024,7 @@ def _test_Image_save(imgtype):
             if imgtype > 0:
                 assert np.all(np.isclose(img.voxToWorldMat, xform))
 
-            for (x, y, z), v in zip(randvoxes, randvals):
+            for (x, y, z), v in zip(rvoxs, rvals):
                 assert np.isclose(img[x, y, z], v)
 
             # Load the image back in
@@ -1036,7 +1036,7 @@ def _test_Image_save(imgtype):
             if imgtype > 0:
                 assert np.all(np.isclose(img.voxToWorldMat, xform))
 
-            for (x, y, z), v in zip(randvoxes, randvals):
+            for (x, y, z), v in zip(rvoxs, rvals):
                 assert np.isclose(img[x, y, z], v)
             img2 = None
 
diff --git a/tests/test_imagewrapper.py b/tests/test_imagewrapper.py
index b074358d28f6ee05101fa4e7a9a714249c7820dc..1237cd55d02966fc5596c32825dcec071f9c8b2e 100644
--- a/tests/test_imagewrapper.py
+++ b/tests/test_imagewrapper.py
@@ -257,6 +257,55 @@ def coverageDataRange(data, coverage, slices=None):
     return np.min(volmin), np.max(volmax)
 
 
+def test_expectedShape():
+
+    tests = [
+        ((slice(None), ), (10,),
+         (1, (10, ))),
+
+        ((slice(None), slice(None)),
+         (10, 10), (2, (10, 10))),
+
+        ((slice(None), slice(None), slice(None)),
+         (10, 10, 10), (3, (10, 10, 10))),
+
+        ((slice(None), slice(None), slice(None)),
+         (10, 10, 10), (3, (10, 10, 10))),
+
+        ((slice(None), slice(None), slice(None), slice(None)),
+         (10, 10, 10, 10), (4, (10, 10, 10, 10))),
+
+        ((1, slice(None), slice(None)),
+         (10, 10, 10), (2, (10, 10))),
+
+        ((slice(1, 3), slice(None), slice(None)),
+         (10, 10, 10), (3, (2, 10, 10))),
+
+        ((slice(None), 1, slice(None)),
+         (10, 10, 10), (2, (10, 10))),
+
+        ((slice(None), slice(1, 3), slice(None)),
+         (10, 10, 10), (3, (10, 2, 10))),
+
+        ((slice(None), slice(None), 1),
+         (10, 10, 10), (2, (10, 10))),
+
+        ((slice(None), slice(None), slice(1, 3), ),
+         (10, 10, 10), (3, (10, 10, 2))),
+
+        ((slice(None), slice(None), slice(1, 20), ),
+         (10, 10, 10), (3, (10, 10, 9))),
+    ]
+
+    for slc, shape, exp in tests:
+
+        explen, exp = exp
+        gotlen, got = imagewrap.expectedShape(slc, shape)
+
+        assert explen     == gotlen
+        assert tuple(exp) == tuple(got)
+
+
 def test_sliceObjToSliceTuple():
 
     func  = imagewrap.sliceObjToSliceTuple