lundi 26 juillet 2021

std::string::append crashes program with "std::bad_alloc"

I have a text file which contains a list of data relating to name, position, and height. My program parses this data into a vector map, then uses this data to construct an xml file using boost::property_tree. The text file is about 3500 lines, and the program consistently crashes at line 1773 with:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

At first I thought maybe the size limit was being reached, but reading up on std::string shows that the target computer should be able to allocate the size required. Regardless, I decided to test with std::string::size , std::string::length, std::string::capacity, std::string::max_size which showed (respectively):

...
...
6572094845  6572094845 6626476032 9223372036854775807
6579537815  6579537815 6626476032 9223372036854775807
6586984998  6586984998 6626476032 9223372036854775807
6594436394  6594436394 6626476032 9223372036854775807
6601892003  6601892003 6626476032 9223372036854775807
6609351825  6609351825 6626476032 9223372036854775807
6616815856  6616815856 6626476032 9223372036854775807
6624284100  6624284100 6626476032 9223372036854775807

std::string::capacity was seen to increase once std::string::length == std::string::capacity.

gdb bt after compiling for debug:

(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007fd67037e921 in __GI_abort () at abort.c:79
#2  0x00007fd6709d3957 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007fd6709d9ae6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007fd6709d9b21 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007fd6709d9d54 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007fd6709da2dc in operator new(unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007fd670a6bb8b in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8  0x00007fd670a6d133 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_append(char const*, unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9  0x000056104c176f3a in main (argc=1, argv=0x7ffc0af8b9a8) at /home/code/hello_world/createWorld.cpp:224

Example line in text file being read:

713.258 235.418 ABCD1234567     2898

Code:

int main(int argc, char **argv)
{
    CreateWorld *newWorld = new CreateWorld();
    lastModelsParser *lastModels = new lastModelsParser();

    const string filenameModel = "model.sdf";
    const string fileNameWorld = "TEMPLATE_default_world.xml";
    string lastModels = "lastmodels.txt";
    
    ptree ptWorld, ptModel, ptNewWorld, ptNewModel;

    std::ifstream ifsModel(filenameModel,std::ifstream::binary);
    std::ifstream ifsWorld(fileNameWorld,std::ifstream::binary);
    std::ofstream newWorldFile("NEW_WORLD.xml");

    std::ostringstream worldOSS, modelOSS, newWorldOSS;

    read_xml(ifsWorld, ptWorld, boost::property_tree::xml_parser::trim_whitespace);         // read xml data into ptree
    read_xml(ifsModel, ptModel, boost::property_tree::xml_parser::trim_whitespace);         // read xml data into ptree

    vector<lastModelsParser::lastModel> _lastModels;

    lastModels->ParseToXML(lastModelsFile);
    _lastModels = lastModels->getlastModels();

    uint16_t lastModelsEntry = 0;
    std::string newModelString;

    for(auto i:_lastModels){
        ptNewModel = newWorld->modelModifier(ptModel, 
            _lastModels.at(lastModelsEntry).pX,
            _lastModels.at(lastModelsEntry).pY,
            _lastModels.at(lastModelsEntry).name, 
            _lastModels.at(lastModelsEntry).height);

        boost::property_tree::xml_parser::write_xml_element(modelOSS, ptNewModel.front().first, ptNewModel.back().second, 1, xml_settings);
        
        newModelString.append(modelOSS.str());              // CRASHES HERE 
 
        lastModelsEntry++;        
    }

    // append to world.xml
    boost::property_tree::write_xml(worldOSS, ptWorld, xml_settings);           // write xml data into OSStreams
    boost::property_tree::write_xml(modelOSS, ptModel, xml_settings);           // write xml data into OSStreams   
    size_t worldPos = worldOSS.str().find("</world>");

    std::string newWorldString = worldOSS.str().insert(worldPos,newModelString+"\n\t");

    newWorldFile << newWorldString ;
    

    delete(lastModels);
    delete(newWorld);

    return EXIT_SUCCESS;
}                                                                                                                                                                                                                           

Edit. Valgrind output

  1. valgrind --tool=massif --massif-out-file=memleak.txt ./createNewWorld
heap_tree=detailed
n2: 6636657886 (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
 n2: 6626476282 0x5160B89: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
  n2: 6626476282 0x5162131: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_append(char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
   n0: 6626476033 0x149F38: main (in /home/code/hello_world/createNewWorld)
   n0: 249 in 2 places, all below massif's threshold (1.00%)
  n0: 0 in 2 places, all below massif's threshold (1.00%)
 n0: 10181604 in 18 places, all below massif's threshold (1.00%)
  1. valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out_1.txt ./createNewWorld
...
--4758-- memcheck GC: 1000 nodes, 0 survivors (0.0%)
--4758-- memcheck GC: 1000 nodes, 0 survivors (0.0%)
--4758-- memcheck GC: 1000 nodes, 0 survivors (0.0%)
--4758-- memcheck GC: 1000 nodes, 0 survivors (0.0%)
==4758== Warning: set address range perms: large range [0xee015040, 0x1b37d5041) (undefined)

Aucun commentaire:

Enregistrer un commentaire