Opened 14 years ago

Closed 13 years ago

Last modified 13 years ago

#2889 closed Bugs (fixed)

Unit Test framework does things that OS X's malloc dislikes

Reported by: akim.demaille@… Owned by: Gennadiy Rozental
Milestone: Boost 1.41.0 Component: test
Version: Boost Release Branch Severity: Showstopper
Keywords: osx Cc: akos@…

Description

Using the attached file, compiled as follows, OS X's malloc reports an invalid free. This is annoying, as we run our test with such instrumentation to catch other kinds of errors.

This is Mac OS X 10.5.6. Boost 1.38 installed by MacPorts.

$ g++ -Wall tests/libport/cli.cc -o cli -I/opt/local/include -L/opt/local/lib -lboost_unit_test_framework-mt
$ MallocErrorAbort=1 MallocScribble=1 ./cli
cli(50514) malloc: enabling abort() on bad malloc or free
cli(50514) malloc: enabling scribbling to detect mods to free blocks
cli(50514) malloc: enabling abort() on bad malloc or free
Running 1 test case...

*** No errors detected
cli(50514) malloc: *** error for object 0x55555555: Non-aligned pointer being freed
*** set a breakpoint in malloc_error_break to debug
zsh: abort      MallocErrorAbort=1 MallocScribble=1 ./cli
$ g++ --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5484)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

The documentation for MallocScribble (man malloc) reads:

If set, fill memory that has been deallocated with 0x55 bytes. This increases the likelihood that a program will fail due to accessing memory that is no longer allocated.

Attachments (1)

cli.cc (314 bytes ) - added by akim.demaille@… 14 years ago.
A source file to reproduce the problem

Download all attachments as: .zip

Change History (10)

by akim.demaille@…, 14 years ago

Attachment: cli.cc added

A source file to reproduce the problem

comment:1 by Marshall Clow, 13 years ago

Investigation results: The stack trace for the error is:

Breakpoint 1, 0x94ddf4a9 in malloc_error_break ()
(gdb) bt
#0  0x94ddf4a9 in malloc_error_break ()
#1  0x94dda497 in szone_error ()
#2  0x94d04463 in szone_free ()
#3  0x94d042cd in free ()
#4  0x0002ee92 in boost::unit_test::framework_impl::clear ()
#5  0x0002efbd in boost::unit_test::framework_impl::~framework_impl ()
#6  0x00008453 in __tcf_1 ()
#7  0x94d26cfc in __cxa_finalize ()
#8  0x94d26bf0 in exit ()
#9  0x000025c7 in start ()

comment:2 by warren.seine@…, 13 years ago

Same behavior experienced with Boost.Filesystem trying to run "simple_ls.cpp" (from Boost.Filesystem tutorials).

Using:

  • Mac OS X 10.5.6
  • g++ 4.3.3
  • Boost 1.38

Here is the stack trace:

Breakpoint 1, 0x94f824a9 in malloc_error_break ()
(gdb) bt
#0  0x94f824a9 in malloc_error_break ()
#1  0x94f7d497 in szone_error ()
#2  0x94ea7463 in szone_free ()
#3  0x94ea72cd in free ()
#4  0x001b6745 in operator delete ()
#5  0x9281f02a in std::string::_Rep::_M_destroy ()
#6  0x9281f99d in std::string::_M_mutate ()
#7  0x9281fa44 in std::string::_M_replace_safe ()
#8  0x9281fae8 in std::string::assign ()
#9  0x00015bed in boost::filesystem::detail::get_current_path_api ()
#10 0x00004dee in boost::filesystem::current_path<boost::filesystem::basic_path<std::string, boost::filesystem::path_traits> > ()
#11 0x0000507b in boost::filesystem::initial_path<boost::filesystem::basic_path<std::string, boost::filesystem::path_traits> > ()
#12 0x00001a4b in main ()

Please note that the bug seems to be specific to Mac OS X.

comment:3 by akim.demaille@…, 13 years ago

Severity: ProblemRegression

It is worth noting that Valgrind has the same opinion: something invalid is done. This is Mac OS X 10.5, boost 1.39:

==71960== Memcheck, a memory error detector
==71960== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==71960== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==71960== Command: ./cli
==71960== 
--71960-- ./cli:
--71960-- dSYM directory is missing; consider using --dsymutil=yes
Running 1 test case...

*** No errors detected
==71960== Invalid read of size 4
==71960==    at 0x7969F: __tcf_1 (in /opt/local/lib/libboost_unit_test_framework-mt.dylib)
==71960==    by 0x21FDBB: __cxa_finalize (in /usr/lib/libSystem.B.dylib)
==71960==    by 0x21FCAF: exit (in /usr/lib/libSystem.B.dylib)
==71960==    by 0x198A: (below main) (in ./cli)
==71960==  Address 0x40d684 is 20 bytes inside a block of size 24 free'd
==71960==    at 0x13B1A: operator delete(void*) (vg_replace_malloc.c:346)
==71960==    by 0x7D65E: std::_Rb_tree<unsigned long, std::pair<unsigned long const, boost::unit_test::test_unit*>, std::_Select1st<std::pair<unsigned long const, boost::unit_test::test_unit*> >, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, boost::unit_test::test_unit*> > >::erase(std::_Rb_tree_iterator<std::pair<unsigned long const, boost::unit_test::test_unit*> >, std::_Rb_tree_iterator<std::pair<unsigned long const, boost::unit_test::test_unit*> >) (in /opt/local/lib/libboost_unit_test_framework-mt.dylib)
==71960==    by 0x7D70E: std::_Rb_tree<unsigned long, std::pair<unsigned long const, boost::unit_test::test_unit*>, std::_Select1st<std::pair<unsigned long const, boost::unit_test::test_unit*> >, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, boost::unit_test::test_unit*> > >::erase(unsigned long const&) (in /opt/local/lib/libboost_unit_test_framework-mt.dylib)
==71960==    by 0x7A0E3: boost::unit_test::framework::deregister_test_unit(boost::unit_test::test_unit*) (in /opt/local/lib/libboost_unit_test_framework-mt.dylib)
==71960==    by 0x95219: boost::unit_test::test_unit::~test_unit() (in /opt/local/lib/libboost_unit_test_framework-mt.dylib)
==71960==    by 0x7969B: __tcf_1 (in /opt/local/lib/libboost_unit_test_framework-mt.dylib)
==71960==    by 0x21FDBB: __cxa_finalize (in /usr/lib/libSystem.B.dylib)
==71960==    by 0x21FCAF: exit (in /usr/lib/libSystem.B.dylib)
==71960==    by 0x198A: (below main) (in ./cli)
==71960== 
==71960== 
==71960== HEAP SUMMARY:
==71960==     in use at exit: 4,484 bytes in 11 blocks
==71960==   total heap usage: 61 allocs, 50 frees, 531,099 bytes allocated
==71960== 
==71960== LEAK SUMMARY:
==71960==    definitely lost: 0 bytes in 0 blocks
==71960==    indirectly lost: 0 bytes in 0 blocks
==71960==      possibly lost: 0 bytes in 0 blocks
==71960==    still reachable: 4,104 bytes in 2 blocks
==71960==         suppressed: 380 bytes in 9 blocks
==71960== Rerun with --leak-check=full to see details of leaked memory
==71960== 
==71960== For counts of detected and suppressed errors, rerun with: -v
==71960== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

The problem is now even more acute on Snow Leopard (10.6), with Boost.Test 1.40. Using the same file, and compiled with Apple's GCC-4.2:

$ ./cli
Running 1 test case...

*** No errors detected
cli(38688) malloc: *** error for object 0x30001002034f0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
zsh: abort      ./cli

i.e., the test fails. My whole test suite is red, not a single test passes, because of this problem. If you are still hoping this is some compiler error, I'm afraid to say that GCC 4.5 features the exact same behavior.

The stack trace is beautifully useless. "Of course" it is some destructor that is doing something wrong. But which one is an exercise left to the reader.

#0  0x00007fff8605dbe1 in malloc_error_break ()
#1  0x00007fff85f87203 in free ()
#2  0x0000000100010d62 in __tcf_1 ()
#3  0x00007fff85f933f4 in __cxa_finalize ()
#4  0x00007fff85f9330c in exit ()
#5  0x0000000100001487 in start ()

Changing to regression, as it's getting worse.

comment:4 by Gennadiy Rozental, 13 years ago

Resolution: fixed
Status: newclosed

(In [56467]) apparently compiler might want to examine tu.second twice: before and after calling destructor Fixes #2889 Fixes #3432 Fixes #2647

comment:5 by tegtmeye@…, 13 years ago

Milestone: Boost 1.39.0Boost 1.41.0
Resolution: fixed
Severity: RegressionShowstopper
Status: closedreopened
Version: Boost 1.38.0Boost Release Branch

The following crashes on Mac 10.6. ie completely broken 10.6 v1.40 and trunk

rotor:~ tegtmeye$ g++ boost_test.cc /usr/local/lib/libboost_unit_test_framework.a rotor:~ tegtmeye$ ./a.out Running 4 test cases...

* No errors detected a.out(69716) malloc: * error for object 0x30001002002e0: pointer being freed was not allocated * set a breakpoint in malloc_error_break to debug Abort trap rotor:~ tegtmeye$ cat boost_test.cc #define BOOST_TEST_MODULE footest test #include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE( test1 ) {

BOOST_CHECK( true );

}

BOOST_AUTO_TEST_CASE( test2 ) {

BOOST_CHECK( true );

}

BOOST_AUTO_TEST_CASE( test3 ) {

BOOST_CHECK( true );

}

BOOST_AUTO_TEST_CASE( test4 ) {

BOOST_CHECK( true );

} rotor:~ tegtmeye$ g++ --version i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) Copyright (C) 2007 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rotor:~ tegtmeye$

comment:6 by Ákos Maróy <akos@…>, 13 years ago

Cc: akos@… added

comment:7 by Ákos Maróy <akos@…>, 13 years ago

see also #3635 , a duplicate entry

comment:8 by Gennadiy Rozental, 13 years ago

Resolution: fixed
Status: reopenedclosed

(In [57991]) merge memory fix. Fixes #2889

comment:9 by anonymous, 13 years ago

It seems this was merged into the release branch after the 1.41.0 branch. I hope the fix will be included in the next release. BTW this affects FreeBSD in the very same way.

Note: See TracTickets for help on using tickets.