Crash when call DirectoryIterator::next()


#1

Hello! I scan directory for find files with definite extension in app. And sometimes app crashed.
0 libsystem_kernel.dylib 0x00007fff8e319286 __pthread_kill + 10 1 libsystem_c.dylib 0x00007fff99c7c9b3 abort + 129 2 libc++abi.dylib 0x00007fff902d9a21 abort_message + 257 3 libc++abi.dylib 0x00007fff903019d1 default_terminate_handler() + 267 4 libobjc.A.dylib 0x00007fff94edc7d6 _objc_terminate() + 103 5 libc++abi.dylib 0x00007fff902ff0a1 std::__terminate(void (*)()) + 8 6 libc++abi.dylib 0x00007fff902feb30 __cxa_throw + 121 7 libobjc.A.dylib 0x00007fff94ed8898 objc_exception_throw + 341 8 com.apple.CoreFoundation 0x00007fff90854eed +[NSException raise:format:] + 205 9 com.apple.Foundation 0x00007fff9174b43d -[NSFileManager fileSystemRepresentationWithPath:] + 332 10 com.apple.Foundation 0x00007fff917dba8b -[NSAllDescendantPathsEnumerator nextObject] + 325 11 0x0000000106843914 juce::DirectoryIterator::NativeIterator::Pimpl::next(juce::String&, bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 148 12 0x000000010680a882 juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 626 13 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 14 c 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 15 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 16 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 17 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 18 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 19 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 20 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 21 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 22 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 23 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 24 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 25 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 26 0x000000010680a7eb juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) + 475 27 0x000000010680a601 juce::DirectoryIterator::next() + 33


#2

Can you debug to find out what the file is that it’s trying to scan at that point?


#3

I will try. But it sometimes not crashed. Scan files perform in separate thread.


#4

It does look like a crash deep inside Apple’s code, which is really odd. Not sure there’s anything we could do in JUCE to avoid that, but would be interesting to understand what the circumstances are.


#5

…just one other idea: Are you definitely not doing something silly like deleting the DirectoryIterator on another thread while it’s being used?


#6

DirectoryIterator just local for this thread.
`
for (int i = 0; i < whereToLook.size() && !isStopScanning ; i++)
{

    DirectoryIterator *iterator = new DirectoryIterator(whereToLook[i],
                                                        true,
                                                        globalWildCard, File::findFilesAndDirectories);
    while (getNext(iterator, whereToLook.size(),currentProgress) && !isStopScanning)
    {
        File current = iterator->getFile();
        // ...            
    }        
    delete iterator;
}`

#7

Ouch… that unnecessary heap allocation and use of delete will make a lot of our readers wince!

But yes, it should still work. You’re not accidentally deleting the iterator in some of the code you’ve not included, perhaps?


#8

No. You mean getNext()?
`

bool getNext(DirectoryIterator *iterator, int numOfDirs, double &currentProgress)
{

bool result = iterator->next();
if  (result)
{
    double progressBuffer = progress;
    progressBuffer -= currentProgress;
    currentProgress = iterator->getEstimatedProgress() / numOfDirs;
    progressBuffer += currentProgress;
    progress = progressBuffer;
}
return result;

}`


#9

OK, well I don’t know then.

But please, for your own sake learn to use RAII properly and never use ‘delete’! You’ll write far better code that way.

And FYI if you indent your code by 4 spaces and leave a blank line before it, it’ll show up here with the correct formatting.


#10

I’ve gotten this same crash (highly infrequently) from the File class when I call deleteRecusively();

The crash stack trace lands on the DirectoryIterator::NativeIterator::Pimpl next() function while checking the enumerator for nil, it’s a SIGBUS error:

    bool next (String& filenameFound,
               bool* const isDir, bool* const isHidden, int64* const fileSize,
               Time* const modTime, Time* const creationTime, bool* const isReadOnly)
    {
        JUCE_AUTORELEASEPOOL
        {
            const char* wildcardUTF8 = nullptr;

            for (;;)
            {
                NSString* file;
 **CRASH HERE:**  if (enumerator == nil || (file = [enumerator nextObject]) == nil)
                    return false;

                [enumerator skipDescendents];
                filenameFound = nsStringToJuce (file).convertToPrecomposedUnicode();

                if (wildcardUTF8 == nullptr)
                    wildcardUTF8 = wildCard.toUTF8();

                if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0)
                    continue;

                const String fullPath (parentDir + filenameFound);
                updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly);

                if (isHidden != nullptr)
                    *isHidden = FileHelpers::isHiddenFile (fullPath);

                return true;
            }
        }
    }

The only file types in the folder are .png images & text code files. I don’t think it has to do with the file type as it is working fine 99% of the time.

stack trace:

#9	0x00000001256b444e in juce::DirectoryIterator::NativeIterator::Pimpl::next(juce::String&, bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) at /Users/mumu/Development/Plugins/Test/Builds/MacOSX/../../JuceLibraryCode/modules/juce_core/native/juce_mac_Files.mm:347
#10	0x000000012565264e in juce::DirectoryIterator::NativeIterator::next(juce::String&, bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) at /Users/mumu/Development/Plugins/Test/Builds/MacOSX/../../JuceLibraryCode/modules/juce_core/native/juce_mac_Files.mm:390
#11	0x000000012565214c in juce::DirectoryIterator::next(bool*, bool*, long long*, juce::Time*, juce::Time*, bool*) at /Users/mumu/Development/Plugins/Test/Builds/MacOSX/../../JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.cpp:91
#12	0x0000000125651fd3 in juce::DirectoryIterator::next() at /Users/mumu/Development/Plugins/Test/Builds/MacOSX/../../JuceLibraryCode/modules/juce_core/files/juce_DirectoryIterator.cpp:70
#13	0x0000000125654da7 in juce::File::findChildFiles(juce::Array<juce::File, juce::DummyCriticalSection, 0>&, int, bool, juce::String const&) const at /Users/mumu/Development/Plugins/Test/Builds/MacOSX/../../JuceLibraryCode/modules/juce_core/files/juce_File.cpp:554
#14	0x0000000125654f80 in juce::File::deleteRecursively() const at /Users/mumu/Development/Plugins/Test/Builds/MacOSX/../../JuceLibraryCode/modules/juce_core/files/juce_File.cpp:271