Merge revisions 14230, 14602, and 14604 from the BUF_REMOVAL branch to trunk.
The change eliminates the fixed size buffers in gen_suppression and
show_used_suppressions. This is achieved by changing the return type from
VG_TDICT_CALL(tool_get_extra_suppression_info and
VG_TDICT_CALL(tool_print_extra_suppression_use from Bool to SizeT.
A return value of 0 indicates that nothing (except the terminating '\0'
which is always inserted) was written to the buffer. This corresponds to the
previous False return value. A return value which is equal to the buffer
size (that was passed in as function argument) indicates that the buffer was
not large enough. The caller then resizes the buffer and retries.
Otherwise, the buffer was large enough.
Regtested with a resize value of 1.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14606 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_errormgr.c b/coregrind/m_errormgr.c
index 0de1529..f2766e9 100644
--- a/coregrind/m_errormgr.c
+++ b/coregrind/m_errormgr.c
@@ -362,8 +362,6 @@
 */
 static void gen_suppression(Error* err)
 {
-   HChar       xtra[256]; /* assumed big enough (is overrun-safe) */
-   Bool        anyXtra;
    const HChar* name;
    ExeContext* ec;
    XArray* /* HChar */ text;
@@ -394,12 +392,21 @@
    VG_(xaprintf)(text, "   <%s>\n", dummy_name);
    VG_(xaprintf)(text, "   %s:%s\n", VG_(details).name, name);
 
-   VG_(memset)(xtra, 0, sizeof(xtra));
-   anyXtra = VG_TDICT_CALL(tool_get_extra_suppression_info,
-                           err, xtra, sizeof(xtra));
-   vg_assert(xtra[sizeof(xtra)-1] == 0);
+   HChar       *xtra = NULL;
+   SizeT       xtra_size = 0;
+   SizeT       num_written;
 
-   if (anyXtra)
+   do {
+      xtra_size += 256;
+      xtra = VG_(realloc)("errormgr.gen_suppression.2", xtra,xtra_size);
+      num_written = VG_TDICT_CALL(tool_get_extra_suppression_info,
+                                  err, xtra, xtra_size);
+   } while (num_written == xtra_size);  // resize buffer and retry
+
+   // Ensure buffer is properly terminated
+   vg_assert(xtra[num_written] == '\0');
+
+   if (num_written)
       VG_(xaprintf)(text, "   %s\n", xtra);
 
    // Print stack trace elements
@@ -432,7 +439,7 @@
       VG_(printf_xml)("    <sname>%s</sname>\n", dummy_name);
       VG_(printf_xml)(
                       "    <skind>%pS:%pS</skind>\n", VG_(details).name, name);
-      if (anyXtra)
+      if (num_written)
          VG_(printf_xml)("    <skaux>%pS</skaux>\n", xtra);
 
       // Print stack trace elements
@@ -454,6 +461,7 @@
    }
 
    VG_(deleteXA)(text);
+   VG_(free)(xtra);
 }
 
 
@@ -932,19 +940,28 @@
                                  "  </pair>\n",
                                  su->count, su->sname );
       } else {
-         HChar       xtra[256]; /* assumed big enough (is overrun-safe) */
-         Bool        anyXtra;
+         HChar      *xtra = NULL;
+         Int         xtra_size = 0;
+         SizeT       num_written;
          // blank line before the first shown suppression, if any
          if (!any_supp)
             VG_(dmsg)("\n");
-         VG_(memset)(xtra, 0, sizeof(xtra));
-         anyXtra = VG_TDICT_CALL(tool_print_extra_suppression_use,
-                                 su, xtra, sizeof(xtra));
-         vg_assert(xtra[sizeof(xtra)-1] == 0);
+
+         do {
+            xtra_size += 256;
+            xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size);
+            num_written = VG_TDICT_CALL(tool_print_extra_suppression_use,
+                                        su, xtra, xtra_size);
+         } while (num_written == xtra_size); // resize buffer and retry
+
+         // Ensure buffer is properly terminated
+         vg_assert(xtra[num_written] == '\0');
+
          VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
                    VG_(clo_suppressions)[su->clo_suppressions_i],
                    su->sname_lineno,
-                   anyXtra ? " " : "", xtra);
+                   num_written ? " " : "", xtra);
+         VG_(free)(xtra);
       }
       any_supp = True;
    }
diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c
index e367767..cdeabb2 100644
--- a/coregrind/m_libcprint.c
+++ b/coregrind/m_libcprint.c
@@ -227,6 +227,17 @@
 
 /* --------- snprintf --------- */
 
+/* The return value of VG_(snprintf) and VG_(vsnprintf) differs from
+   what is defined in C99. Let S be the size of the buffer as given in
+   the 2nd argument.
+   Return value R:
+     R < S:  The output string was successfully written to the buffer.
+             It is null-terminated and R == strlen( output string )
+     R == S: The supplied buffer was too small to hold the output string.
+             The first S-1 characters of the output string were written
+             to the buffer followed by the terminating null character.
+*/
+
 typedef 
    struct {
       HChar* buf;
diff --git a/coregrind/m_tooliface.c b/coregrind/m_tooliface.c
index 4b1c96e..e96a9a1 100644
--- a/coregrind/m_tooliface.c
+++ b/coregrind/m_tooliface.c
@@ -236,8 +236,8 @@
    Bool (*read_extra) (Int, HChar**, SizeT*, Int*, Supp*),
    Bool (*matches)    (Error*, Supp*),
    const HChar* (*name) (Error*),
-   Bool (*get_xtra_si)(Error*,/*OUT*/HChar*,Int),
-   Bool (*print_xtra_su)(Supp*,/*OUT*/HChar*,Int),
+   SizeT (*get_xtra_si)(Error*,/*OUT*/HChar*,Int),
+   SizeT (*print_xtra_su)(Supp*,/*OUT*/HChar*,Int),
    void (*update_xtra_su)(Error*, Supp*)
 )
 {
diff --git a/coregrind/pub_core_tooliface.h b/coregrind/pub_core_tooliface.h
index 65311d8..585170b 100644
--- a/coregrind/pub_core_tooliface.h
+++ b/coregrind/pub_core_tooliface.h
@@ -128,8 +128,8 @@
                                               Supp*);
    Bool  (*tool_error_matches_suppression)   (Error*, Supp*);
    const HChar* (*tool_get_error_name)       (Error*);
-   Bool  (*tool_get_extra_suppression_info)  (Error*,/*OUT*/HChar*,Int);
-   Bool  (*tool_print_extra_suppression_use) (Supp*,/*OUT*/HChar*,Int);
+   SizeT (*tool_get_extra_suppression_info)  (Error*,/*OUT*/HChar*,Int);
+   SizeT (*tool_print_extra_suppression_use) (Supp*,/*OUT*/HChar*,Int);
    void  (*tool_update_extra_suppression_use) (Error*, Supp*);
 
    // VG_(needs).superblock_discards
diff --git a/drd/drd_error.c b/drd/drd_error.c
index 7e6b5e1..1d8f0e3 100644
--- a/drd/drd_error.c
+++ b/drd/drd_error.c
@@ -600,17 +600,21 @@
  * define any 'extra' suppression information.
  */
 static
-Bool drd_get_extra_suppression_info(Error* e,
-                                    /*OUT*/HChar* buf, Int nBuf)
+SizeT drd_get_extra_suppression_info(Error* e,
+                                     /*OUT*/HChar* buf, Int nBuf)
 {
-   return False;
+   tl_assert(nBuf >= 1);
+   buf[0] = '\0';
+   return 0;
 }
 
 static
-Bool drd_print_extra_suppression_use(Supp* su,
-                                     /*OUT*/HChar* buf, Int nBuf)
+SizeT drd_print_extra_suppression_use(Supp* su,
+                                      /*OUT*/HChar* buf, Int nBuf)
 {
-   return False;
+   tl_assert(nBuf >= 1);
+   buf[0] = '\0';
+   return 0;
 }
 
 static
diff --git a/exp-sgcheck/pc_common.c b/exp-sgcheck/pc_common.c
index 741d54a..27dd2f2 100644
--- a/exp-sgcheck/pc_common.c
+++ b/exp-sgcheck/pc_common.c
@@ -777,26 +777,29 @@
    }
 }
 
-Bool pc_get_extra_suppression_info ( Error* err,
-                                     /*OUT*/HChar* buf, Int nBuf )
+SizeT pc_get_extra_suppression_info ( Error* err,
+                                      /*OUT*/HChar* buf, Int nBuf )
 {
    ErrorKind ekind = VG_(get_error_kind )(err);
    tl_assert(buf);
-   tl_assert(nBuf >= 16); // stay sane
+   tl_assert(nBuf >= 1);
+
    if (XE_SysParam == ekind) {
       const HChar* errstr = VG_(get_error_string)(err);
       tl_assert(errstr);
-      VG_(snprintf)(buf, nBuf-1, "%s", errstr);
-      return True;
+      return VG_(snprintf)(buf, nBuf, "%s", errstr);
    } else {
-      return False;
+      buf[0] = '\0';
+      return 0;
    }
 }
 
-Bool pc_print_extra_suppression_use ( Supp* su,
-                                      /*OUT*/HChar* buf, Int nBuf )
+SizeT pc_print_extra_suppression_use ( Supp* su,
+                                       /*OUT*/HChar* buf, Int nBuf )
 {
-   return False;
+   tl_assert(nBuf >= 1);
+   buf[0] = '\0';
+   return 0;
 }
 
 void pc_update_extra_suppression_use (Error* err, Supp* su)
diff --git a/exp-sgcheck/pc_common.h b/exp-sgcheck/pc_common.h
index f783d4b..f0d3a86 100644
--- a/exp-sgcheck/pc_common.h
+++ b/exp-sgcheck/pc_common.h
@@ -56,9 +56,9 @@
                                       SizeT* nBufp, Int* lineno, Supp* su );
 Bool pc_error_matches_suppression (Error* err, Supp* su);
 const HChar* pc_get_error_name ( Error* err );
-Bool pc_get_extra_suppression_info ( Error* err,
+SizeT pc_get_extra_suppression_info ( Error* err,
                                      /*OUT*/HChar* buf, Int nBuf );
-Bool pc_print_extra_suppression_use ( Supp* su,
+SizeT pc_print_extra_suppression_use ( Supp* su,
                                       /*OUT*/HChar* buf, Int nBuf );
 void pc_update_extra_suppression_use (Error* err, Supp* su);
 
diff --git a/helgrind/hg_errors.c b/helgrind/hg_errors.c
index 93ea58d..fc33bed 100644
--- a/helgrind/hg_errors.c
+++ b/helgrind/hg_errors.c
@@ -1308,18 +1308,22 @@
    }
 }
 
-Bool HG_(get_extra_suppression_info) ( Error* err,
+SizeT HG_(get_extra_suppression_info) ( Error* err,
                                        /*OUT*/HChar* buf, Int nBuf )
 {
+   tl_assert(nBuf >= 1);
    /* Do nothing */
-   return False;
+   buf[0] = '\0';
+   return 0;
 }
 
-Bool HG_(print_extra_suppression_use) ( Supp* su,
+SizeT HG_(print_extra_suppression_use) ( Supp* su,
                                         /*OUT*/HChar* buf, Int nBuf )
 {
+   tl_assert(nBuf >= 1);
    /* Do nothing */
-   return False;
+   buf[0] = '\0';
+   return 0;
 }
 
 void HG_(update_extra_suppression_use) ( Error* err, Supp* su )
diff --git a/helgrind/hg_errors.h b/helgrind/hg_errors.h
index 03a6086..76f2145 100644
--- a/helgrind/hg_errors.h
+++ b/helgrind/hg_errors.h
@@ -44,9 +44,9 @@
                                          Int* lineno, Supp* su );
 Bool  HG_(error_matches_suppression) ( Error* err, Supp* su );
 const HChar* HG_(get_error_name) ( Error* err );
-Bool  HG_(get_extra_suppression_info) ( Error* err,
+SizeT HG_(get_extra_suppression_info) ( Error* err,
                                         /*OUT*/HChar* buf, Int nBuf );
-Bool  HG_(print_extra_suppression_use) ( Supp* su,
+SizeT HG_(print_extra_suppression_use) ( Supp* su,
                                          /*OUT*/HChar* buf, Int nBuf );
 void  HG_(update_extra_suppression_use) ( Error* err, Supp* su );
 
diff --git a/include/pub_tool_tooliface.h b/include/pub_tool_tooliface.h
index 4349c1b..ad503b0 100644
--- a/include/pub_tool_tooliface.h
+++ b/include/pub_tool_tooliface.h
@@ -335,21 +335,19 @@
 
    // This should print into buf[0..nBuf-1] any extra info for the
    // error, for --gen-suppressions, but not including any leading
-   // spaces nor a trailing newline.  When called, buf[0 .. nBuf-1]
-   // will be zero filled, and it is expected and checked that the
-   // last element is still zero after the call.  In other words the
-   // tool may not overrun the buffer, and this is checked for.  If
-   // there is any info printed in the buffer, return True, otherwise
-   // do nothing, and return False.  This function is the inverse of
-   // VG_(tdict).tool_read_extra_suppression_info().
-   Bool (*print_extra_suppression_info)(Error* err,
-                                        /*OUT*/HChar* buf, Int nBuf),
+   // spaces nor a trailing newline.  The string needs to be null 
+   // terminated. If the buffer is large enough to hold the string
+   // including the terminating null character the function shall
+   // return the value that strlen would return for the string.
+   // If the buffer is too small the function shall return nBuf.
+   SizeT (*print_extra_suppression_info)(Error* err,
+                                         /*OUT*/HChar* buf, Int nBuf),
 
    // This is similar to print_extra_suppression_info, but is used
    // to print information such as additional statistical counters
    // as part of the used suppression list produced by -v.
-   Bool (*print_extra_suppression_use)(Supp* su,
-                                       /*OUT*/HChar* buf, Int nBuf),
+   SizeT (*print_extra_suppression_use)(Supp* su,
+                                        /*OUT*/HChar* buf, Int nBuf),
 
    // Called by error mgr once it has been established that err
    // is suppressed by su. update_extra_suppression_use typically
diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c
index 2efa2b6..1f031c6 100644
--- a/memcheck/mc_errors.c
+++ b/memcheck/mc_errors.c
@@ -1511,51 +1511,51 @@
    }
 }
 
-Bool MC_(get_extra_suppression_info) ( Error* err,
-                                       /*OUT*/HChar* buf, Int nBuf )
+SizeT MC_(get_extra_suppression_info) ( Error* err,
+                                        /*OUT*/HChar* buf, Int nBuf )
 {
    ErrorKind ekind = VG_(get_error_kind )(err);
    tl_assert(buf);
-   tl_assert(nBuf >= 16); // stay sane
+   tl_assert(nBuf >= 1);
+
    if (Err_RegParam == ekind || Err_MemParam == ekind) {
       const HChar* errstr = VG_(get_error_string)(err);
       tl_assert(errstr);
-      VG_(snprintf)(buf, nBuf-1, "%s", errstr);
-      return True;
+      return VG_(snprintf)(buf, nBuf, "%s", errstr);
    } else if (Err_Leak == ekind) {
       MC_Error* extra = VG_(get_error_extra)(err);
-      VG_(snprintf)
-         (buf, nBuf-1, "match-leak-kinds: %s",
+      return VG_(snprintf) (buf, nBuf, "match-leak-kinds: %s",
           pp_Reachedness_for_leak_kinds(extra->Err.Leak.lr->key.state));
-      return True;
    } else if (Err_FishyValue == ekind) {
       MC_Error* extra = VG_(get_error_extra)(err);
-      VG_(snprintf)
-         (buf, nBuf-1, "%s(%s)", extra->Err.FishyValue.function_name,
-          extra->Err.FishyValue.argument_name);
-      return True;
+      return VG_(snprintf) (buf, nBuf, "%s(%s)",
+                            extra->Err.FishyValue.function_name,
+                            extra->Err.FishyValue.argument_name);
    } else {
-      return False;
+      buf[0] = '\0';
+      return 0;
    }
 }
 
-Bool MC_(print_extra_suppression_use) ( Supp *su,
-                                        /*OUT*/HChar *buf, Int nBuf )
+SizeT MC_(print_extra_suppression_use) ( Supp *su,
+                                         /*OUT*/HChar *buf, Int nBuf )
 {
+   tl_assert(nBuf >= 1);
+
    if (VG_(get_supp_kind)(su) == LeakSupp) {
       MC_LeakSuppExtra *lse = (MC_LeakSuppExtra*) VG_(get_supp_extra) (su);
 
       if (lse->leak_search_gen == MC_(leak_search_gen)
           && lse->blocks_suppressed > 0) {
-         VG_(snprintf) (buf, nBuf-1, 
-                        "suppressed: %'lu bytes in %'lu blocks",
-                        lse->bytes_suppressed,
-                        lse->blocks_suppressed);
-         return True;
-      } else
-         return False;
-   } else
-      return False;
+         return VG_(snprintf) (buf, nBuf,
+                               "suppressed: %'lu bytes in %'lu blocks",
+                               lse->bytes_suppressed,
+                               lse->blocks_suppressed);
+      }
+   }
+
+   buf[0] = '\0';
+   return 0;
 }
 
 void MC_(update_extra_suppression_use) ( Error* err, Supp* su)
diff --git a/memcheck/mc_include.h b/memcheck/mc_include.h
index 39e0382..26ad25e 100644
--- a/memcheck/mc_include.h
+++ b/memcheck/mc_include.h
@@ -405,10 +405,10 @@
 
 Bool MC_(error_matches_suppression) ( Error* err, Supp* su );
 
-Bool MC_(get_extra_suppression_info) ( Error* err,
-                                       /*OUT*/HChar* buf, Int nBuf );
-Bool MC_(print_extra_suppression_use) ( Supp* su,
+SizeT MC_(get_extra_suppression_info) ( Error* err,
                                         /*OUT*/HChar* buf, Int nBuf );
+SizeT MC_(print_extra_suppression_use) ( Supp* su,
+                                         /*OUT*/HChar* buf, Int nBuf );
 void MC_(update_extra_suppression_use) ( Error* err, Supp* su );
 
 const HChar* MC_(get_error_name) ( Error* err );