BIND 10 master, updated. 9204d1f5951ea88ce351297885c83be3ceb33344 Merge remote-tracking branch 'refs/remotes/origin/master'

BIND 10 source code commits bind10-changes at lists.isc.org
Fri May 17 07:32:16 UTC 2013


The branch, master has been updated
       via  9204d1f5951ea88ce351297885c83be3ceb33344 (commit)
       via  e41be59e113c11dbad91634d47c832dffa628e8f (commit)
       via  686768228ffccfa16bc367776cff3eb6dd9f86dc (commit)
       via  433488548230ab8742f9d7b71fa33bc56484ec86 (commit)
       via  8b47d98c888f29facede10aecc8bf4d39d8f21ce (commit)
       via  8da51f50f03d1b84d9be0bb73d4091ddf32149fb (commit)
       via  52588836afbc4f6d66fd93d30bc37867bfeb2eb8 (commit)
       via  02fb830f3e15239a263d109e8bda0256418401bb (commit)
       via  a5eb53f5b3fcf01e6df58325e11269e62e259197 (commit)
       via  e1ff4dda628311346a699da5adf402d859a517cb (commit)
       via  929f85f8deb68ba58610354c8161c0e1c0806006 (commit)
       via  c7b8894303b7e88629c0b838080bfc6097c05ec8 (commit)
       via  d35ac0a1d9375ec6e4c01db0d2107ecf177b7ab8 (commit)
       via  ac01dfd069e66c85409e93b40385a393bb5c5a59 (commit)
       via  61e6c39d6f14c8d06956e92002b53f9448453b4d (commit)
       via  598d81ecdbc43b8e6869ba65c60b1d7b4fb155e3 (commit)
       via  cdb6afba87fa03187512682b8348e65dc5e24a0f (commit)
       via  5dc80a3df42d7725b56cc33d33249363a7a14279 (commit)
       via  b9c101fd307c164f7551d00068358828af4ed549 (commit)
       via  025659c532f8521d8a36476d2f1a14593c9690b5 (commit)
       via  4df6d1597b68281fee3999542219c18029b168eb (commit)
       via  423740919b7a050dc1255a0ebdc6ab6b71ea777f (commit)
       via  f0229b977d354a137df49137655eb3ec56d96f97 (commit)
       via  2cab68004571463fdaeefe5659380fbbf9c54e01 (commit)
       via  807f3b5cd6b5f7daed92413e9ab771ec500b6536 (commit)
       via  772de981b14ae73731b54e6dcc5b84935584f1ce (commit)
       via  bd04d06c2d51af45ed818e90ef500936dafca1c4 (commit)
       via  44160bfeffd56f5ccd6c8400eb8c3e883ac10b19 (commit)
       via  29f6d05f66afabcd46c532622b10b370b65d3090 (commit)
       via  f941f042dc2c953390354434e9a4563cb67b14e0 (commit)
       via  54b12f14d032796a8d6638cdbbf6ba5d63835478 (commit)
       via  689aa37ea4cc087ad0affeedb2b4f8de5b29919d (commit)
       via  f4ca083e427788a22a4979a104b517a5a4ef3df9 (commit)
       via  3a6ae66c2a737475ed55fb28cd3cd49b49e7295e (commit)
       via  7184eb4185f5bd6577dda90e5100c13e238ed8fe (commit)
       via  2f220f9ff1a51348ea225d72a75d58d5d81031aa (commit)
       via  a87cf3103eb903132064550a8e75715d9b644620 (commit)
       via  427bc05eee647c9c5afb013f07c0cc73ff17aecc (commit)
       via  4f5e8221042782288e57974e38d4ab7d9de54740 (commit)
       via  a6949cd6433d089e240c6bdec095e12c4230214d (commit)
       via  42a5a7952572019c06a8dddec9994cdbe54e0d4a (commit)
       via  bc8cc9cf605cfbe065d0e27e8a081e5f54c6a4cd (commit)
       via  69abb657226d2002827b238503ef0f31a81d66c0 (commit)
       via  a752e1aeacc9470ff3dfb172bf3f9064eefc3161 (commit)
       via  d42136528ea0edc6c7ea45c3c4d4c542217f9d33 (commit)
       via  1024b43c68506682dd55cf1cf9c5fc9dbc8cd96b (commit)
       via  31df868ff405b57c6767fad73a7ba82ac0544e4a (commit)
       via  51c2df1a2974002d93335c5d762353795ba8ac92 (commit)
       via  1d139b0a312bae07267448c6e679b50ce24e5fc2 (commit)
      from  c077699ff43ddc2dff552b616044dab306f23666 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 9204d1f5951ea88ce351297885c83be3ceb33344
Merge: e41be59 c077699
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Fri May 17 09:32:08 2013 +0200

    Merge remote-tracking branch 'refs/remotes/origin/master'

commit e41be59e113c11dbad91634d47c832dffa628e8f
Merge: 0b690e4 6867682
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Fri May 17 08:52:32 2013 +0200

    Merge #2836
    
    Make the zone loading work even on top of MemorySegmentMapped. In
    particular, handle the MemorySegmentGrown exception, which may cause
    relocation of data.

-----------------------------------------------------------------------

Summary of changes:
 .../auth/tests/datasrc_clients_builder_unittest.cc |    2 +
 src/lib/datasrc/memory/Makefile.am                 |    1 +
 src/lib/datasrc/memory/domaintree.h                |   23 ++-
 src/lib/datasrc/memory/rdataset.h                  |    9 +
 .../datasrc/memory/segment_object_holder.cc}       |   34 ++--
 src/lib/datasrc/memory/segment_object_holder.h     |   82 ++++++--
 src/lib/datasrc/memory/zone_data.cc                |    8 +-
 src/lib/datasrc/memory/zone_data.h                 |   27 +++
 src/lib/datasrc/memory/zone_data_loader.cc         |   70 ++++---
 src/lib/datasrc/memory/zone_data_loader.h          |    2 +-
 src/lib/datasrc/memory/zone_data_updater.cc        |   74 ++++---
 src/lib/datasrc/memory/zone_data_updater.h         |   43 ++--
 src/lib/datasrc/memory/zone_table.cc               |    8 +-
 src/lib/datasrc/memory/zone_table.h                |   18 ++
 src/lib/datasrc/memory/zone_writer.cc              |   32 +--
 src/lib/datasrc/tests/client_list_unittest.cc      |    2 +
 src/lib/datasrc/tests/memory/rdataset_unittest.cc  |   74 +++----
 .../tests/memory/rrset_collection_unittest.cc      |   18 +-
 .../tests/memory/segment_object_holder_unittest.cc |   78 +++++++-
 .../tests/memory/zone_data_loader_unittest.cc      |   36 ++++
 .../tests/memory/zone_data_updater_unittest.cc     |  205 ++++++++++++++++----
 .../datasrc/tests/memory/zone_finder_unittest.cc   |   56 +++---
 .../datasrc/tests/memory/zone_table_unittest.cc    |   31 +--
 src/lib/util/memory_segment_mapped.cc              |   30 ++-
 src/lib/util/memory_segment_mapped.h               |    9 +-
 .../util/tests/memory_segment_mapped_unittest.cc   |    5 +-
 26 files changed, 714 insertions(+), 263 deletions(-)
 copy src/{bin/resolver/bench/dummy_work.h => lib/datasrc/memory/segment_object_holder.cc} (64%)

-----------------------------------------------------------------------
diff --git a/src/bin/auth/tests/datasrc_clients_builder_unittest.cc b/src/bin/auth/tests/datasrc_clients_builder_unittest.cc
index 5a24b30..8aa223b 100644
--- a/src/bin/auth/tests/datasrc_clients_builder_unittest.cc
+++ b/src/bin/auth/tests/datasrc_clients_builder_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <util/unittests/check_valgrind.h>
 
 #include <dns/name.h>
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index 44fe806..434eaf2 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -17,6 +17,7 @@ libdatasrc_memory_la_SOURCES += rdata_serialization.h rdata_serialization.cc
 libdatasrc_memory_la_SOURCES += zone_data.h zone_data.cc
 libdatasrc_memory_la_SOURCES += rrset_collection.h rrset_collection.cc
 libdatasrc_memory_la_SOURCES += segment_object_holder.h
+libdatasrc_memory_la_SOURCES += segment_object_holder.cc
 libdatasrc_memory_la_SOURCES += logger.h logger.cc
 libdatasrc_memory_la_SOURCES += zone_table.h zone_table.cc
 libdatasrc_memory_la_SOURCES += zone_finder.h zone_finder.cc
diff --git a/src/lib/datasrc/memory/domaintree.h b/src/lib/datasrc/memory/domaintree.h
index d503a11..4c6199a 100644
--- a/src/lib/datasrc/memory/domaintree.h
+++ b/src/lib/datasrc/memory/domaintree.h
@@ -1301,15 +1301,24 @@ public:
     /// doesn't exist.
     ///
     /// This method normally involves resource allocation.  If it fails
-    /// the corresponding standard exception will be thrown.
+    /// \c std::bad_alloc will be thrown.  Also, depending on details of the
+    /// specific \c MemorySegment, it can propagate the \c MemorySegmentGrown
+    /// exception.
     ///
     /// This method does not provide the strong exception guarantee in its
-    /// strict sense; if an exception is thrown in the middle of this
-    /// method, the internal structure may change.  However, it should
-    /// still retain the same property as a mapping container before this
-    /// method is called.  For example, the result of \c find() should be
-    /// the same.  This method provides the weak exception guarantee in its
-    /// normal sense.
+    /// strict sense; there can be new empty nodes that are superdomains of
+    /// the domain to be inserted as a side effect.  However, the tree
+    /// retains internal integrity otherwise, and, in particular, the intended
+    /// insert operation is "resumable": if the \c insert() method is called
+    /// again with the same argument after resolving the cause of the
+    /// exception (possibly multiple times), it should now succeed.  Note,
+    /// however, that in case of \c MemorySegmentGrown the address of the
+    /// `DomainTree` object may have been reallocated if it was created with
+    /// the same \c MemorySegment (which will often be the case in practice).
+    /// So the caller may have to re-get the address before calling \c insert
+    /// again.  It can be done using the concept of "named addresses" of
+    /// \c MemorySegment, or the direct caller may not have to worry about it
+    /// if this condition is guaranteed at a higher level.
     ///
     /// \param mem_sgmt A \c MemorySegment object for allocating memory of
     /// a new node to be inserted.  Must be the same segment as that used
diff --git a/src/lib/datasrc/memory/rdataset.h b/src/lib/datasrc/memory/rdataset.h
index 58201b1..caef551 100644
--- a/src/lib/datasrc/memory/rdataset.h
+++ b/src/lib/datasrc/memory/rdataset.h
@@ -176,6 +176,15 @@ public:
     /// it cannot contain more than 65535 RRSIGs.  If the given RRset(s) fail
     /// to meet this condition, an \c RdataSetError exception will be thrown.
     ///
+    /// This method ensures there'll be no memory leak on exception.
+    /// But addresses allocated from \c mem_sgmt could be relocated if
+    /// \c util::MemorySegmentGrown is thrown; the caller or its upper layer
+    /// must be aware of that possibility and update any such addresses
+    /// accordingly.  On successful return, this method ensures there's no
+    /// address relocation.
+    ///
+    /// \throw util::MemorySegmentGrown The memory segment has grown, possibly
+    ///     relocating data.
     /// \throw isc::BadValue Given RRset(s) are invalid (see the description)
     /// \throw RdataSetError Number of RDATAs exceed the limits
     /// \throw std::bad_alloc Memory allocation fails.
diff --git a/src/lib/datasrc/memory/segment_object_holder.cc b/src/lib/datasrc/memory/segment_object_holder.cc
new file mode 100644
index 0000000..40c5ef7
--- /dev/null
+++ b/src/lib/datasrc/memory/segment_object_holder.cc
@@ -0,0 +1,40 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "segment_object_holder.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include <cassert>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace detail {
+
+std::string
+getNextHolderName() {
+    static uint64_t index = 0;
+    ++index;
+    // in practice we should be able to assume this, uint64 is large
+    // and should not overflow
+    assert(index != 0);
+    return ("Segment object holder auto name " +
+            boost::lexical_cast<std::string>(index));
+}
+
+}
+}
+}
+}
diff --git a/src/lib/datasrc/memory/segment_object_holder.h b/src/lib/datasrc/memory/segment_object_holder.h
index 384f4ef..a716d4a 100644
--- a/src/lib/datasrc/memory/segment_object_holder.h
+++ b/src/lib/datasrc/memory/segment_object_holder.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -16,39 +16,99 @@
 #define DATASRC_MEMORY_SEGMENT_OBJECT_HOLDER_H 1
 
 #include <util/memory_segment.h>
+#include <string>
+#include <cassert>
 
 namespace isc {
 namespace datasrc {
 namespace memory {
 namespace detail {
 
+// Internal function to get next yet unused name of segment holder.
+// We need the names of holders to be unique per segment at any given
+// momemnt. This just keeps incrementing number after a prefix with
+// each call, it should be enough (we assert it does not wrap around,
+// but 64bits should be enough).
+//
+// Also, it is not thread safe.
+std::string
+getNextHolderName();
+
 // A simple holder to create and use some objects in this implementation
 // in an exception safe manner.   It works like std::auto_ptr but much
 // more simplified.
+//
+// Note, however, that it doesn't take the pointer to hold on construction.
+// This is because the constructor itself can throw or cause address
+// reallocation inside the memory segment.  If that happens various
+// undesirable effects can happen, such as memory leak or unintentional access
+// to the pre-reallocated address.  To make it safer, we use a separate
+// \c set() method, which is exception free and doesn't cause address
+// reallocation.  So the typical usage is to first construct the holder
+// object, then the object to be held, immediately followed by a call to \c
+// set(). Subsequent access to the held address should be done via the \c get()
+// method.  get() ensures the address is always valid in the memory segment
+// even if address reallocation happens between set() and get().
+//
 // template parameter T is the type of object allocated by mem_sgmt.
 // template parameter ARG_T is the type that will be passed to destroy()
 // (deleter functor, etc).  It must be copyable.
 template <typename T, typename ARG_T>
 class SegmentObjectHolder {
 public:
-    SegmentObjectHolder(util::MemorySegment& mem_sgmt, T* obj, ARG_T arg) :
-        mem_sgmt_(mem_sgmt), obj_(obj), arg_(arg)
-    {}
+    SegmentObjectHolder(util::MemorySegment& mem_sgmt, ARG_T arg) :
+        mem_sgmt_(mem_sgmt), arg_(arg),
+        holder_name_(getNextHolderName()), holding_(true)
+    {
+        if (mem_sgmt_.setNamedAddress(holder_name_.c_str(), NULL)) {
+            // OK. We've grown. The caller might need to be informed, so
+            // we throw. But then, we don't get our destructor, so we
+            // release the memory right away.
+            mem_sgmt_.clearNamedAddress(holder_name_.c_str());
+            isc_throw(isc::util::MemorySegmentGrown,
+                      "Segment grown when allocating holder");
+        }
+    }
     ~SegmentObjectHolder() {
-        if (obj_ != NULL) {
-            T::destroy(mem_sgmt_, obj_, arg_);
+        if (holding_) {
+            // Use release, as it removes the stored address from segment
+            T* obj = release();
+            if (obj) { // May be NULL if set wasn't called
+                T::destroy(mem_sgmt_, obj, arg_);
+            }
+        }
+    }
+    void set(T* obj) {
+        const bool grown = mem_sgmt_.setNamedAddress(holder_name_.c_str(),
+                                                     obj);
+        // We reserve the space in the constructor, should not grow now
+        assert(!grown);
+    }
+    T* get() {
+        if (holding_) {
+            const util::MemorySegment::NamedAddressResult result =
+                mem_sgmt_.getNamedAddress(holder_name_.c_str());
+            assert(result.first);
+            return (static_cast<T*>(result.second));
+        } else {
+            return (NULL);
         }
     }
-    T* get() { return (obj_); }
     T* release() {
-        T* ret = obj_;
-        obj_ = NULL;
-        return (ret);
+        if (holding_) {
+            T* obj = get();
+            mem_sgmt_.clearNamedAddress(holder_name_.c_str());
+            holding_ = false;
+            return (obj);
+        } else {
+            return (NULL);
+        }
     }
 private:
     util::MemorySegment& mem_sgmt_;
-    T* obj_;
     ARG_T arg_;
+    const std::string holder_name_;
+    bool holding_;
 };
 
 } // detail
diff --git a/src/lib/datasrc/memory/zone_data.cc b/src/lib/datasrc/memory/zone_data.cc
index d32fc87..bb626c1 100644
--- a/src/lib/datasrc/memory/zone_data.cc
+++ b/src/lib/datasrc/memory/zone_data.cc
@@ -91,8 +91,8 @@ NSEC3Data::create(util::MemorySegment& mem_sgmt,
     // (with an assertion check for that).
     typedef boost::function<void(RdataSet*)> RdataSetDeleterType;
     detail::SegmentObjectHolder<ZoneTree, RdataSetDeleterType> holder(
-        mem_sgmt, ZoneTree::create(mem_sgmt, true),
-        boost::bind(nullDeleter, _1));
+        mem_sgmt, boost::bind(nullDeleter, _1));
+    holder.set(ZoneTree::create(mem_sgmt, true));
 
     ZoneTree* tree = holder.get();
     const ZoneTree::Result result =
@@ -165,8 +165,8 @@ ZoneData::create(util::MemorySegment& mem_sgmt, const Name& zone_origin) {
     // NSEC3Data::create().
     typedef boost::function<void(RdataSet*)> RdataSetDeleterType;
     detail::SegmentObjectHolder<ZoneTree, RdataSetDeleterType> holder(
-        mem_sgmt, ZoneTree::create(mem_sgmt, true),
-        boost::bind(nullDeleter, _1));
+        mem_sgmt, boost::bind(nullDeleter, _1));
+    holder.set(ZoneTree::create(mem_sgmt, true));
 
     ZoneTree* tree = holder.get();
     ZoneNode* origin_node = NULL;
diff --git a/src/lib/datasrc/memory/zone_data.h b/src/lib/datasrc/memory/zone_data.h
index c6b3dcc..d511e47 100644
--- a/src/lib/datasrc/memory/zone_data.h
+++ b/src/lib/datasrc/memory/zone_data.h
@@ -86,6 +86,15 @@ public:
     /// The NSEC3 parameters are extracted and stored within the created
     /// \c NSEC3Data object.
     ///
+    /// This method ensures there'll be no memory leak on exception.
+    /// But addresses allocated from \c mem_sgmt could be relocated if
+    /// \c util::MemorySegmentGrown is thrown; the caller or its upper layer
+    /// must be aware of that possibility and update any such addresses
+    /// accordingly.  On successful return, this method ensures there's no
+    /// address relocation.
+    ///
+    /// \throw util::MemorySegmentGrown The memory segment has grown, possibly
+    ///     relocating data.
     /// \throw std::bad_alloc Memory allocation fails.
     ///
     /// \param mem_sgmt A \c MemorySegment from which memory for the new
@@ -102,6 +111,15 @@ public:
     /// The NSEC3 hash parameters are extracted and stored within the created
     /// \c NSEC3Data object.
     ///
+    /// This method ensures there'll be no memory leak on exception.
+    /// But addresses allocated from \c mem_sgmt could be relocated if
+    /// \c util::MemorySegmentGrown is thrown; the caller or its upper layer
+    /// must be aware of that possibility and update any such addresses
+    /// accordingly.  On successful return, this method ensures there's no
+    /// address relocation.
+    ///
+    /// \throw util::MemorySegmentGrown The memory segment has grown, possibly
+    ///     relocating data.
     /// \throw std::bad_alloc Memory allocation fails.
     ///
     /// \param mem_sgmt A \c MemorySegment from which memory for the new
@@ -375,6 +393,15 @@ public:
 public:
     /// \brief Allocate and construct \c ZoneData.
     ///
+    /// This method ensures there'll be no memory leak on exception.
+    /// But addresses allocated from \c mem_sgmt could be relocated if
+    /// \c util::MemorySegmentGrown is thrown; the caller or its upper layer
+    /// must be aware of that possibility and update any such addresses
+    /// accordingly.  On successful return, this method ensures there's no
+    /// address relocation.
+    ///
+    /// \throw util::MemorySegmentGrown The memory segment has grown, possibly
+    ///     relocating data.
     /// \throw std::bad_alloc Memory allocation fails.
     ///
     /// \param mem_sgmt A \c MemorySegment from which memory for the new
diff --git a/src/lib/datasrc/memory/zone_data_loader.cc b/src/lib/datasrc/memory/zone_data_loader.cc
index d66fb3b..e796dd4 100644
--- a/src/lib/datasrc/memory/zone_data_loader.cc
+++ b/src/lib/datasrc/memory/zone_data_loader.cc
@@ -131,7 +131,7 @@ ZoneDataLoader::flushNodeRRsets() {
     }
 
     // Normally rrsigsets map should be empty at this point, but it's still
-    // possible that an RRSIG that don't has covered RRset is added; they
+    // possible that an RRSIG that doesn't have covered RRset is added; they
     // still remain in the map.  We add them to the zone separately.
     BOOST_FOREACH(NodeRRsetsVal val, node_rrsigsets_) {
         updater_.add(ConstRRsetPtr(), val.second);
@@ -182,35 +182,47 @@ loadZoneDataInternal(util::MemorySegment& mem_sgmt,
                      const Name& zone_name,
                      boost::function<void(LoadCallback)> rrset_installer)
 {
-    SegmentObjectHolder<ZoneData, RRClass> holder(
-        mem_sgmt, ZoneData::create(mem_sgmt, zone_name), rrclass);
-
-    ZoneDataLoader loader(mem_sgmt, rrclass, zone_name, *holder.get());
-    rrset_installer(boost::bind(&ZoneDataLoader::addFromLoad, &loader, _1));
-    // Add any last RRsets that were left
-    loader.flushNodeRRsets();
-
-    const ZoneNode* origin_node = holder.get()->getOriginNode();
-    const RdataSet* rdataset = origin_node->getData();
-    // If the zone is NSEC3-signed, check if it has NSEC3PARAM
-    if (holder.get()->isNSEC3Signed()) {
-        if (RdataSet::find(rdataset, RRType::NSEC3PARAM()) == NULL) {
-            LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
-                arg(zone_name).arg(rrclass);
+    while (true) { // Try as long as it takes to load and grow the segment
+        bool created = false;
+        try {
+            SegmentObjectHolder<ZoneData, RRClass> holder(mem_sgmt, rrclass);
+            holder.set(ZoneData::create(mem_sgmt, zone_name));
+
+            // Nothing from this point on should throw MemorySegmentGrown.
+            // It is handled inside here.
+            created = true;
+
+            ZoneDataLoader loader(mem_sgmt, rrclass, zone_name, *holder.get());
+            rrset_installer(boost::bind(&ZoneDataLoader::addFromLoad, &loader,
+                                        _1));
+            // Add any last RRsets that were left
+            loader.flushNodeRRsets();
+
+            const ZoneNode* origin_node = holder.get()->getOriginNode();
+            const RdataSet* rdataset = origin_node->getData();
+            // If the zone is NSEC3-signed, check if it has NSEC3PARAM
+            if (holder.get()->isNSEC3Signed()) {
+                if (RdataSet::find(rdataset, RRType::NSEC3PARAM()) == NULL) {
+                    LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
+                        arg(zone_name).arg(rrclass);
+                }
+            }
+
+            RRsetCollection collection(*(holder.get()), rrclass);
+            const dns::ZoneCheckerCallbacks
+                callbacks(boost::bind(&logError, &zone_name, &rrclass, _1),
+                          boost::bind(&logWarning, &zone_name, &rrclass, _1));
+            if (!dns::checkZone(zone_name, rrclass, collection, callbacks)) {
+                isc_throw(ZoneValidationError,
+                          "Errors found when validating zone: "
+                          << zone_name << "/" << rrclass);
+            }
+
+            return (holder.release());
+        } catch (const util::MemorySegmentGrown&) {
+            assert(!created);
         }
     }
-
-    RRsetCollection collection(*(holder.get()), rrclass);
-    const dns::ZoneCheckerCallbacks
-        callbacks(boost::bind(&logError, &zone_name, &rrclass, _1),
-                  boost::bind(&logWarning, &zone_name, &rrclass, _1));
-    if (!dns::checkZone(zone_name, rrclass, collection, callbacks)) {
-        isc_throw(ZoneValidationError,
-                  "Errors found when validating zone: "
-                  << zone_name << "/" << rrclass);
-    }
-
-    return (holder.release());
 }
 
 // A wrapper for dns::MasterLoader used by loadZoneData() below.  Essentially
@@ -256,7 +268,7 @@ loadZoneData(util::MemorySegment& mem_sgmt,
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD_FROM_FILE).
         arg(zone_name).arg(rrclass).arg(zone_file);
 
-     return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
+    return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
                                  boost::bind(masterLoaderWrapper,
                                              zone_file.c_str(),
                                              zone_name, rrclass,
diff --git a/src/lib/datasrc/memory/zone_data_loader.h b/src/lib/datasrc/memory/zone_data_loader.h
index 32ed58b..56e1ada 100644
--- a/src/lib/datasrc/memory/zone_data_loader.h
+++ b/src/lib/datasrc/memory/zone_data_loader.h
@@ -57,7 +57,7 @@ ZoneData* loadZoneData(util::MemorySegment& mem_sgmt,
 /// \c iterator.
 ///
 /// Throws \c ZoneDataUpdater::AddError if invalid or inconsistent data
-/// is present in the \c zone_file. Throws \c isc::Unexpected if empty
+/// is present in the \c iterator. Throws \c isc::Unexpected if empty
 /// RRsets are passed by the zone iterator. Throws \c EmptyZone if an
 /// empty zone would be created due to the \c loadZoneData().
 ///
diff --git a/src/lib/datasrc/memory/zone_data_updater.cc b/src/lib/datasrc/memory/zone_data_updater.cc
index 4d7e7e0..a8a88e6 100644
--- a/src/lib/datasrc/memory/zone_data_updater.cc
+++ b/src/lib/datasrc/memory/zone_data_updater.cc
@@ -49,14 +49,14 @@ ZoneDataUpdater::addWildcards(const Name& name) {
             // Ensure a separate level exists for the "wildcarding"
             // name, and mark the node as "wild".
             ZoneNode* node;
-            zone_data_.insertName(mem_sgmt_, wname.split(1), &node);
+            zone_data_->insertName(mem_sgmt_, wname.split(1), &node);
             node->setFlag(ZoneData::WILDCARD_NODE);
 
             // Ensure a separate level exists for the wildcard name.
             // Note: for 'name' itself we do this later anyway, but the
             // overhead should be marginal because wildcard names should
             // be rare.
-            zone_data_.insertName(mem_sgmt_, wname, &node);
+            zone_data_->insertName(mem_sgmt_, wname, &node);
         }
     }
 }
@@ -210,7 +210,7 @@ ZoneDataUpdater::validate(const isc::dns::ConstRRsetPtr rrset) const {
 const NSEC3Hash*
 ZoneDataUpdater::getNSEC3Hash() {
     if (hash_ == NULL) {
-        NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+        NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
         // This should never be NULL in this codepath.
         assert(nsec3_data != NULL);
 
@@ -231,11 +231,11 @@ ZoneDataUpdater::setupNSEC3(const ConstRRsetPtr rrset) {
         dynamic_cast<const T&>(
             rrset->getRdataIterator()->getCurrent());
 
-    NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+    NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
     if (nsec3_data == NULL) {
         nsec3_data = NSEC3Data::create(mem_sgmt_, zone_name_, nsec3_rdata);
-        zone_data_.setNSEC3Data(nsec3_data);
-        zone_data_.setSigned(true);
+        zone_data_->setNSEC3Data(nsec3_data);
+        zone_data_->setSigned(true);
     } else {
         const NSEC3Hash* hash = getNSEC3Hash();
         if (!hash->match(nsec3_rdata)) {
@@ -247,14 +247,14 @@ ZoneDataUpdater::setupNSEC3(const ConstRRsetPtr rrset) {
 }
 
 void
-ZoneDataUpdater::addNSEC3(const Name& name, const ConstRRsetPtr rrset,
-                          const ConstRRsetPtr rrsig)
+ZoneDataUpdater::addNSEC3(const Name& name, const ConstRRsetPtr& rrset,
+                          const ConstRRsetPtr& rrsig)
 {
     if (rrset) {
         setupNSEC3<generic::NSEC3>(rrset);
     }
 
-    NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+    NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
     if (nsec3_data == NULL) {
         // This is some tricky case: an RRSIG for NSEC3 is given without the
         // covered NSEC3, and we don't even know any NSEC3 related data.
@@ -283,14 +283,14 @@ ZoneDataUpdater::addNSEC3(const Name& name, const ConstRRsetPtr rrset,
 
 void
 ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
-                             const ConstRRsetPtr rrset,
-                             const ConstRRsetPtr rrsig)
+                             const ConstRRsetPtr& rrset,
+                             const ConstRRsetPtr& rrsig)
 {
     if (rrtype == RRType::NSEC3()) {
         addNSEC3(name, rrset, rrsig);
     } else {
         ZoneNode* node;
-        zone_data_.insertName(mem_sgmt_, name, &node);
+        zone_data_->insertName(mem_sgmt_, name, &node);
 
         RdataSet* rdataset_head = node->getData();
 
@@ -334,7 +334,7 @@ ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
         // Ok, we just put it in.
 
         // Convenient (and more efficient) shortcut to check RRsets at origin
-        const bool is_origin = (node == zone_data_.getOriginNode());
+        const bool is_origin = (node == zone_data_->getOriginNode());
 
         // If this RRset creates a zone cut at this node, mark the node
         // indicating the need for callback in find().  Note that we do this
@@ -356,7 +356,7 @@ ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
             // (conceptually "signed" is a broader notion but our
             // current zone finder implementation regards "signed" as
             // "NSEC signed")
-            zone_data_.setSigned(true);
+            zone_data_->setSigned(true);
         }
 
         // If we are adding a new SOA at the origin, update zone's min TTL.
@@ -365,7 +365,7 @@ ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
         // this should be only once in normal cases) update the TTL.
         if (rrset && rrtype == RRType::SOA() && is_origin) {
             // Our own validation ensures the RRset is not empty.
-            zone_data_.setMinTTL(
+            zone_data_->setMinTTL(
                 dynamic_cast<const generic::SOA&>(
                     rrset->getRdataIterator()->getCurrent()).getMinimum());
         }
@@ -373,6 +373,24 @@ ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
 }
 
 void
+ZoneDataUpdater::addInternal(const isc::dns::Name& name,
+                     const isc::dns::RRType& rrtype,
+                     const isc::dns::ConstRRsetPtr& rrset,
+                     const isc::dns::ConstRRsetPtr& rrsig)
+{
+    // Add wildcards possibly contained in the owner name to the domain
+    // tree.  This can only happen for the normal (non-NSEC3) tree.
+    // Note: this can throw an exception, breaking strong exception
+    // guarantee.  (see also the note for the call to contextCheck()
+    // above).
+    if (rrtype != RRType::NSEC3()) {
+        addWildcards(name);
+    }
+
+    addRdataSet(name, rrtype, rrset, rrsig);
+}
+
+void
 ZoneDataUpdater::add(const ConstRRsetPtr& rrset,
                      const ConstRRsetPtr& sig_rrset)
 {
@@ -397,16 +415,22 @@ ZoneDataUpdater::add(const ConstRRsetPtr& rrset,
         arg(rrset ? rrtype.toText() : "RRSIG(" + rrtype.toText() + ")").
         arg(zone_name_);
 
-    // Add wildcards possibly contained in the owner name to the domain
-    // tree.  This can only happen for the normal (non-NSEC3) tree.
-    // Note: this can throw an exception, breaking strong exception
-    // guarantee.  (see also the note for the call to contextCheck()
-    // above).
-    if (rrtype != RRType::NSEC3()) {
-        addWildcards(name);
-    }
-
-    addRdataSet(name, rrtype, rrset, sig_rrset);
+    // Store the address, it may change during growth and the address inside
+    // would get updated.
+    bool added = false;
+    do {
+        try {
+            addInternal(name, rrtype, rrset, sig_rrset);
+            added = true;
+        } catch (const isc::util::MemorySegmentGrown&) {
+            // The segment has grown. So, we update the base pointer (because
+            // the data may have been remapped somewhere else in the process).
+            zone_data_ =
+                static_cast<ZoneData*>(
+                    mem_sgmt_.getNamedAddress("updater_zone_data").second);
+        }
+        // Retry if it didn't add due to the growth
+    } while (!added);
 }
 
 } // namespace memory
diff --git a/src/lib/datasrc/memory/zone_data_updater.h b/src/lib/datasrc/memory/zone_data_updater.h
index 9d669a0..e8826bd 100644
--- a/src/lib/datasrc/memory/zone_data_updater.h
+++ b/src/lib/datasrc/memory/zone_data_updater.h
@@ -57,14 +57,15 @@ public:
 
     /// The constructor.
     ///
-    /// \throw none
-    ///
     /// \param mem_sgmt The memory segment used for the zone data.
     /// \param rrclass The RRclass of the zone data.
     /// \param zone_name The Name of the zone under which records will be
     ///                  added.
-    //  \param zone_data The ZoneData object which is populated with
-    //                   record data.
+    /// \param zone_data The ZoneData object which is populated with
+    ///                  record data.
+    /// \throw InvalidOperation if there's already a zone data updater
+    ///    on the given memory segment. Currently, at most one zone data
+    ///    updater may exist on the same memory segment.
     ZoneDataUpdater(util::MemorySegment& mem_sgmt,
                     isc::dns::RRClass rrclass,
                     const isc::dns::Name& zone_name,
@@ -72,12 +73,25 @@ public:
        mem_sgmt_(mem_sgmt),
        rrclass_(rrclass),
        zone_name_(zone_name),
-       zone_data_(zone_data),
-       hash_(NULL)
-    {}
+       hash_(NULL),
+       zone_data_(&zone_data)
+    {
+        if (mem_sgmt_.getNamedAddress("updater_zone_data").first) {
+            isc_throw(isc::InvalidOperation, "A ZoneDataUpdater already exists"
+                      " on this memory segment. Destroy it first.");
+        }
+        if (mem_sgmt_.setNamedAddress("updater_zone_data", zone_data_)) {
+            // It might have relocated during the set
+            zone_data_ =
+                static_cast<ZoneData*>(mem_sgmt_.getNamedAddress(
+                                           "updater_zone_data").second);
+        }
+        assert(zone_data_);
+    }
 
     /// The destructor.
     ~ZoneDataUpdater() {
+        mem_sgmt_.clearNamedAddress("updater_zone_data");
         delete hash_;
     }
 
@@ -159,6 +173,11 @@ private:
     // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
     void addWildcards(const isc::dns::Name& name);
 
+    void addInternal(const isc::dns::Name& name,
+                     const isc::dns::RRType& rrtype,
+                     const isc::dns::ConstRRsetPtr& rrset,
+                     const isc::dns::ConstRRsetPtr& rrsig);
+
     // Does some checks in context of the data that are already in the
     // zone.  Currently checks for forbidden combinations of RRsets in
     // the same domain (CNAME+anything, DNAME+NS).  If such condition is
@@ -175,19 +194,19 @@ private:
     template <typename T>
     void setupNSEC3(const isc::dns::ConstRRsetPtr rrset);
     void addNSEC3(const isc::dns::Name& name,
-                  const isc::dns::ConstRRsetPtr rrset,
-                  const isc::dns::ConstRRsetPtr rrsig);
+                  const isc::dns::ConstRRsetPtr& rrset,
+                  const isc::dns::ConstRRsetPtr& rrsig);
     void addRdataSet(const isc::dns::Name& name,
                      const isc::dns::RRType& rrtype,
-                     const isc::dns::ConstRRsetPtr rrset,
-                     const isc::dns::ConstRRsetPtr rrsig);
+                     const isc::dns::ConstRRsetPtr& rrset,
+                     const isc::dns::ConstRRsetPtr& rrsig);
 
     util::MemorySegment& mem_sgmt_;
     const isc::dns::RRClass rrclass_;
     const isc::dns::Name& zone_name_;
-    ZoneData& zone_data_;
     RdataEncoder encoder_;
     const isc::dns::NSEC3Hash* hash_;
+    ZoneData* zone_data_;
 };
 
 } // namespace memory
diff --git a/src/lib/datasrc/memory/zone_table.cc b/src/lib/datasrc/memory/zone_table.cc
index 77071f4..2ecf14a 100644
--- a/src/lib/datasrc/memory/zone_table.cc
+++ b/src/lib/datasrc/memory/zone_table.cc
@@ -50,8 +50,8 @@ typedef boost::function<void(ZoneData*)> ZoneDataDeleterType;
 ZoneTable*
 ZoneTable::create(util::MemorySegment& mem_sgmt, const RRClass& zone_class) {
     SegmentObjectHolder<ZoneTableTree, ZoneDataDeleterType> holder(
-        mem_sgmt, ZoneTableTree::create(mem_sgmt),
-        boost::bind(deleteZoneData, &mem_sgmt, _1, zone_class));
+        mem_sgmt, boost::bind(deleteZoneData, &mem_sgmt, _1, zone_class));
+    holder.set(ZoneTableTree::create(mem_sgmt));
     void* p = mem_sgmt.allocate(sizeof(ZoneTable));
     ZoneTable* zone_table = new(p) ZoneTable(zone_class, holder.get());
     holder.release();
@@ -77,8 +77,8 @@ ZoneTable::addZone(util::MemorySegment& mem_sgmt, RRClass zone_class,
     if (content == NULL) {
         isc_throw(isc::BadValue, "Zone content must not be NULL");
     }
-    SegmentObjectHolder<ZoneData, RRClass> holder(mem_sgmt, content,
-                                                  zone_class);
+    SegmentObjectHolder<ZoneData, RRClass> holder(mem_sgmt, zone_class);
+    holder.set(content);
     // Get the node where we put the zone
     ZoneTableNode* node(NULL);
     switch (zones_->insert(mem_sgmt, zone_name, &node)) {
diff --git a/src/lib/datasrc/memory/zone_table.h b/src/lib/datasrc/memory/zone_table.h
index 2774df3..d3bf903 100644
--- a/src/lib/datasrc/memory/zone_table.h
+++ b/src/lib/datasrc/memory/zone_table.h
@@ -115,6 +115,15 @@ public:
     /// from the given memory segment, constructs the object, and returns
     /// a pointer to it.
     ///
+    /// This method ensures there'll be no memory leak on exception.
+    /// But addresses allocated from \c mem_sgmt could be relocated if
+    /// \c util::MemorySegmentGrown is thrown; the caller or its upper layer
+    /// must be aware of that possibility and update any such addresses
+    /// accordingly.  On successful return, this method ensures there's no
+    /// address relocation.
+    ///
+    /// \throw util::MemorySegmentGrown The memory segment has grown, possibly
+    ///     relocating data.
     /// \throw std::bad_alloc Memory allocation fails.
     ///
     /// \param mem_sgmt A \c MemorySegment from which memory for the new
@@ -149,6 +158,15 @@ public:
     ///
     /// This method adds a given zone data to the internal table.
     ///
+    /// This method ensures there'll be no memory leak on exception.
+    /// But addresses allocated from \c mem_sgmt could be relocated if
+    /// \c util::MemorySegmentGrown is thrown; the caller or its upper layer
+    /// must be aware of that possibility and update any such addresses
+    /// accordingly.  On successful return, this method ensures there's no
+    /// address relocation.
+    ///
+    /// \throw util::MemorySegmentGrown The memory segment has grown, possibly
+    ///     relocating data.
     /// \throw std::bad_alloc Internal resource allocation fails.
     ///
     /// \param mem_sgmt The \c MemorySegment to allocate zone data to be
diff --git a/src/lib/datasrc/memory/zone_writer.cc b/src/lib/datasrc/memory/zone_writer.cc
index 3cb646a..a2b1ac7 100644
--- a/src/lib/datasrc/memory/zone_writer.cc
+++ b/src/lib/datasrc/memory/zone_writer.cc
@@ -54,14 +54,13 @@ ZoneWriter::load() {
     }
 
     zone_data_ = load_action_(segment_.getMemorySegment());
+    segment_.resetHeader();
 
     if (!zone_data_) {
         // Bug inside load_action_.
         isc_throw(isc::InvalidOperation, "No data returned from load action");
     }
 
-    segment_.resetHeader();
-
     state_ = ZW_LOADED;
 }
 
@@ -71,18 +70,25 @@ ZoneWriter::install() {
         isc_throw(isc::InvalidOperation, "No data to install");
     }
 
-    ZoneTable* table(segment_.getHeader().getTable());
-    if (!table) {
-        isc_throw(isc::Unexpected, "No zone table present");
+    // FIXME: This retry is currently untested, as there seems to be no
+    // reasonable way to create a zone table segment with non-local memory
+    // segment. Once there is, we should provide the test.
+    while (state_ != ZW_INSTALLED) {
+        try {
+            ZoneTable* table(segment_.getHeader().getTable());
+            if (table == NULL) {
+                isc_throw(isc::Unexpected, "No zone table present");
+            }
+            const ZoneTable::AddResult result(table->addZone(
+                                                  segment_.getMemorySegment(),
+                                                  rrclass_, origin_,
+                                                  zone_data_));
+            state_ = ZW_INSTALLED;
+            zone_data_ = result.zone_data;
+        } catch (const isc::util::MemorySegmentGrown&) {}
+
+        segment_.resetHeader();
     }
-    const ZoneTable::AddResult result(table->addZone(
-                                          segment_.getMemorySegment(),
-                                          rrclass_, origin_, zone_data_));
-
-    state_ = ZW_INSTALLED;
-    zone_data_ = result.zone_data;
-
-    segment_.resetHeader();
 }
 
 void
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index 745654c..f57aa30 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
 #include <datasrc/cache_config.h>
diff --git a/src/lib/datasrc/tests/memory/rdataset_unittest.cc b/src/lib/datasrc/tests/memory/rdataset_unittest.cc
index 1a964ef..31e5be2 100644
--- a/src/lib/datasrc/tests/memory/rdataset_unittest.cc
+++ b/src/lib/datasrc/tests/memory/rdataset_unittest.cc
@@ -191,20 +191,16 @@ TEST_F(RdataSetTest, mergeCreate) {
             SCOPED_TRACE("creating merge case " + lexical_cast<string>(i) +
                          ", " + lexical_cast<string>(j));
             // Create old rdataset
-            SegmentObjectHolder<RdataSet, RRClass> holder1(
-                mem_sgmt_,
-                RdataSet::create(mem_sgmt_, encoder_,
+            SegmentObjectHolder<RdataSet, RRClass> holder1(mem_sgmt_, rrclass);
+            holder1.set(RdataSet::create(mem_sgmt_, encoder_,
                                  (i & 1) != 0 ? a_rrsets[0] : null_rrset,
-                                 (i & 2) != 0 ? rrsig_rrsets[0] : null_rrset),
-                rrclass);
+                                 (i & 2) != 0 ? rrsig_rrsets[0] : null_rrset));
             // Create merged rdataset, based on the old one and RRsets
-            SegmentObjectHolder<RdataSet, RRClass> holder2(
-                mem_sgmt_,
-                RdataSet::create(mem_sgmt_, encoder_,
+            SegmentObjectHolder<RdataSet, RRClass> holder2(mem_sgmt_, rrclass);
+            holder2.set(RdataSet::create(mem_sgmt_, encoder_,
                                  (j & 1) != 0 ? a_rrsets[1] : null_rrset,
                                  (j & 2) != 0 ? rrsig_rrsets[1] : null_rrset,
-                                 holder1.get()),
-                rrclass);
+                                 holder1.get()));
 
             // Set up the expected data for the case.
             vector<string> expected_rdata;
@@ -241,16 +237,14 @@ TEST_F(RdataSetTest, duplicate) {
 
     // After suppressing duplicates, it should be the same as the default
     // RdataSet.  Check that.
-    SegmentObjectHolder<RdataSet, RRClass> holder1(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_, dup_rrset, dup_rrsig), rrclass);
+    SegmentObjectHolder<RdataSet, RRClass> holder1(mem_sgmt_, rrclass);
+    holder1.set(RdataSet::create(mem_sgmt_, encoder_, dup_rrset, dup_rrsig));
     checkRdataSet(*holder1.get(), def_rdata_txt_, def_rrsig_txt_);
 
     // Confirm the same thing for the merge mode.
-    SegmentObjectHolder<RdataSet, RRClass> holder2(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_, a_rrset_, rrsig_rrset_,
-                         holder1.get()), rrclass);
+    SegmentObjectHolder<RdataSet, RRClass> holder2(mem_sgmt_, rrclass);
+    holder2.set(RdataSet::create(mem_sgmt_, encoder_, a_rrset_, rrsig_rrset_,
+                                 holder1.get()));
     checkRdataSet(*holder2.get(), def_rdata_txt_, def_rrsig_txt_);
 }
 
@@ -275,24 +269,21 @@ TEST_F(RdataSetTest, getNext) {
 
 TEST_F(RdataSetTest, find) {
     // Create some RdataSets and make a chain of them.
-    SegmentObjectHolder<RdataSet, RRClass> holder1(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_, a_rrset_, ConstRRsetPtr()),
-        RRClass::IN());
+    SegmentObjectHolder<RdataSet, RRClass> holder1(mem_sgmt_, RRClass::IN());
+    holder1.set(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                 ConstRRsetPtr()));
     ConstRRsetPtr aaaa_rrset =
         textToRRset("www.example.com. 1076895760 IN AAAA 2001:db8::1");
-    SegmentObjectHolder<RdataSet, RRClass> holder2(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset, ConstRRsetPtr()),
-        RRClass::IN());
+    SegmentObjectHolder<RdataSet, RRClass> holder2(mem_sgmt_, RRClass::IN());
+    holder2.set(RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset,
+                                 ConstRRsetPtr()));
     ConstRRsetPtr sigonly_rrset =
         textToRRset("www.example.com. 1076895760 IN RRSIG "
                     "TXT 5 2 3600 20120814220826 20120715220826 "
                     "1234 example.com. FAKE");
-    SegmentObjectHolder<RdataSet, RRClass> holder3(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(), sigonly_rrset),
-        RRClass::IN());
+    SegmentObjectHolder<RdataSet, RRClass> holder3(mem_sgmt_, RRClass::IN());
+    holder3.set(RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
+                                 sigonly_rrset));
 
     RdataSet* rdataset_a = holder1.get();
     RdataSet* rdataset_aaaa = holder2.get();
@@ -376,10 +367,8 @@ TEST_F(RdataSetTest, createManyRRs) {
 
 TEST_F(RdataSetTest, mergeCreateManyRRs) {
     ConstRRsetPtr rrset = textToRRset("example.com. 3600 IN TXT some-text");
-    SegmentObjectHolder<RdataSet, RRClass> holder(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_, rrset, ConstRRsetPtr()),
-        RRClass::IN());
+    SegmentObjectHolder<RdataSet, RRClass> holder(mem_sgmt_, RRClass::IN());
+    holder.set(RdataSet::create(mem_sgmt_, encoder_, rrset, ConstRRsetPtr()));
 
     checkCreateManyRRs(boost::bind(&RdataSet::create, _1, _2, _3, _4,
                                    holder.get()), rrset->getRdataCount());
@@ -474,10 +463,8 @@ TEST_F(RdataSetTest, mergeCreateManyRRSIGs) {
     ConstRRsetPtr rrsig = textToRRset(
         "example.com. 3600 IN RRSIG A 5 2 3600 20120814220826 20120715220826 "
         "1234 example.com. FAKEFAKE");
-    SegmentObjectHolder<RdataSet, RRClass> holder(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(), rrsig),
-        rrclass);
+    SegmentObjectHolder<RdataSet, RRClass> holder(mem_sgmt_, rrclass);
+    holder.set(RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(), rrsig));
 
     checkCreateManyRRSIGs(boost::bind(&RdataSet::create, _1, _2, _3, _4,
                                       holder.get()), rrsig->getRdataCount());
@@ -543,12 +530,10 @@ TEST_F(RdataSetTest, badCreate) {
 TEST_F(RdataSetTest, badMergeCreate) {
     // The 'old RdataSet' for merge.  Its content doesn't matter much; the test
     // should trigger exception before examining it except for the last checks.
-    SegmentObjectHolder<RdataSet, RRClass> holder(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_,
+    SegmentObjectHolder<RdataSet, RRClass> holder(mem_sgmt_, RRClass::IN());
+    holder.set(RdataSet::create(mem_sgmt_, encoder_,
                          textToRRset("www.example.com. 0 IN AAAA 2001:db8::1"),
-                         ConstRRsetPtr()),
-        RRClass::IN());
+                         ConstRRsetPtr()));
 
     checkBadCreate(boost::bind(&RdataSet::create, _1, _2, _3, _4,
                                holder.get()));
@@ -585,9 +570,8 @@ TEST_F(RdataSetTest, varyingTTL) {
     RdataSet::destroy(mem_sgmt_, rdataset, rrclass);
 
     // RRSIG's TTL is smaller
-    SegmentObjectHolder<RdataSet, RRClass> holder1(
-        mem_sgmt_,
-        RdataSet::create(mem_sgmt_, encoder_, aaaa_large, sig_small), rrclass);
+    SegmentObjectHolder<RdataSet, RRClass> holder1(mem_sgmt_, rrclass);
+    holder1.set(RdataSet::create(mem_sgmt_, encoder_, aaaa_large, sig_small));
     EXPECT_EQ(RRTTL(10), restoreTTL(holder1.get()->getTTLData()));
 
     // Merging another RRset (w/o sig) that has larger TTL
diff --git a/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc b/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
index 6329b6b..f3d3934 100644
--- a/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
+++ b/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
@@ -24,6 +24,8 @@
 
 #include <gtest/gtest.h>
 
+#include <boost/scoped_ptr.hpp>
+
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace std;
@@ -43,22 +45,24 @@ public:
         rrclass("IN"),
         origin("example.org"),
         zone_file(TEST_DATA_DIR "/rrset-collection.zone"),
-        zone_data_holder(mem_sgmt,
-                         loadZoneData(mem_sgmt, rrclass, origin, zone_file),
-                         rrclass),
-        collection(*zone_data_holder.get(), rrclass)
-    {}
+        zone_data_holder(mem_sgmt, rrclass)
+    {
+        zone_data_holder.set(loadZoneData(mem_sgmt, rrclass, origin,
+                                          zone_file));
+        collection.reset(new RRsetCollection(*zone_data_holder.get(),
+                                             rrclass));
+    }
 
     const RRClass rrclass;
     const Name origin;
     std::string zone_file;
     test::MemorySegmentMock mem_sgmt;
     SegmentObjectHolder<ZoneData, RRClass> zone_data_holder;
-    RRsetCollection collection;
+    boost::scoped_ptr<RRsetCollection> collection;
 };
 
 TEST_F(RRsetCollectionTest, find) {
-    const RRsetCollection& ccln = collection;
+    const RRsetCollection& ccln = *collection;
     ConstRRsetPtr rrset = ccln.find(Name("www.example.org"), rrclass,
                                     RRType::A());
     EXPECT_TRUE(rrset);
diff --git a/src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc b/src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc
index d27e364..73aa18b 100644
--- a/src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc
@@ -12,10 +12,17 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <util/memory_segment_local.h>
+#include <util/memory_segment_mapped.h>
 
 #include <datasrc/memory/segment_object_holder.h>
 
+#ifdef USE_SHARED_MEMORY
+#include <boost/interprocess/managed_mapped_file.hpp>
+#endif
+
 #include <gtest/gtest.h>
 
 using namespace isc::util;
@@ -24,12 +31,14 @@ using namespace isc::datasrc::memory::detail;
 
 namespace {
 const int TEST_ARG_VAL = 42;    // arbitrary chosen magic number
+const char* const mapped_file = TEST_DATA_BUILDDIR "/test.mapped";
 
 class TestObject {
 public:
     static void destroy(MemorySegment& sgmt, TestObject* obj, int arg) {
         sgmt.deallocate(obj, sizeof(*obj));
         EXPECT_EQ(TEST_ARG_VAL, arg);
+        EXPECT_TRUE(obj);
     }
 };
 
@@ -42,7 +51,8 @@ useHolder(MemorySegment& sgmt, TestObject* obj, bool release) {
     // deallocate().
 
     typedef SegmentObjectHolder<TestObject, int> HolderType;
-    HolderType holder(sgmt, obj, TEST_ARG_VAL);
+    HolderType holder(sgmt, TEST_ARG_VAL);
+    holder.set(obj);
     EXPECT_EQ(obj, holder.get());
     if (release) {
         EXPECT_EQ(obj, holder.release());
@@ -64,4 +74,70 @@ TEST(SegmentObjectHolderTest, foo) {
     useHolder(sgmt, obj, false);
     EXPECT_TRUE(sgmt.allMemoryDeallocated());
 }
+
+// Test nothing bad happens if the holder is not set before it is destroyed
+TEST(SegmentObjectHolderTest, destroyNotSet) {
+    MemorySegmentLocal sgmt;
+    {
+        typedef SegmentObjectHolder<TestObject, int> HolderType;
+        HolderType holder(sgmt, TEST_ARG_VAL);
+    }
+    EXPECT_TRUE(sgmt.allMemoryDeallocated());
+}
+
+#ifdef USE_SHARED_MEMORY
+// Keep allocating bigger and bigger chunks of data until the allocation
+// fails with growing the segment.
+void
+allocateUntilGrows(MemorySegment& segment, size_t& current_size) {
+    // Create an object that will not be explicitly deallocated.
+    // It must be deallocated by the segment holder and even in case
+    // the position moved.
+    void *object_memory = segment.allocate(sizeof(TestObject));
+    TestObject* object = new(object_memory) TestObject;
+    SegmentObjectHolder<TestObject, int> holder(segment, TEST_ARG_VAL);
+    holder.set(object);
+    while (true) {
+        void* data = segment.allocate(current_size);
+        segment.deallocate(data, current_size);
+        current_size *= 2;
+    }
+}
+
+// Check that the segment thing releases stuff even in case it throws
+// SegmentGrown exception and the thing moves address
+TEST(SegmentObjectHolderTest, grow) {
+    MemorySegmentMapped segment(mapped_file,
+                                isc::util::MemorySegmentMapped::CREATE_ONLY);
+    // Allocate a bit of memory, to get a unique address
+    void* mark = segment.allocate(1);
+    segment.setNamedAddress("mark", mark);
+
+    // We'd like to cause 'mark' will be mapped at a different address on
+    // MemorySegmentGrown; there doesn't seem to be a reliable and safe way
+    // to cause this situation, but opening another mapped region seems to
+    // often work in practice.  We use Boost managed_mapped_file directly
+    // to ignore the imposed file lock with MemorySegmentMapped.
+    using boost::interprocess::managed_mapped_file;
+    using boost::interprocess::open_only;
+    managed_mapped_file mapped_sgmt(open_only, mapped_file);
+
+    // Try allocating bigger and bigger chunks of data until the segment
+    // actually relocates
+    size_t alloc_size = 1024;
+    EXPECT_THROW(allocateUntilGrows(segment, alloc_size), MemorySegmentGrown);
+    // Confirm it's now mapped at a different address.
+    EXPECT_NE(mark, segment.getNamedAddress("mark").second)
+        << "portability assumption for the test doesn't hold; "
+        "disable the test by setting env variable GTEST_FILTER to "
+        "'-SegmentObjectHolderTest.grow'";
+    mark = segment.getNamedAddress("mark").second;
+    segment.clearNamedAddress("mark");
+    segment.deallocate(mark, 1);
+    EXPECT_TRUE(segment.allMemoryDeallocated());
+    // Remove the file
+    EXPECT_EQ(0, unlink(mapped_file));
+}
+#endif
+
 }
diff --git a/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
index 47ec4d3..bfd79a5 100644
--- a/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
@@ -16,11 +16,16 @@
 #include <datasrc/memory/rdataset.h>
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/segment_object_holder.h>
+#include <datasrc/zone_iterator.h>
 
 #include <util/buffer.h>
 
 #include <dns/name.h>
 #include <dns/rrclass.h>
+#include <dns/rdataclass.h>
+#include <util/memory_segment_mapped.h>
+#include <util/memory_segment_local.h>
 
 #include <datasrc/tests/memory/memory_segment_mock.h>
 
@@ -28,9 +33,13 @@
 
 using namespace isc::dns;
 using namespace isc::datasrc::memory;
+using isc::util::MemorySegmentMapped;
+using isc::datasrc::memory::detail::SegmentObjectHolder;
 
 namespace {
 
+const char* const mapped_file = TEST_DATA_BUILDDIR "/test.mapped";
+
 class ZoneDataLoaderTest : public ::testing::Test {
 protected:
     ZoneDataLoaderTest() : zclass_(RRClass::IN()), zone_data_(NULL) {}
@@ -73,4 +82,31 @@ TEST_F(ZoneDataLoaderTest, zoneMinTTL) {
     EXPECT_EQ(RRTTL(1200), RRTTL(b));
 }
 
+// Load bunch of small zones, hoping some of the relocation will happen
+// during the memory creation, not only Rdata creation.
+TEST(ZoneDataLoaterTest, relocate) {
+    MemorySegmentMapped segment(mapped_file,
+                                isc::util::MemorySegmentMapped::CREATE_ONLY,
+                                4096);
+    const size_t zone_count = 10000;
+    typedef SegmentObjectHolder<ZoneData, RRClass> Holder;
+    typedef boost::shared_ptr<Holder> HolderPtr;
+    std::vector<HolderPtr> zones;
+    for (size_t i = 0; i < zone_count; ++i) {
+        // Load some zone
+        ZoneData* data = loadZoneData(segment, RRClass::IN(),
+                                      Name("example.org"),
+                                      TEST_DATA_DIR
+                                      "/example.org-nsec3-signed.zone");
+        // Store it, so it is cleaned up later
+        zones.push_back(HolderPtr(new Holder(segment, RRClass::IN())));
+        zones.back()->set(data);
+
+    }
+    // Deallocate all the zones now.
+    zones.clear();
+    EXPECT_TRUE(segment.allMemoryDeallocated());
+    EXPECT_EQ(0, unlink(mapped_file));
+}
+
 }
diff --git a/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
index 94870f9..f3e814a 100644
--- a/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
 #include <datasrc/memory/zone_data_updater.h>
 #include <datasrc/memory/rdataset.h>
 #include <datasrc/memory/zone_data.h>
@@ -25,11 +27,14 @@
 #include <dns/rrset.h>
 #include <dns/rrttl.h>
 
+#include <util/memory_segment_local.h>
+#include <util/memory_segment_mapped.h>
 #include <datasrc/tests/memory/memory_segment_mock.h>
 
 #include <gtest/gtest.h>
 
 #include <boost/scoped_ptr.hpp>
+#include <boost/lexical_cast.hpp>
 
 #include <cassert>
 
@@ -39,71 +44,158 @@ using namespace isc::datasrc::memory;
 
 namespace {
 
-class ZoneDataUpdaterTest : public ::testing::Test {
+const char* const mapped_file = TEST_DATA_BUILDDIR "/test.mapped";
+
+// An abstract factory class for the segments. We want fresh segment for each
+// test, so we have different factories for them.
+class SegmentCreator {
+public:
+    virtual ~SegmentCreator() {}
+    typedef boost::shared_ptr<isc::util::MemorySegment> SegmentPtr;
+    // Create the segment.
+    virtual SegmentPtr create() const = 0;
+    // Clean-up after the test. Most of them will be just NOP (the default),
+    // but the file-mapped one needs to remove the file.
+    virtual void cleanup() const {}
+};
+
+ZoneNode*
+getNode(isc::util::MemorySegment& mem_sgmt, const Name& name,
+        ZoneData* zone_data)
+{
+    ZoneNode* node = NULL;
+    zone_data->insertName(mem_sgmt, name, &node);
+    EXPECT_NE(static_cast<ZoneNode*>(NULL), node);
+    return (node);
+}
+
+class ZoneDataUpdaterTest : public ::testing::TestWithParam<SegmentCreator*> {
 protected:
     ZoneDataUpdaterTest() :
         zname_("example.org"), zclass_(RRClass::IN()),
-        zone_data_(ZoneData::create(mem_sgmt_, zname_)),
-        updater_(new ZoneDataUpdater(mem_sgmt_, zclass_, zname_, *zone_data_))
-    {}
+        mem_sgmt_(GetParam()->create())
+    {
+        ZoneData* data = ZoneData::create(*mem_sgmt_, zname_);
+        mem_sgmt_->setNamedAddress("Test zone data", data);
+        updater_.reset(new ZoneDataUpdater(*mem_sgmt_, zclass_, zname_,
+                                           *data));
+    }
 
     ~ZoneDataUpdaterTest() {
-        if (zone_data_ != NULL) {
-            ZoneData::destroy(mem_sgmt_, zone_data_, zclass_);
-        }
-        if (!mem_sgmt_.allMemoryDeallocated()) {
+        assert(updater_);
+        ZoneData::destroy(*mem_sgmt_, getZoneData(), zclass_);
+        // Release the updater, so it frees all memory inside the segment too
+        updater_.reset();
+        mem_sgmt_->clearNamedAddress("Test zone data");
+        if (!mem_sgmt_->allMemoryDeallocated()) {
             ADD_FAILURE() << "Memory leak detected";
         }
+        GetParam()->cleanup();
     }
 
     void clearZoneData() {
-        assert(zone_data_ != NULL);
-        ZoneData::destroy(mem_sgmt_, zone_data_, zclass_);
-        zone_data_ = ZoneData::create(mem_sgmt_, zname_);
-        updater_.reset(new ZoneDataUpdater(mem_sgmt_, zclass_, zname_,
-                                           *zone_data_));
+        assert(updater_);
+        ZoneData::destroy(*mem_sgmt_, getZoneData(), zclass_);
+        mem_sgmt_->clearNamedAddress("Test zone data");
+        updater_.reset();
+        ZoneData* data = ZoneData::create(*mem_sgmt_, zname_);
+        mem_sgmt_->setNamedAddress("Test zone data", data);
+        updater_.reset(new ZoneDataUpdater(*mem_sgmt_, zclass_, zname_,
+                                           *data));
+    }
+
+    ZoneData* getZoneData() {
+        return (static_cast<ZoneData*>(
+            mem_sgmt_->getNamedAddress("Test zone data").second));
     }
 
     const Name zname_;
     const RRClass zclass_;
-    test::MemorySegmentMock mem_sgmt_;
-    ZoneData* zone_data_;
+    boost::shared_ptr<isc::util::MemorySegment> mem_sgmt_;
     boost::scoped_ptr<ZoneDataUpdater> updater_;
 };
 
-TEST_F(ZoneDataUpdaterTest, bothNull) {
+class TestSegmentCreator : public SegmentCreator {
+public:
+    virtual SegmentPtr create() const {
+        return (SegmentPtr(new test::MemorySegmentMock));
+    }
+};
+
+TestSegmentCreator test_segment_creator;
+
+INSTANTIATE_TEST_CASE_P(TestSegment, ZoneDataUpdaterTest,
+                        ::testing::Values(static_cast<SegmentCreator*>(
+                            &test_segment_creator)));
+
+class MemorySegmentCreator : public SegmentCreator {
+public:
+    virtual SegmentPtr create() const {
+        // We are not really supposed to create the segment directly in real
+        // code, but it should be OK inside tests.
+        return (SegmentPtr(new isc::util::MemorySegmentLocal));
+    }
+};
+
+MemorySegmentCreator memory_segment_creator;
+
+INSTANTIATE_TEST_CASE_P(LocalSegment, ZoneDataUpdaterTest,
+                        ::testing::Values(static_cast<SegmentCreator*>(
+                            &memory_segment_creator)));
+
+class MappedSegmentCreator : public SegmentCreator {
+public:
+    MappedSegmentCreator(size_t initial_size =
+                         isc::util::MemorySegmentMapped::INITIAL_SIZE) :
+        initial_size_(initial_size)
+    {}
+    virtual SegmentPtr create() const {
+        return (SegmentPtr(new isc::util::MemorySegmentMapped(
+                               mapped_file,
+                               isc::util::MemorySegmentMapped::CREATE_ONLY,
+                               initial_size_)));
+    }
+    virtual void cleanup() const {
+        EXPECT_EQ(0, unlink(mapped_file));
+    }
+private:
+    const size_t initial_size_;
+};
+
+#ifdef USE_SHARED_MEMORY
+// There should be no initialization fiasco there. We only set int value inside
+// and don't use it until the create() is called.
+MappedSegmentCreator small_creator(4092), default_creator;
+
+INSTANTIATE_TEST_CASE_P(MappedSegment, ZoneDataUpdaterTest, ::testing::Values(
+                            static_cast<SegmentCreator*>(&small_creator),
+                            static_cast<SegmentCreator*>(&default_creator)));
+#endif
+
+TEST_P(ZoneDataUpdaterTest, bothNull) {
     // At least either covered RRset or RRSIG must be non NULL.
     EXPECT_THROW(updater_->add(ConstRRsetPtr(), ConstRRsetPtr()),
                  ZoneDataUpdater::NullRRset);
 }
 
-ZoneNode*
-getNode(isc::util::MemorySegment& mem_sgmt, const Name& name,
-        ZoneData* zone_data)
-{
-    ZoneNode* node = NULL;
-    zone_data->insertName(mem_sgmt, name, &node);
-    EXPECT_NE(static_cast<ZoneNode*>(NULL), node);
-    return (node);
-}
-
-TEST_F(ZoneDataUpdaterTest, zoneMinTTL) {
+TEST_P(ZoneDataUpdaterTest, zoneMinTTL) {
     // If we add SOA, zone's min TTL will be updated.
     updater_->add(textToRRset(
                       "example.org. 3600 IN SOA . . 0 0 0 0 1200",
                       zclass_, zname_),
                   ConstRRsetPtr());
-    isc::util::InputBuffer b(zone_data_->getMinTTLData(), sizeof(uint32_t));
+    isc::util::InputBuffer b(getZoneData()->getMinTTLData(), sizeof(uint32_t));
     EXPECT_EQ(RRTTL(1200), RRTTL(b));
 }
 
-TEST_F(ZoneDataUpdaterTest, rrsigOnly) {
+TEST_P(ZoneDataUpdaterTest, rrsigOnly) {
     // RRSIG that doesn't have covered RRset can be added.  The resulting
     // rdataset won't have "normal" RDATA but sig RDATA.
     updater_->add(ConstRRsetPtr(), textToRRset(
                       "www.example.org. 3600 IN RRSIG A 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    ZoneNode* node = getNode(mem_sgmt_, Name("www.example.org"), zone_data_);
+    ZoneNode* node = getNode(*mem_sgmt_, Name("www.example.org"),
+                             getZoneData());
     const RdataSet* rdset = node->getData();
     ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
     rdset = RdataSet::find(rdset, RRType::A(), true);
@@ -121,7 +213,7 @@ TEST_F(ZoneDataUpdaterTest, rrsigOnly) {
     updater_->add(ConstRRsetPtr(), textToRRset(
                       "*.wild.example.org. 3600 IN RRSIG A 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    node = getNode(mem_sgmt_, Name("wild.example.org"), zone_data_);
+    node = getNode(*mem_sgmt_, Name("wild.example.org"), getZoneData());
     EXPECT_TRUE(node->getFlag(ZoneData::WILDCARD_NODE));
 
     // Simply adding RRSIG covering (delegating NS) shouldn't enable callback
@@ -129,14 +221,14 @@ TEST_F(ZoneDataUpdaterTest, rrsigOnly) {
     updater_->add(ConstRRsetPtr(), textToRRset(
                       "child.example.org. 3600 IN RRSIG NS 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    node = getNode(mem_sgmt_, Name("child.example.org"), zone_data_);
+    node = getNode(*mem_sgmt_, Name("child.example.org"), getZoneData());
     EXPECT_FALSE(node->getFlag(ZoneNode::FLAG_CALLBACK));
 
     // Same for DNAME
     updater_->add(ConstRRsetPtr(), textToRRset(
                       "dname.example.org. 3600 IN RRSIG DNAME 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    node = getNode(mem_sgmt_, Name("dname.example.org"), zone_data_);
+    node = getNode(*mem_sgmt_, Name("dname.example.org"), getZoneData());
     EXPECT_FALSE(node->getFlag(ZoneNode::FLAG_CALLBACK));
 
     // Likewise, RRSIG for NSEC3PARAM alone shouldn't make the zone
@@ -144,13 +236,13 @@ TEST_F(ZoneDataUpdaterTest, rrsigOnly) {
     updater_->add(ConstRRsetPtr(), textToRRset(
                       "example.org. 3600 IN RRSIG NSEC3PARAM 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    EXPECT_FALSE(zone_data_->isNSEC3Signed());
+    EXPECT_FALSE(getZoneData()->isNSEC3Signed());
 
     // And same for (RRSIG for) NSEC and "is signed".
     updater_->add(ConstRRsetPtr(), textToRRset(
                       "example.org. 3600 IN RRSIG NSEC 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    EXPECT_FALSE(zone_data_->isSigned());
+    EXPECT_FALSE(getZoneData()->isSigned());
 }
 
 // Commonly used checks for rrsigForNSEC3Only
@@ -168,7 +260,7 @@ checkNSEC3Rdata(isc::util::MemorySegment& mem_sgmt, const Name& name,
     EXPECT_EQ(1, rdset->getSigRdataCount());
 }
 
-TEST_F(ZoneDataUpdaterTest, rrsigForNSEC3Only) {
+TEST_P(ZoneDataUpdaterTest, rrsigForNSEC3Only) {
     // Adding only RRSIG covering NSEC3 is tricky.  It should go to the
     // separate NSEC3 tree, but the separate space is only created when
     // NSEC3 or NSEC3PARAM is added.  So, in many cases RRSIG-only is allowed,
@@ -183,12 +275,12 @@ TEST_F(ZoneDataUpdaterTest, rrsigForNSEC3Only) {
                   textToRRset(
                       "example.org. 3600 IN RRSIG NSEC3PARAM 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    EXPECT_TRUE(zone_data_->isNSEC3Signed());
+    EXPECT_TRUE(getZoneData()->isNSEC3Signed());
     updater_->add(ConstRRsetPtr(),
                   textToRRset(
                       "09GM.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    checkNSEC3Rdata(mem_sgmt_, Name("09GM.example.org"), zone_data_);
+    checkNSEC3Rdata(*mem_sgmt_, Name("09GM.example.org"), getZoneData());
 
     // Clear the current content of zone, then add NSEC3
     clearZoneData();
@@ -201,7 +293,7 @@ TEST_F(ZoneDataUpdaterTest, rrsigForNSEC3Only) {
                   textToRRset(
                       "09GM.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
                       "20150420235959 20051021000000 1 example.org. FAKE"));
-    checkNSEC3Rdata(mem_sgmt_, Name("09GM.example.org"), zone_data_);
+    checkNSEC3Rdata(*mem_sgmt_, Name("09GM.example.org"), getZoneData());
 
     // If we add only RRSIG without any NSEC3 related data beforehand,
     // it will be rejected; it's a limitation of the current implementation.
@@ -214,4 +306,39 @@ TEST_F(ZoneDataUpdaterTest, rrsigForNSEC3Only) {
                  isc::NotImplemented);
 }
 
+// Generate many small RRsets. This tests that the underlying memory segment
+// can grow during the execution and that the updater handles that well.
+//
+// Some of the grows will happen inserting the RRSIG, some with the TXT. Or,
+// at least we hope so.
+TEST_P(ZoneDataUpdaterTest, manySmallRRsets) {
+    for (size_t i = 0; i < 32768; ++i) {
+        const std::string name(boost::lexical_cast<std::string>(i) +
+                               ".example.org.");
+        updater_->add(textToRRset(name + " 3600 IN TXT " +
+                                  std::string(30, 'X')),
+                      textToRRset(name + " 3600 IN RRSIG TXT 5 3 3600 "
+                                  "20150420235959 20051021000000 1 "
+                                  "example.org. FAKE"));
+        ZoneNode* node = getNode(*mem_sgmt_,
+                                 Name(boost::lexical_cast<std::string>(i) +
+                                      ".example.org"), getZoneData());
+        const RdataSet* rdset = node->getData();
+        ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
+        rdset = RdataSet::find(rdset, RRType::TXT(), true);
+        ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
+        EXPECT_EQ(1, rdset->getRdataCount());
+        EXPECT_EQ(1, rdset->getSigRdataCount());
+    }
+}
+
+TEST_P(ZoneDataUpdaterTest, updaterCollision) {
+    ZoneData* zone_data = ZoneData::create(*mem_sgmt_,
+                                           Name("another.example.com."));
+    EXPECT_THROW(ZoneDataUpdater(*mem_sgmt_, RRClass::IN(),
+                                 Name("another.example.com."), *zone_data),
+                 isc::InvalidOperation);
+    ZoneData::destroy(*mem_sgmt_, zone_data, RRClass::IN());
+}
+
 }
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index be53820..e07ab27 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -98,7 +98,7 @@ protected:
         origin_("example.org"),
         zone_data_(ZoneData::create(mem_sgmt_, origin_)),
         zone_finder_(*zone_data_, class_),
-        updater_(mem_sgmt_, class_, origin_, *zone_data_)
+        updater_(new ZoneDataUpdater(mem_sgmt_, class_, origin_, *zone_data_))
     {
         // Build test RRsets.  Below, we construct an RRset for
         // each textual RR(s) of zone_data, and assign it to the corresponding
@@ -196,7 +196,7 @@ protected:
     }
 
     void addToZoneData(const ConstRRsetPtr rrset) {
-        updater_.add(rrset, rrset->getRRsig());
+        updater_->add(rrset, rrset->getRRsig());
     }
 
     /// \brief expensive rrset converter
@@ -224,7 +224,7 @@ protected:
     MemorySegmentMock mem_sgmt_;
     memory::ZoneData* zone_data_;
     memory::InMemoryZoneFinder zone_finder_;
-    ZoneDataUpdater updater_;
+    boost::scoped_ptr<ZoneDataUpdater> updater_;
 
     // Placeholder for storing RRsets to be checked with rrsetsCheck()
     vector<ConstRRsetPtr> actual_rrsets_;
@@ -1549,19 +1549,19 @@ TEST_F(InMemoryZoneFinderTest, findOrphanRRSIG) {
     // Add A for ns.example.org, and RRSIG-only covering TXT for the same name.
     // query for the TXT should result in NXRRSET.
     addToZoneData(rr_ns_a_);
-    updater_.add(ConstRRsetPtr(),
-                 textToRRset(
-                     "ns.example.org. 300 IN RRSIG TXT 5 3 300 20120814220826 "
-                     "20120715220826 1234 example.com. FAKE"));
+    updater_->add(ConstRRsetPtr(),
+                  textToRRset(
+                      "ns.example.org. 300 IN RRSIG TXT 5 3 300 20120814220826 "
+                      "20120715220826 1234 example.com. FAKE"));
     findTest(Name("ns.example.org"), RRType::TXT(),
              ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
 
     // Add RRSIG-only covering NSEC.  This shouldn't be returned when NSEC is
     // requested, whether it's for NXRRSET or NXDOMAIN
-    updater_.add(ConstRRsetPtr(),
-                 textToRRset(
-                     "ns.example.org. 300 IN RRSIG NSEC 5 3 300 "
-                     "20120814220826 20120715220826 1234 example.com. FAKE"));
+    updater_->add(ConstRRsetPtr(),
+                  textToRRset(
+                      "ns.example.org. 300 IN RRSIG NSEC 5 3 300 "
+                      "20120814220826 20120715220826 1234 example.com. FAKE"));
     // The added RRSIG for NSEC could be used for NXRRSET but shouldn't
     findTest(Name("ns.example.org"), RRType::TXT(),
              ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
@@ -1572,29 +1572,29 @@ TEST_F(InMemoryZoneFinderTest, findOrphanRRSIG) {
              expected_flags, NULL, ZoneFinder::FIND_DNSSEC);
 
     // RRSIG-only CNAME shouldn't be accidentally confused with real CNAME.
-    updater_.add(ConstRRsetPtr(),
-                 textToRRset(
-                     "nocname.example.org. 300 IN RRSIG CNAME 5 3 300 "
-                     "20120814220826 20120715220826 1234 example.com. FAKE"));
+    updater_->add(ConstRRsetPtr(),
+                  textToRRset(
+                      "nocname.example.org. 300 IN RRSIG CNAME 5 3 300 "
+                      "20120814220826 20120715220826 1234 example.com. FAKE"));
     findTest(Name("nocname.example.org"), RRType::A(),
              ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
 
     // RRSIG-only for NS wouldn't invoke delegation anyway, but we check this
     // case explicitly.
-    updater_.add(ConstRRsetPtr(),
-                 textToRRset(
-                     "nodelegation.example.org. 300 IN RRSIG NS 5 3 300 "
-                     "20120814220826 20120715220826 1234 example.com. FAKE"));
+    updater_->add(ConstRRsetPtr(),
+                  textToRRset(
+                      "nodelegation.example.org. 300 IN RRSIG NS 5 3 300 "
+                      "20120814220826 20120715220826 1234 example.com. FAKE"));
     findTest(Name("nodelegation.example.org"), RRType::A(),
              ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
     findTest(Name("www.nodelegation.example.org"), RRType::A(),
              ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
 
     // Same for RRSIG-only for DNAME
-    updater_.add(ConstRRsetPtr(),
-                 textToRRset(
-                     "nodname.example.org. 300 IN RRSIG DNAME 5 3 300 "
-                     "20120814220826 20120715220826 1234 example.com. FAKE"));
+    updater_->add(ConstRRsetPtr(),
+                  textToRRset(
+                      "nodname.example.org. 300 IN RRSIG DNAME 5 3 300 "
+                      "20120814220826 20120715220826 1234 example.com. FAKE"));
     findTest(Name("www.nodname.example.org"), RRType::A(),
              ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
     // If we have a delegation NS at this node, it will be a bit trickier,
@@ -1614,6 +1614,7 @@ TEST_F(InMemoryZoneFinderTest, NSECNonExistentTest) {
     const Name name("example.com.");
     shared_ptr<ZoneTableSegment> ztable_segment(
          new ZoneTableSegmentMock(class_, mem_sgmt_));
+    updater_.reset();
     loadZoneIntoTable(*ztable_segment, name, class_,
                       TEST_DATA_DIR "/2504-test.zone");
     InMemoryClient client(ztable_segment, class_);
@@ -1758,10 +1759,10 @@ TEST_F(InMemoryZoneFinderNSEC3Test, RRSIGOnly) {
     // add an RRSIG-only NSEC3 to the NSEC3 space, and try to find it; it
     // should result in an exception.
     const string n8_hash = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
-    updater_.add(ConstRRsetPtr(),
-                 textToRRset(
-                     n8_hash + ".example.org. 300 IN RRSIG NSEC3 5 3 300 "
-                     "20120814220826 20120715220826 1234 example.com. FAKE"));
+    updater_->add(ConstRRsetPtr(),
+                  textToRRset(
+                      n8_hash + ".example.org. 300 IN RRSIG NSEC3 5 3 300 "
+                      "20120814220826 20120715220826 1234 example.com. FAKE"));
     EXPECT_THROW(zone_finder_.findNSEC3(Name("n8.example.org"), false),
                  DataSourceError);
 }
@@ -1776,6 +1777,7 @@ TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3MissingOrigin) {
      const Name name("example.com.");
      shared_ptr<ZoneTableSegment> ztable_segment(
           new ZoneTableSegmentMock(class_, mem_sgmt_));
+     updater_.reset();
      loadZoneIntoTable(*ztable_segment, name, class_,
                        TEST_DATA_DIR "/2503-test.zone");
      InMemoryClient client(ztable_segment, class_);
diff --git a/src/lib/datasrc/tests/memory/zone_table_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
index 6599f3b..300a50e 100644
--- a/src/lib/datasrc/tests/memory/zone_table_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
@@ -79,7 +79,8 @@ TEST_F(ZoneTableTest, addZone) {
     EXPECT_EQ(0, zone_table->getZoneCount()); // count is still 0
 
     SegmentObjectHolder<ZoneData, RRClass> holder1(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, zname1), zclass_);
+        mem_sgmt_, zclass_);
+    holder1.set(ZoneData::create(mem_sgmt_, zname1));
     const ZoneData* data1(holder1.get());
     // Normal successful case.
     const ZoneTable::AddResult result1(zone_table->addZone(mem_sgmt_, zclass_,
@@ -93,7 +94,8 @@ TEST_F(ZoneTableTest, addZone) {
 
     // Duplicate add doesn't replace the existing data.
     SegmentObjectHolder<ZoneData, RRClass> holder2(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, zname1), zclass_);
+        mem_sgmt_, zclass_);
+    holder2.set(ZoneData::create(mem_sgmt_, zname1));
     const ZoneTable::AddResult result2(zone_table->addZone(mem_sgmt_, zclass_,
                                                            zname1,
                                                            holder2.release()));
@@ -107,8 +109,8 @@ TEST_F(ZoneTableTest, addZone) {
     EXPECT_EQ(1, zone_table->getZoneCount()); // count doesn't change.
 
     SegmentObjectHolder<ZoneData, RRClass> holder3(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, Name("EXAMPLE.COM")),
-                                    zclass_);
+        mem_sgmt_, zclass_);
+    holder3.set(ZoneData::create(mem_sgmt_, Name("EXAMPLE.COM")));
     // names are compared in a case insensitive manner.
     const ZoneTable::AddResult result3(zone_table->addZone(mem_sgmt_, zclass_,
                                                            Name("EXAMPLE.COM"),
@@ -117,13 +119,15 @@ TEST_F(ZoneTableTest, addZone) {
     ZoneData::destroy(mem_sgmt_, result3.zone_data, zclass_);
     // Add some more different ones.  Should just succeed.
     SegmentObjectHolder<ZoneData, RRClass> holder4(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, zname2), zclass_);
+        mem_sgmt_, zclass_);
+    holder4.set(ZoneData::create(mem_sgmt_, zname2));
     EXPECT_EQ(result::SUCCESS,
               zone_table->addZone(mem_sgmt_, zclass_, zname2,
                                   holder4.release()).code);
     EXPECT_EQ(2, zone_table->getZoneCount());
     SegmentObjectHolder<ZoneData, RRClass> holder5(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, zname3), zclass_);
+        mem_sgmt_, zclass_);
+    holder5.set(ZoneData::create(mem_sgmt_, zname3));
     EXPECT_EQ(result::SUCCESS,
               zone_table->addZone(mem_sgmt_, zclass_, zname3,
                                   holder5.release()).code);
@@ -133,7 +137,8 @@ TEST_F(ZoneTableTest, addZone) {
     // tree.  It still shouldn't cause memory leak (which would be detected
     // in TearDown()).
     SegmentObjectHolder<ZoneData, RRClass> holder6(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, Name("example.org")), zclass_);
+        mem_sgmt_, zclass_);
+    holder6.set(ZoneData::create(mem_sgmt_, Name("example.org")));
     mem_sgmt_.setThrowCount(1);
     EXPECT_THROW(zone_table->addZone(mem_sgmt_, zclass_, Name("example.org"),
                                      holder6.release()),
@@ -142,17 +147,20 @@ TEST_F(ZoneTableTest, addZone) {
 
 TEST_F(ZoneTableTest, findZone) {
     SegmentObjectHolder<ZoneData, RRClass> holder1(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, zname1), zclass_);
+        mem_sgmt_, zclass_);
+    holder1.set(ZoneData::create(mem_sgmt_, zname1));
     ZoneData* zone_data = holder1.get();
     EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zclass_, zname1,
                                                    holder1.release()).code);
     SegmentObjectHolder<ZoneData, RRClass> holder2(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, zname2), zclass_);
+        mem_sgmt_, zclass_);
+    holder2.set(ZoneData::create(mem_sgmt_, zname2));
     EXPECT_EQ(result::SUCCESS,
               zone_table->addZone(mem_sgmt_, zclass_, zname2,
                                   holder2.release()).code);
     SegmentObjectHolder<ZoneData, RRClass> holder3(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, zname3), zclass_);
+        mem_sgmt_, zclass_);
+    holder3.set(ZoneData::create(mem_sgmt_, zname3));
     EXPECT_EQ(result::SUCCESS,
               zone_table->addZone(mem_sgmt_, zclass_, zname3,
                                   holder3.release()).code);
@@ -177,7 +185,8 @@ TEST_F(ZoneTableTest, findZone) {
     // make sure the partial match is indeed the longest match by adding
     // a zone with a shorter origin and query again.
     SegmentObjectHolder<ZoneData, RRClass> holder4(
-        mem_sgmt_, ZoneData::create(mem_sgmt_, Name("com")), zclass_);
+        mem_sgmt_, zclass_);
+    holder4.set(ZoneData::create(mem_sgmt_, Name("com")));
     EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zclass_,
                                                    Name("com"),
                                                    holder4.release()).code);
diff --git a/src/lib/util/memory_segment_mapped.cc b/src/lib/util/memory_segment_mapped.cc
index 0d82ffd..8c76e74 100644
--- a/src/lib/util/memory_segment_mapped.cc
+++ b/src/lib/util/memory_segment_mapped.cc
@@ -171,6 +171,7 @@ struct MemorySegmentMapped::Impl {
     void growSegment() {
         // We first need to unmap it before calling grow().
         const size_t prev_size = base_sgmt_->get_size();
+        base_sgmt_->flush();
         base_sgmt_.reset();
 
         // Double the segment size.  In theory, this process could repeat
@@ -181,16 +182,21 @@ struct MemorySegmentMapped::Impl {
         const size_t new_size = prev_size * 2;
         assert(new_size > prev_size);
 
-        if (!BaseSegment::grow(filename_.c_str(), new_size - prev_size)) {
-            throw std::bad_alloc();
-        }
+        const bool grown = BaseSegment::grow(filename_.c_str(),
+                                             new_size - prev_size);
 
+        // Remap the file, whether or not grow() succeeded.  this should
+        // normally succeed(*), but it's not 100% guaranteed.  We abort
+        // if it fails (see the method description in the header file).
+        // (*) Although it's not formally documented, the implementation
+        // of grow() seems to provide strong guarantee, i.e, if it fails
+        // the underlying file can be used with the previous size.
         try {
-            // Remap the grown file; this should succeed, but it's not 100%
-            // guaranteed.  If it fails we treat it as if we fail to create
-            // the new segment.
             base_sgmt_.reset(new BaseSegment(open_only, filename_.c_str()));
-        } catch (const boost::interprocess::interprocess_exception& ex) {
+        } catch (...) {
+            abort();
+        }
+        if (!grown) {
             throw std::bad_alloc();
         }
     }
@@ -402,14 +408,20 @@ MemorySegmentMapped::shrinkToFit() {
         return;
     }
 
-    // First, (unmap and) close the underlying file.
+    // First, unmap the underlying file.
+    impl_->base_sgmt_->flush();
     impl_->base_sgmt_.reset();
 
     BaseSegment::shrink_to_fit(impl_->filename_.c_str());
     try {
         // Remap the shrunk file; this should succeed, but it's not 100%
         // guaranteed.  If it fails we treat it as if we fail to create
-        // the new segment.
+        // the new segment.  Note that this is different from the case where
+        // reset() after grow() fails.  While the same argument can apply
+        // in theory, it should be less likely that other methods will be
+        // called after shrinkToFit() (and the destructor can still be called
+        // safely), so we give the application an opportunity to handle the
+        // case as gracefully as possible.
         impl_->base_sgmt_.reset(
             new BaseSegment(open_only, impl_->filename_.c_str()));
     } catch (const boost::interprocess::interprocess_exception& ex) {
diff --git a/src/lib/util/memory_segment_mapped.h b/src/lib/util/memory_segment_mapped.h
index 7702d88..f5596f6 100644
--- a/src/lib/util/memory_segment_mapped.h
+++ b/src/lib/util/memory_segment_mapped.h
@@ -150,7 +150,14 @@ public:
 
     /// \brief Allocate/acquire a segment of memory.
     ///
-    /// This version can throw \c MemorySegmentGrown.
+    /// This version can throw \c MemorySegmentGrown.  Furthermore, there is
+    /// a very small chance that the object loses its integrity and can't be
+    /// usable in the case where \c MemorySegmentGrown would be thrown.
+    /// In this case, throwing a different exception wouldn't help, because
+    /// an application trying to provide exception safety might then call
+    /// deallocate() or named address APIs on this object, which would simply
+    /// cause a crash.  So, while suboptimal, this method just aborts the
+    /// program in this case, indicating there's no hope to shutdown cleanly.
     ///
     /// This method cannot be called if the segment object is created in the
     /// read-only mode; in that case MemorySegmentError will be thrown.
diff --git a/src/lib/util/tests/memory_segment_mapped_unittest.cc b/src/lib/util/tests/memory_segment_mapped_unittest.cc
index 475d3e5..287ee38 100644
--- a/src/lib/util/tests/memory_segment_mapped_unittest.cc
+++ b/src/lib/util/tests/memory_segment_mapped_unittest.cc
@@ -238,11 +238,12 @@ TEST_F(MemorySegmentMappedTest, allocate) {
 
 TEST_F(MemorySegmentMappedTest, badAllocate) {
     // Make the mapped file non-writable; managed_mapped_file::grow() will
-    // fail, resulting in std::bad_alloc
+    // fail, resulting in abort.
     const int ret = chmod(mapped_file, 0444);
     ASSERT_EQ(0, ret);
 
-    EXPECT_THROW(segment_->allocate(DEFAULT_INITIAL_SIZE * 2), std::bad_alloc);
+    EXPECT_DEATH_IF_SUPPORTED(
+        {segment_->allocate(DEFAULT_INITIAL_SIZE * 2);}, "");
 }
 
 // XXX: this test can cause too strong side effect (creating a very large



More information about the bind10-changes mailing list