]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Allows to only output "new" loss records when doing a leak search.
authorPhilippe Waroquiers <philippe.waroquiers@skynet.be>
Fri, 30 Dec 2022 19:05:40 +0000 (20:05 +0100)
committerPhilippe Waroquiers <philippe.waroquiers@skynet.be>
Fri, 30 Dec 2022 19:56:47 +0000 (20:56 +0100)
In the memcheck monitor 'leak_search', add a "new" keyword corresponding
to the delta leak search mode LCD_New.

Add a new client request VALGRIND_DO_NEW_LEAK_CHECK.

When doing a delta leak search, new loss records are marked with "new"
(whatever the delta leak search mode).

Note that trailing white spaces were removed in mc_main.c.
A much small diff can be looked at by using the -w diff option.

15 files changed:
NEWS
gdbserver_tests/mchelp.stdoutB.exp
gdbserver_tests/mcleak.stderr.exp
gdbserver_tests/mcleak.stderrB.exp
gdbserver_tests/mcleak.stdinB.gdb
gdbserver_tests/mcleak.stdoutB.exp
memcheck/docs/mc-manual.xml
memcheck/mc_errors.c
memcheck/mc_include.h
memcheck/mc_leakcheck.c
memcheck/mc_main.c
memcheck/memcheck.h
memcheck/tests/filter_stderr.in
memcheck/tests/leak-delta.c
memcheck/tests/leak-delta.stderr.exp

diff --git a/NEWS b/NEWS
index 16ae313dfc8b92ae37775587557999c0eb439257..f73541187adee5a6b99579682d849f26f3a3ee56 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,16 @@ AMD64/macOS 10.13 and nanoMIPS/Linux.
 
 * ==================== TOOL CHANGES ===================
 
+* Memcheck:
+  - When doing a delta leak_search, it is now possible to only
+    output the new loss records compared to the previous leak search.
+    This is available in the memcheck monitor command 'leak_search'
+    by specifying the "new" keyword or in your program by using
+    the client request VALGRIND_DO_NEW_LEAK_CHECK.
+    Whenever a "delta" leak search is done (i.e. when specifying
+    "new" or "increased" or "changed" in the monitor command),
+    the new loss records have a "new" marker.
+
 * Helgrind:
   - The option ---history-backtrace-size=<number> allows to configure
     the number of entries to record in the stack traces of "old"
index 6f45932d108f66526bd204a0b31f2c73014917cc..916c8a70d2d956271d646af648d8233be1b2da7c 100644 (file)
@@ -32,7 +32,7 @@ memcheck monitor commands:
   leak_check [full*|summary|xtleak]
                 [kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]
                 [heuristics heur1,heur2,...]
-                [increased*|changed|any]
+                [new|increased*|changed|any]
                 [unlimited*|limited <max_loss_records_output>]
             * = defaults
          xtleak produces an xtree full leak result in xtleak.kcg.%p.%n
@@ -106,7 +106,7 @@ memcheck monitor commands:
   leak_check [full*|summary|xtleak]
                 [kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]
                 [heuristics heur1,heur2,...]
-                [increased*|changed|any]
+                [new|increased*|changed|any]
                 [unlimited*|limited <max_loss_records_output>]
             * = defaults
          xtleak produces an xtree full leak result in xtleak.kcg.%p.%n
index 0496c1d6aad92f15221166fd1c2baeeda9d19c1b..c6f0b01ff69992d3f7c155f126340ce124d85818 100644 (file)
@@ -2,8 +2,8 @@
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 expecting to have NO details
 expecting details +10 bytes lost, +21 bytes reachable
 expecting details +65 bytes reachable
@@ -12,24 +12,30 @@ expecting details +10 bytes reachable
 expecting details -10 bytes reachable, +10 bytes lost
 expecting details -10 bytes lost, +10 bytes reachable
 expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable
+expecting details 42 (+42) bytes lost, 43 (+43) bytes reachable
+expecting to have NO details
 finished
-leaked:      32 bytes in  1 blocks
+leaked:     117 bytes in  3 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:24)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
+85 bytes in 2 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:53)
+   by 0x........: main (leak-delta.c:72)
index 7ed392057a12ef576c7a9858f18efbff8ea065d5..6e6ee24870e5efb42448396f9debfcb481a5e439 100644 (file)
@@ -1,77 +1,89 @@
 vgdb-error value changed from 0 to 999999
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:24)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
+42 (+42) 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:53)
+   by 0x........: main (leak-delta.c:72)
+43 (+43) 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:53)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:24)
+   by 0x........: main (leak-delta.c:72)
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
 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)
-32 bytes in 1 blocks are definitely lost in loss record ... of ...
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
+85 bytes in 2 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)
+   by 0x........: f (leak-delta.c:53)
+   by 0x........: main (leak-delta.c:72)
 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)
-33 bytes in 1 blocks are still reachable in loss record ... of ...
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
+85 bytes in 2 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)
-32 bytes in 1 blocks are definitely lost in loss record ... of ...
+   by 0x........: f (leak-delta.c:53)
+   by 0x........: main (leak-delta.c:72)
+85 bytes in 2 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:53)
+   by 0x........: main (leak-delta.c:72)
+85 bytes in 2 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)
+   by 0x........: f (leak-delta.c:53)
+   by 0x........: main (leak-delta.c:72)
index 437556ab66f22c46a955d91099adf30b7d7f80ff..0862a85414922b76e15b94c1cc27084ba9f53fe0 100644 (file)
@@ -70,6 +70,15 @@ continue
 #   fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
 up
 monitor leak_check full reachable changed
+continue
+#   b42_43[0]--;
+#   fprintf(stderr, "expecting details 42 (+42) bytes lost, 43 (+43) bytes reachable\n"); fflush(stderr); breakme();
+up
+monitor leak_check full reachable new
+continue
+#   b42_43[1]--;
+#   fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+monitor leak_check full reachable new
 # output all leak records:
 monitor leak_check full reachable any unlimited
 # output the 2 biggest leak records:
index 41be83e6841f4320fe6d3a84dbc635ffa6e8184f..62b7449fcb3d4c5eb38293c699afe947348777d7 100644 (file)
@@ -1,48 +1,56 @@
-Breakpoint 1 at 0x........: file leak-delta.c, line 9.
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:16
-16        fprintf(stderr, "expecting details 10 bytes reachable\n"); fflush(stderr); breakme();
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:19
-19        fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:24
-24        fprintf(stderr, "expecting details +10 bytes lost, +21 bytes reachable\n"); fflush(stderr); breakme();
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:29
-29        fprintf(stderr, "expecting details +65 bytes reachable\n"); fflush(stderr); breakme();
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:32
-32        fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:36
-36        fprintf(stderr, "expecting details +10 bytes reachable\n"); fflush(stderr); breakme();
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:40
-40        fprintf(stderr, "expecting details -10 bytes reachable, +10 bytes lost\n"); fflush(stderr); breakme();
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:44
-44        fprintf(stderr, "expecting details -10 bytes lost, +10 bytes reachable\n"); fflush(stderr); breakme();
-Continuing.
-Breakpoint 1, breakme () at leak-delta.c:9
-9      static void breakme() {};
-#1  0x........ in f () at leak-delta.c:48
-48        fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
+Breakpoint 1 at 0x........: file leak-delta.c, line 10.
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:17
+17        fprintf(stderr, "expecting details 10 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:20
+20        fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:25
+25        fprintf(stderr, "expecting details +10 bytes lost, +21 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:30
+30        fprintf(stderr, "expecting details +65 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:33
+33        fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:37
+37        fprintf(stderr, "expecting details +10 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:41
+41        fprintf(stderr, "expecting details -10 bytes reachable, +10 bytes lost\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:45
+45        fprintf(stderr, "expecting details -10 bytes lost, +10 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:49
+49        fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
+#1  0x........ in f () at leak-delta.c:56
+56        fprintf(stderr, "expecting details 42 (+42) bytes lost, 43 (+43) bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:10
+10     static void breakme() {};
 Continuing.
 Program exited normally.
index 4de7c3debcbde0dfd9035ddd350403ad9e76ff51..2eb5b12f92bb943438cdf13af8d36c5710c8eba8 100644 (file)
@@ -1930,7 +1930,7 @@ Address 0x8049E28 len 1 defined
     <para><varname>leak_check [full*|summary|xtleak]
                               [kinds &lt;set&gt;|reachable|possibleleak*|definiteleak]
                               [heuristics heur1,heur2,...]
-                              [increased*|changed|any]
+                              [new|increased*|changed|any]
                               [unlimited*|limited &lt;max_loss_records_output&gt;]
           </varname>
     performs a leak check. The <varname>*</varname> in the arguments
@@ -1980,18 +1980,22 @@ Address 0x8049E28 len 1 defined
     <varname>heuristics none</varname>.
     </para>
 
-    <para>The <varname>[increased*|changed|any]</varname> argument controls what
-    kinds of changes are shown for a <varname>full</varname> leak search. The
-    value <varname>increased</varname> specifies that only block
+    <para>The <varname>[new|increased*|changed|any]</varname> 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>new</varname> specifies to show only the block
+    allocation stacks that are new since the previous leak search.
     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.
+    should be shown, regardless of any increase or decrease.
+    If <varname>new</varname> or <varname>increased</varname> or
+    <varname>changed</varname> are specified, the leak report entries will show
+    the delta relative to the previous leak report and the new loss records
+    will have a "new" marker (even when <varname>increased</varname> or
+    <varname>changed</varname> were specified).
     </para>
 
     <para>The following example shows usage of the 
@@ -2004,7 +2008,7 @@ Address 0x8049E28 len 1 defined
     there was no increase since the previous leak search.</para>
 <programlisting><![CDATA[
 (gdb) monitor leak_check full possibleleak increased
-==19520== 16 (+16) bytes in 1 (+1) blocks are possibly lost in loss record 9 of 12
+==19520== 16 (+16) bytes in 1 (+1) blocks are possibly lost in new loss record 9 of 12
 ==19520==    at 0x40070B4: malloc (vg_replace_malloc.c:263)
 ==19520==    by 0x80484D5: mk (leak-cases.c:52)
 ==19520==    by 0x804855F: f (leak-cases.c:81)
@@ -2294,6 +2298,12 @@ arguments.</para>
     has no return value.</para>
   </listitem>
 
+  <listitem>
+    <para><varname>VALGRIND_DO_NEW_LEAK_CHECK</varname>: same as
+   <varname> VALGRIND_DO_LEAK_CHECK</varname> but only shows the new
+    entries 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
index d47cfa771302a4a12378ba07829e333234e37a54..ee5533a632232589e8a8adaaea7d1f3c50f54212 100644 (file)
@@ -329,9 +329,15 @@ static void pp_LossRecord(UInt n_this_record, UInt n_total_records,
    HChar d_direct_bytes[31];
    HChar d_indirect_bytes[31];
    HChar d_num_blocks[31];
+   /* A loss record that had an old number of blocks 0 is a new loss record.
+      We mark it as new only when doing any kind of delta leak search. */
+   const HChar *new_loss_record_marker
+      = MC_(detect_memory_leaks_last_delta_mode) != LCD_Any
+      && lr->old_num_blocks == 0
+      ? "new " : "";
 
    MC_(snprintf_delta) (d_bytes, sizeof(d_bytes),
-                        lr->szB + lr->indirect_szB, 
+                        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, sizeof(d_direct_bytes),
@@ -353,14 +359,15 @@ static void pp_LossRecord(UInt n_this_record, UInt n_total_records,
          emit( "  <xwhat>\n" );
          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",
+               " are %s in %sloss record %'u of %'u</text>\n",
                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),
+               new_loss_record_marker,
                n_this_record, n_total_records );
-         // Nb: don't put commas in these XML numbers 
+         // Nb: don't put commas in these XML numbers
          emit( "    <leakedbytes>%lu</leakedbytes>\n",
                lr->szB + lr->indirect_szB );
          emit( "    <leakedblocks>%u</leakedblocks>\n", lr->num_blocks );
@@ -368,10 +375,11 @@ static void pp_LossRecord(UInt n_this_record, UInt n_total_records,
       } else {
          emit( "  <xwhat>\n" );
          emit( "    <text>%'lu%s bytes in %'u%s blocks"
-               " are %s in loss record %'u of %'u</text>\n",
+               " are %s in %sloss record %'u of %'u</text>\n",
                lr->szB, d_direct_bytes,
                lr->num_blocks, d_num_blocks,
-               str_leak_lossmode(lr->key.state), 
+               str_leak_lossmode(lr->key.state),
+               new_loss_record_marker,
                n_this_record, n_total_records );
          emit( "    <leakedbytes>%lu</leakedbytes>\n", lr->szB);
          emit( "    <leakedblocks>%u</leakedblocks>\n", lr->num_blocks);
@@ -382,20 +390,22 @@ static void pp_LossRecord(UInt n_this_record, UInt n_total_records,
       if (lr->indirect_szB > 0) {
          emit(
             "%'lu%s (%'lu%s direct, %'lu%s indirect) bytes in %'u%s blocks"
-            " are %s in loss record %'u of %'u\n",
+            " are %s in %sloss record %'u of %'u\n",
             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),
+            new_loss_record_marker,
             n_this_record, n_total_records
          );
       } else {
          emit(
-            "%'lu%s bytes in %'u%s blocks are %s in loss record %'u of %'u\n",
+            "%'lu%s bytes in %'u%s blocks are %s in %sloss record %'u of %'u\n",
             lr->szB, d_direct_bytes,
             lr->num_blocks, d_num_blocks,
             str_leak_lossmode(lr->key.state),
+            new_loss_record_marker,
             n_this_record, n_total_records
          );
       }
index 035c2276cf123b5d3dab3a6d52a727741c59a352..30d0affdb2a73cb74d685106f219c9c08d7bf0ef 100644 (file)
@@ -430,10 +430,11 @@ typedef
 
 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
+      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.
+      LCD_New        // Output new loss records.
    }
    LeakCheckDeltaMode;
 
index c78960c0cbeb2661adffc84e25efeb4f5a6f4207..b2a133f3fe7e3f8cf9d7db1cfc2a9d710bff6423 100644 (file)
@@ -1275,25 +1275,29 @@ static void get_printing_rules(LeakCheckParams* lcp,
    Bool delta_considered;
 
    switch (lcp->deltamode) {
-   case LCD_Any: 
+   case LCD_Any:
       delta_considered = lr->num_blocks > 0;
       break;
    case LCD_Increased:
-      delta_considered 
+      delta_considered
          = lr->szB > lr->old_szB
          || lr->indirect_szB > lr->old_indirect_szB
          || lr->num_blocks > lr->old_num_blocks;
       break;
-   case LCD_Changed: 
+   case LCD_Changed:
       delta_considered = lr->szB != lr->old_szB
          || lr->indirect_szB != lr->old_indirect_szB
          || lr->num_blocks != lr->old_num_blocks;
       break;
+   case LCD_New:
+      delta_considered
+         = lr->num_blocks > 0 && lr->old_num_blocks == 0;
+      break;
    default:
       tl_assert(0);
    }
 
-   *print_record = lcp->mode == LC_Full && delta_considered 
+   *print_record = lcp->mode == LC_Full && delta_considered
       && RiS(lr->key.state,lcp->show_leak_kinds);
    // 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
index 94af5b28a22757a23c7295f02f87784166ed41bc..fe15d233214d2eb1cfa634e9f78540f6e5d4facb 100644 (file)
@@ -10,7 +10,7 @@
    This file is part of MemCheck, a heavyweight Valgrind tool for
    detecting memory errors.
 
-   Copyright (C) 2000-2017 Julian Seward 
+   Copyright (C) 2000-2017 Julian Seward
       jseward@acm.org
 
    This program is free software; you can redistribute it and/or
@@ -64,7 +64,7 @@ static void ocache_sarp_Clear_Origins ( Addr, UWord ); /* fwds */
 /*------------------------------------------------------------*/
 /*--- Fast-case knobs                                      ---*/
 /*------------------------------------------------------------*/
+
 // Comment these out to disable the fast cases (don't just set them to zero).
 
 /* PERF_FAST_LOADV is in mc_include.h */
@@ -113,8 +113,8 @@ static void ocache_sarp_Clear_Origins ( Addr, UWord ); /* fwds */
 /*------------------------------------------------------------*/
 
 /* All reads and writes are checked against a memory map (a.k.a. shadow
-   memory), which records the state of all memory in the process.  
-   
+   memory), which records the state of all memory in the process.
+
    On 32-bit machines the memory map is organised as follows.
    The top 16 bits of an address are used to index into a top-level
    map table, containing 65536 entries.  Each entry is a pointer to a
@@ -222,7 +222,7 @@ static void ocache_sarp_Clear_Origins ( Addr, UWord ); /* fwds */
 // Ie. instead of particular value bits being held in certain addresses, in
 // this case certain addresses are represented by particular value bits.
 // See insert_vabits2_into_vabits8() for an example.
-// 
+//
 // But note that we don't compress the V bits stored in registers;  they
 // need to be explicit to made the shadow operations possible.  Therefore
 // when moving values between registers and memory we need to convert
@@ -272,7 +272,7 @@ static INLINE Bool is_start_of_sm ( Addr a ) {
 
 STATIC_ASSERT(SM_CHUNKS % 2 == 0);
 
-typedef 
+typedef
    union {
       UChar vabits8[SM_CHUNKS];
       UShort vabits16[SM_CHUNKS/2];
@@ -307,7 +307,7 @@ static SecMap* copy_for_writing ( SecMap* dist_sm )
 
    new_sm = VG_(am_shadow_alloc)(sizeof(SecMap));
    if (new_sm == NULL)
-      VG_(out_of_memory_NORETURN)( "memcheck:allocate new SecMap", 
+      VG_(out_of_memory_NORETURN)( "memcheck:allocate new SecMap",
                                    sizeof(SecMap) );
    VG_(memcpy)(new_sm, dist_sm, sizeof(SecMap));
    update_SM_counts(dist_sm, new_sm);
@@ -358,14 +358,14 @@ static void update_SM_counts(SecMap* oldSM, SecMap* newSM)
    if (n_noaccess_SMs  > max_noaccess_SMs ) max_noaccess_SMs  = n_noaccess_SMs;
    if (n_undefined_SMs > max_undefined_SMs) max_undefined_SMs = n_undefined_SMs;
    if (n_defined_SMs   > max_defined_SMs  ) max_defined_SMs   = n_defined_SMs;
-   if (n_non_DSM_SMs   > max_non_DSM_SMs  ) max_non_DSM_SMs   = n_non_DSM_SMs;   
+   if (n_non_DSM_SMs   > max_non_DSM_SMs  ) max_non_DSM_SMs   = n_non_DSM_SMs;
 }
 
 /* --------------- Primary maps --------------- */
 
 /* The main primary map.  This covers some initial part of the address
    space, addresses 0 .. (N_PRIMARY_MAP << 16)-1.  The rest of it is
-   handled using the auxiliary primary map.  
+   handled using the auxiliary primary map.
 */
 #if ENABLE_ASSEMBLY_HELPERS && defined(PERF_FAST_LOADV) \
     && (defined(VGP_arm_linux) \
@@ -387,7 +387,7 @@ MC_MAIN_STATIC SecMap* primary_map[N_PRIMARY_MAP];
    LAYOUT: the first word has to be the key for OSet fast lookups.
 */
 typedef
-   struct { 
+   struct {
       Addr    base;
       SecMap* sm;
    }
@@ -403,7 +403,7 @@ typedef
 static struct {
           Addr       base;
           AuxMapEnt* ent; // pointer to the matching auxmap_L2 node
-       } 
+       }
        auxmap_L1[N_AUXMAP_L1];
 
 static OSet* auxmap_L2 = NULL;
@@ -451,7 +451,7 @@ static const HChar* check_auxmap_L1_L2_sanity ( Word* n_secmaps_found )
       /* 32-bit platform */
       if (VG_(OSetGen_Size)(auxmap_L2) != 0)
          return "32-bit: auxmap_L2 is non-empty";
-      for (i = 0; i < N_AUXMAP_L1; i++) 
+      for (i = 0; i < N_AUXMAP_L1; i++)
         if (auxmap_L1[i].base != 0 || auxmap_L1[i].ent != NULL)
       return "32-bit: auxmap_L1 is non-empty";
    } else {
@@ -631,8 +631,8 @@ static INLINE SecMap** get_secmap_high_ptr ( Addr a )
 
 static INLINE SecMap** get_secmap_ptr ( Addr a )
 {
-   return ( a <= MAX_PRIMARY_ADDRESS 
-          ? get_secmap_low_ptr(a) 
+   return ( a <= MAX_PRIMARY_ADDRESS
+          ? get_secmap_low_ptr(a)
           : get_secmap_high_ptr(a));
 }
 
@@ -665,7 +665,7 @@ static INLINE SecMap* get_secmap_for_writing_high ( Addr a )
 /* Produce the secmap for 'a', either from the primary map or by
    ensuring there is an entry for it in the aux primary map.  The
    secmap may be a distinguished one as the caller will only want to
-   be able to read it. 
+   be able to read it.
 */
 static INLINE SecMap* get_secmap_for_reading ( Addr a )
 {
@@ -767,7 +767,7 @@ UChar get_vabits2 ( Addr a )
 
 // *** WARNING! ***
 // Any time this function is called, if it is possible that any of the
-// 4 2-bit fields in vabits8 are equal to VA_BITS2_PARTDEFINED, then the 
+// 4 2-bit fields in vabits8 are equal to VA_BITS2_PARTDEFINED, then the
 // corresponding entry(s) in the sec-V-bits table must also be set!
 static INLINE
 UChar get_vabits8_for_aligned_word32 ( Addr a )
@@ -847,13 +847,13 @@ Bool get_vbits8 ( Addr a, UChar* vbits8 )
 // Note: the nodes in this table can become stale.  Eg. if you write a PDB,
 // then overwrite the same address with a fully defined byte, the sec-V-bit
 // node will not necessarily be removed.  This is because checking for
-// whether removal is necessary would slow down the fast paths.  
+// whether removal is necessary would slow down the fast paths.
 //
 // To avoid the stale nodes building up too much, we periodically (once the
 // table reaches a certain size) garbage collect (GC) the table by
 // traversing it and evicting any nodes not having PDB.
 // If more than a certain proportion of nodes survived, we increase the
-// table size so that GCs occur less often.  
+// table size so that GCs occur less often.
 //
 // This policy is designed to avoid bad table bloat in the worst case where
 // a program creates huge numbers of stale PDBs -- we would get this bloat
@@ -881,7 +881,7 @@ Bool get_vbits8 ( Addr a, UChar* vbits8 )
 // will be deleted and re-added less frequently.
 //
 // The previous scaling up mechanism (now called STEPUP) is retained:
-// if residency exceeds 50%, the table is scaled up, although by a 
+// if residency exceeds 50%, the table is scaled up, although by a
 // factor sqrt(2) rather than 2 as before.  This effectively doubles the
 // frequency of GCs when there are many PDBs at reduces the tendency of
 // stale PDBs to reside for long periods in the table.
@@ -930,20 +930,20 @@ static Int  secVBitLimit = 1000;
 // come out anyway.
 static UInt GCs_done = 0;
 
-typedef 
+typedef
    struct {
       Addr  a;
       UChar vbits8[BYTES_PER_SEC_VBIT_NODE];
-   } 
+   }
    SecVBitNode;
 
 static OSet* createSecVBitTable(void)
 {
    OSet* newSecVBitTable;
    newSecVBitTable = VG_(OSetGen_Create_With_Pool)
-      ( offsetof(SecVBitNode, a), 
+      ( offsetof(SecVBitNode, a),
         NULL, // use fast comparisons
-        VG_(malloc), "mc.cSVT.1 (sec VBit table)", 
+        VG_(malloc), "mc.cSVT.1 (sec VBit table)",
         VG_(free),
         1000,
         sizeof(SecVBitNode));
@@ -971,7 +971,7 @@ static void gcSecVBitTable(void)
          if (VA_BITS2_PARTDEFINED == get_vabits2(n->a + i)) {
             // Found a non-stale byte, so keep =>
             // Insert a copy of the node into the new table.
-            SecVBitNode* n2 = 
+            SecVBitNode* n2 =
                VG_(OSetGen_AllocNode)(secVBitTable2, sizeof(SecVBitNode));
             *n2 = *n;
             VG_(OSetGen_Insert)(secVBitTable2, n2);
@@ -994,7 +994,7 @@ static void gcSecVBitTable(void)
    }
 
    // Increase table size if necessary.
-   if ((Double)n_survivors 
+   if ((Double)n_survivors
        > ((Double)secVBitLimit * STEPUP_SURVIVOR_PROPORTION)) {
       secVBitLimit = (Int)((Double)secVBitLimit * (Double)STEPUP_GROWTH_FACTOR);
       if (VG_(clo_verbosity) > 1)
@@ -1004,7 +1004,7 @@ static void gcSecVBitTable(void)
    }
    else
    if (secVBitLimit < DRIFTUP_MAX_SIZE
-       && (Double)n_survivors 
+       && (Double)n_survivors
           > ((Double)secVBitLimit * DRIFTUP_SURVIVOR_PROPORTION)) {
       secVBitLimit = (Int)((Double)secVBitLimit * (Double)DRIFTUP_GROWTH_FACTOR);
       if (VG_(clo_verbosity) > 1)
@@ -1069,7 +1069,7 @@ static void set_sec_vbits8(Addr a, UWord vbits8)
 
 /* Returns the offset in memory of the byteno-th most significant byte
    in a wordszB-sized word, given the specified endianness. */
-static INLINE UWord byte_offset_w ( UWord wordszB, Bool bigendian, 
+static INLINE UWord byte_offset_w ( UWord wordszB, Bool bigendian,
                                     UWord byteno ) {
    return bigendian ? (wordszB-1-byteno) : byteno;
 }
@@ -1460,7 +1460,7 @@ ULong mc_LOADVn_slow ( Addr a, SizeT nBits, Bool bigendian )
       PROF_EVENT(MCPE_LOADVN_SLOW_LOOP);
       ai = a + byte_offset_w(szB, bigendian, i);
       ok = get_vbits8(ai, &vbits8);
-      vbits64 <<= 8; 
+      vbits64 <<= 8;
       vbits64 |= vbits8;
       if (!ok) n_addrs_bad++;
       pessim64 <<= 8;
@@ -1590,7 +1590,7 @@ void mc_STOREVn_slow ( Addr a, SizeT nBits, ULong vbytes, Bool bigendian )
       SecMap* sm       = get_secmap_for_reading(a);
       UWord   sm_off16 = SM_OFF_16(a);
       UWord   vabits16 = sm->vabits16[sm_off16];
-      if (LIKELY( !is_distinguished_sm(sm) && 
+      if (LIKELY( !is_distinguished_sm(sm) &&
                           (VA_BITS16_DEFINED   == vabits16 ||
                            VA_BITS16_UNDEFINED == vabits16) )) {
          /* Handle common case quickly: a is suitably aligned, */
@@ -1617,7 +1617,7 @@ void mc_STOREVn_slow ( Addr a, SizeT nBits, ULong vbytes, Bool bigendian )
       SecMap* sm      = get_secmap_for_reading(a);
       UWord   sm_off  = SM_OFF(a);
       UWord   vabits8 = sm->vabits8[sm_off];
-      if (LIKELY( !is_distinguished_sm(sm) && 
+      if (LIKELY( !is_distinguished_sm(sm) &&
                           (VA_BITS8_DEFINED   == vabits8 ||
                            VA_BITS8_UNDEFINED == vabits8) )) {
          /* Handle common case quickly: a is suitably aligned, */
@@ -1727,7 +1727,7 @@ static void set_address_range_perms ( Addr a, SizeT lenT, UWord vabits16,
    // * one partial sec-map                  (p)         1
    // - one whole sec-map                    (P)         2
    //
-   // * two partial sec-maps                 (pp)        1,3 
+   // * two partial sec-maps                 (pp)        1,3
    // - one partial, one whole sec-map       (pP)        1,2
    // - one whole, one partial sec-map       (Pp)        2,3
    // - two whole sec-maps                   (PP)        2,2
@@ -1976,7 +1976,7 @@ static void make_mem_defined_if_addressable ( Addr a, SizeT len )
          set_vabits2(a+i, VA_BITS2_DEFINED);
          if (UNLIKELY(MC_(clo_mc_level) >= 3)) {
             MC_(helperc_b_store1)( a+i, 0 ); /* clear the origin tag */
-         } 
+         }
       }
    }
 }
@@ -1993,7 +1993,7 @@ static void make_mem_defined_if_noaccess ( Addr a, SizeT len )
          set_vabits2(a+i, VA_BITS2_DEFINED);
          if (UNLIKELY(MC_(clo_mc_level) >= 3)) {
             MC_(helperc_b_store1)( a+i, 0 ); /* clear the origin tag */
-         } 
+         }
       }
    }
 }
@@ -2024,8 +2024,8 @@ void MC_(copy_address_range_state) ( Addr src, Addr dst, SizeT len )
       while (len >= 4) {
          vabits8 = get_vabits8_for_aligned_word32( src+i );
          set_vabits8_for_aligned_word32( dst+i, vabits8 );
-         if (LIKELY(VA_BITS8_DEFINED == vabits8 
-                            || VA_BITS8_UNDEFINED == vabits8 
+         if (LIKELY(VA_BITS8_DEFINED == vabits8
+                            || VA_BITS8_UNDEFINED == vabits8
                             || VA_BITS8_NOACCESS == vabits8)) {
             /* do nothing */
          } else {
@@ -2541,7 +2541,7 @@ static void init_OCache ( void )
    tl_assert(ocacheL1 == NULL);
    ocacheL1 = VG_(am_shadow_alloc)(sizeof(OCache));
    if (ocacheL1 == NULL) {
-      VG_(out_of_memory_NORETURN)( "memcheck:allocating ocacheL1", 
+      VG_(out_of_memory_NORETURN)( "memcheck:allocating ocacheL1",
                                    sizeof(OCache) );
    }
    tl_assert(ocacheL1 != NULL);
@@ -2708,7 +2708,7 @@ static OCacheLine* find_OCacheLine_SLOW ( Addr a )
          } else {
             stats_ocacheL1_found_at_N++;
          }
-         if (UNLIKELY(0 == (ocacheL1_event_ctr++ 
+         if (UNLIKELY(0 == (ocacheL1_event_ctr++
                             & ((1<<OC_MOVE_FORWARDS_EVERY_BITS)-1)))) {
             moveLineForwards( &ocacheL1->set[setno], line );
             line--;
@@ -2802,7 +2802,7 @@ static INLINE void set_aligned_word64_Origin_to_undef ( Addr a, UInt otag )
    { OCacheLine* line;
      UWord lineoff = oc_line_offset(a);
      if (OC_ENABLE_ASSERTIONS) {
-        tl_assert(lineoff >= 0 
+        tl_assert(lineoff >= 0
                   && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
      }
      line = find_OCacheLine( a );
@@ -2940,7 +2940,7 @@ void make_aligned_word64_undefined_w_otag ( Addr a, UInt otag )
    //// Set the origins for a+0 .. a+7
    { OCacheLine* line;
      UWord lineoff = oc_line_offset(a);
-     tl_assert(lineoff >= 0 
+     tl_assert(lineoff >= 0
                && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
      line = find_OCacheLine( a );
      line->u.main.descr[lineoff+0] = 0xF;
@@ -2978,7 +2978,7 @@ void make_aligned_word64_noaccess ( Addr a )
       if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
          OCacheLine* line;
          UWord lineoff = oc_line_offset(a);
-         tl_assert(lineoff >= 0 
+         tl_assert(lineoff >= 0
                    && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
          line = find_OCacheLine( a );
          line->u.main.descr[lineoff+0] = 0;
@@ -3777,7 +3777,7 @@ void MC_(helperc_MAKE_STACK_UNINIT_w_o) ( Addr base, UWord len, Addr nia )
    } else {
       MC_(make_mem_undefined_w_otag)(base, len, otag);
    }
-#  endif 
+#  endif
 
    /* Idea is: go fast when
          * 8-aligned and length is 128
@@ -3974,7 +3974,7 @@ void MC_(helperc_MAKE_STACK_UNINIT_no_o) ( Addr base, UWord len )
    } else {
       make_mem_undefined(base, len);
    }
-#  endif 
+#  endif
 
    /* Idea is: go fast when
          * 8-aligned and length is 128
@@ -4118,7 +4118,7 @@ void MC_(helperc_MAKE_STACK_UNINIT_128_no_o) ( Addr base )
    } else {
       make_mem_undefined(base, 128);
    }
-#  endif 
+#  endif
 
    /* Idea is: go fast when
          * 16-aligned and length is 128
@@ -4162,7 +4162,7 @@ void MC_(helperc_MAKE_STACK_UNINIT_128_no_o) ( Addr base )
          }
       }
    }
-   
+
    /* The same, but for when base is 8 % 16, which is the situation
       with RSP for amd64-ELF immediately after call instructions.
    */
@@ -4214,12 +4214,12 @@ void MC_(helperc_MAKE_STACK_UNINIT_128_no_o) ( Addr base )
 /*--- Checking memory                                      ---*/
 /*------------------------------------------------------------*/
 
-typedef 
+typedef
    enum {
-      MC_Ok = 5, 
-      MC_AddrErr = 6, 
+      MC_Ok = 5,
+      MC_AddrErr = 6,
       MC_ValueErr = 7
-   } 
+   }
    MC_ReadResult;
 
 
@@ -4249,7 +4249,7 @@ Bool MC_(check_mem_is_noaccess) ( Addr a, SizeT len, Addr* bad_addr )
    return True;
 }
 
-static Bool is_mem_addressable ( Addr a, SizeT len, 
+static Bool is_mem_addressable ( Addr a, SizeT len,
                                  /*OUT*/Addr* bad_addr )
 {
    SizeT i;
@@ -4337,8 +4337,8 @@ static void is_mem_defined_comprehensive (
       PROF_EVENT(MCPE_IS_MEM_DEFINED_COMPREHENSIVE_LOOP);
       vabits2 = get_vabits2(a);
       switch (vabits2) {
-         case VA_BITS2_DEFINED: 
-            a++; 
+         case VA_BITS2_DEFINED:
+            a++;
             break;
          case VA_BITS2_UNDEFINED:
          case VA_BITS2_PARTDEFINED:
@@ -4421,7 +4421,7 @@ void check_mem_is_addressable ( CorePart part, ThreadId tid, const HChar* s,
    if (!ok) {
       switch (part) {
       case Vg_CoreSysCall:
-         MC_(record_memparam_error) ( tid, bad_addr, 
+         MC_(record_memparam_error) ( tid, bad_addr,
                                       /*isAddrErr*/True, s, 0/*otag*/ );
          break;
 
@@ -4438,7 +4438,7 @@ void check_mem_is_addressable ( CorePart part, ThreadId tid, const HChar* s,
 static
 void check_mem_is_defined ( CorePart part, ThreadId tid, const HChar* s,
                             Addr base, SizeT size )
-{     
+{
    UInt otag = 0;
    Addr bad_addr;
    MC_ReadResult res = is_mem_defined ( base, size, &bad_addr, &otag );
@@ -4451,12 +4451,12 @@ void check_mem_is_defined ( CorePart part, ThreadId tid, const HChar* s,
          MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
                                       isAddrErr ? 0 : otag );
          break;
-      
+
       case Vg_CoreSysCallArgInMem:
          MC_(record_regparam_error) ( tid, s, otag );
          break;
 
-      /* If we're being asked to jump to a silly address, record an error 
+      /* If we're being asked to jump to a silly address, record an error
          message before potentially crashing the entire system. */
       case Vg_CoreTranslate:
          MC_(record_jump_error)( tid, bad_addr );
@@ -4571,7 +4571,7 @@ void mc_new_mem_startup( Addr a, SizeT len,
 {
    // Because code is defined, initialised variables get put in the data
    // segment and are defined, and uninitialised variables get put in the
-   // bss segment and are auto-zeroed (and so defined).  
+   // bss segment and are auto-zeroed (and so defined).
    //
    // It's possible that there will be padding between global variables.
    // This will also be auto-zeroed, and marked as defined by Memcheck.  If
@@ -4629,7 +4629,7 @@ static UInt mb_get_origin_for_guest_offset ( ThreadId tid,
    chunks of guest state, hence the _SIZE value, which has to be as
    big as the biggest guest state.
 */
-static void mc_post_reg_write ( CorePart part, ThreadId tid, 
+static void mc_post_reg_write ( CorePart part, ThreadId tid,
                                 PtrdiffT offset, SizeT size)
 {
 #  define MAX_REG_WRITE_SIZE 2264
@@ -4640,18 +4640,18 @@ static void mc_post_reg_write ( CorePart part, ThreadId tid,
 #  undef MAX_REG_WRITE_SIZE
 }
 
-static 
-void mc_post_reg_write_clientcall ( ThreadId tid, 
+static
+void mc_post_reg_write_clientcall ( ThreadId tid,
                                     PtrdiffT offset, SizeT size, Addr f)
 {
    mc_post_reg_write(/*dummy*/0, tid, offset, size);
 }
 
-/* Look at the definedness of the guest's shadow state for 
-   [offset, offset+len).  If any part of that is undefined, record 
+/* Look at the definedness of the guest's shadow state for
+   [offset, offset+len).  If any part of that is undefined, record
    a parameter error.
 */
-static void mc_pre_reg_read ( CorePart part, ThreadId tid, const HChar* s, 
+static void mc_pre_reg_read ( CorePart part, ThreadId tid, const HChar* s,
                               PtrdiffT offset, SizeT size)
 {
    Int   i;
@@ -5088,7 +5088,7 @@ void mc_STOREV64 ( Addr a, ULong vbits64, Bool isBigEndian )
          if (!is_distinguished_sm(sm) && VA_BITS16_DEFINED == vabits16) {
             sm->vabits16[sm_off16] = VA_BITS16_UNDEFINED;
             return;
-         } 
+         }
          PROF_EVENT(MCPE_STOREV64_SLOW3);
          mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
          return;
@@ -5303,7 +5303,7 @@ __asm__( /* Derived from NCode template */
 ".global vgMemCheck_helperc_LOADV16le   \n"
 ".type   vgMemCheck_helperc_LOADV16le, %function \n"
 "vgMemCheck_helperc_LOADV16le:          \n" //
-"      tst    r0, #1                    \n" // 
+"      tst    r0, #1                    \n" //
 "      bne    .LLV16LEc12               \n" // if misaligned
 "      lsr    r2, r0, #16               \n" // r2 = pri-map-ix
 "      movw   r3, #:lower16:primary_map \n" //
@@ -5445,7 +5445,7 @@ void mc_STOREV16 ( Addr a, UWord vbits16, Bool isBigEndian )
          if (LIKELY(vabits8 == VA_BITS8_DEFINED)) {
             return;
          }
-         if (!is_distinguished_sm(sm) 
+         if (!is_distinguished_sm(sm)
              && accessible_vabits4_in_vabits8(a, vabits8)) {
             insert_vabits4_into_vabits8( a, VA_BITS4_DEFINED,
                                          &(sm->vabits8[sm_off]) );
@@ -5458,7 +5458,7 @@ void mc_STOREV16 ( Addr a, UWord vbits16, Bool isBigEndian )
          if (vabits8 == VA_BITS8_UNDEFINED) {
             return;
          }
-         if (!is_distinguished_sm(sm)  
+         if (!is_distinguished_sm(sm)
              && accessible_vabits4_in_vabits8(a, vabits8)) {
             insert_vabits4_into_vabits8( a, VA_BITS4_UNDEFINED,
                                          &(sm->vabits8[sm_off]) );
@@ -5693,7 +5693,7 @@ void MC_(helperc_STOREV8) ( Addr a, UWord vbits8 )
          if (LIKELY(vabits8 == VA_BITS8_DEFINED)) {
             return; // defined on defined
          }
-         if (!is_distinguished_sm(sm) 
+         if (!is_distinguished_sm(sm)
              && VA_BITS2_NOACCESS != extract_vabits2_from_vabits8(a, vabits8)) {
             // direct mod
             insert_vabits2_into_vabits8( a, VA_BITS2_DEFINED,
@@ -5708,8 +5708,8 @@ void MC_(helperc_STOREV8) ( Addr a, UWord vbits8 )
          if (vabits8 == VA_BITS8_UNDEFINED) {
             return; // undefined on undefined
          }
-         if (!is_distinguished_sm(sm) 
-             && (VA_BITS2_NOACCESS 
+         if (!is_distinguished_sm(sm)
+             && (VA_BITS2_NOACCESS
                  != extract_vabits2_from_vabits8(a, vabits8))) {
             // direct mod
             insert_vabits2_into_vabits8( a, VA_BITS2_UNDEFINED,
@@ -5755,7 +5755,7 @@ void MC_(helperc_value_check8_fail_w_o) ( UWord origin ) {
    MC_(record_value_error) ( VG_(get_running_tid)(), 8, (UInt)origin );
 }
 
-VG_REGPARM(2) 
+VG_REGPARM(2)
 void MC_(helperc_value_checkN_fail_w_o) ( HWord sz, UWord origin ) {
    MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, (UInt)origin );
 }
@@ -5782,7 +5782,7 @@ void MC_(helperc_value_check8_fail_no_o) ( void ) {
    MC_(record_value_error) ( VG_(get_running_tid)(), 8, 0/*origin*/ );
 }
 
-VG_REGPARM(1) 
+VG_REGPARM(1)
 void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) {
    MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, 0/*origin*/ );
 }
@@ -5801,13 +5801,13 @@ void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) {
 /* Nb: We used to issue various definedness/addressability errors from here,
    but we took them out because they ranged from not-very-helpful to
    downright annoying, and they complicated the error data structures. */
-static Int mc_get_or_set_vbits_for_client ( 
-   Addr a, 
-   Addr vbits, 
-   SizeT szB, 
-   Bool setting, /* True <=> set vbits,  False <=> get vbits */ 
-   Bool is_client_request /* True <=> real user request 
-                             False <=> internal call from gdbserver */ 
+static Int mc_get_or_set_vbits_for_client (
+   Addr a,
+   Addr vbits,
+   SizeT szB,
+   Bool setting, /* True <=> set vbits,  False <=> get vbits */
+   Bool is_client_request /* True <=> real user request
+                             False <=> internal call from gdbserver */
 )
 {
    SizeT i;
@@ -5918,7 +5918,7 @@ static void init_shadow_memory ( void )
    /* Auxiliary primary maps */
    init_auxmap_L1_L2();
 
-   /* auxmap_size = auxmap_used = 0; 
+   /* auxmap_size = auxmap_used = 0;
       no ... these are statically initialised */
 
    /* Secondary V bit table */
@@ -6320,7 +6320,7 @@ static void mc_print_usage(void)
 }
 
 static void mc_print_debug_usage(void)
-{  
+{
    VG_(printf)(
 "    (none)\n"
    );
@@ -6332,13 +6332,13 @@ static void mc_print_debug_usage(void)
 /*------------------------------------------------------------*/
 
 /* Client block management:
-  
+
    This is managed as an expanding array of client block descriptors.
    Indices of live descriptors are issued to the client, so it can ask
    to free them later.  Therefore we cannot slide live entries down
    over dead ones.  Instead we must use free/inuse flags and scan for
    an empty slot at allocation time.  This in turn means allocation is
-   relatively expensive, so we hope this does not happen too often. 
+   relatively expensive, so we hope this does not happen too often.
 
    An unused block has start == size == 0
 */
@@ -6391,7 +6391,7 @@ Int alloc_client_block ( void )
    sz_new = (cgbs == NULL) ? 10 : (2 * cgb_size);
 
    cgbs_new = VG_(malloc)( "mc.acb.1", sz_new * sizeof(CGenBlock) );
-   for (i = 0; i < cgb_used; i++) 
+   for (i = 0; i < cgb_used; i++)
       cgbs_new[i] = cgbs[i];
 
    if (cgbs != NULL)
@@ -6408,14 +6408,14 @@ Int alloc_client_block ( void )
 
 static void show_client_block_stats ( void )
 {
-   VG_(message)(Vg_DebugMsg, 
+   VG_(message)(Vg_DebugMsg,
       "general CBs: %llu allocs, %llu discards, %llu maxinuse, %llu search\n",
-      cgb_allocs, cgb_discards, cgb_used_MAX, cgb_search 
+      cgb_allocs, cgb_discards, cgb_used_MAX, cgb_search
    );
 }
 static void print_monitor_help ( void )
 {
-   VG_(gdb_printf) 
+   VG_(gdb_printf)
       (
 "\n"
 "memcheck monitor commands:\n"
@@ -6436,7 +6436,7 @@ static void print_monitor_help ( void )
 "  leak_check [full*|summary|xtleak]\n"
 "                [kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]\n"
 "                [heuristics heur1,heur2,...]\n"
-"                [increased*|changed|any]\n"
+"                [new|increased*|changed|any]\n"
 "                [unlimited*|limited <max_loss_records_output>]\n"
 "            * = defaults\n"
 "         xtleak produces an xtree full leak result in xtleak.kcg.%%p.%%n\n"
@@ -6574,9 +6574,9 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
    /* NB: if possible, avoid introducing a new command below which
       starts with the same first letter(s) as an already existing
       command. This ensures a shorter abbreviation for the user. */
-   switch (VG_(keyword_id) 
+   switch (VG_(keyword_id)
            ("help get_vbits leak_check make_memory check_memory "
-            "block_list who_points_at xb xtmemory", 
+            "block_list who_points_at xb xtmemory",
             wcmd, kwd_report_duplicated_matches)) {
    case -2: /* multiple matches */
       return True;
@@ -6593,10 +6593,10 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
          Int i;
          Int unaddressable = 0;
          for (i = 0; i < szB; i++) {
-            Int res = mc_get_or_set_vbits_for_client 
-               (address+i, (Addr) &vbits, 1, 
+            Int res = mc_get_or_set_vbits_for_client
+               (address+i, (Addr) &vbits, 1,
                 False, /* get them */
-                False  /* is client request */ ); 
+                False  /* is client request */ );
             /* we are before the first character on next line, print a \n. */
             if ((i % 32) == 0 && i != 0)
                VG_(printf) ("\n");
@@ -6625,7 +6625,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
       LeakCheckParams lcp;
       HChar* xt_filename = NULL;
       HChar* kw;
-      
+
       lcp.mode               = LC_Full;
       lcp.show_leak_kinds    = R2S(Possible) | R2S(Unreached);
       lcp.errors_for_leak_kinds = 0; // no errors for interactive leak search.
@@ -6634,15 +6634,15 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
       lcp.max_loss_records_output = 999999999;
       lcp.requested_by_monitor_command = True;
       lcp.xt_filename = NULL;
-      
-      for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr); 
-           kw != NULL; 
+
+      for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr);
+           kw != NULL;
            kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
-         switch (VG_(keyword_id) 
+         switch (VG_(keyword_id)
                  ("full summary xtleak "
                   "kinds reachable possibleleak definiteleak "
                   "heuristics "
-                  "increased changed any "
+                  "new increased changed any "
                   "unlimited limited ",
                   kw, kwd_report_all)) {
          case -2: err++; break;
@@ -6653,14 +6653,14 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
             lcp.mode = LC_Summary; break;
          case  2: /* xtleak */
             lcp.mode = LC_Full;
-            xt_filename 
+            xt_filename
                = VG_(expand_file_name)("--xtleak-mc_main.c",
                                        "xtleak.kcg.%p.%n");
             lcp.xt_filename = xt_filename;
             break;
          case  3: { /* kinds */
             wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
-            if (wcmd == NULL 
+            if (wcmd == NULL
                 || !VG_(parse_enum_set)(MC_(parse_leak_kinds_tokens),
                                         True/*allow_all*/,
                                         wcmd,
@@ -6674,7 +6674,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
             lcp.show_leak_kinds = MC_(all_Reachedness)();
             break;
          case  5: /* possibleleak */
-            lcp.show_leak_kinds 
+            lcp.show_leak_kinds
                = R2S(Possible) | R2S(IndirectLeak) | R2S(Unreached);
             break;
          case  6: /* definiteleak */
@@ -6682,7 +6682,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
             break;
          case  7: { /* heuristics */
             wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
-            if (wcmd == NULL 
+            if (wcmd == NULL
                 || !VG_(parse_enum_set)(MC_(parse_leak_heuristics_tokens),
                                         True,/*allow_all*/
                                         wcmd,
@@ -6692,15 +6692,17 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
             }
             break;
          }
-         case  8: /* increased */
+         case  8: /* new */
+            lcp.deltamode = LCD_New; break;
+         case  9: /* increased */
             lcp.deltamode = LCD_Increased; break;
-         case  9: /* changed */
+         case 10: /* changed */
             lcp.deltamode = LCD_Changed; break;
-         case 10: /* any */
+         case 11: /* any */
             lcp.deltamode = LCD_Any; break;
-         case 11: /* unlimited */
+         case 12: /* unlimited */
             lcp.max_loss_records_output = 999999999; break;
-         case 12: { /* limited */
+         case 13: { /* limited */
             Int int_value;
             const HChar* endptr;
 
@@ -6732,11 +6734,11 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
          VG_(free)(xt_filename);
       return True;
    }
-      
+
    case  3: { /* make_memory */
       Addr address;
       SizeT szB = 1;
-      Int kwdid = VG_(keyword_id) 
+      Int kwdid = VG_(keyword_id)
          ("noaccess undefined defined Definedifaddressable",
           VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
       if (!VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr))
@@ -6745,7 +6747,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
       case -2: break;
       case -1: break;
       case  0: MC_(make_mem_noaccess) (address, szB); break;
-      case  1: make_mem_undefined_w_tid_and_okind ( address, szB, tid, 
+      case  1: make_mem_undefined_w_tid_and_okind ( address, szB, tid,
                                                     MC_OKIND_USER ); break;
       case  2: MC_(make_mem_defined) ( address, szB ); break;
       case  3: make_mem_defined_if_addressable ( address, szB ); break;;
@@ -6765,7 +6767,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
       ExeContext* origin_ec;
       MC_ReadResult res;
 
-      Int kwdid = VG_(keyword_id) 
+      Int kwdid = VG_(keyword_id)
          ("addressable defined",
           VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
       if (!VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr))
@@ -6775,7 +6777,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
       case -1: break;
       case  0: /* addressable */
          if (is_mem_addressable ( address, szB, &bad_addr ))
-            VG_(printf) ("Address %p len %lu addressable\n", 
+            VG_(printf) ("Address %p len %lu addressable\n",
                              (void *)address, szB);
          else
             VG_(printf)
@@ -6793,17 +6795,17 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
          else if (MC_ValueErr == res) {
             okind = otag & 3;
             switch (okind) {
-            case MC_OKIND_STACK:   
+            case MC_OKIND_STACK:
                src = " was created by a stack allocation"; break;
-            case MC_OKIND_HEAP:    
+            case MC_OKIND_HEAP:
                src = " was created by a heap allocation"; break;
-            case MC_OKIND_USER:    
+            case MC_OKIND_USER:
                src = " was created by a client request"; break;
-            case MC_OKIND_UNKNOWN: 
+            case MC_OKIND_UNKNOWN:
                src = ""; break;
             default: tl_assert(0);
             }
-            VG_(printf) 
+            VG_(printf)
                ("Address %p len %lu not defined:\n"
                 "Uninitialised value at %p%s\n",
                 (void *)address, szB, (void *) bad_addr, src);
@@ -6834,11 +6836,11 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
          UInt limit_blocks = 999999999;
          Int int_value;
          UInt heuristics = 0;
-         
+
          for (wl = VG_(strtok_r) (NULL, " ", &ssaveptr);
               wl != NULL;
               wl = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
-            switch (VG_(keyword_id) ("unlimited limited heuristics ", 
+            switch (VG_(keyword_id) ("unlimited limited heuristics ",
                                      wl,  kwd_report_all)) {
             case -2: return True;
             case -1: return True;
@@ -6864,7 +6866,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
                break;
             case  2: /* heuristics */
                wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
-               if (wcmd == NULL 
+               if (wcmd == NULL
                    || !VG_(parse_enum_set)(MC_(parse_leak_heuristics_tokens),
                                            True,/*allow_all*/
                                            wcmd,
@@ -6955,7 +6957,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
       return True;
    }
 
-   default: 
+   default:
       tl_assert(0);
       return False;
    }
@@ -7002,7 +7004,7 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
          UInt otagV     = 0;
          Bool errorA    = False;
          Addr bad_addrA = 0;
-         is_mem_defined_comprehensive( 
+         is_mem_defined_comprehensive(
             arg[1], arg[2],
             &errorV, &bad_addrV, &otagV, &errorA, &bad_addrA
          );
@@ -7030,17 +7032,17 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
 
       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, 
+            VG_(message)(Vg_UserMsg,
                          "Warning: unknown memcheck leak search mode\n");
             lcp.mode = LC_Full;
          }
-          
+
          lcp.show_leak_kinds = MC_(clo_show_leak_kinds);
          lcp.errors_for_leak_kinds = MC_(clo_error_for_leak_kinds);
          lcp.heuristics = MC_(clo_leak_check_heuristics);
@@ -7051,16 +7053,18 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
             lcp.deltamode = LCD_Increased;
          else if (arg[2] == 2)
             lcp.deltamode = LCD_Changed;
+         else if (arg[2] == 3)
+            lcp.deltamode = LCD_New;
          else {
             VG_(message)
-               (Vg_UserMsg, 
+               (Vg_UserMsg,
                 "Warning: unknown memcheck leak search deltamode\n");
             lcp.deltamode = LCD_Any;
          }
          lcp.max_loss_records_output = 999999999;
          lcp.requested_by_monitor_command = False;
          lcp.xt_filename = NULL;
-         
+
          MC_(detect_memory_leaks)(tid, &lcp);
          *ret = 0; /* return value is meaningless */
          break;
@@ -7072,7 +7076,7 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
          break;
 
       case VG_USERREQ__MAKE_MEM_UNDEFINED:
-         make_mem_undefined_w_tid_and_okind ( arg[1], arg[2], tid, 
+         make_mem_undefined_w_tid_and_okind ( arg[1], arg[2], tid,
                                               MC_OKIND_USER );
          *ret = -1;
          break;
@@ -7101,7 +7105,7 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
          break;
 
       case VG_USERREQ__DISCARD: /* discard */
-         if (cgbs == NULL 
+         if (cgbs == NULL
              || arg[2] >= cgb_used ||
              (cgbs[arg[2]].start == 0 && cgbs[arg[2]].size == 0)) {
             *ret = 1;
@@ -7117,7 +7121,7 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
       case VG_USERREQ__GET_VBITS:
          *ret = mc_get_or_set_vbits_for_client
                    ( arg[1], arg[2], arg[3],
-                     False /* get them */, 
+                     False /* get them */,
                      True /* is client request */ );
          break;
 
@@ -7164,7 +7168,7 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
          UInt rzB       =       arg[3];
          Bool is_zeroed = (Bool)arg[4];
 
-         MC_(new_block) ( tid, p, sizeB, /*ignored*/0, is_zeroed, 
+         MC_(new_block) ( tid, p, sizeB, /*ignored*/0, is_zeroed,
                           MC_AllocCustom, MC_(malloc_list) );
          if (rzB > 0) {
             MC_(make_mem_noaccess) ( p - rzB, rzB);
@@ -7206,7 +7210,7 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
 
          // The create_mempool function does not know these mempool flags,
          // pass as booleans.
-         MC_(create_mempool) ( pool, rzB, is_zeroed, 
+         MC_(create_mempool) ( pool, rzB, is_zeroed,
                                (flags & VALGRIND_MEMPOOL_AUTO_FREE),
                                (flags & VALGRIND_MEMPOOL_METAPOOL) );
          return True;
@@ -7291,7 +7295,7 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
 
       default:
          VG_(message)(
-            Vg_UserMsg, 
+            Vg_UserMsg,
             "Warning: unknown memcheck client request code %llx\n",
             (ULong)arg[0]
          );
@@ -7320,10 +7324,10 @@ static const HChar* MC_(event_ctr_name)[MCPE_LAST] = {
    [MCPE_STOREVN_SLOW] = "STOREVn_slow",
    [MCPE_STOREVN_SLOW_LOOP] = "STOREVn_slow(loop)",
    [MCPE_MAKE_ALIGNED_WORD32_UNDEFINED] = "make_aligned_word32_undefined",
-   [MCPE_MAKE_ALIGNED_WORD32_UNDEFINED_SLOW] = 
+   [MCPE_MAKE_ALIGNED_WORD32_UNDEFINED_SLOW] =
         "make_aligned_word32_undefined_slow",
    [MCPE_MAKE_ALIGNED_WORD64_UNDEFINED] = "make_aligned_word64_undefined",
-   [MCPE_MAKE_ALIGNED_WORD64_UNDEFINED_SLOW] = 
+   [MCPE_MAKE_ALIGNED_WORD64_UNDEFINED_SLOW] =
         "make_aligned_word64_undefined_slow",
    [MCPE_MAKE_ALIGNED_WORD32_NOACCESS] = "make_aligned_word32_noaccess",
    [MCPE_MAKE_ALIGNED_WORD32_NOACCESS_SLOW] =
@@ -7469,7 +7473,7 @@ static void done_prof_mem ( void )
       if (MC_(event_ctr)[i] > 0) {
          spaced = False;
          ++n;
-         VG_(printf)( "prof mem event %3d: %11llu   %s\n", 
+         VG_(printf)( "prof mem event %3d: %11llu   %s\n",
                       i, MC_(event_ctr)[i],
                       MC_(event_ctr_name)[i]);
       }
@@ -8054,7 +8058,7 @@ static void mc_post_clo_init ( void )
    //   uninitialized, but in practice will retain previous contents [zero in
    //   this case.]"
    //
-   // In short: 
+   // In short:
    //
    //   A key property of sbrk/brk is that new whole pages that are supplied
    //   by the operating system *do* get initialized to zero.
@@ -8123,7 +8127,7 @@ static void mc_post_clo_init ( void )
       // Activate full xtree memory profiling.
       VG_(XTMemory_Full_init)(VG_(XT_filter_1top_and_maybe_below_main));
    }
-   
+
 }
 
 static void print_SM_info(const HChar* type, Int n_SMs)
@@ -8147,19 +8151,19 @@ static void mc_print_stats (void)
       n_sanity_cheap, n_sanity_expensive );
    VG_(message)(Vg_DebugMsg,
       " memcheck: auxmaps: %llu auxmap entries (%lluk, %lluM) in use\n",
-      n_auxmap_L2_nodes, 
-      n_auxmap_L2_nodes * 64, 
+      n_auxmap_L2_nodes,
+      n_auxmap_L2_nodes * 64,
       n_auxmap_L2_nodes / 16 );
    VG_(message)(Vg_DebugMsg,
       " memcheck: auxmaps_L1: %llu searches, %llu cmps, ratio %llu:10\n",
       n_auxmap_L1_searches, n_auxmap_L1_cmps,
-      (10ULL * n_auxmap_L1_cmps) 
-         / (n_auxmap_L1_searches ? n_auxmap_L1_searches : 1) 
-   );   
+      (10ULL * n_auxmap_L1_cmps)
+         / (n_auxmap_L1_searches ? n_auxmap_L1_searches : 1)
+   );
    VG_(message)(Vg_DebugMsg,
       " memcheck: auxmaps_L2: %llu searches, %llu nodes\n",
       n_auxmap_L2_searches, n_auxmap_L2_nodes
-   );   
+   );
 
    print_SM_info("n_issued     ", n_issued_SMs);
    print_SM_info("n_deissued   ", n_deissued_SMs);
@@ -8176,7 +8180,7 @@ static void mc_print_stats (void)
    // Note that the pool allocator has some additional small overhead
    // which is not counted in the below.
    // Hardwiring this logic sucks, but I don't see how else to do it.
-   max_secVBit_szB = max_secVBit_nodes * 
+   max_secVBit_szB = max_secVBit_nodes *
          (3*sizeof(Word) + VG_ROUNDUP(sizeof(SecVBitNode), sizeof(void*)));
    max_shmem_szB   = sizeof(primary_map) + max_SMs_szB + max_secVBit_szB;
 
@@ -8195,13 +8199,13 @@ static void mc_print_stats (void)
    if (MC_(clo_mc_level) >= 3) {
       VG_(message)(Vg_DebugMsg,
                    " ocacheL1: %'14lu refs   %'14lu misses (%'lu lossage)\n",
-                   stats_ocacheL1_find, 
+                   stats_ocacheL1_find,
                    stats_ocacheL1_misses,
                    stats_ocacheL1_lossage );
       VG_(message)(Vg_DebugMsg,
                    " ocacheL1: %'14lu at 0   %'14lu at 1\n",
-                   stats_ocacheL1_find - stats_ocacheL1_misses 
-                      - stats_ocacheL1_found_at_1 
+                   stats_ocacheL1_find - stats_ocacheL1_misses
+                      - stats_ocacheL1_found_at_1
                       - stats_ocacheL1_found_at_N,
                    stats_ocacheL1_found_at_1 );
       VG_(message)(Vg_DebugMsg,
@@ -8320,7 +8324,7 @@ static void mc_fini ( Int exitcode )
       mc_print_stats();
 
    if (0) {
-      VG_(message)(Vg_DebugMsg, 
+      VG_(message)(Vg_DebugMsg,
         "------ Valgrind's client block stats follow ---------------\n" );
       show_client_block_stats();
    }
@@ -8395,7 +8399,7 @@ static void mc_pre_clo_init(void)
                                    MC_(__builtin_vec_delete),
                                    MC_(__builtin_vec_delete_aligned),
                                    MC_(realloc),
-                                   MC_(malloc_usable_size), 
+                                   MC_(malloc_usable_size),
                                    MC_MALLOC_DEFAULT_REDZONE_SZB );
    MC_(Malloc_Redzone_SzB) = VG_(malloc_effective_client_redzone_size)();
 
@@ -8408,12 +8412,12 @@ static void mc_pre_clo_init(void)
    // mc_new_mem_mmap.
    VG_(track_new_mem_mmap)        ( mc_new_mem_mmap );
    VG_(track_change_mem_mprotect) ( mc_new_mem_mprotect );
-   
+
    VG_(track_copy_mem_remap)      ( MC_(copy_address_range_state) );
 
-   VG_(track_die_mem_stack_signal)( MC_(make_mem_noaccess) ); 
+   VG_(track_die_mem_stack_signal)( MC_(make_mem_noaccess) );
    VG_(track_die_mem_brk)         ( MC_(make_mem_noaccess) );
-   VG_(track_die_mem_munmap)      ( MC_(make_mem_noaccess) ); 
+   VG_(track_die_mem_munmap)      ( MC_(make_mem_noaccess) );
 
    /* Defer the specification of the new_mem_stack functions to the
       post_clo_init function, since we need to first parse the command
@@ -8431,7 +8435,7 @@ static void mc_pre_clo_init(void)
    VG_(track_die_mem_stack_160)   ( mc_die_mem_stack_160 );
 #  endif
    VG_(track_die_mem_stack)       ( mc_die_mem_stack     );
-   
+
    VG_(track_ban_mem_stack)       ( MC_(make_mem_noaccess) );
 
    VG_(track_pre_mem_read)        ( check_mem_is_defined );
index 8450f0ba969f6ad59a13bbaaad5e9a887bc81ede..53700542c6238d689172b0c6d204f44a205b0c66 100644 (file)
@@ -204,6 +204,13 @@ typedef
     VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK,  \
                                     0, 2, 0, 0, 0)
 
+/* Same as VALGRIND_DO_LEAK_CHECK but only showing new entries
+   i.e. loss records that were not there in the previous leak
+   search. */
+#define VALGRIND_DO_NEW_LEAK_CHECK                              \
+    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK,  \
+                                    0, 3, 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_STMT(VG_USERREQ__DO_LEAK_CHECK,   \
index a410fa89e725d134536768c4ca710f9be581bd11..b0dc31d1b168ee8d78526c02203c17fcfa9cce13 100755 (executable)
@@ -22,7 +22,7 @@ $SED "s/checked [0-9,]* bytes./checked ... bytes./" |
 # More leak check filtering.  For systems that do extra libc allocations
 # (eg. Darwin) there may be extra (reachable, and thus not shown) loss
 # records.  So we filter out the loss record numbers.
-perl -p -e "s/in loss record \d+ of \d+/in loss record ... of .../" |
+perl -p -e "s/in (?:new )?loss record \d+ of \d+/in loss record ... of .../" |
 
 # Filter out glibc debuginfo if installed.
 perl -p -e "s/\(syscall-template.S:[0-9]*\)/(in \/...libc...)/" |
index b95a8feba04bf772684d4e719175c866e70530d7..a20f7d4c5cd979dabad86b240828800df98c79ac 100644 (file)
@@ -6,6 +6,7 @@
 char *b10;
 char *b21;
 char *b32_33[2];
+char *b42_43[2];
 static void breakme() {};
 void f(void)
 {
@@ -47,7 +48,18 @@ void f(void)
    b32_33[0]--;
    fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
    VALGRIND_DO_CHANGED_LEAK_CHECK;
-   
+
+   for (i = 0; i < 2; i ++)
+      b42_43[i] = malloc (42+i);
+
+   b42_43[0]--;
+   fprintf(stderr, "expecting details 42 (+42) bytes lost, 43 (+43) bytes reachable\n"); fflush(stderr); breakme();
+   VALGRIND_DO_NEW_LEAK_CHECK;
+
+   b42_43[1]--;
+   fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+   VALGRIND_DO_NEW_LEAK_CHECK;
+
    fprintf(stderr, "finished\n");
 }
 
index ad8eebc1a7d7eacfa94b40dfa871ec9e11ffe7b9..a25bdac841bf7784432aaa6311c6e60f0710b84a 100644 (file)
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:24)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
 
+expecting details 42 (+42) bytes lost, 43 (+43) bytes reachable
+42 (+42) 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:53)
+   by 0x........: main (leak-delta.c:72)
+
+43 (+43) 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:53)
+   by 0x........: main (leak-delta.c:72)
+
+expecting to have NO details
 finished
-leaked:      32 bytes in  1 blocks
+leaked:     117 bytes in  3 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)
+   by 0x........: f (leak-delta.c:15)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:24)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
 
 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)
+   by 0x........: f (leak-delta.c:29)
+   by 0x........: main (leak-delta.c:72)
+
+85 bytes in 2 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:53)
+   by 0x........: main (leak-delta.c:72)