Memcheck:
* add delta leak checking functionality
* some editing of related manual sections
(Philippe Waroquiers, philippe.waroquiers@skynet.be).  Bug 214909
comment 105.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11838 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/docs/xml/manual-core-adv.xml b/docs/xml/manual-core-adv.xml
index c9dd667..9e3f0fc 100644
--- a/docs/xml/manual-core-adv.xml
+++ b/docs/xml/manual-core-adv.xml
@@ -495,12 +495,12 @@
 
 <para>Each tool can also provide tool-specific monitor commands.
 An example of a tool specific monitor command is the Memcheck monitor
-command <computeroutput>mc.leak_check any full
-reachable</computeroutput>.  This requests a full reporting of the
+command <computeroutput>mc.leak_check full
+reachable any</computeroutput>.  This requests a full reporting of the
 allocated memory blocks.  To have this leak check executed, use the GDB
 command:
 <screen><![CDATA[
-(gdb) monitor mc.leak_check any full reachable
+(gdb) monitor mc.leak_check full reachable any
 ]]></screen>
 </para>
 
@@ -511,7 +511,7 @@
 be tool-specific and is handed to the tool for execution.  For example:
 </para>
 <programlisting><![CDATA[
-(gdb) monitor mc.leak_check any full reachable
+(gdb) monitor mc.leak_check full reachable any
 ==2418== 100 bytes in 1 blocks are still reachable in loss record 1 of 1
 ==2418==    at 0x4006E9E: malloc (vg_replace_malloc.c:236)
 ==2418==    by 0x804884F: main (prog.c:88)
@@ -532,12 +532,12 @@
 <computeroutput>mc.leak_check</computeroutput>
 command can also be typed as:
 <screen><![CDATA[
-(gdb) mo mc.l a f r
+(gdb) mo mc.l f r a
 ]]></screen>
 
 The letters <computeroutput>mo</computeroutput> are recognised by GDB as being
 an abbreviation for <computeroutput>monitor</computeroutput>.  So GDB sends the
-string <computeroutput>mc.l a f r</computeroutput> to the Valgrind
+string <computeroutput>mc.l f r a</computeroutput> to the Valgrind
 gdbserver.  The letters provided in this string are unambiguous for the
 Valgrind gdbserver.  This therefore gives the same output as the
 unabbreviated command and arguments.  If the provided abbreviation is
@@ -556,7 +556,7 @@
 by the process 3145:
 <screen><![CDATA[
 vgdb --pid=3145 mc.leak_check any full reachable
-vgdb --pid=3145 mc.l a f r
+vgdb --pid=3145 mc.l f r a
 ]]></screen></para>
 
 <para>Note that the Valgrind gdbserver automatically continues the
diff --git a/gdbserver_tests/mchelp.stdoutB.exp b/gdbserver_tests/mchelp.stdoutB.exp
index 6499f33..90a93de 100644
--- a/gdbserver_tests/mchelp.stdoutB.exp
+++ b/gdbserver_tests/mchelp.stdoutB.exp
@@ -21,11 +21,11 @@
   mc.check_memory [addressable|defined] <addr> [<len>]
         check that <len> (or 1) bytes at <addr> have the given accessibility
             and outputs a description of <addr>
-  mc.leak_check [full*|summary]
-                [reachable|leakpossible*|definiteleak]
+  mc.leak_check [full*|summary] [reachable|leakpossible*|definiteleak]
+                [increased*|changed|any]
             * = defaults
         Examples: mc.leak_check
-                  mc.leak_check any summary
+                  mc.leak_check summary any
 
 general valgrind monitor commands:
   help [debug]             : monitor command help. With debug: + debugging commands
@@ -57,10 +57,10 @@
   mc.check_memory [addressable|defined] <addr> [<len>]
         check that <len> (or 1) bytes at <addr> have the given accessibility
             and outputs a description of <addr>
-  mc.leak_check [full*|summary]
-                [reachable|leakpossible*|definiteleak]
+  mc.leak_check [full*|summary] [reachable|leakpossible*|definiteleak]
+                [increased*|changed|any]
             * = defaults
         Examples: mc.leak_check
-                  mc.leak_check any summary
+                  mc.leak_check summary any
 
 monitor command request to kill this process
diff --git a/gdbserver_tests/mcleak.stderr.exp b/gdbserver_tests/mcleak.stderr.exp
index 734ff4a..76c4fdb 100644
--- a/gdbserver_tests/mcleak.stderr.exp
+++ b/gdbserver_tests/mcleak.stderr.exp
@@ -1,4 +1,6 @@
 (action at startup) vgdb me ... 
+
+
 expecting details 10 bytes reachable
 10 bytes in 1 blocks are still reachable in loss record ... of ...
    at 0x........: malloc (vg_replace_malloc.c:...)
diff --git a/gdbserver_tests/mcleak.stdinB.gdb b/gdbserver_tests/mcleak.stdinB.gdb
index 15c533b..a185f72 100644
--- a/gdbserver_tests/mcleak.stdinB.gdb
+++ b/gdbserver_tests/mcleak.stdinB.gdb
@@ -13,13 +13,13 @@
 #
 #   fprintf(stderr, "expecting details 10 bytes reachable\n"); fflush(stderr); breakme();
 up
-monitor mc.leak_check any reachable full
+monitor mc.leak_check full reachable any
 continue
 #   VALGRIND_DO_LEAK_CHECK;
 #
 #   fprintf(stderr, "expecting to have NO details\n"); fflush(stderr);
 up
-monitor mc.leak_check increased reachable full
+monitor mc.leak_check full reachable increased
 continue
 #   VALGRIND_DO_ADDED_LEAK_CHECK;
 #
@@ -27,7 +27,7 @@
 #   b21 = malloc (21);
 #   fprintf(stderr, "expecting details +10 bytes lost, +21 bytes reachable\n"); fflush(stderr); breakme();
 up
-monitor mc.leak_check increased reachable full
+monitor mc.leak_check full reachable increased
 continue
 #   VALGRIND_DO_ADDED_LEAK_CHECK;
 #
@@ -35,41 +35,41 @@
 #      b32_33[i] = malloc (32+i);
 #   fprintf(stderr, "expecting details +65 bytes reachable\n"); fflush(stderr); breakme();
 up
-monitor mc.leak_check increased reachable full
+monitor mc.leak_check full reachable increased
 continue
 #   VALGRIND_DO_ADDED_LEAK_CHECK;
 #
 #   fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
 up
-monitor mc.leak_check increased reachable full
+monitor mc.leak_check full reachable increased
 continue
 #   VALGRIND_DO_ADDED_LEAK_CHECK;
 #
 #   b10++;
 #   fprintf(stderr, "expecting details +10 bytes reachable\n"); fflush(stderr); breakme();
 up
-monitor mc.leak_check increased reachable full
+monitor mc.leak_check full reachable increased
 continue
 #   VALGRIND_DO_ADDED_LEAK_CHECK;
 #
 #   b10--;
 #   fprintf(stderr, "expecting details -10 bytes reachable, +10 bytes lost\n"); fflush(stderr); breakme();
 up
-monitor mc.leak_check changed reachable full
+monitor mc.leak_check full reachable changed
 continue
 #   VALGRIND_DO_CHANGED_LEAK_CHECK;
 #
 #   b10++;
 #   fprintf(stderr, "expecting details -10 bytes lost, +10 bytes reachable\n"); fflush(stderr); breakme();
 up
-monitor mc.leak_check changed reachable full
+monitor mc.leak_check full reachable changed
 continue
 #   VALGRIND_DO_CHANGED_LEAK_CHECK;
 #
 #   b32_33[0]--;
 #   fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
 up
-monitor mc.leak_check changed reachable full
+monitor mc.leak_check full reachable changed
 continue
 #   VALGRIND_DO_CHANGED_LEAK_CHECK;
 #
diff --git a/gdbserver_tests/mcleak.stdoutB.exp b/gdbserver_tests/mcleak.stdoutB.exp
index b3e1aec..ff66b9d 100644
--- a/gdbserver_tests/mcleak.stdoutB.exp
+++ b/gdbserver_tests/mcleak.stdoutB.exp
@@ -1,5 +1,3 @@
-Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcleak
-0x........ in _start () from ...start file...
 Breakpoint 1 at 0x........: file leak-delta.c, line 9.
 Continuing.
 Breakpoint 1, breakme () at leak-delta.c:9
diff --git a/gdbserver_tests/mcleak.vgtest b/gdbserver_tests/mcleak.vgtest
index 71d87bc..1c410a4 100644
--- a/gdbserver_tests/mcleak.vgtest
+++ b/gdbserver_tests/mcleak.vgtest
@@ -1,8 +1,7 @@
 # test the memcheck leak functionality.
 prog: ../memcheck/tests/leak-delta
 vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcleak -q --leak-check=yes --show-reachable=yes --leak-resolution=high
-# temorarily disabled, waiting for leak-delta test program (next patch)
-prereq: test -e gdb -a -x ../memcheck/tests/leak-delta
+prereq: test -e gdb
 stdout_filter: filter_memcheck_monitor
 stderr_filter: filter_memcheck_monitor
 progB: gdb
diff --git a/memcheck/docs/mc-manual.xml b/memcheck/docs/mc-manual.xml
index 8493e31..29c8df0 100644
--- a/memcheck/docs/mc-manual.xml
+++ b/memcheck/docs/mc-manual.xml
@@ -1272,23 +1272,27 @@
 
 <sect1 id="mc-manual.monitor-commands" xreflabel="Memcheck Monitor Commands">
 <title>Memcheck Monitor Commands</title>
-<para>The Memcheck tool provides monitor commands handled by the Valgrind
-gdbserver (see <xref linkend="manual-core-adv.gdbserver-commandhandling"/>).
+<para>The Memcheck tool provides monitor commands handled by Valgrind's
+built-in gdbserver (see <xref linkend="manual-core-adv.gdbserver-commandhandling"/>).
 </para>
 
 <itemizedlist>
   <listitem>
     <para><varname>mc.get_vbits &lt;addr&gt; [&lt;len&gt;]</varname>
-    outputs the validity bits for the range of &lt;len&gt; (default 1)
-    bytes at &lt;addr&gt;.  The validity of each byte of the range is
-    given using two hexadecimal digits.  These hexadecimal digits are
-    encoding the validity of each bit of the corresponding byte, using
-    0 if the bit is valid and 1 if the bit is invalid. In the
-    following example, 'string10' is an array of 10 characters in
-    which one byte on two is undefined. If a byte is not addressable,
-    its validity bits are replaced by __. In the below example, the byte 
-    corresponding to string10[5]
-    is not addressable.</para>
+    shows the definedness (V) bits for &lt;len&gt; (default 1) bytes
+    starting at &lt;addr&gt;.  The definedness of each byte in the
+    range is given using two hexadecimal digits.  These hexadecimal
+    digits encode the validity of each bit of the corresponding byte,
+    using 0 if the bit is defined and 1 if the bit is undefined.
+    If a byte is not addressable, its validity bits are replaced
+    by <varname>__</varname> (a double underscore).
+    </para>
+    <para>
+    In the following example, <varname>string10</varname> is an array
+    of 10 characters, in which the even numbered bytes are
+    undefined. In the below example, the byte corresponding
+    to <varname>string10[5]</varname> is not addressable.
+    </para>
 <programlisting><![CDATA[
 (gdb) p &string10
 $4 = (char (*)[10]) 0x8049e28
@@ -1299,14 +1303,22 @@
   </listitem>
 
   <listitem>
-    <para><varname>mc.make_memory [noaccess|undefined|defined|ifaddressabledefined] &lt;addr&gt; [&lt;len&gt;]</varname>
-    marks the range of &lt;len&gt; (default 1) bytes at &lt;addr&gt;
-    with the given accessibility. Marking with 'noaccess' changes the
-    (A) bits of the range to be not addressable.  Marking with
-    'undefined' or 'defined' are changing the definedness of the
-    range.  'ifaddressabledefined' marks the range as defined but only
-    if the range is addressable.  In the following example, the first
-    byte of the 'string10' is marked as defined.
+    <para><varname>mc.make_memory
+    [noaccess|undefined|defined|ifaddressabledefined] &lt;addr&gt;
+    [&lt;len&gt;]</varname> marks the range of &lt;len&gt; (default 1)
+    bytes at &lt;addr&gt; as having the given status. Parameter
+    <varname>noaccess</varname> marks the range as non-accessible, so
+    Memcheck will report an error on any access to it.
+    <varname>undefined</varname> or <varname>defined</varname> mark
+    the area as accessible, but Memcheck regards the bytes in it
+    respectively as having undefined or defined values.
+    <varname>ifaddressabledefined</varname> marks as defined, bytes in
+    the range which are already addressible, but makes no change to
+    the status of bytes in the range which are not addressible.</para>
+
+    <para>
+    In the following example, the first byte of the
+    <varname>string10</varname> is marked as defined:
     </para>
 <programlisting><![CDATA[
 (gdb) monitor mc.make_memory defined 0x8049e28  1
@@ -1319,10 +1331,11 @@
   <listitem>
     <para><varname>mc.check_memory [addressable|defined] &lt;addr&gt;
     [&lt;len&gt;]</varname> checks that the range of &lt;len&gt;
-    (default 1) bytes at &lt;addr&gt; has the given accessibility.  It
-    then outputs a description of &lt;addr&gt;. In the below case, a
-    detailed description is given as the option --read-var-info=yes
-    was used to start Valgrind.
+    (default 1) bytes at &lt;addr&gt; has the specified accessibility.  It
+    then outputs a description of &lt;addr&gt;. In the following example, a
+    detailed description is given available because 
+    the option <option>--read-var-info=yes</option>
+    was given Valgrind at startup:
     </para>
 <programlisting><![CDATA[
 (gdb) monitor mc.check_memory defined 0x8049e28  1
@@ -1334,58 +1347,93 @@
   </listitem>
 
   <listitem>
-    <para><varname>mc.leak_check
-    [full*|summary] [reachable|leakpossible*|definiteleak]</varname>
-    starts a leak checking. The * in the arguments above indicates the
-    default value. </para>
+    <para><varname>mc.leak_check [full*|summary]
+                                 [reachable|leakpossible*|definiteleak]
+                                 [increased*|changed|any]
+          </varname>
+    performs a leak check. The <varname>*</varname> in the arguments
+    indicates the default value. </para>
 
-    <para> If the first argument is 'summary', only a summary of
-    the leak search is given.
+    <para> If the first argument is <varname>summary</varname>, only a
+    summary of the leak search is given; otherwise a full leak report
+    is produced.  A full leak report gives detailed information for
+    each leak: the stack trace where the leaked blocks were allocated,
+    the number of blocks leaked and their total size.  When a full
+    report is requested, the next two arguments further specify what
+    kind of leaks to report.  A leak's details are shown if they match
+    both the second and third argument.
     </para>
 
-    <para>The second argument controls which entries are output
-    for a 'full' leak search.  The value 'definiteleak' indicates to
-    output only the definitely leaked blocks. The value 'leakpossible'
-    will output in addition the possibly leaked blocks. The value
-    'reachable' will output all blocks (reachable, possibly leaked,
-    definitely leaked).
+    <para>The second argument controls what kind of blocks are shown for
+    a <varname>full</varname> leak search.  The
+    value <varname>definiteleak</varname> specifies that only
+    definitely leaked blocks should be shown.  The
+    value <varname>leakpossible</varname> will also show possibly
+    leaked blocks (those for which only an interior pointer was
+    found).  The value
+    <varname>reachable</varname> will show all block categories
+    (reachable, possibly leaked, definitely leaked).
     </para>
-    <para>The below is an example of using the mc.leak_check monitor
-    command on the leak-cases Memcheck regression tests.</para>
+
+    <para>The third argument controls what kinds of changes are shown
+    for a <varname>full</varname> leak search. The
+    value <varname>increased</varname> specifies that only block
+    allocation stacks with an increased number of leaked bytes or
+    blocks since the previous leak check should be shown.  The
+    value <varname>changed</varname> specifies that allocation stacks
+    with any change since the previous leak check should be shown.
+    The value <varname>any</varname> specifies that all leak entries
+    should be shown, regardless of any increase or decrease.  When
+    If <varname>increased</varname> or <varname>changed</varname> are
+    specified, the leak report entries will show the delta relative to
+    the previous leak report.
+    </para>
+
+    <para>The following example shows usage of the 
+    <varname>mc.leak_check monitor</varname> command on
+    the <varname>memcheck/tests/leak-cases.c</varname> regression
+    test. The first command outputs one entry having an increase in
+    the leaked bytes.  The second command is the same as the first
+    command, but uses the abbreviated forms accepted by GDB and the
+    Valgrind gdbserver. It only outputs the summary information, as
+    there was no increase since the previous leak search.</para>
 <programlisting><![CDATA[
-(gdb)  monitor mc.leak_check full leakpossible
-==14729== 16 bytes in 1 blocks are possibly lost in loss record 13 of 16
+(gdb) monitor mc.leak_check full leakpossible increased
+==14729== 16 (+16) bytes in 1 (+1) blocks are possibly lost in loss record 13 of 16
 ==14729==    at 0x4006E9E: malloc (vg_replace_malloc.c:236)
 ==14729==    by 0x80484D5: mk (leak-cases.c:52)
 ==14729==    by 0x804855F: f (leak-cases.c:81)
 ==14729==    by 0x80488F5: main (leak-cases.c:107)
 ==14729== 
 ==14729== LEAK SUMMARY:
-==14729==    definitely lost: 32 bytes in 2 blocks
-==14729==    indirectly lost: 16 bytes in 1 blocks
-==14729==      possibly lost: 32 bytes in 2 blocks
-==14729==    still reachable: 96 bytes in 6 blocks
-==14729==         suppressed: 0 bytes in 0 blocks
+==14729==    definitely lost: 32 (+0) bytes in 2 (+0) blocks
+==14729==    indirectly lost: 16 (+0) bytes in 1 (+0) blocks
+==14729==      possibly lost: 32 (+16) bytes in 2 (+1) blocks
+==14729==    still reachable: 96 (+16) bytes in 6 (+1) blocks
+==14729==         suppressed: 0 (+0) bytes in 0 (+0) blocks
 ==14729== Reachable blocks (those to which a pointer was found) are not shown.
-==14729== To see them, rerun with: --leak-check=full --show-reachable=yes
+==14729== o see them, add 'reachable any' args to mc.leak_check
 ==14729== 
 (gdb) mo mc.l
 ==14729== LEAK SUMMARY:
-==14729==    definitely lost: 32 bytes in 2 blocks
-==14729==    indirectly lost: 16 bytes in 1 blocks
-==14729==      possibly lost: 32 bytes in 2 blocks
-==14729==    still reachable: 96 bytes in 6 blocks
-==14729==         suppressed: 0 bytes in 0 blocks
+==14729==    definitely lost: 32 (+0) bytes in 2 (+0) blocks
+==14729==    indirectly lost: 16 (+0) bytes in 1 (+0) blocks
+==14729==      possibly lost: 32 (+0) bytes in 2 (+0) blocks
+==14729==    still reachable: 96 (+0) bytes in 6 (+0) blocks
+==14729==         suppressed: 0 (+0) bytes in 0 (+0) blocks
 ==14729== Reachable blocks (those to which a pointer was found) are not shown.
-==14729== To see them, rerun with: --leak-check=full --show-reachable=yes
+==14729== To see them, add 'reachable any' args to mc.leak_check
 ==14729== 
 (gdb) 
 ]]></programlisting>
-    <para>Note that when using the Valgrind gdbserver, it is not
-    needed to rerun with --leak-check=full --show-reachable=yes to see
-    the reachable blocks. You can obtain the same information without
-    rerunning by using the gdb command 'monitor mc.leak_check full
-    reachable' (or, using abbreviation: 'mo mc.l f r').
+    <para>Note that when using Valgrind's gdbserver, it is not
+    necessary to rerun
+    with <option>--leak-check=full</option>
+    <option>--show-reachable=yes</option> to see the reachable
+    blocks. You can obtain the same information without rerunning by
+    using the GDB command <computeroutput>monitor mc.leak_check full
+    reachable any</computeroutput> (or, using
+    abbreviation: <computeroutput>mo mc.l f r a</computeroutput>).
     </para>
   </listitem>
 </itemizedlist>
@@ -1443,6 +1491,22 @@
   </listitem>
 
   <listitem>
+    <para><varname>VALGRIND_DO_ADDED_LEAK_CHECK</varname>: same as
+   <varname> VALGRIND_DO_LEAK_CHECK</varname> but only shows the
+    entries for which there was an increase in leaked bytes or leaked
+    number of blocks since the previous leak search.  It has no return
+    value.</para>
+  </listitem>
+
+  <listitem>
+    <para><varname>VALGRIND_DO_CHANGED_LEAK_CHECK</varname>: same as
+    <varname>VALGRIND_DO_LEAK_CHECK</varname> but only shows the
+    entries for which there was an increase or decrease in leaked
+    bytes or leaked number of blocks since the previous leak search. It
+    has no return value.</para>
+  </listitem>
+
+  <listitem>
     <para><varname>VALGRIND_DO_QUICK_LEAK_CHECK</varname>: like
     <varname>VALGRIND_DO_LEAK_CHECK</varname>, except it produces only a leak
     summary (like <option>--leak-check=summary</option>).
diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c
index e013328..09074c2 100644
--- a/memcheck/mc_errors.c
+++ b/memcheck/mc_errors.c
@@ -432,6 +432,20 @@
    }
 }
 
+char * MC_(snprintf_delta) (char * buf, Int size, 
+                            SizeT current_val, SizeT old_val, 
+                            LeakCheckDeltaMode delta_mode)
+{
+   if (delta_mode == LCD_Any)
+      buf[0] = '\0';
+   else if (current_val >= old_val)
+      VG_(snprintf) (buf, size, " (+%'lu)", current_val - old_val);
+   else
+      VG_(snprintf) (buf, size, " (-%'lu)", old_val - current_val);
+
+   return buf;
+}
+
 void MC_(pp_Error) ( Error* err )
 {
    const Bool xml  = VG_(clo_xml); /* a shorthand */
@@ -702,15 +716,41 @@
          UInt        n_this_record   = extra->Err.Leak.n_this_record;
          UInt        n_total_records = extra->Err.Leak.n_total_records;
          LossRecord* lr              = extra->Err.Leak.lr;
+         // char arrays to produce the indication of increase/decrease in case
+         // of delta_mode != LC_Any
+         char        d_bytes[20];
+         char        d_direct_bytes[20];
+         char        d_indirect_bytes[20];
+         char        d_num_blocks[20];
+
+         MC_(snprintf_delta) (d_bytes, 20, 
+                              lr->szB + lr->indirect_szB, 
+                              lr->old_szB + lr->old_indirect_szB,
+                              MC_(detect_memory_leaks_last_delta_mode));
+         MC_(snprintf_delta) (d_direct_bytes, 20,
+                              lr->szB,
+                              lr->old_szB,
+                              MC_(detect_memory_leaks_last_delta_mode));
+         MC_(snprintf_delta) (d_indirect_bytes, 20,
+                              lr->indirect_szB,
+                              lr->old_indirect_szB,
+                              MC_(detect_memory_leaks_last_delta_mode));
+         MC_(snprintf_delta) (d_num_blocks, 20,
+                              (SizeT) lr->num_blocks,
+                              (SizeT) lr->old_num_blocks,
+                              MC_(detect_memory_leaks_last_delta_mode));
+
          if (xml) {
             emit("  <kind>%s</kind>\n", xml_leak_kind(lr->key.state));
             if (lr->indirect_szB > 0) {
                emit( "  <xwhat>\n" );
-               emit( "    <text>%'lu (%'lu direct, %'lu indirect) bytes "
-                     "in %'u blocks"
+               emit( "    <text>%'lu%s (%'lu%s direct, %'lu%s indirect) bytes "
+                     "in %'u%s blocks"
                      " are %s in loss record %'u of %'u</text>\n",
-                     lr->szB + lr->indirect_szB, lr->szB, lr->indirect_szB,
-                     lr->num_blocks,
+                     lr->szB + lr->indirect_szB, d_bytes,
+                     lr->szB, d_direct_bytes,
+                     lr->indirect_szB, d_indirect_bytes,
+                     lr->num_blocks, d_num_blocks,
                      str_leak_lossmode(lr->key.state),
                      n_this_record, n_total_records );
                // Nb: don't put commas in these XML numbers 
@@ -720,9 +760,10 @@
                emit( "  </xwhat>\n" );
             } else {
                emit( "  <xwhat>\n" );
-               emit( "    <text>%'lu bytes in %'u blocks"
+               emit( "    <text>%'lu%s bytes in %'u%s blocks"
                      " are %s in loss record %'u of %'u</text>\n",
-                     lr->szB, lr->num_blocks,
+                     lr->szB, d_direct_bytes,
+                     lr->num_blocks, d_num_blocks,
                      str_leak_lossmode(lr->key.state), 
                      n_this_record, n_total_records );
                emit( "    <leakedbytes>%ld</leakedbytes>\n", lr->szB);
@@ -733,16 +774,21 @@
          } else { /* ! if (xml) */
             if (lr->indirect_szB > 0) {
                emit(
-                  "%'lu (%'lu direct, %'lu indirect) bytes in %'u blocks"
+                  "%'lu%s (%'lu%s direct, %'lu%s indirect) bytes in %'u%s blocks"
                   " are %s in loss record %'u of %'u\n",
-                  lr->szB + lr->indirect_szB, lr->szB, lr->indirect_szB,
-                  lr->num_blocks, str_leak_lossmode(lr->key.state),
+                  lr->szB + lr->indirect_szB, d_bytes,
+                  lr->szB, d_direct_bytes,
+                  lr->indirect_szB, d_indirect_bytes,
+                  lr->num_blocks, d_num_blocks,
+                  str_leak_lossmode(lr->key.state),
                   n_this_record, n_total_records
                );
             } else {
                emit(
-                  "%'lu bytes in %'u blocks are %s in loss record %'u of %'u\n",
-                  lr->szB, lr->num_blocks, str_leak_lossmode(lr->key.state),
+                  "%'lu%s bytes in %'u%s blocks are %s in loss record %'u of %'u\n",
+                  lr->szB, d_direct_bytes,
+                  lr->num_blocks, d_num_blocks,
+                  str_leak_lossmode(lr->key.state),
                   n_this_record, n_total_records
                );
             }
diff --git a/memcheck/mc_include.h b/memcheck/mc_include.h
index d6edbf2..0b9d345 100644
--- a/memcheck/mc_include.h
+++ b/memcheck/mc_include.h
@@ -270,6 +270,15 @@
    }
    LeakCheckMode;
 
+typedef
+   enum {
+      LCD_Any,       // output all loss records, whatever the delta
+      LCD_Increased, // output loss records with an increase in size or blocks
+      LCD_Changed,   // output loss records with an increase or 
+                     //decrease in size or blocks
+   }
+   LeakCheckDeltaMode;
+
 /* When a LossRecord is put into an OSet, these elements represent the key. */
 typedef
    struct _LossRecordKey {
@@ -287,10 +296,33 @@
       SizeT szB;          // Sum of all MC_Chunk.szB values.
       SizeT indirect_szB; // Sum of all LC_Extra.indirect_szB values.
       UInt  num_blocks;   // Number of blocks represented by the record.
+      SizeT old_szB;          // old_* values are the values found during the 
+      SizeT old_indirect_szB; // previous leak search. old_* values are used to
+      UInt  old_num_blocks;   // output only the changed/new loss records
    }
    LossRecord;
 
-void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckMode mode );
+typedef
+   struct _LeakCheckParams {
+      LeakCheckMode mode;
+      Bool show_reachable;
+      Bool show_possibly_lost;
+      LeakCheckDeltaMode deltamode;
+      Bool requested_by_monitor_command; // True when requested by gdb/vgdb.
+   }
+   LeakCheckParams;
+
+void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams lcp);
+
+// maintains the lcp.deltamode given in the last call to detect_memory_leaks
+extern LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
+
+// if delta_mode == LC_Any, prints in buf an empty string
+// otherwise prints a delta in the layout  " (+%'lu)" or " (-%'lu)" 
+extern char * MC_(snprintf_delta) (char * buf, Int size, 
+                                   SizeT current_val, SizeT old_val, 
+                                   LeakCheckDeltaMode delta_mode);
+
 
 Bool MC_(is_valid_aligned_word)     ( Addr a );
 Bool MC_(is_within_valid_secondary) ( Addr a );
diff --git a/memcheck/mc_leakcheck.c b/memcheck/mc_leakcheck.c
index 016109c..41c9b71 100644
--- a/memcheck/mc_leakcheck.c
+++ b/memcheck/mc_leakcheck.c
@@ -434,6 +434,16 @@
 static MC_Chunk** lc_chunks;
 // How many chunks we're dealing with.
 static Int        lc_n_chunks;
+// chunks will be converted and merged in loss record, maintained in lr_table
+// lr_table elements are kept from one leak_search to another to implement
+// the "print new/changed leaks" client request
+static OSet*        lr_table;
+
+// DeltaMode used the last time we called detect_memory_leaks.
+// The recorded leak errors must be output using a logic based on this delta_mode.
+// The below avoids replicating the delta_mode in each LossRecord.
+LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
+
 
 // This has the same number of entries as lc_chunks, and each entry
 // in lc_chunks corresponds with the entry here (ie. lc_chunks[i] and
@@ -770,20 +780,35 @@
    return 0;
 }
 
-static void print_results(ThreadId tid, Bool is_full_check)
+static void print_results(ThreadId tid, LeakCheckParams lcp)
 {
    Int          i, n_lossrecords;
-   OSet*        lr_table;
    LossRecord** lr_array;
    LossRecord*  lr;
    Bool         is_suppressed;
+   SizeT        old_bytes_leaked      = MC_(bytes_leaked); /* to report delta in summary */
+   SizeT        old_bytes_indirect    = MC_(bytes_indirect); 
+   SizeT        old_bytes_dubious     = MC_(bytes_dubious); 
+   SizeT        old_bytes_reachable   = MC_(bytes_reachable); 
+   SizeT        old_bytes_suppressed  = MC_(bytes_suppressed); 
+   SizeT        old_blocks_leaked     = MC_(blocks_leaked);
+   SizeT        old_blocks_indirect   = MC_(blocks_indirect);
+   SizeT        old_blocks_dubious    = MC_(blocks_dubious);
+   SizeT        old_blocks_reachable  = MC_(blocks_reachable);
+   SizeT        old_blocks_suppressed = MC_(blocks_suppressed);
 
-   // Create the lr_table, which holds the loss records.
-   lr_table =
-      VG_(OSetGen_Create)(offsetof(LossRecord, key),
-                          cmp_LossRecordKey_LossRecord,
-                          VG_(malloc), "mc.pr.1",
-                          VG_(free)); 
+   if (lr_table == NULL)
+      // Create the lr_table, which holds the loss records.
+      // If the lr_table already exists, it means it contains
+      // loss_records from the previous leak search. The old_*
+      // values in these records are used to implement the
+      // leak check delta mode
+      lr_table =
+         VG_(OSetGen_Create)(offsetof(LossRecord, key),
+                             cmp_LossRecordKey_LossRecord,
+                             VG_(malloc), "mc.pr.1",
+                             VG_(free));
+
 
    // Convert the chunks into loss records, merging them where appropriate.
    for (i = 0; i < lc_n_chunks; i++) {
@@ -810,6 +835,9 @@
          lr->szB              = ch->szB;
          lr->indirect_szB     = ex->indirect_szB;
          lr->num_blocks       = 1;
+         lr->old_szB          = 0;
+         lr->old_indirect_szB = 0;
+         lr->old_num_blocks   = 0;
          VG_(OSetGen_Insert)(lr_table, lr);
       }
    }
@@ -837,7 +865,7 @@
 
    // Print the loss records (in size order) and collect summary stats.
    for (i = 0; i < n_lossrecords; i++) {
-      Bool count_as_error, print_record;
+      Bool count_as_error, print_record, delta_considered;
       // Rules for printing:
       // - We don't show suppressed loss records ever (and that's controlled
       //   within the error manager).
@@ -851,18 +879,37 @@
       // includes indirectly lost blocks!
       //
       lr = lr_array[i];
-      print_record = is_full_check &&
-                     ( MC_(clo_show_reachable) ||
+      switch (lcp.deltamode) {
+         case LCD_Any: 
+            delta_considered = lr->num_blocks > 0;
+            break;
+         case LCD_Increased:
+            delta_considered 
+               = lr_array[i]->szB > lr_array[i]->old_szB
+                 || lr_array[i]->indirect_szB > lr_array[i]->old_indirect_szB
+                 || lr->num_blocks > lr->old_num_blocks;
+            break;
+         case LCD_Changed: 
+            delta_considered = lr_array[i]->szB != lr_array[i]->old_szB
+            || lr_array[i]->indirect_szB != lr_array[i]->old_indirect_szB
+            || lr->num_blocks != lr->old_num_blocks;
+            break;
+         default:
+            tl_assert(0);
+      }
+
+      print_record = lcp.mode == LC_Full && delta_considered &&
+                     ( lcp.show_reachable ||
                        Unreached == lr->key.state || 
-                       ( MC_(clo_show_possibly_lost) && 
+                       ( lcp.show_possibly_lost && 
                          Possible  == lr->key.state ) );
-      // We don't count a leaks as errors with --leak-check=summary.
+      // We don't count a leaks as errors with lcp.mode==LC_Summary.
       // Otherwise you can get high error counts with few or no error
       // messages, which can be confusing.  Also, you could argue that
       // indirect leaks should be counted as errors, but it seems better to
       // make the counting criteria similar to the printing criteria.  So we
       // don't count them.
-      count_as_error = is_full_check && 
+      count_as_error = lcp.mode == LC_Full && delta_considered &&
                        ( Unreached == lr->key.state || 
                          Possible  == lr->key.state );
       is_suppressed = 
@@ -894,31 +941,74 @@
       }
    }
 
+   for (i = 0; i < n_lossrecords; i++)
+      {
+         if (lr->num_blocks == 0)
+            // remove from lr_table the old loss_records with 0 bytes found
+            VG_(OSetGen_Remove) (lr_table, &lr_array[i]->key);
+         else
+            {
+               // move the leak sizes to old_* and zero the current sizes
+               // for next leak search
+               lr_array[i]->old_szB          = lr_array[i]->szB;
+               lr_array[i]->old_indirect_szB = lr_array[i]->indirect_szB;
+               lr_array[i]->old_num_blocks   = lr_array[i]->num_blocks;
+               lr_array[i]->szB              = 0;
+               lr_array[i]->indirect_szB     = 0;
+               lr_array[i]->num_blocks       = 0;
+            }
+      }
+   VG_(free)(lr_array); 
+
    if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
+      char d_bytes[20];
+      char d_blocks[20];
+
       VG_(umsg)("LEAK SUMMARY:\n");
-      VG_(umsg)("   definitely lost: %'lu bytes in %'lu blocks\n",
-                MC_(bytes_leaked), MC_(blocks_leaked) );
-      VG_(umsg)("   indirectly lost: %'lu bytes in %'lu blocks\n",
-                MC_(bytes_indirect), MC_(blocks_indirect) );
-      VG_(umsg)("     possibly lost: %'lu bytes in %'lu blocks\n",
-                MC_(bytes_dubious), MC_(blocks_dubious) );
-      VG_(umsg)("   still reachable: %'lu bytes in %'lu blocks\n",
-                MC_(bytes_reachable), MC_(blocks_reachable) );
-      VG_(umsg)("        suppressed: %'lu bytes in %'lu blocks\n",
-                MC_(bytes_suppressed), MC_(blocks_suppressed) );
-      if (!is_full_check &&
+      VG_(umsg)("   definitely lost: %'lu%s bytes in %'lu%s blocks\n",
+                MC_(bytes_leaked), 
+                MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_leaked), old_bytes_leaked, lcp.deltamode),
+                MC_(blocks_leaked),
+                MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_leaked), old_blocks_leaked, lcp.deltamode));
+      VG_(umsg)("   indirectly lost: %'lu%s bytes in %'lu%s blocks\n",
+                MC_(bytes_indirect), 
+                MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_indirect), old_bytes_indirect, lcp.deltamode),
+                MC_(blocks_indirect),
+                MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_indirect), old_blocks_indirect, lcp.deltamode) );
+      VG_(umsg)("     possibly lost: %'lu%s bytes in %'lu%s blocks\n",
+                MC_(bytes_dubious), 
+                MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_dubious), old_bytes_dubious, lcp.deltamode), 
+                MC_(blocks_dubious),
+                MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_dubious), old_blocks_dubious, lcp.deltamode) );
+      VG_(umsg)("   still reachable: %'lu%s bytes in %'lu%s blocks\n",
+                MC_(bytes_reachable), 
+                MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_reachable), old_bytes_reachable, lcp.deltamode), 
+                MC_(blocks_reachable),
+                MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_reachable), old_blocks_reachable, lcp.deltamode) );
+      VG_(umsg)("        suppressed: %'lu%s bytes in %'lu%s blocks\n",
+                MC_(bytes_suppressed), 
+                MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_suppressed), old_bytes_suppressed, lcp.deltamode), 
+                MC_(blocks_suppressed),
+                MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_suppressed), old_blocks_suppressed, lcp.deltamode) );
+      if (lcp.mode != LC_Full &&
           (MC_(blocks_leaked) + MC_(blocks_indirect) +
            MC_(blocks_dubious) + MC_(blocks_reachable)) > 0) {
-         VG_(umsg)("Rerun with --leak-check=full to see details "
-                   "of leaked memory\n");
+         if (lcp.requested_by_monitor_command)
+            VG_(umsg)("To see details of leaked memory, give 'full' arg to mc.leak_check\n");
+         else
+            VG_(umsg)("Rerun with --leak-check=full to see details "
+                      "of leaked memory\n");
       }
-      if (is_full_check &&
-          MC_(blocks_reachable) > 0 && !MC_(clo_show_reachable))
+      if (lcp.mode == LC_Full &&
+          MC_(blocks_reachable) > 0 && !lcp.show_reachable)
       {
          VG_(umsg)("Reachable blocks (those to which a pointer "
                    "was found) are not shown.\n");
-         VG_(umsg)("To see them, rerun with: --leak-check=full "
-                   "--show-reachable=yes\n");
+         if (lcp.requested_by_monitor_command)
+            VG_(umsg)("To see them, add 'reachable any' args to mc.leak_check\n");
+         else
+            VG_(umsg)("To see them, rerun with: --leak-check=full "
+                      "--show-reachable=yes\n");
       }
       VG_(umsg)("\n");
    }
@@ -928,16 +1018,26 @@
 /*--- Top-level entry point.                               ---*/
 /*------------------------------------------------------------*/
 
-void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckMode mode )
+void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams lcp)
 {
    Int i, j;
    
-   tl_assert(mode != LC_Off);
+   tl_assert(lcp.mode != LC_Off);
+
+   MC_(detect_memory_leaks_last_delta_mode) = lcp.deltamode;
 
    // Get the chunks, stop if there were none.
    lc_chunks = find_active_chunks(&lc_n_chunks);
    if (lc_n_chunks == 0) {
       tl_assert(lc_chunks == NULL);
+      if (lr_table != NULL) {
+         // forget the previous recorded LossRecords as next leak search will in any case
+         // just create new leaks.
+         // Maybe it would be better to rather call print_result ?
+         // (at least when leak decrease are requested)
+         // This will then output all LossRecords with a size decreasing to 0
+         VG_(OSetGen_Destroy) (lr_table);
+      }
       if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
          VG_(umsg)("All heap blocks were freed -- no leaks are possible\n");
          VG_(umsg)("\n");
@@ -1124,7 +1224,7 @@
       }
    }
       
-   print_results( tid, ( mode == LC_Full ? True : False ) );
+   print_results( tid, lcp);
 
    VG_(free) ( lc_chunks );
    VG_(free) ( lc_extras );
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index 0cdb4a5..24ece12 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -4945,11 +4945,11 @@
 "  mc.check_memory [addressable|defined] <addr> [<len>]\n"
 "        check that <len> (or 1) bytes at <addr> have the given accessibility\n"
 "            and outputs a description of <addr>\n"
-"  mc.leak_check [full*|summary]\n"
-"                [reachable|leakpossible*|definiteleak]\n"
+"  mc.leak_check [full*|summary] [reachable|leakpossible*|definiteleak]\n"
+"                [increased*|changed|any]\n"
 "            * = defaults\n"
 "        Examples: mc.leak_check\n"
-"                  mc.leak_check any summary\n"
+"                  mc.leak_check summary any\n"
 "\n");
 }
 
@@ -5013,40 +5013,50 @@
    }
    case  2: { /* mc.leak_check */
       Int err = 0;
-      Bool save_clo_show_reachable = MC_(clo_show_reachable);
-      Bool save_clo_show_possibly_lost = MC_(clo_show_possibly_lost);
+      LeakCheckParams lcp;
       Char* kw;
-
-      LeakCheckMode mode;
       
-      MC_(clo_show_reachable) = False;
-      mode = LC_Full;
+      lcp.mode               = LC_Full;
+      lcp.show_reachable     = False;
+      lcp.show_possibly_lost = True;
+      lcp.deltamode          = LCD_Increased;
+      lcp.requested_by_monitor_command = True;
       
       for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr); 
            kw != NULL; 
            kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
          switch (VG_(keyword_id) 
                  ("full summary "
-                  "reachable leakpossible definiteleak",
+                  "reachable leakpossible definiteleak "
+                  "increased changed any",
                   kw, kwd_report_all)) {
          case -2: err++; break;
          case -1: err++; break;
-         case  0: mode = LC_Full; break;
-         case  1: mode = LC_Summary; break;
-         case  2: MC_(clo_show_reachable) = True; 
-                  MC_(clo_show_possibly_lost) = True; break;
-         case  3: MC_(clo_show_reachable) = False;
-                  MC_(clo_show_possibly_lost) = True; break;
-         case  4: MC_(clo_show_reachable) = False;
-                  MC_(clo_show_possibly_lost) = False; break;
-         default: tl_assert (0);
+         case  0: /* full */
+            lcp.mode = LC_Full; break;
+         case  1: /* summary */
+            lcp.mode = LC_Summary; break;
+         case  2: /* reachable */
+            lcp.show_reachable = True; 
+            lcp.show_possibly_lost = True; break;
+         case  3: /* leakpossible */
+            lcp.show_reachable = False;
+            lcp.show_possibly_lost = True; break;
+         case  4: /* definiteleak */
+            lcp.show_reachable = False;
+            lcp.show_possibly_lost = False; break;
+         case  5: /* increased */
+            lcp.deltamode = LCD_Increased; break;
+         case  6: /* changed */
+            lcp.deltamode = LCD_Changed; break;
+         case  7: /* any */
+            lcp.deltamode = LCD_Any; break;
+         default:
+            tl_assert (0);
          }
       }
       if (!err)
-         MC_(detect_memory_leaks)(tid, mode);
-      
-      MC_(clo_show_reachable) = save_clo_show_reachable;
-      MC_(clo_show_possibly_lost) = save_clo_show_possibly_lost;
+         MC_(detect_memory_leaks)(tid, lcp);
       return True;
    }
       
@@ -5189,10 +5199,40 @@
          break;
       }
 
-      case VG_USERREQ__DO_LEAK_CHECK:
-         MC_(detect_memory_leaks)(tid, arg[1] ? LC_Summary : LC_Full);
+      case VG_USERREQ__DO_LEAK_CHECK: {
+         LeakCheckParams lcp;
+         
+         if (arg[1] == 0)
+            lcp.mode = LC_Full;
+         else if (arg[1] == 1)
+            lcp.mode = LC_Summary;
+         else {
+            VG_(message)(Vg_UserMsg, 
+                         "Warning: unknown memcheck leak search mode\n");
+            lcp.mode = LC_Full;
+         }
+          
+         lcp.show_reachable = MC_(clo_show_reachable);
+         lcp.show_possibly_lost = MC_(clo_show_possibly_lost);
+
+         if (arg[2] == 0)
+            lcp.deltamode = LCD_Any;
+         else if (arg[2] == 1)
+            lcp.deltamode = LCD_Increased;
+         else if (arg[2] == 2)
+            lcp.deltamode = LCD_Changed;
+         else {
+            VG_(message)
+               (Vg_UserMsg, 
+                "Warning: unknown memcheck leak search deltamode\n");
+            lcp.deltamode = LCD_Any;
+         }
+         lcp.requested_by_monitor_command = False;
+         
+         MC_(detect_memory_leaks)(tid, lcp);
          *ret = 0; /* return value is meaningless */
          break;
+      }
 
       case VG_USERREQ__MAKE_MEM_NOACCESS:
          MC_(make_mem_noaccess) ( arg[1], arg[2] );
@@ -5854,7 +5894,13 @@
    MC_(print_malloc_stats)();
 
    if (MC_(clo_leak_check) != LC_Off) {
-      MC_(detect_memory_leaks)(1/*bogus ThreadId*/, MC_(clo_leak_check));
+      LeakCheckParams lcp;
+      lcp.mode = MC_(clo_leak_check);
+      lcp.show_reachable = MC_(clo_show_reachable);
+      lcp.show_possibly_lost = MC_(clo_show_possibly_lost);
+      lcp.deltamode = LCD_Any;
+      lcp.requested_by_monitor_command = False;
+      MC_(detect_memory_leaks)(1/*bogus ThreadId*/, lcp);
    } else {
       if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
          VG_(umsg)(
diff --git a/memcheck/memcheck.h b/memcheck/memcheck.h
index 628511b..19acca2 100644
--- a/memcheck/memcheck.h
+++ b/memcheck/memcheck.h
@@ -188,6 +188,26 @@
                             VG_USERREQ__DO_LEAK_CHECK,           \
                             0, 0, 0, 0, 0)
 
+/* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for
+   which there was an increase in leaked bytes or leaked nr of blocks
+   since the previous leak search. */
+#define VALGRIND_DO_ADDED_LEAK_CHECK                             \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            0, 1, 0, 0, 0);                      \
+   }
+
+/* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with
+   increased or decreased leaked bytes/blocks since previous leak
+   search. */
+#define VALGRIND_DO_CHANGED_LEAK_CHECK                           \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            0, 2, 0, 0, 0);                      \
+   }
+
 /* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
 #define VALGRIND_DO_QUICK_LEAK_CHECK                             \
     VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                           \
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index 1d54f37..93939a9 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -88,6 +88,7 @@
 	leak-cases-possible.vgtest leak-cases-possible.stderr.exp \
 	leak-cases-summary.vgtest leak-cases-summary.stderr.exp \
 	leak-cycle.vgtest leak-cycle.stderr.exp \
+	leak-delta.vgtest leak-delta.stderr.exp \
 	leak-pool-0.vgtest leak-pool-0.stderr.exp \
 	leak-pool-1.vgtest leak-pool-1.stderr.exp \
 	leak-pool-2.vgtest leak-pool-2.stderr.exp \
@@ -219,6 +220,7 @@
 	leak-0 \
 	leak-cases \
 	leak-cycle \
+	leak-delta \
 	leak-pool \
 	leak-tree \
 	long_namespace_xml \
diff --git a/memcheck/tests/leak-delta.c b/memcheck/tests/leak-delta.c
new file mode 100644
index 0000000..b95a8fe
--- /dev/null
+++ b/memcheck/tests/leak-delta.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "../memcheck.h"
+#include "leak.h"
+
+char *b10;
+char *b21;
+char *b32_33[2];
+static void breakme() {};
+void f(void)
+{
+   int i;
+
+   b10 = malloc (10);
+
+   fprintf(stderr, "expecting details 10 bytes reachable\n"); fflush(stderr); breakme();
+   VALGRIND_DO_LEAK_CHECK;
+
+   fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+   VALGRIND_DO_ADDED_LEAK_CHECK;
+
+   b10--; // lose b10
+   b21 = malloc (21);
+   fprintf(stderr, "expecting details +10 bytes lost, +21 bytes reachable\n"); fflush(stderr); breakme();
+   VALGRIND_DO_ADDED_LEAK_CHECK;
+
+   for (i = 0; i < 2; i ++)
+      b32_33[i] = malloc (32+i);
+   fprintf(stderr, "expecting details +65 bytes reachable\n"); fflush(stderr); breakme();
+   VALGRIND_DO_ADDED_LEAK_CHECK;
+
+   fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+   VALGRIND_DO_ADDED_LEAK_CHECK;
+
+   b10++;
+   fprintf(stderr, "expecting details +10 bytes reachable\n"); fflush(stderr); breakme();
+   VALGRIND_DO_ADDED_LEAK_CHECK;
+
+   b10--;
+   fprintf(stderr, "expecting details -10 bytes reachable, +10 bytes lost\n"); fflush(stderr); breakme();
+   VALGRIND_DO_CHANGED_LEAK_CHECK;
+
+   b10++;
+   fprintf(stderr, "expecting details -10 bytes lost, +10 bytes reachable\n"); fflush(stderr); breakme();
+   VALGRIND_DO_CHANGED_LEAK_CHECK;
+
+   b32_33[0]--;
+   fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
+   VALGRIND_DO_CHANGED_LEAK_CHECK;
+   
+   fprintf(stderr, "finished\n");
+}
+
+int main(void)
+{
+   DECLARE_LEAK_COUNTERS;
+
+   GET_INITIAL_LEAK_COUNTS;
+
+   f();   // see leak-cases.c
+
+
+   GET_FINAL_LEAK_COUNTS;
+
+   PRINT_LEAK_COUNTS(stderr);
+
+   return 0;
+}
diff --git a/memcheck/tests/leak-delta.stderr.exp b/memcheck/tests/leak-delta.stderr.exp
new file mode 100644
index 0000000..ad8eebc
--- /dev/null
+++ b/memcheck/tests/leak-delta.stderr.exp
@@ -0,0 +1,89 @@
+expecting details 10 bytes reachable
+10 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+expecting to have NO details
+expecting details +10 bytes lost, +21 bytes reachable
+10 (+10) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+21 (+21) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:23)
+   by 0x........: main (leak-delta.c:60)
+
+expecting details +65 bytes reachable
+65 (+65) bytes in 2 (+2) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
+expecting to have NO details
+expecting details +10 bytes reachable
+10 (+10) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+expecting details -10 bytes reachable, +10 bytes lost
+0 (-10) bytes in 0 (-1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+10 (+10) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+expecting details -10 bytes lost, +10 bytes reachable
+0 (-10) bytes in 0 (-1) blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+10 (+10) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable
+32 (+32) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
+33 (-32) bytes in 1 (-1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
+finished
+leaked:      32 bytes in  1 blocks
+dubious:      0 bytes in  0 blocks
+reachable:   64 bytes in  3 blocks
+suppressed:   0 bytes in  0 blocks
+10 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+21 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:23)
+   by 0x........: main (leak-delta.c:60)
+
+32 bytes in 1 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
+33 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
diff --git a/memcheck/tests/leak-delta.vgtest b/memcheck/tests/leak-delta.vgtest
new file mode 100644
index 0000000..db86b27
--- /dev/null
+++ b/memcheck/tests/leak-delta.vgtest
@@ -0,0 +1,2 @@
+prog: leak-delta
+vgopts: -q --leak-check=yes --show-reachable=yes --leak-resolution=high