简体   繁体   中英

EXC_BAD_ACCESS - C++ substr function

I have a function that uses c++ substr. This function sometimes randomly crashes at the end of the program (when called from a separate thread) on Linux and macOS.

Here is the function:

bool mkpath( string path )
{
bool bSuccess = false;
int nRC = ::mkdir( path.c_str(), 0775 );
if( nRC == -1 )
{
    switch( errno )
    {
        case ENOENT:
            //parent didn't exist, try to create it
            if( mkpath( path.substr(0, path.find_last_of('/')) ) )
            {
                //Now, try to create again.
                int status = ::mkdir( path.c_str(), 0775 );
                bSuccess = (0 == status || errno == EEXIST);
            }
            else
            {
                bSuccess = false;
            }
            break;
        case EEXIST:
            //Done!
            bSuccess = true;
            break;
        default:
            bSuccess = false;
            break;
    }
}
else
    bSuccess = true;
return bSuccess;
}

The lldb backtrace is as follows:

* thread #4, stop reason = EXC_BAD_ACCESS (code=2, address=0x70000097fff8)
* frame #0: 0x00007fff73d2a81a libsystem_malloc.dylib`tiny_malloc_from_free_list + 8
frame #1: 0x00007fff73d2a297 libsystem_malloc.dylib`tiny_malloc_should_clear + 288
frame #2: 0x00007fff73d290c6 libsystem_malloc.dylib`szone_malloc_should_clear + 66
frame #3: 0x00007fff73d27d7a libsystem_malloc.dylib`malloc_zone_malloc + 104
frame #4: 0x00007fff73d27cf5 libsystem_malloc.dylib`malloc + 21
frame #5: 0x00007fff70ea0dea libc++abi.dylib`operator new(unsigned long) + 26
frame #6: 0x00007fff70e73d70 libc++.1.dylib`std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> 
>::basic_string(std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> > const&, unsigned long, unsigned long, std::__1::allocator<char> 
const&) + 132
frame #7: 0x0000000103821467 libSampleLibrary.dylib`std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >::substr(unsigned long, unsigned 
long) const + 87
frame #8: 0x0000000103820c77 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 135
frame #9: 0x0000000103820c80 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 144
frame #10: 0x0000000103820c80 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 144
frame #11: 0x0000000103820c80 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 144
frame #12: 0x0000000103820c80 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 144
frame #13: 0x0000000103820c80 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 144
frame #14: 0x0000000103820c80 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 144
frame #15: 0x0000000103820c80 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 144
...

Any possible reason why this could happen? The thread from where this is called can be canceled from outside as we have added

pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

at the first line in function from where this function gets called.

Whenever this crash occurs I see the following line in the backtrace more the 5400 times which is very surprising:

frame #15: 0x0000000103820c80 libSampleLibrary.dylib`mkpath(std::__1::basic_string<char, 
std::__1::char_traits<char>, std::__1::allocator<char> >) + 144

I further debugged and it turned out a static variable (homePath) gets corrupted (returns junk). The mkpath() function gets it value from the following function:

string GetSettingFilePath()
{
    static string homePath = "";
    if(!homePath.empty()){
        
        // sometimes homePath variable returns junk at the program exit
        return homePath;
    }

    struct passwd* pwd = getpwuid(getuid());

    if (pwd)
    {
        homePath = pwd->pw_dir;
    }
    else
    {
        // try the $HOME environment variable
        homePath = getenv("HOME");
    }
    if (homePath.empty())
    {
        homePath = "./";
    }
    return homePath
}

Since homePath variable returns junk sometimes at the program exit though it is set correctly, it caused infinite recursion. But why this static variable inside the function returns junk when called at the program exit.

If you call mkpath recursively, and the string in path doesn't have a slash / . then you will have infinite recursion.

The recursion will be infinite as you will call mkpath with the exact same argument it was already called with.

You should check if path really have a slash / before doing the recursive call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM