Home | History | Annotate | Download | only in tsan
      1 /* Copyright (c) 2008-2010, Google Inc.
      2  * All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Neither the name of Google Inc. nor the names of its
     11  * contributors may be used to endorse or promote products derived from
     12  * this software without specific prior written permission.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 // This file is part of ThreadSanitizer, a dynamic data race detector.
     28 // Author: Konstantin Serebryany.
     29 
     30 // This file contains tests for various parts of ThreadSanitizer.
     31 
     32 #include <gtest/gtest.h>
     33 
     34 #include "ts_heap_info.h"
     35 #include "ts_simple_cache.h"
     36 #include "dense_multimap.h"
     37 
     38 // Testing the HeapMap.
     39 struct TestHeapInfo {
     40   uintptr_t ptr;
     41   uintptr_t size;
     42   int       val;
     43   TestHeapInfo() : ptr(0), size(0), val(0) { }
     44   TestHeapInfo(uintptr_t p, uintptr_t s, uintptr_t v) :
     45     ptr(p), size(s), val(v) { }
     46 };
     47 
     48 TEST(ThreadSanitizer, HeapInfoTest) {
     49   HeapMap<TestHeapInfo> map;
     50   TestHeapInfo *info;
     51   EXPECT_EQ(0U, map.size());
     52   EXPECT_EQ(NULL, map.GetInfo(12345));
     53 
     54   // Insert range [1000, 1000+100) with value 1.
     55   map.InsertInfo(1000, TestHeapInfo(1000, 100, 1));
     56   EXPECT_EQ(1U, map.size());
     57   info = map.GetInfo(1000);
     58   EXPECT_TRUE(info);
     59   EXPECT_EQ(1000U, info->ptr);
     60   EXPECT_EQ(100U, info->size);
     61   EXPECT_EQ(1, info->val);
     62 
     63   EXPECT_TRUE(map.GetInfo(1000));
     64   EXPECT_EQ(1, info->val);
     65   EXPECT_TRUE(map.GetInfo(1050));
     66   EXPECT_EQ(1, info->val);
     67   EXPECT_TRUE(map.GetInfo(1099));
     68   EXPECT_EQ(1, info->val);
     69   EXPECT_FALSE(map.GetInfo(1100));
     70   EXPECT_FALSE(map.GetInfo(2000));
     71 
     72   EXPECT_EQ(NULL, map.GetInfo(2000));
     73   EXPECT_EQ(NULL, map.GetInfo(3000));
     74 
     75   // Insert range [2000, 2000+200) with value 2.
     76   map.InsertInfo(2000, TestHeapInfo(2000, 200, 2));
     77   EXPECT_EQ(2U, map.size());
     78 
     79   info = map.GetInfo(1000);
     80   EXPECT_TRUE(info);
     81   EXPECT_EQ(1, info->val);
     82 
     83   info = map.GetInfo(2000);
     84   EXPECT_TRUE(info);
     85   EXPECT_EQ(2, info->val);
     86 
     87   info = map.GetInfo(1000);
     88   EXPECT_TRUE(info);
     89   EXPECT_EQ(1, info->val);
     90   EXPECT_TRUE((info = map.GetInfo(1050)));
     91   EXPECT_EQ(1, info->val);
     92   EXPECT_TRUE((info = map.GetInfo(1099)));
     93   EXPECT_EQ(1, info->val);
     94   EXPECT_FALSE(map.GetInfo(1100));
     95 
     96   EXPECT_TRUE((info = map.GetInfo(2000)));
     97   EXPECT_EQ(2, info->val);
     98   EXPECT_TRUE((info = map.GetInfo(2199)));
     99   EXPECT_EQ(2, info->val);
    100 
    101   EXPECT_FALSE(map.GetInfo(2200));
    102   EXPECT_FALSE(map.GetInfo(3000));
    103 
    104   // Insert range [3000, 3000+300) with value 3.
    105   map.InsertInfo(3000, TestHeapInfo(3000, 300, 3));
    106   EXPECT_EQ(3U, map.size());
    107 
    108   EXPECT_TRUE((info = map.GetInfo(1000)));
    109   EXPECT_EQ(1, info->val);
    110 
    111   EXPECT_TRUE((info = map.GetInfo(2000)));
    112   EXPECT_EQ(2, info->val);
    113 
    114   EXPECT_TRUE((info = map.GetInfo(3000)));
    115   EXPECT_EQ(3, info->val);
    116 
    117   EXPECT_TRUE((info = map.GetInfo(1050)));
    118   EXPECT_EQ(1, info->val);
    119 
    120   EXPECT_TRUE((info = map.GetInfo(2100)));
    121   EXPECT_EQ(2, info->val);
    122 
    123   EXPECT_TRUE((info = map.GetInfo(3200)));
    124   EXPECT_EQ(3, info->val);
    125 
    126   // Remove range [2000,2000+200)
    127   map.EraseInfo(2000);
    128   EXPECT_EQ(2U, map.size());
    129 
    130   EXPECT_TRUE((info = map.GetInfo(1050)));
    131   EXPECT_EQ(1, info->val);
    132 
    133   EXPECT_FALSE(map.GetInfo(2100));
    134 
    135   EXPECT_TRUE((info = map.GetInfo(3200)));
    136   EXPECT_EQ(3, info->val);
    137 
    138 }
    139 
    140 TEST(ThreadSanitizer, PtrToBoolCacheTest) {
    141   PtrToBoolCache<256> c;
    142   bool val = false;
    143   EXPECT_FALSE(c.Lookup(123, &val));
    144 
    145   c.Insert(0, false);
    146   c.Insert(1, true);
    147   c.Insert(2, false);
    148   c.Insert(3, true);
    149 
    150   EXPECT_TRUE(c.Lookup(0, &val));
    151   EXPECT_EQ(false, val);
    152   EXPECT_TRUE(c.Lookup(1, &val));
    153   EXPECT_EQ(true, val);
    154   EXPECT_TRUE(c.Lookup(2, &val));
    155   EXPECT_EQ(false, val);
    156   EXPECT_TRUE(c.Lookup(3, &val));
    157   EXPECT_EQ(true, val);
    158 
    159   EXPECT_FALSE(c.Lookup(256, &val));
    160   EXPECT_FALSE(c.Lookup(257, &val));
    161   EXPECT_FALSE(c.Lookup(258, &val));
    162   EXPECT_FALSE(c.Lookup(259, &val));
    163 
    164   c.Insert(0, true);
    165   c.Insert(1, false);
    166 
    167   EXPECT_TRUE(c.Lookup(0, &val));
    168   EXPECT_EQ(true, val);
    169   EXPECT_TRUE(c.Lookup(1, &val));
    170   EXPECT_EQ(false, val);
    171   EXPECT_TRUE(c.Lookup(2, &val));
    172   EXPECT_EQ(false, val);
    173   EXPECT_TRUE(c.Lookup(3, &val));
    174   EXPECT_EQ(true, val);
    175 
    176   c.Insert(256, false);
    177   c.Insert(257, false);
    178   EXPECT_FALSE(c.Lookup(0, &val));
    179   EXPECT_FALSE(c.Lookup(1, &val));
    180   EXPECT_TRUE(c.Lookup(2, &val));
    181   EXPECT_EQ(false, val);
    182   EXPECT_TRUE(c.Lookup(3, &val));
    183   EXPECT_EQ(true, val);
    184   EXPECT_TRUE(c.Lookup(256, &val));
    185   EXPECT_EQ(false, val);
    186   EXPECT_TRUE(c.Lookup(257, &val));
    187   EXPECT_EQ(false, val);
    188 }
    189 
    190 TEST(ThreadSanitizer, IntPairToBoolCacheTest) {
    191   IntPairToBoolCache<257> c;
    192   bool val = false;
    193   map<pair<int,int>, bool> m;
    194 
    195   for (int i = 0; i < 1000000; i++) {
    196     int a = (rand() % 1024) + 1;
    197     int b = (rand() % 1024) + 1;
    198 
    199     if (c.Lookup(a, b, &val)) {
    200       EXPECT_EQ(1U, m.count(make_pair(a,b)));
    201       EXPECT_EQ(val, m[make_pair(a,b)]);
    202     }
    203 
    204     val = (rand() % 2) == 1;
    205     c.Insert(a, b, val);
    206     m[make_pair(a,b)] = val;
    207   }
    208 }
    209 
    210 TEST(ThreadSanitizer, DenseMultimapTest) {
    211   typedef DenseMultimap<int, 3> Map;
    212 
    213   Map m1(1, 2);
    214   EXPECT_EQ(m1[0], 1);
    215   EXPECT_EQ(m1[1], 2);
    216   EXPECT_EQ(m1.size(), 2U);
    217 
    218   Map m2(3, 2);
    219   EXPECT_EQ(m2[0], 2);
    220   EXPECT_EQ(m2[1], 3);
    221   EXPECT_EQ(m2.size(), 2U);
    222 
    223   Map m3(m1, 0);
    224   EXPECT_EQ(m3.size(), 3U);
    225   EXPECT_EQ(m3[0], 0);
    226   EXPECT_EQ(m3[1], 1);
    227   EXPECT_EQ(m3[2], 2);
    228 
    229   Map m4(m3, 1);
    230   EXPECT_EQ(m4.size(), 4U);
    231   EXPECT_EQ(m4[0], 0);
    232   EXPECT_EQ(m4[1], 1);
    233   EXPECT_EQ(m4[2], 1);
    234   EXPECT_EQ(m4[3], 2);
    235 
    236   Map m5(m4, 5);
    237   Map m6(m5, -2);
    238   Map m7(m6, 2);
    239   EXPECT_EQ(m7.size(), 7U);
    240 
    241   EXPECT_TRUE(m7.has(-2));
    242   EXPECT_TRUE(m7.has(0));
    243   EXPECT_TRUE(m7.has(1));
    244   EXPECT_TRUE(m7.has(2));
    245   EXPECT_TRUE(m7.has(5));
    246   EXPECT_FALSE(m7.has(3));
    247   EXPECT_FALSE(m7.has(-1));
    248   EXPECT_FALSE(m7.has(4));
    249 
    250   Map m8(m7, Map::REMOVE, 1);
    251   EXPECT_EQ(m8.size(), 6U);
    252   EXPECT_TRUE(m8.has(1));
    253 
    254   Map m9(m8, Map::REMOVE, 1);
    255   EXPECT_EQ(m9.size(), 5U);
    256   EXPECT_FALSE(m9.has(1));
    257 }
    258 
    259 TEST(ThreadSanitizer, NormalizeFunctionNameNotChangingTest) {
    260   const char *samples[] = {
    261     // These functions should not be changed by NormalizeFunctionName():
    262     // C functions
    263     "main",
    264     "pthread_mutex_unlock",
    265     "pthread_create@@GLIBC_2.2.5",
    266     "pthread_create@*"
    267 
    268     // Valgrind can give us this, we should keep it.
    269     "(below main)",
    270 
    271     // C++ operators
    272     "operator new[]",
    273     "operator delete[]",
    274 
    275     // PIN on Windows handles non-templated C++ code well
    276     "my_namespace::ClassName::Method",
    277     "PositiveTests_HarmfulRaceInDtor::A::~A",
    278     "PositiveTests_HarmfulRaceInDtor::B::`scalar deleting destructor'",
    279 
    280     // Objective-C on Mac
    281     "+[NSNavFBENode _virtualNodeOfType:]",
    282     "-[NSObject(NSObject) autorelease]",
    283     "-[NSObject(NSKeyValueCoding) setValue:forKeyPath:]",
    284     "-[NSCell(NSPrivate_CellMouseTracking) _setMouseTrackingInRect:ofView:]",
    285     // TODO(glider): other interesting cases from Objective-C?
    286     // Should we "s/:.*\]/\]/" ?
    287   };
    288 
    289   for (size_t i = 0; i < sizeof(samples) / sizeof(samples[0]); i += 2) {
    290     EXPECT_STREQ(samples[i], NormalizeFunctionName(samples[i]).c_str());
    291   }
    292 }
    293 
    294 TEST(ThreadSanitizer, NormalizeFunctionNameChangingTest) {
    295   const char *samples[] = {
    296     // These functions should be changed by removing <.*> and (.*) while
    297     // correctly handling the "function returns a [template] function pointer"
    298     // case.
    299     // This is a list of (full demangled name, short name) pairs.
    300     "SuppressionTests::Foo(int*)", "SuppressionTests::Foo",
    301     "logging::LogMessage::Init(char const*, int)", "logging::LogMessage::Init",
    302     "void DispatchToMethod<net::SpdySession, void (net::SpdySession::*)(int), int>(net::SpdySession*, void (net::SpdySession::*)(int), Tuple1<int> const&)",
    303         "DispatchToMethod",
    304     "MessageLoop::DeferOrRunPendingTask(MessageLoop::PendingTask const&)",
    305         "MessageLoop::DeferOrRunPendingTask",
    306     "spdy::SpdyFramer::ProcessInput(char const*, unsigned long)",
    307         "spdy::SpdyFramer::ProcessInput",
    308     "base::RefCountedThreadSafe<history::HistoryBackend, base::DefaultRefCountedThreadSafeTraits<history::HistoryBackend> >::Release() const",
    309         "base::RefCountedThreadSafe::Release",
    310     "net::X509Certificate::Verify(std::string const&, int, net::CertVerifyResult*) const",
    311         "net::X509Certificate::Verify",
    312 
    313     "(anonymous namespace)::ExtentToStringSet(ExtensionExtent const&, std::set<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)",
    314         "::ExtentToStringSet",
    315 
    316     "scoped_ptr<(anonymous namespace)::ImportEndedObserver>::operator->() const",
    317         "scoped_ptr::operator->",
    318 
    319     "int (anonymous namespace)::ValueCompare<long>(long, long)",
    320         "::ValueCompare",
    321 
    322     "std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > const& std::__median<std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> >, (anonymous namespace)::CompareQuality>(std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > const&, std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > const&, std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > const&, (anonymous namespace)::CompareQuality)",
    323         "std::__median",
    324 
    325     "std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::_Setprecision)",
    326         "std::operator<<",
    327 
    328     "net::(anonymous namespace)::CookieSignature::operator<(net::(anonymous namespace)::CookieSignature const&) const",
    329         "net::::CookieSignature::operator<",
    330 
    331     "v8::Handle<v8::Value> (*v8::ToCData<v8::Handle<v8::Value> (*)(v8::Arguments const&)>(v8::internal::Object*))(v8::Arguments const&)",
    332         "v8::ToCData",
    333 
    334     "v8::internal::Handle<v8::internal::Object> v8::FromCData<v8::Handle<v8::Value> (*)(v8::Local<v8::String>, v8::AccessorInfo const&)>(v8::Handle<v8::Value> (*)(v8::Local<v8::String>, v8::AccessorInfo const&))",
    335         "v8::FromCData",
    336 
    337     "WebCore::operator<<(WebCore::TextStream&, WebCore::LineCap)",
    338         "WebCore::operator<<",
    339 
    340     "__gnu_cxx::__normal_iterator<void (**)(), std::vector<void (*)(), std::allocator<void (*)()> > >::base() const",
    341         "__gnu_cxx::__normal_iterator::base",
    342 
    343     "__gnu_cxx::__normal_iterator<device_orientation::DataFetcher* (* const*)(), std::vector<device_orientation::DataFetcher* (*)(), std::allocator<device_orientation::DataFetcher* (*)()> > >::operator++()",
    344         "__gnu_cxx::__normal_iterator::operator++",
    345 
    346     "__gnu_cxx::__normal_iterator<std::pair<int, std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > >*, std::vector<std::pair<int, std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > >, std::allocator<std::pair<int, std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > > > > >::operator->() const",
    347         "__gnu_cxx::__normal_iterator::operator->",
    348 
    349     "std::less<CancelableRequestConsumerTSimple<PageUsageData*>::PendingRequest>::operator()(CancelableRequestConsumerTSimple<PageUsageData*>::PendingRequest const&, CancelableRequestConsumerTSimple<PageUsageData*>::PendingRequest const&) const",
    350         "std::less::operator()",
    351 
    352     "SuppressionTests::MyClass<int>::Fooz(int*) const",
    353         "SuppressionTests::MyClass::Fooz",
    354 
    355     // Templates and functions returning function pointers
    356     "void (*SuppressionTests::TemplateFunction1<void (*)(int*)>(void (*)(int*)))(int*)",
    357         "SuppressionTests::TemplateFunction1",  // Valgrind, Linux
    358     "void SuppressionTests::TemplateFunction2<void>()",
    359         "SuppressionTests::TemplateFunction2",  // OMG, return type in template
    360     "void (**&SuppressionTests::TemplateFunction3<void (*)(int)>())",
    361         "SuppressionTests::TemplateFunction3",  // Valgrind, Linux
    362 
    363     "SuppressionTests::TemplateFunction1<void (__cdecl*)(int *)>",
    364         "SuppressionTests::TemplateFunction1",  // PIN, Windows
    365     "SuppressionTests::MyClass<int>::Fooz",
    366         "SuppressionTests::MyClass::Fooz",
    367     "std::operator<<char,std::char_traits<char>,std::allocator<char> >",
    368         "(malformed frame)",  // Should be "std::operator<"? Really?
    369     "std::_Ranit<stdext::_Hash<stdext::_Hmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,int,stdext::hash_compare<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,int> >,0> >::_List_position,int,stdext::_Hash<stdext::_Hmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,int,stdext::hash_compare<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,int> >,0> >::_List_position const *,stdext::_Hash<stdext::_Hmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,int,stdext::hash_compare<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,int> >,0> >::_List_position const &>::_Ranit<stdext::_Hash<stdext::_Hmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,int,stdext::hash_compare<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,int> >,0> >::_List_position,int,stdext::_Hash<stdext::_Hmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,int,stdext::hash_compare<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,std::allocator<std::pair<std::basic",
    370         "(malformed frame)",
    371     "std::_Tree_val<std::_Tmap_traits<net::`anonymous namespace'::CookieSignature,std::set<std::_Tree<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,net::CookieMonster::CanonicalCookie *,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,net::CookieMonster::CanonicalCookie *> >,1> >::iterator,net::`anonymous namespace'::OrderByCreationTimeDesc,std::allocator<std::_Tree<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,net::CookieMonster::CanonicalCookie *,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,net::CookieMonster::CanonicalCookie *> >,1> >::iterator> >,std::less<net::`anonymous namespace'::CookieSignature>,std::allocator<std::pair<net::`anonymous namespace'::CookieSignature const ,std::set<std::_Tree<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,net::CookieMonster::CanonicalCookie *,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,net::CookieMonster::CanonicalCookie *> >,1> >::iterator,net::`anonymous namespace'::OrderByCreationTimeDesc,std::allocator<std::_Tree<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,net::CookieMonster::CanonicalCookie *,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,net::CookieMonster::CanonicalCookie *> >,1> >::iterator> > > >,0> >::~_Tree_val<std::_Tmap_traits<net::`anonymous namespace'::CookieSignature,std::set<std::_Tree<std::_Tmap_traits<std::basic_string<",
    372         "(malformed frame)",
    373 
    374     "__gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*)",
    375         "__gnu_cxx::new_allocator::allocate",
    376 
    377     "PositiveTests_HarmfulRaceInDtor::A::~A()",  // Valgrind, Linux
    378         "PositiveTests_HarmfulRaceInDtor::A::~A",
    379 
    380     "X::foo(int*) const()",   // GCC, Linux
    381         "X::foo",
    382     "X::foo(int*) const volatile",
    383         "X::foo",
    384 
    385     "base::(anonymous namespace)::ThreadFunc(void*)",
    386       "base::::ThreadFunc",  // TODO(timurrrr): keep "anonymous namespace"?
    387 
    388     "operator new[](unsigned long)", "operator new[]",  // Valgrind, Linux
    389   };
    390 
    391   for (size_t i = 0; i < sizeof(samples) / sizeof(samples[0]); i += 2) {
    392     EXPECT_STREQ(samples[i+1], NormalizeFunctionName(samples[i]).c_str());
    393   }
    394 }
    395 
    396 int main(int argc, char **argv) {
    397   testing::InitGoogleTest(&argc, argv);
    398   return RUN_ALL_TESTS();
    399 }
    400