opensim-org / opensim-core

SimTK OpenSim C++ libraries and command-line applications, and Java/Python wrapping.
https://opensim.stanford.edu
Apache License 2.0
778 stars 310 forks source link

Loading `Model`s from XML causes memory leaks #3537

Open nickbianco opened 1 year ago

nickbianco commented 1 year ago

Detectable via memory leak tools (e.g., libASAN).

adamkewley commented 1 year ago

Initial investigation (here) found that this is probably the culprit:

Here is an example reproduction of the leak from OpenSim (it's in simbody, but here is how it manifests via the OpenSim API):

#!/usr/bin/env bash
set -xeuo pipefail

# get sources + models
git clone https://github.com/opensim-org/opensim-core
git clone https://github.com/opensim-org/opensim-models

# configure + build deps with libASAN
CCFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address cmake -S opensim-core/dependencies/ -B osim-deps-libasan-build -DCMAKE_INSTALL_PREFIX=${PWD}/osim-deps-libasan-install
cmake --build osim-deps-libasan-build/ -j$(nproc)

# bodge a test script over an existing binary in OpenSim
cat << EOF > opensim-core/OpenSim/Tests/Wrapping/testWrapping.cpp
#include <OpenSim/Simulation/Model/Model.h>

int main(int argc, char* argv[]) {
    for (int i = 1; i < argc; ++i) {
        OpenSim::Model{argv[i]};
    }
    return 0;
}
EOF

# configure + build the bodged binary with libASAN
CCFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address cmake -S opensim-core -B osim-libasan-build -DOPENSIM_DEPENDENCIES_DIR=${PWD}/osim-deps-libasan-install -DOPENSIM_WITH_CASADI=OFF -DOPENSIM_WITH_TROPTER=OFF -DBUILD_API_ONLY=ON
cmake --build osim-libasan-build --target testWrapping -j$(nproc)

./osim-libasan-build/testWrapping opensim-models/Models/RajagopalModel/Rajagopal2015.osim

Example output (./osim-libasan-build/testWrapping opensim-models/Models/RajagopalModel/Rajagopal2015.osim):

=================================================================
==17784==ERROR: LeakSanitizer: detected memory leaks

Indirect leak of 231984 byte(s) in 1074 object(s) allocated from:
    #0 0x7f0e614871e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7f0e5bb73f31 in SimTK::TiXmlNode::Identify(char const*, SimTK::TiXmlEncoding) /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/src/tinyxmlparser.cpp:943

Indirect leak of 91208 byte(s) in 877 object(s) allocated from:
    #0 0x7f0e614871e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7f0e5bb73b63 in SimTK::TiXmlNode::Identify(char const*, SimTK::TiXmlEncoding) /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/src/tinyxmlparser.cpp:919

Indirect leak of 84920 byte(s) in 1070 object(s) allocated from:
    #0 0x7f0e614871e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7f0e5afd90bd in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (/lib/x86_64-linux-gnu/libstdc++.so.6+0x14c0bd)

Indirect leak of 74368 byte(s) in 664 object(s) allocated from:
    #0 0x7f0e614871e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7f0e5bb7c521 in SimTK::TiXmlElement::ReadValue(char const*, SimTK::TiXmlParsingData*, SimTK::TiXmlEncoding) /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/src/tinyxmlparser.cpp:1248

Indirect leak of 10152 byte(s) in 47 object(s) allocated from:
    #0 0x7f0e614871e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7f0e5bb6bc6d in SimTK::TiXmlElement::Clone() const /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/src/tinyxml.cpp:993

Indirect leak of 4816 byte(s) in 43 object(s) allocated from:
    #0 0x7f0e614871e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7f0e5bb65fda in SimTK::TiXmlText::Clone() const /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/src/tinyxml.cpp:1527

Indirect leak of 520 byte(s) in 5 object(s) allocated from:
    #0 0x7f0e614871e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7f0e5bb65e77 in SimTK::TiXmlComment::Clone() const /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/src/tinyxml.cpp:1473

Indirect leak of 380 byte(s) in 6 object(s) allocated from:
    #0 0x7f0e614871e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x7f0e5bb5d66e in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) /usr/include/c++/11/bits/basic_string.tcc:219
    #2 0x7f0e5bb5d66e in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) /usr/include/c++/11/bits/basic_string.h:539
    #3 0x7f0e5bb5d66e in SimTK::String::String(char const*) /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/./include/SimTKcommon/internal/String.h:71
    #4 0x7f0e5bb5d66e in SimTK::TiXmlNode::SetValue(char const*) /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/src/tinyxml.h:526
    #5 0x7f0e5bb5d66e in SimTK::TiXmlNode::CopyTo(SimTK::TiXmlNode*) const /home/adam/iss3537/opensim-core/dependencies/simbody/SimTKcommon/src/tinyxml.cpp:205

SUMMARY: AddressSanitizer: 498348 byte(s) leaked in 3786 allocation(s).