Reputation: 1101
I am building a dynamic library on mac in C++11 using the clang compiler and libc++ standard library. When I run valgrind on my test code which links to my dynamic library I get one block of memory that is definitely lost. Here is the valgrind report:
==45659== 36 bytes in 1 blocks are definitely lost in loss record 57 of 228
==45659== at 0x66BB: malloc (vg_replace_malloc.c:300)
==45659== by 0x31EAB0: __Balloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==45659== by 0x31F2A5: __d2b_D2A (in /usr/lib/system/libsystem_c.dylib)
==45659== by 0x31BED6: __dtoa (in /usr/lib/system/libsystem_c.dylib)
==45659== by 0x3438A9: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==45659== by 0x36A2DA: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==45659== by 0x34FF66: _vsnprintf (in /usr/lib/system/libsystem_c.dylib)
==45659== by 0x34FFC5: vsnprintf_l (in /usr/lib/system/libsystem_c.dylib)
==45659== by 0x34057A: snprintf_l (in /usr/lib/system/libsystem_c.dylib)
==45659== by 0x10C75A: std::__1::num_put<char, std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > >::do_put(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, std::__1::ios_base&, char, double) const (in /usr/lib/libc++.1.dylib)
==45659== by 0xF3221: std::__1::basic_ostream<char, std::__1::char_traits<char> >::operator<<(double) (in /usr/lib/libc++.1.dylib)
==45659== by 0x12102: lmpsdata::header_data::write_dimension(std::__1::basic_ofstream<char, std::__1::char_traits<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) (header_data.cpp:75)
==45659==
==45659== LEAK SUMMARY:
==45659== definitely lost: 36 bytes in 1 blocks
==45659== indirectly lost: 0 bytes in 0 blocks
==45659== possibly lost: 0 bytes in 0 blocks
==45659== still reachable: 18,340 bytes in 215 blocks
==45659== suppressed: 25,274 bytes in 374 blocks
That particular section of code does not deal with any memory I have dynamically allocated, only STL objects and streams are used. I have attached both the header file and the method reported by valgrind as causing the leak. Can someone please explain what is going on here? I am absolutely baffled.
header_data.h
#ifndef ____header_data__
#define ____header_data__
#include <string>
#include <fstream>
#include <cstdint>
#include <vector>
#include <map>
namespace lmpsdata {
class header_data
{//LAMMPS header information
//only the point particle header information has been implemented
//since the current atom base class is designed for point particles only
public:
header_data():xdim(2), ydim(2), zdim(2), tiltdim(3) {}
//methods
void read(const std::string &, const std::string &);
void write(std::ofstream &, const std::string &); //this write command will replace the one
std::string check_header_keyword(const std::string &, bool &);
uint64_t get(const std::string&);
std::vector<double>& get_vector(const std::string&);
void set(const std::string&, uint64_t);
void set_vector(const std::string&, std::vector<double>&);
private:
//methods
void read_dimension(const std::string&, const std::string&);
void write_dimension(std::ofstream&, const std::string&);
//members
uint64_t atomnum;
uint64_t bondnum;
uint64_t anglenum;
uint64_t dihedralnum;
uint64_t impropernum;
uint64_t atomtypenum;
uint64_t bondtypenum;
uint64_t angletypenum;
uint64_t dihedraltypenum;
uint64_t impropertypenum;
uint64_t extrabondnum;
std::vector<double> xdim;
std::vector<double> ydim;
std::vector<double> zdim;
std::vector<double> tiltdim;//for use with triclinic system
std::map<std::string, uint64_t&> int_map {
{"atoms", atomnum},
{"bonds", bondnum},
{"angles", anglenum},
{"dihedrals", dihedralnum},
{"impropers", impropernum},
{"atom types", atomtypenum},
{"bond types", bondtypenum},
{"angle types", angletypenum},
{"dihedral types", dihedraltypenum},
{"improper types", impropertypenum},
{"extra bond per atom", extrabondnum},
};
std::map<std::string, std::vector<double>&> v_map {
{"xlo xhi", xdim},
{"ylo yhi", ydim},
{"zlo zhi", zdim},
{"xy xz yz", tiltdim}
};
};
}
#endif /* defined(____header_data__) */
lmpsdata.cpp only write_dimension method and beginning of file is shown
#include "header_data.h"
#include <stdexcept>
using namespace lmpsdata;
void header_data::write_dimension(std::ofstream &file, const std::string& keyword)
{
std::vector<double>& data = v_map.at(keyword);
for (auto value: data) {
file << value << " ";
}
}
If more information is needed please let me know.
Upvotes: 2
Views: 853
Reputation: 94829
You have not mentioned the exact versions of OSX and valgrind that you're using. I've not been able to entirely reproduce this on the version that I'm using (OSX 10.10; valgrind HEAD==Valgrind-3.11.0.SVN).
This is not in the C++
standard library, but in the C
library. You should be able to reproduce it (almost identically) with the simple code:
#include <stdio.h>
#include <xlocale.h>
int
main(int argc, char **argv)
{
locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
double d = 22.22;
char buffer[1024];
snprintf_l(buffer, 1024, loc, "%f\n", d);
printf("%s", buffer);
freelocale(loc);
}
When run with valgrind --show-leak-kinds=all --leak-check=full ./leak
I see some 'still reachable' leaks (yours should show actual leaks in this case):
==26151== 32 bytes in 1 blocks are still reachable in loss record 28 of 85
==26151== at 0x10000850B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==26151== by 0x1002BC7DF: __Balloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002B9533: __rv_alloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002B9B3A: __dtoa (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002E1D52: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x10030A9AE: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002EF154: _vsnprintf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002EF1B3: vsnprintf_l (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002DF5F7: snprintf_l (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x100000ECA: main (leak.cpp:10)
==26151==
==26151== 36 bytes in 1 blocks are still reachable in loss record 30 of 85
==26151== at 0x10000850B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==26151== by 0x1002BC7DF: __Balloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002BD055: __d2b_D2A (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002B986B: __dtoa (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002E1D52: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x10030A9AE: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002EF154: _vsnprintf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002EF1B3: vsnprintf_l (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002DF5F7: snprintf_l (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x100000ECA: main (leak.cpp:10)
==26151==
==26151== 80 bytes in 1 blocks are still reachable in loss record 47 of 85
==26151== at 0x10000850B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==26151== by 0x1002BC736: __Balloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002BD055: __d2b_D2A (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002B986B: __dtoa (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002E1D52: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x10030A9AE: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002EF154: _vsnprintf (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002EF1B3: vsnprintf_l (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x1002DF5F7: snprintf_l (in /usr/lib/system/libsystem_c.dylib)
==26151== by 0x100000ECA: main (leak.cpp:10)
I'd put in a suppression for it, as it's almost undoubtably not a real leak and is completely out of your control.
looking at the published OSX libc source, I can't see where the bug is present - 320 and later all look OK; with the underlying code appearing to allocate and free where necessary. The bug may have been introduced and fixed, though, as I didn't perform an exhaustive trawl of all the sources; the file in question is vfprintf.c, you're looking at the dtoaresult
assignments & frees.
To determine your version of libc, you can do:
$ otool -l /usr/lib/system/libsystem_c.dylib | grep -A5 ID_
On my system I get the output:
cmd LC_ID_DYLIB
cmdsize 64
name /usr/lib/system/libsystem_c.dylib (offset 24)
time stamp 1 Thu Jan 1 01:00:01 1970
current version 1044.10.1
compatibility version 1.0.0
997, I think, is mavericks (10.9). I don't know if they introduced a leak in the code at some point in the mavericks timeframe and then fixed it - there doesn't appear to be a code path in the __vfprintf
routine that actually leaks in any of the published source.
Upvotes: 1