Add client requests
   VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE and
   VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE
and supporting machinery for managing whole-address-space sparse
mappings.  n-i-bz.  In support of
https://bugzilla.mozilla.org/show_bug.cgi?id=970643



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13884 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NEWS b/NEWS
index 88dff2e..11b6723 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,11 @@
 
 * ==================== TOOL CHANGES ====================
 
+* Memcheck:
+  - new client requests 
+    VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE and
+    VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE
+
 * Helgrind:
 
 * Callgrind:
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index c168ae2..99f767c 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -191,6 +191,7 @@
 	pub_core_mallocfree.h	\
 	pub_core_options.h	\
 	pub_core_oset.h		\
+	pub_core_rangemap.h	\
 	pub_core_redir.h	\
 	pub_core_poolalloc.h	\
 	pub_core_replacemalloc.h\
@@ -292,6 +293,7 @@
 	m_mallocfree.c \
 	m_options.c \
 	m_oset.c \
+	m_rangemap.c \
 	m_redir.c \
 	m_sbprofile.c \
 	m_seqmatch.c \
diff --git a/coregrind/m_rangemap.c b/coregrind/m_rangemap.c
new file mode 100644
index 0000000..b066fb9
--- /dev/null
+++ b/coregrind/m_rangemap.c
@@ -0,0 +1,218 @@
+
+/*--------------------------------------------------------------------*/
+/*--- A mapping where the keys exactly cover the address space.    ---*/
+/*---                                                 m_rangemap.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2014-2014 Mozilla Foundation
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Contributed by Julian Seward <jseward@acm.org> */
+
+#include "pub_core_basics.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_xarray.h"
+#include "pub_core_rangemap.h"    /* self */
+
+
+/* See pub_tool_rangemap.h for details of what this is all about. */
+
+#define UWORD_MIN ((UWord)0)
+#define UWORD_MAX (~(UWord)0)
+
+typedef
+   struct { UWord key_min; UWord key_max; UWord val; }
+   Range;
+
+
+struct _RangeMap {
+   void* (*alloc) ( const HChar*, SizeT ); /* alloc fn (nofail) */
+   const HChar* cc;                 /* cost centre for alloc */
+   void  (*free) ( void* );         /* free fn */
+   XArray* ranges;
+};
+
+
+/* fwds */
+static void preen (/*MOD*/RangeMap* rm);
+static Word find ( RangeMap* rm, UWord key );
+static void split_at ( /*MOD*/RangeMap* rm, UWord key );
+static void show ( RangeMap* rm );
+
+
+RangeMap* VG_(newRangeMap) ( void*(*alloc_fn)(const HChar*,SizeT), 
+                             const HChar* cc,
+                             void(*free_fn)(void*),
+                             UWord initialVal )
+{
+   /* check user-supplied info .. */
+   vg_assert(alloc_fn);
+   vg_assert(free_fn);
+   RangeMap* rm = alloc_fn(cc, sizeof(RangeMap));
+   vg_assert(rm);
+   rm->alloc  = alloc_fn;
+   rm->cc     = cc;
+   rm->free   = free_fn;
+   rm->ranges = VG_(newXA)( alloc_fn, cc, free_fn, sizeof(Range) );
+   vg_assert(rm->ranges);
+   /* Add the initial range */
+   Range r;
+   r.key_min = UWORD_MIN;
+   r.key_max = UWORD_MAX;
+   r.val     = initialVal;
+   Word i = VG_(addToXA)(rm->ranges, &r);
+   vg_assert(i == 0);
+   vg_assert(VG_(sizeXA)(rm->ranges) == 1);
+   /* */
+   return rm;
+}
+
+void VG_(deleteRangeMap) ( RangeMap* rm )
+{
+   vg_assert(rm);
+   vg_assert(rm->free);
+   vg_assert(rm->ranges);
+   VG_(deleteXA)(rm->ranges);
+   rm->free(rm);
+}
+
+void VG_(bindRangeMap) ( RangeMap* rm,
+                         UWord key_min, UWord key_max, UWord val )
+{
+   vg_assert(key_min <= key_max);
+   split_at(rm, key_min);
+   if (key_max < UWORD_MAX)
+      split_at(rm, key_max + 1);
+   Word iMin, iMax, i;
+   iMin = find(rm, key_min);
+   iMax = find(rm, key_max);
+   for (i = iMin; i <= iMax; i++) {
+      Range* rng = VG_(indexXA)(rm->ranges, i);
+      rng->val = val;
+   }
+   preen(rm);
+}
+
+void VG_(lookupRangeMap) ( /*OUT*/UWord* key_min, /*OUT*/UWord* key_max,
+                           /*OUT*/UWord* val, RangeMap* rm, UWord key )
+{
+   Word   i   = find(rm, key);
+   Range* rng = (Range*)VG_(indexXA)(rm->ranges, i);
+   *key_min = rng->key_min;
+   *key_max = rng->key_max;
+   *val     = rng->val;
+}
+
+Word VG_(sizeRangeMap) ( RangeMap* rm )
+{
+   vg_assert(rm && rm->ranges);
+   return VG_(sizeXA)(rm->ranges);
+}
+
+void VG_(indexRangeMap) ( /*OUT*/UWord* key_min, /*OUT*/UWord* key_max,
+                          /*OUT*/UWord* val, RangeMap* rm, Word ix )
+{
+   vg_assert(rm && rm->ranges);
+   Range* rng = (Range*)VG_(indexXA)(rm->ranges, ix);
+   *key_min = rng->key_min;
+   *key_max = rng->key_max;
+   *val     = rng->val;
+}
+
+/* Helper functions, not externally visible. */
+
+static void preen (/*MOD*/RangeMap* rm)
+{
+   Word    i;
+   XArray* ranges = rm->ranges;
+   for (i = 0; i < VG_(sizeXA)(ranges) - 1; i++) {
+      Range* rng0 = VG_(indexXA)(ranges, i+0);
+      Range* rng1 = VG_(indexXA)(ranges, i+1);
+      if (rng0->val != rng1->val)
+         continue;
+      rng0->key_max = rng1->key_max;
+      VG_(removeIndexXA)(ranges, i+1);
+      /* Back up one, so as not to miss an opportunity to merge with
+         the entry after this one. */
+      i--;
+   }
+}
+
+static Word find ( RangeMap* rm, UWord key )
+{
+   XArray* ranges = rm->ranges;
+   Word    lo     = 0;
+   Word    hi     = VG_(sizeXA)(ranges);
+   while (True) {
+      /* The unsearched space is lo .. hi inclusive */
+      if (lo > hi) {
+         /* Not found.  This can't happen. */
+         VG_(core_panic)("RangeMap::find: not found");
+         /*NOTREACHED*/
+         return -1;
+      }
+      Word   mid         = (lo + hi) / 2;
+      Range* mid_rng     = (Range*)VG_(indexXA)(ranges, mid);
+      UWord  key_mid_min = mid_rng->key_min;
+      UWord  key_mid_max = mid_rng->key_max;
+      if (key < key_mid_min) { hi = mid-1; continue; }
+      if (key > key_mid_max) { lo = mid+1; continue; }
+      return mid;
+   }
+}
+
+static void split_at ( /*MOD*/RangeMap* rm, UWord key )
+{
+   XArray* ranges = rm->ranges;
+   Word    i      = find(rm, key);
+   Range   rng_i0 = *(Range*)VG_(indexXA)( ranges, i+0 );
+   if (rng_i0.key_min == key)
+      return;
+   VG_(insertIndexXA)( ranges, i+1, &rng_i0 );
+   /* The insert could have relocated the payload, hence the
+      re-indexing of i+0 here. */
+   Range* rng_i0p = (Range*)VG_(indexXA)( ranges, i+0 );
+   Range* rng_i1p = (Range*)VG_(indexXA)( ranges, i+1 );
+   rng_i0p->key_max = key-1;
+   rng_i1p->key_min = key;
+}
+
+__attribute__((unused))
+static void show ( RangeMap* rm )
+{
+   Word i;
+   VG_(printf)("<< %ld entries:\n", VG_(sizeXA)(rm->ranges) );
+   for (i = 0; i < VG_(sizeXA)(rm->ranges); i++) {
+      Range* rng = (Range*)VG_(indexXA)(rm->ranges, i);
+      VG_(printf)("  %016llx  %016llx  --> 0x%llx\n",
+                  (ULong)rng->key_min, (ULong)rng->key_max, (ULong)rng->val);
+   }
+   VG_(printf)(">>\n");
+}
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                             m_rangemap.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_xarray.c b/coregrind/m_xarray.c
index 3b27d63..c440bfd 100644
--- a/coregrind/m_xarray.c
+++ b/coregrind/m_xarray.c
@@ -325,6 +325,27 @@
    xa->usedsizeE--;
 }
 
+void VG_(insertIndexXA)( XArray* xao, Word n, const void* elem )
+{
+   struct _XArray* xa = (struct _XArray*)xao;
+   vg_assert(xa);
+   vg_assert(n >= 0);
+   vg_assert(n <= xa->usedsizeE);
+   vg_assert(xa->usedsizeE >= 0 && xa->usedsizeE <= xa->totsizeE);
+   ensureSpaceXA( xa );
+   vg_assert(xa->usedsizeE < xa->totsizeE);
+   vg_assert(xa->arr);
+   if (n < xa->usedsizeE) {
+      VG_(memmove) ( ((char*)xa->arr) + (n+1) * xa->elemSzB,
+                     ((char*)xa->arr) + (n+0) * xa->elemSzB,
+                     (xa->usedsizeE - n) * xa->elemSzB );
+   }
+   VG_(memcpy)( ((UChar*)xa->arr) + n * xa->elemSzB,
+                elem, xa->elemSzB );
+   xa->usedsizeE++;
+   xa->sorted = False;
+}
+
 void VG_(getContentsXA_UNSAFE)( XArray* xao,
                                 /*OUT*/void** ctsP,
                                 /*OUT*/Word* usedP )
diff --git a/coregrind/pub_core_rangemap.h b/coregrind/pub_core_rangemap.h
new file mode 100644
index 0000000..d181e1f
--- /dev/null
+++ b/coregrind/pub_core_rangemap.h
@@ -0,0 +1,51 @@
+
+/*--------------------------------------------------------------------*/
+/*--- A mapping where the keys exactly cover the address space.    ---*/
+/*---                                          pub_core_rangemap.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2014-2014 Mozilla Foundation
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Contributed by Julian Seward <jseward@acm.org> */
+
+#ifndef __PUB_CORE_RANGEMAP_H
+#define __PUB_CORE_RANGEMAP_H
+
+//--------------------------------------------------------------------
+// PURPOSE: a mapping from the host machine word (UWord) ranges to
+// arbitrary other UWord values.  The set of ranges exactly covers all
+// possible UWord values.
+// --------------------------------------------------------------------
+
+// No core-only exports; everything in this module is visible to both
+// the core and tools.
+
+#include "pub_tool_rangemap.h"
+
+#endif   // __PUB_CORE_RANGEMAP_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                      pub_core_rangemap.h ---*/
+/*--------------------------------------------------------------------*/
diff --git a/include/Makefile.am b/include/Makefile.am
index 240d293..9b94301 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -25,6 +25,7 @@
 	pub_tool_mallocfree.h 		\
 	pub_tool_options.h 		\
 	pub_tool_oset.h 		\
+	pub_tool_rangemap.h		\
 	pub_tool_redir.h		\
 	pub_tool_replacemalloc.h	\
 	pub_tool_seqmatch.h		\
diff --git a/include/pub_tool_rangemap.h b/include/pub_tool_rangemap.h
new file mode 100644
index 0000000..beb7198
--- /dev/null
+++ b/include/pub_tool_rangemap.h
@@ -0,0 +1,83 @@
+
+/*--------------------------------------------------------------------*/
+/*--- A mapping where the keys exactly cover the address space.    ---*/
+/*---                                          pub_tool_rangemap.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2014-2014 Mozilla Foundation
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Contributed by Julian Seward <jseward@acm.org> */
+
+#ifndef __PUB_TOOL_RANGEMAP_H
+#define __PUB_TOOL_RANGEMAP_H
+
+//--------------------------------------------------------------------
+// PURPOSE: a mapping from the host machine word (UWord) ranges to
+// arbitrary other UWord values.  The set of ranges exactly covers all
+// possible UWord values.
+// --------------------------------------------------------------------
+
+/* It's an abstract type. */
+typedef  struct _RangeMap  RangeMap;
+
+/* Create a new RangeMap, using given allocation and free functions.
+   Alloc fn must not fail (that is, if it returns it must have
+   succeeded.)  The new array will contain a single range covering the
+   entire key space, which will be bound to the value |initialVal|. */
+RangeMap* VG_(newRangeMap) ( void*(*alloc_fn)(const HChar*,SizeT), 
+                             const HChar* cc,
+                             void(*free_fn)(void*),
+                             UWord initialVal );
+
+/* Free all memory associated with a RangeMap. */
+void VG_(deleteRangeMap) ( RangeMap* );
+
+/* Bind the range [key_min, key_max] to val, overwriting any other
+   bindings existing in the range.  Asserts if key_min > key_max.  If
+   as a result of this addition, there come to be multiple adjacent
+   ranges with the same value, these ranges are merged together.  Note
+   that this is slow: O(N) in the number of existing ranges. */
+void VG_(bindRangeMap) ( RangeMap* rm,
+                         UWord key_min, UWord key_max, UWord val );
+
+/* Looks up |key| in the array and returns the associated value and
+   the key bounds.  Can never fail since the RangeMap covers the
+   entire key space.  This is fast: O(log N) in the number of
+   ranges. */
+void VG_(lookupRangeMap) ( /*OUT*/UWord* key_min, /*OUT*/UWord* key_max,
+                           /*OUT*/UWord* val, RangeMap* rm, UWord key );
+
+/* How many elements are there in the map? */
+Word VG_(sizeRangeMap) ( RangeMap* rm );
+
+/* Get the i'th component */
+void VG_(indexRangeMap) ( /*OUT*/UWord* key_min, /*OUT*/UWord* key_max,
+                          /*OUT*/UWord* val, RangeMap* rm, Word ix );
+
+#endif   // __PUB_TOOL_RANGEMAP_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                      pub_tool_rangemap.h ---*/
+/*--------------------------------------------------------------------*/
diff --git a/include/pub_tool_xarray.h b/include/pub_tool_xarray.h
index 3817b20..086f0f4 100644
--- a/include/pub_tool_xarray.h
+++ b/include/pub_tool_xarray.h
@@ -106,10 +106,10 @@
 /* Index into the XArray.  Checks bounds and bombs if the index is
    invalid.  What this returns is the address of the specified element
    in the array, not (of course) the element itself.  Note that the
-   element may get moved by subsequent addToXAs/sortXAs, so you should
-   copy it out immediately and not regard its address as unchanging.
-   Note also that indexXA will of course not return NULL if it
-   succeeds. */
+   element may get moved by subsequent calls to addToXA / sortXA /
+   insertIndexXA, so you should copy it out immediately and not regard
+   its address as unchanging.  Note also that indexXA will of course
+   not return NULL if it succeeds. */
 extern void* VG_(indexXA) ( XArray*, Word );
 
 /* Drop the last n elements of an XArray.  Bombs if there are less
@@ -127,6 +127,13 @@
    array. */
 extern void VG_(removeIndexXA)( XArray*, Word );
 
+/* Insert an element into an XArray at the given index.  The existing
+   element at the index and all above it are slid upwards one slot so
+   as to make space.  Element is copied into the XArray.  This is an
+   O(N) operation, when N is the number of elements after the
+   specified element, in the array. */
+extern void VG_(insertIndexXA)( XArray*, Word, const void* elem );
+
 /* Make a new, completely independent copy of the given XArray, using
    the existing allocation function to allocate the new space.
    Returns NULL if the allocation function didn't manage to allocate
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index cb64cc4..5eda4ff 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -42,6 +42,7 @@
 #include "pub_tool_mallocfree.h"
 #include "pub_tool_options.h"
 #include "pub_tool_oset.h"
+#include "pub_tool_rangemap.h"
 #include "pub_tool_replacemalloc.h"
 #include "pub_tool_tooliface.h"
 #include "pub_tool_threadstate.h"
@@ -1056,28 +1057,58 @@
 
 /* --------------- Ignored address ranges --------------- */
 
-#define M_IGNORE_RANGES 4
-
+/* Denotes the address-error-reportability status for address ranges:
+   IAR_NotIgnored:  the usual case -- report errors in this range
+   IAR_CommandLine: don't report errors -- from command line setting
+   IAR_ClientReq:   don't report errors -- from client request
+*/
 typedef
-   struct {
-      Int  used;
-      Addr start[M_IGNORE_RANGES];
-      Addr end[M_IGNORE_RANGES];
-   }
-   IgnoreRanges;
+   enum { IAR_INVALID=99,
+          IAR_NotIgnored,
+          IAR_CommandLine,
+          IAR_ClientReq }
+   IARKind;
 
-static IgnoreRanges ignoreRanges;
+static const HChar* showIARKind ( IARKind iark )
+{
+   switch (iark) {
+      case IAR_INVALID:     return "INVALID";
+      case IAR_NotIgnored:  return "NotIgnored";
+      case IAR_CommandLine: return "CommandLine";
+      case IAR_ClientReq:   return "ClientReq";
+      default:              return "???";
+   }
+}
+
+// RangeMap<IARKind>
+static RangeMap* gIgnoredAddressRanges = NULL;
+
+static void init_gIgnoredAddressRanges ( void )
+{
+   if (LIKELY(gIgnoredAddressRanges != NULL))
+      return;
+   gIgnoredAddressRanges = VG_(newRangeMap)( VG_(malloc), "mc.igIAR.1",
+                                             VG_(free), IAR_NotIgnored );
+   tl_assert(gIgnoredAddressRanges != NULL);
+}
 
 INLINE Bool MC_(in_ignored_range) ( Addr a )
 {
-   Int i;
-   if (LIKELY(ignoreRanges.used == 0))
+   if (LIKELY(gIgnoredAddressRanges == NULL))
       return False;
-   for (i = 0; i < ignoreRanges.used; i++) {
-      if (a >= ignoreRanges.start[i] && a < ignoreRanges.end[i])
-         return True;
+   UWord how     = IAR_INVALID;
+   UWord key_min = ~(UWord)0;
+   UWord key_max =  (UWord)0;
+   VG_(lookupRangeMap)(&key_min, &key_max, &how, gIgnoredAddressRanges, a);
+   tl_assert(key_min <= a && a <= key_max);
+   switch (how) {
+      case IAR_NotIgnored:  return False;
+      case IAR_CommandLine: return True;
+      case IAR_ClientReq:   return True;
+      default: break; /* invalid */
    }
-   return False;
+   VG_(tool_panic)("MC_(in_ignore_range)");
+   /*NOTREACHED*/
 }
 
 /* Parse two Addr separated by a dash, or fail. */
@@ -1097,24 +1128,22 @@
 }
 
 /* Parse a set of ranges separated by commas into 'ignoreRanges', or
-   fail. */
-
+   fail.  If they are valid, add them to the global set of ignored
+   ranges. */
 static Bool parse_ignore_ranges ( const HChar* str0 )
 {
-   Addr start, end;
-   Bool ok;
+   init_gIgnoredAddressRanges();
    const HChar*  str = str0;
    const HChar** ppc = &str;
-   ignoreRanges.used = 0;
    while (1) {
-      ok = parse_range(ppc, &start, &end);
+      Addr start = ~(Addr)0;
+      Addr end   = (Addr)0;
+      Bool ok    = parse_range(ppc, &start, &end);
       if (!ok)
          return False;
-      if (ignoreRanges.used >= M_IGNORE_RANGES)
+      if (start > end)
          return False;
-      ignoreRanges.start[ignoreRanges.used] = start;
-      ignoreRanges.end[ignoreRanges.used] = end;
-      ignoreRanges.used++;
+      VG_(bindRangeMap)( gIgnoredAddressRanges, start, end, IAR_CommandLine );
       if (**ppc == 0)
          return True;
       if (**ppc != ',')
@@ -1125,6 +1154,44 @@
    return False;
 }
 
+/* Add or remove [start, +len) from the set of ignored ranges. */
+static Bool modify_ignore_ranges ( Bool addRange, Addr start, Addr len )
+{
+   init_gIgnoredAddressRanges();
+   const Bool verbose = (VG_(clo_verbosity) > 1);
+   if (len == 0) {
+      return False;
+   }
+   if (addRange) {
+      VG_(bindRangeMap)(gIgnoredAddressRanges,
+                        start, start+len-1, IAR_ClientReq);
+      if (verbose)
+         VG_(dmsg)("memcheck: modify_ignore_ranges: add %p %p\n",
+                   (void*)start, (void*)(start+len-1));
+   } else {
+      VG_(bindRangeMap)(gIgnoredAddressRanges,
+                        start, start+len-1, IAR_NotIgnored);
+      if (verbose)
+         VG_(dmsg)("memcheck: modify_ignore_ranges: del %p %p\n",
+                   (void*)start, (void*)(start+len-1));
+   }
+   if (verbose) {
+      VG_(dmsg)("memcheck:   now have %ld ranges:\n",
+                VG_(sizeRangeMap)(gIgnoredAddressRanges));
+      Word i;
+      for (i = 0; i < VG_(sizeRangeMap)(gIgnoredAddressRanges); i++) {
+         UWord val     = IAR_INVALID;
+         UWord key_min = ~(UWord)0;
+         UWord key_max = (UWord)0;
+         VG_(indexRangeMap)( &key_min, &key_max, &val,
+                             gIgnoredAddressRanges, i );
+         VG_(dmsg)("memcheck:      [%ld]  %016llx-%016llx  %s\n",
+                   i, (ULong)key_min, (ULong)key_max, showIARKind(val));
+      }
+   }
+   return True;
+}
+
 
 /* --------------- Load/store slow cases. --------------- */
 
@@ -5191,30 +5258,32 @@
                             MC_(clo_leak_resolution), Vg_HighRes) {}
 
    else if VG_STR_CLO(arg, "--ignore-ranges", tmp_str) {
-      Int  i;
-      Bool ok  = parse_ignore_ranges(tmp_str);
-      if (!ok)
-        return False;
-      tl_assert(ignoreRanges.used >= 0);
-      tl_assert(ignoreRanges.used < M_IGNORE_RANGES);
-      for (i = 0; i < ignoreRanges.used; i++) {
-         Addr s = ignoreRanges.start[i];
-         Addr e = ignoreRanges.end[i];
-         Addr limit = 0x4000000; /* 64M - entirely arbitrary limit */
-         if (e <= s) {
-            VG_(message)(Vg_DebugMsg, 
-               "ERROR: --ignore-ranges: end <= start in range:\n");
-            VG_(message)(Vg_DebugMsg, 
-               "       0x%lx-0x%lx\n", s, e);
-            return False;
+      Bool ok = parse_ignore_ranges(tmp_str);
+      if (!ok) {
+         VG_(message)(Vg_DebugMsg, 
+            "ERROR: --ignore-ranges: "
+            "invalid syntax, or end <= start in range\n");
+         return False;
+      }
+      if (gIgnoredAddressRanges) {
+         Word i;
+         for (i = 0; i < VG_(sizeRangeMap)(gIgnoredAddressRanges); i++) {
+            UWord val     = IAR_INVALID;
+            UWord key_min = ~(UWord)0;
+            UWord key_max = (UWord)0;
+            VG_(indexRangeMap)( &key_min, &key_max, &val,
+                                gIgnoredAddressRanges, i );
+            tl_assert(key_min <= key_max);
+            UWord limit = 0x4000000; /* 64M - entirely arbitrary limit */
+            if (key_max - key_min > limit) {
+               VG_(message)(Vg_DebugMsg, 
+                  "ERROR: --ignore-ranges: suspiciously large range:\n");
+               VG_(message)(Vg_DebugMsg, 
+                   "       0x%lx-0x%lx (size %ld)\n", key_min, key_max,
+                   key_max - key_min + 1);
+               return False;
+            }
          }
-         if (e - s > limit) {
-            VG_(message)(Vg_DebugMsg, 
-               "ERROR: --ignore-ranges: suspiciously large range:\n");
-            VG_(message)(Vg_DebugMsg, 
-               "       0x%lx-0x%lx (size %ld)\n", s, e, (UWord)(e-s));
-            return False;
-	 }
       }
    }
 
@@ -5694,7 +5763,6 @@
 static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
 {
    Int   i;
-   Bool  ok;
    Addr  bad_addr;
 
    if (!VG_IS_TOOL_USERREQ('M','C',arg[0])
@@ -5709,16 +5777,19 @@
        && VG_USERREQ__MOVE_MEMPOOL     != arg[0]
        && VG_USERREQ__MEMPOOL_CHANGE   != arg[0]
        && VG_USERREQ__MEMPOOL_EXISTS   != arg[0]
-       && VG_USERREQ__GDB_MONITOR_COMMAND   != arg[0])
+       && VG_USERREQ__GDB_MONITOR_COMMAND   != arg[0]
+       && VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE != arg[0]
+       && VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE != arg[0])
       return False;
 
    switch (arg[0]) {
-      case VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE:
-         ok = is_mem_addressable ( arg[1], arg[2], &bad_addr );
+      case VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE: {
+         Bool ok = is_mem_addressable ( arg[1], arg[2], &bad_addr );
          if (!ok)
             MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
          *ret = ok ? (UWord)NULL : bad_addr;
          break;
+      }
 
       case VG_USERREQ__CHECK_MEM_IS_DEFINED: {
          Bool errorV    = False;
@@ -5997,6 +6068,16 @@
          return handled;
       }
 
+      case VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE:
+      case VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE: {
+         Bool addRange
+            = arg[0] == VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE;
+         Bool ok
+            = modify_ignore_ranges(addRange, arg[1], arg[2]);
+         *ret = ok ? 1 : 0;
+         return True;
+      }
+
       default:
          VG_(message)(
             Vg_UserMsg, 
@@ -6666,6 +6747,41 @@
                    "uninitialised values come from\n");
    }
 
+   /* Print a warning if any client-request generated ignore-ranges
+      still exist.  It would be reasonable to expect that a properly
+      written program would remove any such ranges before exiting, and
+      since they are a bit on the dangerous side, let's comment.  By
+      contrast ranges which are specified on the command line normally
+      pertain to hardware mapped into the address space, and so we
+      can't expect the client to have got rid of them. */
+   if (gIgnoredAddressRanges) {
+      Word i, nBad = 0;
+      for (i = 0; i < VG_(sizeRangeMap)(gIgnoredAddressRanges); i++) {
+         UWord val     = IAR_INVALID;
+         UWord key_min = ~(UWord)0;
+         UWord key_max = (UWord)0;
+         VG_(indexRangeMap)( &key_min, &key_max, &val,
+                             gIgnoredAddressRanges, i );
+         if (val != IAR_ClientReq)
+           continue;
+         /* Print the offending range.  Also, if it is the first,
+            print a banner before it. */
+         nBad++;
+         if (nBad == 1) {
+            VG_(umsg)(
+              "WARNING: exiting program has the following client-requested\n"
+              "WARNING: address error disablement range(s) still in force,\n"
+              "WARNING: "
+                 "possibly as a result of some mistake in the use of the\n"
+              "WARNING: "
+                 "VALGRIND_{DISABLE,ENABLE}_ERROR_REPORTING_IN_RANGE macros.\n"
+            );
+         }
+         VG_(umsg)("   [%ld]  0x%016llx-0x%016llx  %s\n",
+                   i, (ULong)key_min, (ULong)key_max, showIARKind(val));
+      }
+   }
+
    done_prof_mem();
 
    if (VG_(clo_stats))
diff --git a/memcheck/memcheck.h b/memcheck/memcheck.h
index 3af0728..2740578 100644
--- a/memcheck/memcheck.h
+++ b/memcheck/memcheck.h
@@ -96,6 +96,9 @@
       /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */
       VG_USERREQ__COUNT_LEAK_BLOCKS,
 
+      VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE,
+      VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE,
+
       /* This is just for memcheck's internal use - don't use it */
       _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR 
          = VG_USERREQ_TOOL_BASE('M','C') + 256
@@ -283,5 +286,17 @@
                                     (const char*)(zzvbits),     \
                                     (zznbytes), 0, 0 )
 
+/* Disable and re-enable reporting of addressing errors in the
+   specified address range. */
+#define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,    \
+       VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE,      \
+       (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+#define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,    \
+       VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE,       \
+       (_qzz_addr), (_qzz_len), 0, 0, 0)
+
 #endif
 
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index 1874fc4..91a7876 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -102,6 +102,7 @@
 	err_disable2.vgtest err_disable2.stderr.exp \
 	err_disable3.vgtest err_disable3.stderr.exp \
 	err_disable4.vgtest err_disable4.stderr.exp \
+	err_disable_arange1.vgtest err_disable_arange1.stderr.exp \
 	erringfds.stderr.exp erringfds.stdout.exp erringfds.vgtest \
 	error_counts.stderr.exp error_counts.vgtest \
 	errs1.stderr.exp errs1.vgtest \
@@ -294,6 +295,7 @@
 	describe-block \
 	doublefree error_counts errs1 exitprog execve1 execve2 erringfds \
 	err_disable1 err_disable2 err_disable3 err_disable4 \
+	err_disable_arange1 \
 	file_locking \
 	fprw fwrite inits inline \
 	holey_buffer_too_small \
diff --git a/memcheck/tests/err_disable_arange1.c b/memcheck/tests/err_disable_arange1.c
new file mode 100644
index 0000000..fbbecc9
--- /dev/null
+++ b/memcheck/tests/err_disable_arange1.c
@@ -0,0 +1,41 @@
+
+/* Check some aspects of the use of the 
+   VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE and
+   VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE macros. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../memcheck.h"
+
+int main ( void )
+{
+  volatile int* volatile mem
+     = (volatile int* volatile)malloc(1000 * sizeof(int));
+  free((void*)mem);
+
+  // Check that we get an invalid access complaint
+  fprintf(stderr, "\nDoing invalid access.  Expect complaint.\n\n");
+  mem[123] = 0;
+
+  // Now disable error reporting in the range
+  fprintf(stderr, "\nDisabling address error reporting for the range.\n\n");
+  VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(mem, 1000 * sizeof(int));
+
+  // Check that we get an invalid access complaint
+  fprintf(stderr, "\nDoing invalid another access.  Expect no complaint.\n\n");
+  mem[456] = 0;
+ 
+  // Re-enable reporting on the first byte of one word from the ignore range
+  fprintf(stderr, "\nPartially reenabling address error reporting.\n\n");
+  VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(&mem[789], 1);
+
+  // Check that we get an invalid access complaint
+  fprintf(stderr, "\nDoing a third access.  Expect complaint.\n\n");
+  mem[789] = 0;
+
+  // And now quit and expect to see a warning about two remaining ranges
+  fprintf(stderr, "\nExiting.  Expect warnings of 2 remaining ranges.\n\n");
+
+  return 0;
+}
diff --git a/memcheck/tests/err_disable_arange1.stderr.exp b/memcheck/tests/err_disable_arange1.stderr.exp
new file mode 100644
index 0000000..8e979d2
--- /dev/null
+++ b/memcheck/tests/err_disable_arange1.stderr.exp
@@ -0,0 +1,36 @@
+
+Doing invalid access.  Expect complaint.
+
+Invalid write of size 4
+   at 0x........: main (err_disable_arange1.c:19)
+ Address 0x........ is 492 bytes inside a block of size 4,000 free'd
+   at 0x........: free (vg_replace_malloc.c:...)
+   by 0x........: main (err_disable_arange1.c:15)
+
+
+Disabling address error reporting for the range.
+
+
+Doing invalid another access.  Expect no complaint.
+
+
+Partially reenabling address error reporting.
+
+
+Doing a third access.  Expect complaint.
+
+Invalid write of size 4
+   at 0x........: main (err_disable_arange1.c:35)
+ Address 0x........ is 3,156 bytes inside a block of size 4,000 free'd
+   at 0x........: free (vg_replace_malloc.c:...)
+   by 0x........: main (err_disable_arange1.c:15)
+
+
+Exiting.  Expect warnings of 2 remaining ranges.
+
+WARNING: exiting program has the following client-requested
+WARNING: address error disablement range(s) still in force,
+WARNING: possibly as a result of some mistake in the use of the
+WARNING: VALGRIND_{DISABLE,ENABLE}_ERROR_REPORTING_IN_RANGE macros.
+   [1]  0x........-0x........  ClientReq
+   [3]  0x........-0x........  ClientReq
diff --git a/memcheck/tests/err_disable_arange1.vgtest b/memcheck/tests/err_disable_arange1.vgtest
new file mode 100644
index 0000000..48ba25f
--- /dev/null
+++ b/memcheck/tests/err_disable_arange1.vgtest
@@ -0,0 +1,2 @@
+prog: err_disable_arange1
+vgopts: -q