Blob Blame History Raw
commit 13693666bd9fc7be37a907302e5d3d4f4b2c9358
Author: mjw <mjw@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Date:   Sun Nov 15 16:50:43 2015 +0000

    BZ#355188 valgrind should intercept all malloc related global functions.
    
    This implements the interception of all globally public allocation
    functions by default. It works by adding a flag to the spec to say the
    interception only applies to global functions. Which is set for the
    somalloc spec. The librarypath to match is set to "*" unless the user
    overrides it. Then each DiSym keeps track of whether the symbol is local
    or global. For a spec which has isGlobal set only isGlobal symbols will
    match.
    
    Note that because of padding to keep the addresses in DiSym aligned the
    addition of the extra bool isGlobal doesn't actually grow the struct.
    The comments explain how the struct could be made more compact on 32bit
    systems, but this isn't as easy on 64bit systems. So I didn't try to do
    that in this patch.
    
    For ELF symbols keeping track of which are global is trivial. For pdb I
    had to guess and made only the "Public" symbols global. I don't know
    how/if macho keeps track of global symbols or not. For now I just mark
    all of them local (which just means things work as previously on platforms
    that use machos, no non-system symbols are matches by default for somalloc
    unless the user explicitly tells which library name to match).
    
    Included are two testcases for shared libraries (wrapmalloc) and staticly
    linked (wrapmallocstatic) malloc/free overrides that depend on the new
    default. One existing testcase (new_override) was adjusted to explicitly
    not use the new somalloc default because it depends on a user defined
    new implementation that has side-effects and should explicitly not be
    intercepted.
    
    git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15726 a5019735-40e9-0310-863c-91ae7b9d1cf9

diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c
index 6f11cd2..4dc1129 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -4306,7 +4306,8 @@ void VG_(DebugInfo_syms_getidx) ( const DebugInfo *si,
                                   /*OUT*/const HChar**   pri_name,
                                   /*OUT*/const HChar***  sec_names,
                                   /*OUT*/Bool*     isText,
-                                  /*OUT*/Bool*     isIFunc )
+                                  /*OUT*/Bool*     isIFunc,
+                                  /*OUT*/Bool*     isGlobal )
 {
    vg_assert(idx >= 0 && idx < si->symtab_used);
    if (avmas)     *avmas     = si->symtab[idx].avmas;
@@ -4315,6 +4316,7 @@ void VG_(DebugInfo_syms_getidx) ( const DebugInfo *si,
    if (sec_names) *sec_names = si->symtab[idx].sec_names;
    if (isText)    *isText    = si->symtab[idx].isText;
    if (isIFunc)   *isIFunc   = si->symtab[idx].isIFunc;
+   if (isGlobal)  *isGlobal  = si->symtab[idx].isGlobal;
 }
 
 
diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h
index aa1d9f9..a43720a 100644
--- a/coregrind/m_debuginfo/priv_storage.h
+++ b/coregrind/m_debuginfo/priv_storage.h
@@ -75,14 +75,18 @@ typedef
                             the macros defined in pub_core_debuginfo.h */
       const HChar*  pri_name;  /* primary name, never NULL */
       const HChar** sec_names; /* NULL, or a NULL term'd array of other names */
-      // XXX: this could be shrunk (on 32-bit platforms) by using 30
-      // bits for the size and 1 bit each for isText and isIFunc.  If you
-      // do this, make sure that all assignments to the latter two use
-      // 0 or 1 (or True or False), and that a positive number larger
-      // than 1 is never used to represent True.
+      // XXX: DiSym could be shrunk (on 32-bit platforms to exactly 16
+      // bytes, on 64-bit platforms the first 3 pointers already add
+      // up to 24 bytes, so size plus bits will extend to 32 bytes
+      // anyway) by using 29 bits for the size and 1 bit each for
+      // isText, isIFunc and isGlobal.  If you do this, make sure that
+      // all assignments to the latter two use 0 or 1 (or True or
+      // False), and that a positive number larger than 1 is never
+      // used to represent True.
       UInt    size;    /* size in bytes */
       Bool    isText;
       Bool    isIFunc; /* symbol is an indirect function? */
+      Bool    isGlobal; /* Is this symbol globally visible? */
    }
    DiSym;
 
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index 0861725..3820965 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -241,7 +241,8 @@ Bool get_elf_symbol_info (
         Bool*   from_opd_out,   /* ppc64be-linux only: did we deref an
                                   .opd entry? */
         Bool*   is_text_out,    /* is this a text symbol? */
-        Bool*   is_ifunc        /* is this a  STT_GNU_IFUNC function ?*/
+        Bool*   is_ifunc_out,   /* is this a STT_GNU_IFUNC function ?*/
+        Bool*   is_global_out   /* is this a global symbol ?*/
      )
 {
    Bool plausible;
@@ -259,7 +260,8 @@ Bool get_elf_symbol_info (
    SET_TOCPTR_AVMA(*sym_avmas_out, 0);   /* default to unknown/inapplicable */
    SET_LOCAL_EP_AVMA(*sym_avmas_out, 0); /* default to unknown/inapplicable */
    *from_opd_out      = False;
-   *is_ifunc          = False;
+   *is_ifunc_out      = False;
+   *is_global_out     = False;
 
    /* Get the symbol size, but restrict it to fit in a signed 32 bit
       int.  Also, deal with the stupid case of negative size by making
@@ -373,10 +375,14 @@ Bool get_elf_symbol_info (
    /* Check for indirect functions. */
    if (*is_text_out
        && ELFXX_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) {
-       *is_ifunc = True;
+      *is_ifunc_out = True;
    }
 #  endif
 
+   if (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL) {
+      *is_global_out = True;
+   }
+
 #  if defined(VGP_ppc64be_linux)
    /* Allow STT_NOTYPE in the very special case where we're running on
       ppc64be-linux and the symbol is one which the .opd-chasing hack
@@ -777,6 +783,7 @@ void read_elf_symtab__normal(
       SymAVMAs sym_avmas_really;
       Int    sym_size = 0;
       Bool   from_opd = False, is_text = False, is_ifunc = False;
+      Bool   is_global = False;
       DiOffT sym_name_really = DiOffT_INVALID;
       sym_avmas_really.main = 0;
       SET_TOCPTR_AVMA(sym_avmas_really, 0);
@@ -787,7 +794,7 @@ void read_elf_symtab__normal(
                               &sym_name_really, 
                               &sym_avmas_really,
                               &sym_size,
-                              &from_opd, &is_text, &is_ifunc)) {
+                              &from_opd, &is_text, &is_ifunc, &is_global)) {
 
          DiSym  disym;
          VG_(memset)(&disym, 0, sizeof(disym));
@@ -799,6 +806,7 @@ void read_elf_symtab__normal(
          disym.size      = sym_size;
          disym.isText    = is_text;
          disym.isIFunc   = is_ifunc;
+         disym.isGlobal  = is_global;
          if (cstr) { ML_(dinfo_free)(cstr); cstr = NULL; }
          vg_assert(disym.pri_name);
          vg_assert(GET_TOCPTR_AVMA(disym.avmas) == 0);
@@ -847,6 +855,7 @@ typedef
       Bool       from_opd;
       Bool       is_text;
       Bool       is_ifunc;
+      Bool       is_global;
    }
    TempSym;
 
@@ -911,6 +920,7 @@ void read_elf_symtab__ppc64be_linux(
       SymAVMAs sym_avmas_really;
       Int    sym_size = 0;
       Bool   from_opd = False, is_text = False, is_ifunc = False;
+      Bool   is_global = False;
       DiOffT sym_name_really = DiOffT_INVALID;
       DiSym  disym;
       VG_(memset)(&disym, 0, sizeof(disym));
@@ -923,7 +933,7 @@ void read_elf_symtab__ppc64be_linux(
                               &sym_name_really, 
                               &sym_avmas_really,
                               &sym_size,
-                              &from_opd, &is_text, &is_ifunc)) {
+                              &from_opd, &is_text, &is_ifunc, &is_global)) {
 
          /* Check if we've seen this (name,addr) key before. */
          key.addr = sym_avmas_really.main;
@@ -996,6 +1006,7 @@ void read_elf_symtab__ppc64be_linux(
             elem->from_opd = from_opd;
             elem->is_text  = is_text;
             elem->is_ifunc = is_ifunc;
+            elem->is_global = is_global;
             VG_(OSetGen_Insert)(oset, elem);
             if (di->trace_symtab) {
                HChar* str = ML_(img_strdup)(escn_strtab->img, "di.respl.2",
@@ -1034,14 +1045,17 @@ void read_elf_symtab__ppc64be_linux(
       disym.size      = elem->size;
       disym.isText    = elem->is_text;
       disym.isIFunc   = elem->is_ifunc;
+      disym.isGlobal  = elem->is_global;
       if (cstr) { ML_(dinfo_free)(cstr); cstr = NULL; }
       vg_assert(disym.pri_name != NULL);
 
       ML_(addSym) ( di, &disym );
       if (di->trace_symtab) {
-         VG_(printf)("    rec(%c) [%4ld]:          "
+         VG_(printf)("    rec(%c%c%c) [%4ld]:          "
                      "   val %#010lx, toc %#010lx, sz %4d  %s\n",
                      disym.isText ? 't' : 'd',
+                     disym.isIFunc ? 'i' : '-',
+                     disym.isGlobal ? 'g' : 'l',
                      i,
                      disym.avmas.main,
                      GET_TOCPTR_AVMA(disym.avmas),
diff --git a/coregrind/m_debuginfo/readmacho.c b/coregrind/m_debuginfo/readmacho.c
index 98ab048..3d406a4 100644
--- a/coregrind/m_debuginfo/readmacho.c
+++ b/coregrind/m_debuginfo/readmacho.c
@@ -365,6 +365,7 @@ void read_symtab( /*OUT*/XArray* /* DiSym */ syms,
                          di->text_avma+di->text_size - sym_addr;
       disym.isText     = True;
       disym.isIFunc    = False;
+      disym.isGlobal   = False;
       // Lots of user function names get prepended with an underscore.  Eg. the
       // function 'f' becomes the symbol '_f'.  And the "below main"
       // function is called "start".  So we skip the leading underscore, and
diff --git a/coregrind/m_debuginfo/readpdb.c b/coregrind/m_debuginfo/readpdb.c
index 8b63e95..1ebf863 100644
--- a/coregrind/m_debuginfo/readpdb.c
+++ b/coregrind/m_debuginfo/readpdb.c
@@ -1272,6 +1272,7 @@ static ULong DEBUG_SnarfCodeView(
                              // FIXME: .namelen is sizeof(.data) including .name[]
             vsym.isText    = (sym->generic.id == S_PUB_V1);
             vsym.isIFunc   = False;
+            vsym.isGlobal  = True;
             ML_(addSym)( di, &vsym );
             n_syms_read++;
          }
@@ -1299,6 +1300,7 @@ static ULong DEBUG_SnarfCodeView(
             vsym.isText    = !!(IMAGE_SCN_CNT_CODE 
                                 & sectp[sym->data_v2.segment-1].Characteristics);
             vsym.isIFunc   = False;
+            vsym.isGlobal  = True;
             ML_(addSym)( di, &vsym );
             n_syms_read++;
          }
@@ -1332,6 +1334,7 @@ static ULong DEBUG_SnarfCodeView(
             vsym.isText    = !!(IMAGE_SCN_CNT_CODE
                                 & sectp[sym->data_v2.segment-1].Characteristics);
             vsym.isIFunc   = False;
+            vsym.isGlobal  = True;
             ML_(addSym)( di, &vsym );
             n_syms_read++;
          }
@@ -1365,6 +1368,7 @@ static ULong DEBUG_SnarfCodeView(
          vsym.size      = sym->proc_v1.proc_len;
          vsym.isText    = True;
          vsym.isIFunc   = False;
+         vsym.isGlobal  = sym->generic.id == S_GPROC_V1;
          if (debug)
             VG_(umsg)("  Adding function %s addr=%#lx length=%u\n",
                       symname, vsym.avmas.main, vsym.size );
@@ -1386,6 +1390,7 @@ static ULong DEBUG_SnarfCodeView(
          vsym.size      = sym->proc_v2.proc_len;
          vsym.isText    = True;
          vsym.isIFunc   = False;
+         vsym.isGlobal  = sym->generic.id == S_GPROC_V2;
          if (debug)
             VG_(umsg)("  Adding function %s addr=%#lx length=%u\n",
                       symname, vsym.avmas.main, vsym.size );
@@ -1408,6 +1413,7 @@ static ULong DEBUG_SnarfCodeView(
             vsym.size      = sym->proc_v3.proc_len;
             vsym.isText    = 1;
             vsym.isIFunc   = False;
+            vsym.isGlobal  = sym->generic.id == S_GPROC_V3;
             ML_(addSym)( di, &vsym );
             n_syms_read++;
          }
diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c
index 45bc135..7b2e26a 100644
--- a/coregrind/m_debuginfo/storage.c
+++ b/coregrind/m_debuginfo/storage.c
@@ -98,10 +98,11 @@ void ML_(ppSym) ( Int idx, const DiSym* sym )
    vg_assert(sym->pri_name);
    if (sec_names)
       vg_assert(sec_names);
-   VG_(printf)( "%5d:  %c%c %#8lx .. %#8lx (%u)      %s%s",
+   VG_(printf)( "%5d:  %c%c%c %#8lx .. %#8lx (%u)      %s%s",
                 idx,
                 sym->isText ? 'T' : '-',
                 sym->isIFunc ? 'I' : '-',
+                sym->isGlobal ? 'G' : '-',
                 sym->avmas.main, 
                 sym->avmas.main + sym->size - 1, sym->size,
                 sym->pri_name, sec_names ? " " : "" );
@@ -1646,7 +1647,7 @@ static void canonicaliseSymtab ( struct _DebugInfo* di )
    Word  i, j, n_truncated;
    Addr  sta1, sta2, end1, end2, toc1, toc2;
    const HChar *pri1, *pri2, **sec1, **sec2;
-   Bool  ist1, ist2, isf1, isf2;
+   Bool  ist1, ist2, isf1, isf2, isg1, isg2;
 
 #  define SWAP(ty,aa,bb) \
       do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0)
@@ -1693,6 +1694,8 @@ static void canonicaliseSymtab ( struct _DebugInfo* di )
             }
             /* mark w as an IFunc if either w or r are */
             di->symtab[w].isIFunc = di->symtab[w].isIFunc || di->symtab[r].isIFunc;
+            /* likewise for global symbols */
+            di->symtab[w].isGlobal = di->symtab[w].isGlobal || di->symtab[r].isGlobal;
             /* and use ::pri_names to indicate this slot is no longer in use */
             di->symtab[r].pri_name = NULL;
             if (di->symtab[r].sec_names) {
@@ -1796,6 +1799,7 @@ static void canonicaliseSymtab ( struct _DebugInfo* di )
       sec1 = di->symtab[i].sec_names;
       ist1 = di->symtab[i].isText;
       isf1 = di->symtab[i].isIFunc;
+      isg1 = di->symtab[i].isGlobal;
 
       sta2 = di->symtab[i+1].avmas.main;
       end2 = sta2 + di->symtab[i+1].size - 1;
@@ -1805,6 +1809,7 @@ static void canonicaliseSymtab ( struct _DebugInfo* di )
       sec2 = di->symtab[i+1].sec_names;
       ist2 = di->symtab[i+1].isText;
       isf2 = di->symtab[i+1].isIFunc;
+      isg2 = di->symtab[i+1].isGlobal;
 
       if (sta1 < sta2) {
          end1 = sta2 - 1;
@@ -1814,7 +1819,7 @@ static void canonicaliseSymtab ( struct _DebugInfo* di )
             sta1 = end2 + 1;
             SWAP(Addr,sta1,sta2); SWAP(Addr,end1,end2); SWAP(Addr,toc1,toc2);
             SWAP(const HChar*,pri1,pri2); SWAP(const HChar**,sec1,sec2);
-            SWAP(Bool,ist1,ist2); SWAP(Bool,isf1,isf2);
+            SWAP(Bool,ist1,ist2); SWAP(Bool,isf1,isf2); SWAP(Bool, isg1, isg2);
          } else 
          if (end1 < end2) {
             sta2 = end1 + 1;
@@ -1831,6 +1836,7 @@ static void canonicaliseSymtab ( struct _DebugInfo* di )
       di->symtab[i].sec_names = sec1;
       di->symtab[i].isText    = ist1;
       di->symtab[i].isIFunc   = isf1;
+      di->symtab[i].isGlobal  = isg1;
 
       di->symtab[i+1].avmas.main = sta2;
       di->symtab[i+1].size       = end2 - sta2 + 1;
@@ -1840,6 +1846,7 @@ static void canonicaliseSymtab ( struct _DebugInfo* di )
       di->symtab[i+1].sec_names = sec2;
       di->symtab[i+1].isText    = ist2;
       di->symtab[i+1].isIFunc   = isf2;
+      di->symtab[i+1].isGlobal  = isg2;
 
       vg_assert(sta1 <= sta2);
       vg_assert(di->symtab[i].size > 0);
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index 7e4df8d..3d3f70a 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -233,6 +233,7 @@ typedef
       HChar* from_fnpatt;  /* from fnname pattern  */
       Addr   to_addr;      /* where redirecting to */
       Bool   isWrap;       /* wrap or replacement? */
+      Bool   isGlobal;     /* must the symbol to replace be global? */
       Int    becTag; /* 0 through 9999.  Behavioural equivalance class tag.
                         If two wrappers have the same (non-zero) tag, they
                         are promising that they behave identically. */
@@ -388,7 +389,7 @@ static HChar const* advance_to_comma ( HChar const* c ) {
 
 void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
 {
-   Bool         ok, isWrap;
+   Bool         ok, isWrap, isGlobal;
    Int          i, nsyms, becTag, becPrio;
    Spec*        specList;
    Spec*        spec;
@@ -518,13 +519,14 @@ void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
    for (i = 0; i < nsyms; i++) {
       VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas,
                                   NULL, &sym_name_pri, &sym_names_sec,
-                                  &isText, NULL );
+                                  &isText, NULL, NULL );
       /* Set up to conveniently iterate over all names for this symbol. */
       const HChar*  twoslots[2];
       const HChar** names_init =
          alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]);
       const HChar** names;
       for (names = names_init; *names; names++) {
+         isGlobal = False;
          ok = VG_(maybe_Z_demangle)( *names,
                                      &demangled_sopatt,
                                      &demangled_fnpatt,
@@ -579,15 +581,12 @@ void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
                have a matching lib synonym, then replace the sopatt.
                Otherwise, just ignore this redirection spec. */
 
-            if (!VG_(clo_soname_synonyms))
-               continue; // No synonyms => skip the redir.
-
             /* Search for a matching synonym=newname*/
             SizeT const sopatt_syn_len 
                = VG_(strlen)(demangled_sopatt+VG_SO_SYN_PREFIX_LEN);
             HChar const* last = VG_(clo_soname_synonyms);
             
-            while (*last) {
+            while (last != NULL && *last) {
                HChar const* first = last;
                last = advance_to_equal(first);
                
@@ -611,6 +610,17 @@ void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
                   last++;
             }
             
+	    // If the user didn't set it then somalloc is special. We
+	    // want to match public/global symbols that match the
+	    // fnpatt everywhere.
+	    if (replaced_sopatt == NULL
+		&& VG_(strcmp) ( demangled_sopatt, SO_SYN_MALLOC_NAME ) == 0)
+	      {
+		replaced_sopatt = VG_(strdup)("m_redir.rnnD.1", "*");
+		demangled_sopatt = replaced_sopatt;
+		isGlobal = True;
+	      }
+
             // If we have not replaced the sopatt, then skip the redir.
             if (replaced_sopatt == NULL)
                continue;
@@ -621,6 +631,7 @@ void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
          spec->from_fnpatt = dinfo_strdup("redir.rnnD.3", demangled_fnpatt);
          spec->to_addr = sym_avmas.main;
          spec->isWrap = isWrap;
+         spec->isGlobal = isGlobal;
          spec->becTag = becTag;
          spec->becPrio = becPrio;
          /* check we're not adding manifestly stupid destinations */
@@ -653,7 +664,7 @@ void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
       for (i = 0; i < nsyms; i++) {
          VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas,
                                      NULL, &sym_name_pri, &sym_names_sec,
-                                     &isText, NULL );
+                                     &isText, NULL, NULL );
          const HChar*  twoslots[2];
          const HChar** names_init =
             alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]);
@@ -785,7 +796,7 @@ void generate_and_add_actives (
      )
 {
    Spec*   sp;
-   Bool    anyMark, isText, isIFunc;
+   Bool    anyMark, isText, isIFunc, isGlobal;
    Active  act;
    Int     nsyms, i;
    SymAVMAs  sym_avmas;
@@ -813,7 +824,7 @@ void generate_and_add_actives (
    for (i = 0; i < nsyms; i++) {
       VG_(DebugInfo_syms_getidx)( di, i, &sym_avmas,
                                   NULL, &sym_name_pri, &sym_names_sec,
-                                  &isText, &isIFunc );
+                                  &isText, &isIFunc, &isGlobal );
       const HChar*  twoslots[2];
       const HChar** names_init =
          alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]);
@@ -827,7 +838,8 @@ void generate_and_add_actives (
          for (sp = specs; sp; sp = sp->next) {
             if (!sp->mark)
                continue; /* soname doesn't match */
-            if (VG_(string_match)( sp->from_fnpatt, *names )) {
+            if (VG_(string_match)( sp->from_fnpatt, *names )
+		&& (sp->isGlobal == False || isGlobal == True)) {
                /* got a new binding.  Add to collection. */
                act.from_addr   = sym_avmas.main;
                act.to_addr     = sp->to_addr;
@@ -1220,6 +1232,7 @@ static void add_hardwired_spec (const  HChar* sopatt, const HChar* fnpatt,
    spec->from_fnpatt = CONST_CAST(HChar *,fnpatt);
    spec->to_addr     = to_addr;
    spec->isWrap      = False;
+   spec->isGlobal    = False;
    spec->mandatory   = mandatory;
    /* VARIABLE PARTS */
    spec->mark        = False; /* not significant */
@@ -1719,7 +1732,7 @@ static void handle_require_text_symbols ( const DebugInfo* di )
          const HChar** sym_names_sec = NULL;
          VG_(DebugInfo_syms_getidx)( di, j, NULL,
                                      NULL, &sym_name_pri, &sym_names_sec,
-                                     &isText, NULL );
+                                     &isText, NULL, NULL );
          const HChar*  twoslots[2];
          const HChar** names_init =
             alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]);
@@ -1773,10 +1786,11 @@ static void handle_require_text_symbols ( const DebugInfo* di )
 static void show_spec ( const HChar* left, const Spec* spec )
 {
    VG_(message)( Vg_DebugMsg, 
-                 "%s%-25s %-30s %s-> (%04d.%d) 0x%08lx\n",
+                 "%s%-25s %-30s %s%s-> (%04d.%d) 0x%08lx\n",
                  left,
                  spec->from_sopatt, spec->from_fnpatt,
                  spec->isWrap ? "W" : "R",
+                 spec->isGlobal ? "G" : "L",
                  spec->becTag, spec->becPrio,
                  spec->to_addr );
 }
diff --git a/coregrind/m_replacemalloc/vg_replace_malloc.c b/coregrind/m_replacemalloc/vg_replace_malloc.c
index ccac130..3c79c8a 100644
--- a/coregrind/m_replacemalloc/vg_replace_malloc.c
+++ b/coregrind/m_replacemalloc/vg_replace_malloc.c
@@ -291,7 +291,6 @@ static void init(void);
 // For some lines, we will also define a replacement function
 // whose only purpose is to be a soname synonym place holder
 // that can be replaced using --soname-synonyms.
-#define SO_SYN_MALLOC VG_SO_SYN(somalloc)
 
 // malloc
 #if defined(VGO_linux)
diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h
index b698f2c..8f26f25 100644
--- a/coregrind/pub_core_debuginfo.h
+++ b/coregrind/pub_core_debuginfo.h
@@ -216,7 +216,8 @@ void VG_(DebugInfo_syms_getidx)  ( const DebugInfo *di,
                                    /*OUT*/const HChar**   pri_name,
                                    /*OUT*/const HChar***  sec_names,
                                    /*OUT*/Bool*     isText,
-                                   /*OUT*/Bool*     isIFunc );
+                                   /*OUT*/Bool*     isIFunc,
+                                   /*OUT*/Bool*     isGlobal );
 /* ppc64-linux only: find the TOC pointer (R2 value) that should be in
    force at the entry point address of the function containing
    guest_code_addr.  Returns 0 if not known. */
diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml
index edda8a1..c80aab0 100644
--- a/docs/xml/manual-core.xml
+++ b/docs/xml/manual-core.xml
@@ -2315,18 +2315,26 @@ need to use them.</para>
       <option><![CDATA[--soname-synonyms=syn1=pattern1,syn2=pattern2,...]]></option>
     </term>
     <listitem>
-      <para>When a shared library is loaded, Valgrind checks for 
-      functions in the library that must be replaced or wrapped.
-      For example, Memcheck replaces all malloc related
-      functions (malloc, free, calloc, ...) with its own versions.
-      Such replacements are done by default only in shared libraries whose
-      soname matches a predefined soname pattern (e.g.
-      <varname>libc.so*</varname> on linux).
-      By default, no replacement is done for a statically linked
-      library or for alternative libraries such as tcmalloc.
+      <para>When a shared library is loaded, Valgrind checks for
+      functions in the library that must be replaced or wrapped.  For
+      example, Memcheck replaces some string and memory functions
+      (strchr, strlen, strcpy, memchr, memcpy, memmove, etc.) with its
+      own versions.  Such replacements are normally done only in shared
+      libraries whose soname matches a predefined soname pattern (e.g.
+      <varname>libc.so*</varname> on linux).  By default, no
+      replacement is done for a statically linked library or for
+      alternative libraries, except for the allocation functions
+      (malloc, free, calloc, memalign, realloc, operator new, operator
+      delete, etc.) Such allocation functions are intercepted by
+      default in any shared library or in the executable if they are
+      exported as global symbols. This means that if a replacement
+      allocation library such as tcmalloc is found, its functions are
+      also intercepted by default.
+
       In some cases, the replacements allow
       <option>--soname-synonyms</option> to specify one additional
-      synonym pattern, giving flexibility in the replacement. </para>
+      synonym pattern, giving flexibility in the replacement.  Or to
+      prevent interception of all public allocation symbols.</para>
 
       <para>Currently, this flexibility is only allowed for the
       malloc related functions, using the
@@ -2339,27 +2347,31 @@ need to use them.</para>
         <listitem>
 
           <para>Alternate malloc library: to replace the malloc
-          related functions in an alternate library with
-          soname <varname>mymalloclib.so</varname>, give the
+          related functions in a specific alternate library with
+          soname <varname>mymalloclib.so</varname> (and not in any
+          others), give the
           option <option>--soname-synonyms=somalloc=mymalloclib.so</option>.
           A pattern can be used to match multiple libraries sonames.
           For
           example, <option>--soname-synonyms=somalloc=*tcmalloc*</option>
-          will match the soname of all variants of the tcmalloc library
-          (native, debug, profiled, ... tcmalloc variants). </para>
+          will match the soname of all variants of the tcmalloc
+          library (native, debug, profiled, ... tcmalloc
+          variants). </para>
           <para>Note: the soname of a elf shared library can be
           retrieved using the readelf utility. </para>
 
         </listitem>
 
         <listitem>
-          <para>Replacements in a statically linked library are done by
-          using the <varname>NONE</varname> pattern. For example, if
-          you link with <varname>libtcmalloc.a</varname>, memcheck 
-          will properly work when you give the
-          option <option>--soname-synonyms=somalloc=NONE</option>.  Note
-          that a NONE pattern will match the main executable and any
-          shared library having no soname. </para>
+          <para>Replacements in a statically linked library are done
+          by using the <varname>NONE</varname> pattern. For example,
+          if you link with <varname>libtcmalloc.a</varname>, and only
+          want to intercept the malloc related functions in the
+          executable (and standard libraries) themselves, but not any
+          other shared libraries, you can give the
+          option <option>--soname-synonyms=somalloc=NONE</option>.
+          Note that a NONE pattern will match the main executable and
+          any shared library having no soname. </para>
         </listitem>
 
         <listitem>
@@ -2369,6 +2381,17 @@ need to use them.</para>
           </para>
         </listitem>
 
+	<listitem>
+	  <para>To only intercept allocation symbols in the default
+	  system libraries, but not in any other shared library or the
+	  executable defining public malloc or operator new related
+	  functions use a non-existing library name
+	  like <option>--soname-synonyms=somalloc=nouserintercepts</option>
+	  (where <varname>nouserintercepts</varname> can be any
+	  non-existing library name).
+	  </para>
+	</listitem>
+
       </itemizedlist>
    </listitem>
   </varlistentry>
diff --git a/include/pub_tool_redir.h b/include/pub_tool_redir.h
index bac00d7..21d186b 100644
--- a/include/pub_tool_redir.h
+++ b/include/pub_tool_redir.h
@@ -345,6 +345,12 @@
 #define VG_SO_SYN_PREFIX     "VgSoSyn"
 #define VG_SO_SYN_PREFIX_LEN 7
 
+// Special soname synonym place holder for the malloc symbols that can
+// be replaced using --soname-synonyms.  Otherwise will match all
+// public symbols in any shared library/executable.
+#define SO_SYN_MALLOC VG_SO_SYN(somalloc)
+#define SO_SYN_MALLOC_NAME "VgSoSynsomalloc"
+
 #endif   // __PUB_TOOL_REDIR_H
 
 /*--------------------------------------------------------------------*/
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index 68d9ca1..0f34127 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -291,6 +291,9 @@ EXTRA_DIST = \
 	wrap7.vgtest wrap7.stdout.exp wrap7.stderr.exp \
 	wrap8.vgtest wrap8.stdout.exp wrap8.stderr.exp \
 	wrap8.stdout.exp-ppc64 wrap8.stderr.exp-ppc64 \
+	wrapmalloc.vgtest wrapmalloc.stdout.exp wrapmalloc.stderr.exp \
+	wrapmallocstatic.vgtest wrapmallocstatic.stdout.exp \
+	wrapmallocstatic.stderr.exp \
 	writev1.stderr.exp writev1.stderr.exp-solaris writev1.vgtest \
 	xml1.stderr.exp xml1.stdout.exp xml1.vgtest xml1.stderr.exp-s390x-mvc \
 	threadname.vgtest threadname.stderr.exp \
@@ -375,6 +378,7 @@ check_PROGRAMS = \
 	wcs \
 	xml1 \
 	wrap1 wrap2 wrap3 wrap4 wrap5 wrap6 wrap7 wrap7so.so wrap8 \
+	wrapmalloc wrapmallocso.so wrapmallocstatic \
 	writev1
 
 if !SOLARIS_SUN_STUDIO_AS
@@ -570,4 +574,26 @@ else
 				-Wl,-soname -Wl,wrap7so.so
 endif
 
+# Build shared object for wrapmalloc
+wrapmalloc_SOURCES           = wrapmalloc.c
+wrapmalloc_DEPENDENCIES      = wrapmallocso.so
+if VGCONF_OS_IS_DARWIN
+ wrapmalloc_LDADD            = `pwd`/wrapmallocso.so
+ wrapmalloc_LDFLAGS          = $(AM_FLAG_M3264_PRI)
+else
+ wrapmalloc_LDADD            = wrapmallocso.so
+ wrapmalloc_LDFLAGS          = $(AM_FLAG_M3264_PRI) \
+				-Wl,-rpath,$(top_builddir)/memcheck/tests
+endif
+
+wrapmallocso_so_SOURCES      = wrapmallocso.c
+wrapmallocso_so_CFLAGS       = $(AM_CFLAGS) -fpic
+if VGCONF_OS_IS_DARWIN
+ wrapmallocso_so_LDFLAGS     = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+				-dynamiclib -all_load
+else
+ wrapmallocso_so_LDFLAGS     = -fpic $(AM_FLAG_M3264_PRI) -shared \
+				-Wl,-soname -Wl,wrapmallocso.so
+endif
+
 xml1_CFLAGS             = $(AM_CFLAGS) -D_GNU_SOURCE
diff --git a/memcheck/tests/new_override.vgtest b/memcheck/tests/new_override.vgtest
index 50e6240..435e330 100644
--- a/memcheck/tests/new_override.vgtest
+++ b/memcheck/tests/new_override.vgtest
@@ -1,2 +1,6 @@
 prog: new_override
+# Don't override the user defined somalloc functions in this test.
+# The test depends on some side effects and initializing memory done by
+# the user overidden operator new.
+vgopts: --soname-synonyms=somalloc=nouseroverride
 stderr_filter: filter_allocs
diff --git a/memcheck/tests/wrapmalloc.c b/memcheck/tests/wrapmalloc.c
new file mode 100644
index 0000000..2307e77
--- /dev/null
+++ b/memcheck/tests/wrapmalloc.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Test that a program that has malloc/free interposed in a shared
+   library is also intercepted. */
+
+int main ( void )
+{
+   printf ("start\n");
+   void *p = malloc (1024);
+   free (p);
+   printf ("done\n");
+   return 0;
+}
diff --git a/memcheck/tests/wrapmalloc.stderr.exp b/memcheck/tests/wrapmalloc.stderr.exp
new file mode 100644
index 0000000..d937776
--- /dev/null
+++ b/memcheck/tests/wrapmalloc.stderr.exp
@@ -0,0 +1,10 @@
+
+
+HEAP SUMMARY:
+    in use at exit: 0 bytes in 0 blocks
+  total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/wrapmalloc.stdout.exp b/memcheck/tests/wrapmalloc.stdout.exp
new file mode 100644
index 0000000..60b5fd2
--- /dev/null
+++ b/memcheck/tests/wrapmalloc.stdout.exp
@@ -0,0 +1,2 @@
+start
+done
diff --git a/memcheck/tests/wrapmalloc.vgtest b/memcheck/tests/wrapmalloc.vgtest
new file mode 100644
index 0000000..a6dff4e
--- /dev/null
+++ b/memcheck/tests/wrapmalloc.vgtest
@@ -0,0 +1,2 @@
+prog: wrapmalloc
+
diff --git a/memcheck/tests/wrapmallocso.c b/memcheck/tests/wrapmallocso.c
new file mode 100644
index 0000000..985ce56
--- /dev/null
+++ b/memcheck/tests/wrapmallocso.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Fake malloc/free functions that just print something. When run
+   under memcheck these functions will be intercepted and not print
+   anything. */
+
+void *malloc ( size_t size )
+{
+  printf ("malloc\n");
+  return NULL;
+}
+
+void free (void *ptr)
+{
+  printf ("free\n");
+}
diff --git a/memcheck/tests/wrapmallocstatic.c b/memcheck/tests/wrapmallocstatic.c
new file mode 100644
index 0000000..be6573b
--- /dev/null
+++ b/memcheck/tests/wrapmallocstatic.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Test that a program that has malloc/free interposed in the
+   executable is also intercepted. */
+
+int main ( void )
+{
+   printf ("start\n");
+   void *p = malloc (1024);
+   free (p);
+   printf ("done\n");
+   return 0;
+}
+
+/* Fake malloc/free functions that just print something. When run
+   under memcheck these functions will be intercepted and not print
+   anything. */
+
+void *malloc ( size_t size )
+{
+  printf ("malloc\n");
+  return NULL;
+}
+
+void free (void *ptr)
+{
+  printf ("free\n");
+}
diff --git a/memcheck/tests/wrapmallocstatic.stderr.exp b/memcheck/tests/wrapmallocstatic.stderr.exp
new file mode 100644
index 0000000..d937776
--- /dev/null
+++ b/memcheck/tests/wrapmallocstatic.stderr.exp
@@ -0,0 +1,10 @@
+
+
+HEAP SUMMARY:
+    in use at exit: 0 bytes in 0 blocks
+  total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/wrapmallocstatic.stdout.exp b/memcheck/tests/wrapmallocstatic.stdout.exp
new file mode 100644
index 0000000..60b5fd2
--- /dev/null
+++ b/memcheck/tests/wrapmallocstatic.stdout.exp
@@ -0,0 +1,2 @@
+start
+done
diff --git a/memcheck/tests/wrapmallocstatic.vgtest b/memcheck/tests/wrapmallocstatic.vgtest
new file mode 100644
index 0000000..7b3c068
--- /dev/null
+++ b/memcheck/tests/wrapmallocstatic.vgtest
@@ -0,0 +1,2 @@
+prog: wrapmallocstatic
+
diff -ur valgrind-3.11.0.orig/memcheck/tests/Makefile.in valgrind-3.11.0/memcheck/tests/Makefile.in
--- valgrind-3.11.0.orig/memcheck/tests/Makefile.in	2015-11-15 18:08:05.457930383 +0100
+++ valgrind-3.11.0/memcheck/tests/Makefile.in	2015-11-15 18:14:10.828008973 +0100
@@ -185,7 +185,8 @@
 	vcpu_fnfns$(EXEEXT) wcs$(EXEEXT) xml1$(EXEEXT) wrap1$(EXEEXT) \
 	wrap2$(EXEEXT) wrap3$(EXEEXT) wrap4$(EXEEXT) wrap5$(EXEEXT) \
 	wrap6$(EXEEXT) wrap7$(EXEEXT) wrap7so.so$(EXEEXT) \
-	wrap8$(EXEEXT) writev1$(EXEEXT) $(am__EXEEXT_1) \
+	wrap8$(EXEEXT) wrapmalloc$(EXEEXT) wrapmallocso.so$(EXEEXT) \
+	wrapmallocstatic$(EXEEXT) writev1$(EXEEXT) $(am__EXEEXT_1) \
 	$(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \
 	$(am__EXEEXT_5)
 
@@ -736,6 +737,18 @@
 wrap8_SOURCES = wrap8.c
 wrap8_OBJECTS = wrap8.$(OBJEXT)
 wrap8_LDADD = $(LDADD)
+am_wrapmalloc_OBJECTS = wrapmalloc.$(OBJEXT)
+wrapmalloc_OBJECTS = $(am_wrapmalloc_OBJECTS)
+wrapmalloc_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(wrapmalloc_LDFLAGS) \
+	$(LDFLAGS) -o $@
+am_wrapmallocso_so_OBJECTS = wrapmallocso_so-wrapmallocso.$(OBJEXT)
+wrapmallocso_so_OBJECTS = $(am_wrapmallocso_so_OBJECTS)
+wrapmallocso_so_LDADD = $(LDADD)
+wrapmallocso_so_LINK = $(CCLD) $(wrapmallocso_so_CFLAGS) $(CFLAGS) \
+	$(wrapmallocso_so_LDFLAGS) $(LDFLAGS) -o $@
+wrapmallocstatic_SOURCES = wrapmallocstatic.c
+wrapmallocstatic_OBJECTS = wrapmallocstatic.$(OBJEXT)
+wrapmallocstatic_LDADD = $(LDADD)
 writev1_SOURCES = writev1.c
 writev1_OBJECTS = writev1.$(OBJEXT)
 writev1_LDADD = $(LDADD)
@@ -826,7 +839,8 @@
 	$(varinfo5_SOURCES) $(varinfo5so_so_SOURCES) varinfo6.c \
 	varinforestrict.c vcpu_fbench.c vcpu_fnfns.c wcs.c wrap1.c \
 	wrap2.c wrap3.c wrap4.c wrap5.c wrap6.c $(wrap7_SOURCES) \
-	$(wrap7so_so_SOURCES) wrap8.c writev1.c xml1.c
+	$(wrap7so_so_SOURCES) wrap8.c $(wrapmalloc_SOURCES) \
+	$(wrapmallocso_so_SOURCES) wrapmallocstatic.c writev1.c xml1.c
 DIST_SOURCES = accounting.c addressable.c atomic_incs.c badaddrvalue.c \
 	badfree.c badjump.c badjump2.c badloop.c badpoll.c badrw.c \
 	big_blocks_freed_list.c brk2.c buflen_check.c bug155125.c \
@@ -863,7 +877,8 @@
 	$(varinfo5_SOURCES) $(varinfo5so_so_SOURCES) varinfo6.c \
 	varinforestrict.c vcpu_fbench.c vcpu_fnfns.c wcs.c wrap1.c \
 	wrap2.c wrap3.c wrap4.c wrap5.c wrap6.c $(wrap7_SOURCES) \
-	$(wrap7so_so_SOURCES) wrap8.c writev1.c xml1.c
+	$(wrap7so_so_SOURCES) wrap8.c $(wrapmalloc_SOURCES) \
+	$(wrapmallocso_so_SOURCES) wrapmallocstatic.c writev1.c xml1.c
 RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
 	ctags-recursive dvi-recursive html-recursive info-recursive \
 	install-data-recursive install-dvi-recursive \
@@ -1544,6 +1559,9 @@
 	wrap7.vgtest wrap7.stdout.exp wrap7.stderr.exp \
 	wrap8.vgtest wrap8.stdout.exp wrap8.stderr.exp \
 	wrap8.stdout.exp-ppc64 wrap8.stderr.exp-ppc64 \
+	wrapmalloc.vgtest wrapmalloc.stdout.exp wrapmalloc.stderr.exp \
+	wrapmallocstatic.vgtest wrapmallocstatic.stdout.exp \
+	wrapmallocstatic.stderr.exp \
 	writev1.stderr.exp writev1.stderr.exp-solaris writev1.vgtest \
 	xml1.stderr.exp xml1.stdout.exp xml1.vgtest xml1.stderr.exp-s390x-mvc \
 	threadname.vgtest threadname.stderr.exp \
@@ -1662,6 +1680,24 @@
 @VGCONF_OS_IS_DARWIN_TRUE@wrap7so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
 @VGCONF_OS_IS_DARWIN_TRUE@				-dynamiclib -all_load
 
+
+# Build shared object for wrapmalloc
+wrapmalloc_SOURCES = wrapmalloc.c
+wrapmalloc_DEPENDENCIES = wrapmallocso.so
+@VGCONF_OS_IS_DARWIN_FALSE@wrapmalloc_LDADD = wrapmallocso.so
+@VGCONF_OS_IS_DARWIN_TRUE@wrapmalloc_LDADD = `pwd`/wrapmallocso.so
+@VGCONF_OS_IS_DARWIN_FALSE@wrapmalloc_LDFLAGS = $(AM_FLAG_M3264_PRI) \
+@VGCONF_OS_IS_DARWIN_FALSE@				-Wl,-rpath,$(top_builddir)/memcheck/tests
+
+@VGCONF_OS_IS_DARWIN_TRUE@wrapmalloc_LDFLAGS = $(AM_FLAG_M3264_PRI)
+wrapmallocso_so_SOURCES = wrapmallocso.c
+wrapmallocso_so_CFLAGS = $(AM_CFLAGS) -fpic
+@VGCONF_OS_IS_DARWIN_FALSE@wrapmallocso_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
+@VGCONF_OS_IS_DARWIN_FALSE@				-Wl,-soname -Wl,wrapmallocso.so
+
+@VGCONF_OS_IS_DARWIN_TRUE@wrapmallocso_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+@VGCONF_OS_IS_DARWIN_TRUE@				-dynamiclib -all_load
+
 xml1_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE
 all: all-recursive
 
@@ -2286,6 +2322,18 @@
 	@rm -f wrap8$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(wrap8_OBJECTS) $(wrap8_LDADD) $(LIBS)
 
+wrapmalloc$(EXEEXT): $(wrapmalloc_OBJECTS) $(wrapmalloc_DEPENDENCIES) $(EXTRA_wrapmalloc_DEPENDENCIES) 
+	@rm -f wrapmalloc$(EXEEXT)
+	$(AM_V_CCLD)$(wrapmalloc_LINK) $(wrapmalloc_OBJECTS) $(wrapmalloc_LDADD) $(LIBS)
+
+wrapmallocso.so$(EXEEXT): $(wrapmallocso_so_OBJECTS) $(wrapmallocso_so_DEPENDENCIES) $(EXTRA_wrapmallocso_so_DEPENDENCIES) 
+	@rm -f wrapmallocso.so$(EXEEXT)
+	$(AM_V_CCLD)$(wrapmallocso_so_LINK) $(wrapmallocso_so_OBJECTS) $(wrapmallocso_so_LDADD) $(LIBS)
+
+wrapmallocstatic$(EXEEXT): $(wrapmallocstatic_OBJECTS) $(wrapmallocstatic_DEPENDENCIES) $(EXTRA_wrapmallocstatic_DEPENDENCIES) 
+	@rm -f wrapmallocstatic$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(wrapmallocstatic_OBJECTS) $(wrapmallocstatic_LDADD) $(LIBS)
+
 writev1$(EXEEXT): $(writev1_OBJECTS) $(writev1_DEPENDENCIES) $(EXTRA_writev1_DEPENDENCIES) 
 	@rm -f writev1$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(writev1_OBJECTS) $(writev1_LDADD) $(LIBS)
@@ -2446,6 +2494,9 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrap7.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrap7so_so-wrap7so.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrap8.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrapmalloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrapmallocso_so-wrapmallocso.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrapmallocstatic.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/writev1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml1-xml1.Po@am__quote@
 
@@ -3011,6 +3062,20 @@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(wrap7so_so_CFLAGS) $(CFLAGS) -c -o wrap7so_so-wrap7so.obj `if test -f 'wrap7so.c'; then $(CYGPATH_W) 'wrap7so.c'; else $(CYGPATH_W) '$(srcdir)/wrap7so.c'; fi`
 
+wrapmallocso_so-wrapmallocso.o: wrapmallocso.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(wrapmallocso_so_CFLAGS) $(CFLAGS) -MT wrapmallocso_so-wrapmallocso.o -MD -MP -MF $(DEPDIR)/wrapmallocso_so-wrapmallocso.Tpo -c -o wrapmallocso_so-wrapmallocso.o `test -f 'wrapmallocso.c' || echo '$(srcdir)/'`wrapmallocso.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/wrapmallocso_so-wrapmallocso.Tpo $(DEPDIR)/wrapmallocso_so-wrapmallocso.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='wrapmallocso.c' object='wrapmallocso_so-wrapmallocso.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(wrapmallocso_so_CFLAGS) $(CFLAGS) -c -o wrapmallocso_so-wrapmallocso.o `test -f 'wrapmallocso.c' || echo '$(srcdir)/'`wrapmallocso.c
+
+wrapmallocso_so-wrapmallocso.obj: wrapmallocso.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(wrapmallocso_so_CFLAGS) $(CFLAGS) -MT wrapmallocso_so-wrapmallocso.obj -MD -MP -MF $(DEPDIR)/wrapmallocso_so-wrapmallocso.Tpo -c -o wrapmallocso_so-wrapmallocso.obj `if test -f 'wrapmallocso.c'; then $(CYGPATH_W) 'wrapmallocso.c'; else $(CYGPATH_W) '$(srcdir)/wrapmallocso.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/wrapmallocso_so-wrapmallocso.Tpo $(DEPDIR)/wrapmallocso_so-wrapmallocso.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='wrapmallocso.c' object='wrapmallocso_so-wrapmallocso.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(wrapmallocso_so_CFLAGS) $(CFLAGS) -c -o wrapmallocso_so-wrapmallocso.obj `if test -f 'wrapmallocso.c'; then $(CYGPATH_W) 'wrapmallocso.c'; else $(CYGPATH_W) '$(srcdir)/wrapmallocso.c'; fi`
+
 xml1-xml1.o: xml1.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xml1_CFLAGS) $(CFLAGS) -MT xml1-xml1.o -MD -MP -MF $(DEPDIR)/xml1-xml1.Tpo -c -o xml1-xml1.o `test -f 'xml1.c' || echo '$(srcdir)/'`xml1.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/xml1-xml1.Tpo $(DEPDIR)/xml1-xml1.Po
commit d35c2c3197a0ae8398228d19578e1dfcb8401c5f
Author: iraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Date:   Wed Nov 18 04:13:12 2015 +0000

    Expected stderr of test cases wrapmalloc and wrapmallocstatic are overconstrained.
    Fixes BZ#355455.
    
    
    git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15727 a5019735-40e9-0310-863c-91ae7b9d1cf9

diff --git a/memcheck/tests/wrapmalloc.stderr.exp b/memcheck/tests/wrapmalloc.stderr.exp
index d937776..e69de29 100644
--- a/memcheck/tests/wrapmalloc.stderr.exp
+++ b/memcheck/tests/wrapmalloc.stderr.exp
@@ -1,10 +0,0 @@
-
-
-HEAP SUMMARY:
-    in use at exit: 0 bytes in 0 blocks
-  total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
-
-For a detailed leak analysis, rerun with: --leak-check=full
-
-For counts of detected and suppressed errors, rerun with: -v
-ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/wrapmalloc.vgtest b/memcheck/tests/wrapmalloc.vgtest
index a6dff4e..c22f241 100644
--- a/memcheck/tests/wrapmalloc.vgtest
+++ b/memcheck/tests/wrapmalloc.vgtest
@@ -1,2 +1,2 @@
 prog: wrapmalloc
-
+vgopts: -q
diff --git a/memcheck/tests/wrapmallocstatic.stderr.exp b/memcheck/tests/wrapmallocstatic.stderr.exp
index d937776..e69de29 100644
--- a/memcheck/tests/wrapmallocstatic.stderr.exp
+++ b/memcheck/tests/wrapmallocstatic.stderr.exp
@@ -1,10 +0,0 @@
-
-
-HEAP SUMMARY:
-    in use at exit: 0 bytes in 0 blocks
-  total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
-
-For a detailed leak analysis, rerun with: --leak-check=full
-
-For counts of detected and suppressed errors, rerun with: -v
-ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/wrapmallocstatic.vgtest b/memcheck/tests/wrapmallocstatic.vgtest
index 7b3c068..f040756 100644
--- a/memcheck/tests/wrapmallocstatic.vgtest
+++ b/memcheck/tests/wrapmallocstatic.vgtest
@@ -1,2 +1,2 @@
 prog: wrapmallocstatic
-
+vgopts: -q

commit 194731c49eb7d448503a5e8625dd39779c2c9f8b
Author: iraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Date:   Wed Nov 18 20:38:37 2015 +0000

    When searching for global public symbols (like for the somalloc
    synonym symbols), exclude the dynamic (runtime) linker as it is very
    special.
    Fixes BZ#355454
    
    
    git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15728 a5019735-40e9-0310-863c-91ae7b9d1cf9

diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index 3d3f70a..dcf1fb4 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -809,8 +809,19 @@ void generate_and_add_actives (
    anyMark = False;
    for (sp = specs; sp; sp = sp->next) {
       sp->done = False;
-      sp->mark = VG_(string_match)( sp->from_sopatt, 
-                                    VG_(DebugInfo_get_soname)(di) );
+      const HChar *soname = VG_(DebugInfo_get_soname)(di);
+
+      /* When searching for global public symbols (like for the somalloc
+         synonym symbols), exclude the dynamic (runtime) linker as it is very
+         special. See https://bugs.kde.org/show_bug.cgi?id=355454 */
+      if ((VG_(strcmp)(sp->from_sopatt, "*") == 0) &&
+          (sp->isGlobal == True) &&
+          VG_(is_soname_ld_so)(soname)) {
+         sp->mark = False;
+         continue;
+      }
+
+      sp->mark = VG_(string_match)( sp->from_sopatt, soname );
       anyMark = anyMark || sp->mark;
    }
 
@@ -1179,6 +1190,29 @@ Addr VG_(redir_do_lookup) ( Addr orig, Bool* isWrap )
    return r->to_addr;
 }
 
+/* Does the soname represent a dynamic (runtime) linker?
+   Considers various VG_U_LD* entries from pub_tool_redir.h. */
+Bool VG_(is_soname_ld_so) (const HChar *soname)
+{
+#  if defined(VGO_linux)
+   if (VG_STREQ(soname, VG_U_LD_LINUX_SO_3))         return True;
+   if (VG_STREQ(soname, VG_U_LD_LINUX_SO_2))         return True;
+   if (VG_STREQ(soname, VG_U_LD_LINUX_X86_64_SO_2))  return True;
+   if (VG_STREQ(soname, VG_U_LD64_SO_1))             return True;
+   if (VG_STREQ(soname, VG_U_LD64_SO_2))             return True;
+   if (VG_STREQ(soname, VG_U_LD_SO_1))               return True;
+   if (VG_STREQ(soname, VG_U_LD_LINUX_AARCH64_SO_1)) return True;
+   if (VG_STREQ(soname, VG_U_LD_LINUX_ARMHF_SO_3))   return True;
+#  elif defined(VGO_darwin)
+   if (VG_STREQ(soname, VG_U_DYLD)) return True;
+#  elif defined(VGO_solaris)
+   if (VG_STREQ(soname, VG_U_LD_SO_1)) return True;
+#  else
+#    error "Unsupported OS"
+#  endif
+
+   return False;
+}
 
 /*------------------------------------------------------------*/
 /*--- INITIALISATION                                       ---*/
diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml
index c80aab0..758e2f4 100644
--- a/docs/xml/manual-core.xml
+++ b/docs/xml/manual-core.xml
@@ -2322,7 +2322,7 @@ need to use them.</para>
       own versions.  Such replacements are normally done only in shared
       libraries whose soname matches a predefined soname pattern (e.g.
       <varname>libc.so*</varname> on linux).  By default, no
-      replacement is done for a statically linked library or for
+      replacement is done for a statically linked binary or for
       alternative libraries, except for the allocation functions
       (malloc, free, calloc, memalign, realloc, operator new, operator
       delete, etc.) Such allocation functions are intercepted by
@@ -2392,6 +2392,13 @@ need to use them.</para>
 	  </para>
 	</listitem>
 
+      <listitem>
+         <para>Shared library of the dynamic (runtime) linker is excluded from
+         searching for global public symbols, such as those for the malloc
+         related functions (identified by <varname>somalloc</varname> synonym).
+         </para>
+      </listitem>
+
       </itemizedlist>
    </listitem>
   </varlistentry>
diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c
index ae6eec0..9aed05a 100644
--- a/helgrind/hg_main.c
+++ b/helgrind/hg_main.c
@@ -4589,7 +4589,6 @@ static Bool is_in_dynamic_linker_shared_object( Addr ga )
 {
    DebugInfo* dinfo;
    const HChar* soname;
-   if (0) return False;
 
    dinfo = VG_(find_DebugInfo)( ga );
    if (!dinfo) return False;
@@ -4598,23 +4597,7 @@ static Bool is_in_dynamic_linker_shared_object( Addr ga )
    tl_assert(soname);
    if (0) VG_(printf)("%s\n", soname);
 
-#  if defined(VGO_linux)
-   if (VG_STREQ(soname, VG_U_LD_LINUX_SO_3))        return True;
-   if (VG_STREQ(soname, VG_U_LD_LINUX_SO_2))        return True;
-   if (VG_STREQ(soname, VG_U_LD_LINUX_X86_64_SO_2)) return True;
-   if (VG_STREQ(soname, VG_U_LD64_SO_1))            return True;
-   if (VG_STREQ(soname, VG_U_LD64_SO_2))            return True;
-   if (VG_STREQ(soname, VG_U_LD_SO_1))              return True;
-   if (VG_STREQ(soname, VG_U_LD_LINUX_AARCH64_SO_1)) return True;
-   if (VG_STREQ(soname, VG_U_LD_LINUX_ARMHF_SO_3))  return True;
-#  elif defined(VGO_darwin)
-   if (VG_STREQ(soname, VG_U_DYLD)) return True;
-#  elif defined(VGO_solaris)
-   if (VG_STREQ(soname, VG_U_LD_SO_1)) return True;
-#  else
-#    error "Unsupported OS"
-#  endif
-   return False;
+   return VG_(is_soname_ld_so)(soname);
 }
 
 static
diff --git a/include/pub_tool_redir.h b/include/pub_tool_redir.h
index 21d186b..aa879d6 100644
--- a/include/pub_tool_redir.h
+++ b/include/pub_tool_redir.h
@@ -351,6 +351,8 @@
 #define SO_SYN_MALLOC VG_SO_SYN(somalloc)
 #define SO_SYN_MALLOC_NAME "VgSoSynsomalloc"
 
+Bool VG_(is_soname_ld_so) (const HChar *soname);
+
 #endif   // __PUB_TOOL_REDIR_H
 
 /*--------------------------------------------------------------------*/
commit a80c98bab0835b51a2193aec19ce55ad607b7ec0
Author: philippe <philippe@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Date:   Sat Jul 2 18:46:23 2016 +0000

    Fix leak in m_redir.c
    See below discussion for more details.
    
    On Sat, 2016-07-02 at 14:20 +0200, Philippe Waroquiers wrote:
    > I am testing a patch (provided by Julian) that solves a false positive
    > memcheck found at my work.
    >
    > Testing this, I decided to run valgrind under valgrind (not done since
    > a long time).
    >
    > This shows a leak in many tests, the stack trace being such as:
    > ==26246== 336 bytes in 21 blocks are definitely lost in loss record 72 of 141
    > ==26246==    at 0x2801C01D: vgPlain_arena_malloc (m_mallocfree.c:1855)
    > ==26246==    by 0x2801D616: vgPlain_arena_strdup (m_mallocfree.c:2528)
    > ==26246==    by 0x2801D616: vgPlain_strdup (m_mallocfree.c:2600)
    > ==26246==    by 0x2801F5AD: vgPlain_redir_notify_new_DebugInfo (m_redir.c:619)
    > ==26246==    by 0x2803B650: di_notify_ACHIEVE_ACCEPT_STATE (debuginfo.c:771)
    > ==26246==    by 0x2803B650: vgPlain_di_notify_mmap (debuginfo.c:1067)
    > ==26246==    by 0x2806589C: vgModuleLocal_generic_PRE_sys_mmap (syswrap-generic.c:2368)
    > ==26246==    by 0x2809932A: vgSysWrap_amd64_linux_sys_mmap_before (syswrap-amd64-linux.c:637)
    > ==26246==    by 0x28061E11: vgPlain_client_syscall (syswrap-main.c:1906)
    > ==26246==    by 0x2805E9D2: handle_syscall (scheduler.c:1118)
    > ==26246==    by 0x280604A6: vgPlain_scheduler (scheduler.c:1435)
    > ==26246==    by 0x2806FF87: thread_wrapper (syswrap-linux.c:103)
    > ==26246==    by 0x2806FF87: run_a_thread_NORETURN (syswrap-linux.c:156)
    >
    >
    > The strdup call in m_redir.c:619 was introduced by r15726.
    >
    > However, I am not sure this is a bug that is introduced by this change,
    > or if it just reveals a leak that was already there.
    > The "very original" replacement logic did not do memory allocation for
    > the replacement: see m_redir.c in valgrind 3.10.1 : it was just copying
    > some chars from VG_(clo_soname_synonyms) to demangled_sopatt
    
    Yes, it should do exactly the same as the other code paths. If
    replaced_sopatt != NULL then it is an allocated string that has been
    assigned to demangled_sopatt. I had assumed that would take care of the
    life-time issues of the allocated string. But now that I read the code
    it is indeed not so clear.
    
    > Then in 3.11, the fixed size demangled_sopatt was changed to be
    > a dynamically allocated buffer.
    > The revision log 14664 that introduced this explains that the ownership of
    > returned buffer is not easy. It tells at the end:
    > "So the rule of thunb here is: if in doubt strdup the string."
    >
    > but now we have to see when to free what, it seems ???
    >
    > Any thoughts ?
    
    So if replaced_sopatt != NULL, then demangled_sopatt contains the
    allocated string, and it is then immediately copied and assigned to
    spec->from_sopatt. After that it is used under check_ppcTOCs. But there
    it will first be reassigned a new value through maybe_Z_demangle
    (overwriting any existing string being pointed to). So for this
    particular leak it seem fine to free it right after the spec[List] has
    been initialized (line 642).
    
    Cheers,
    
    Mark
    
    
    
    git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15898 a5019735-40e9-0310-863c-91ae7b9d1cf9

diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index 62cb45a..c9e8726 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -616,7 +616,7 @@ void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
 	    if (replaced_sopatt == NULL
 		&& VG_(strcmp) ( demangled_sopatt, SO_SYN_MALLOC_NAME ) == 0)
 	      {
-		replaced_sopatt = VG_(strdup)("m_redir.rnnD.1", "*");
+		replaced_sopatt = dinfo_strdup("m_redir.rnnD.1", "*");
 		demangled_sopatt = replaced_sopatt;
 		isGlobal = True;
 	      }
@@ -640,6 +640,14 @@ void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
          spec->mark = False; /* not significant */
          spec->done = False; /* not significant */
          specList = spec;
+         /* The demangler is the owner of the demangled_sopatt memory,
+            unless it was replaced. In this case, we have to free the
+            replace_sopatt(==demangled_sopatt).  We can free it,
+            because it was dinfo_strup-ed into spec->from_sopatt. */
+         if (replaced_sopatt != NULL) {
+            vg_assert(demangled_sopatt == replaced_sopatt);
+            dinfo_free(replaced_sopatt);
+         }
       }
       free_symname_array(names_init, &twoslots[0]);
    }