2

I found a very weird bug when using FileInfo.Delete() or Directory.Delete(path, true) after copying a folder.

Problem:

  • Copy a folder containing many files and a few subfolders recursively
  • Try to delete the original folder recursively
  • Exactly on the third file inside the folder, the application will crash without throwing an Exception
  • It's not always the same file, as the first two get deleted normally, the third fails. (If I try again, the first will be the one that failed last, and will be succesfully deleted)

Reproduction:

In a WPF application, a button with the following methods cause the crash (later I'll try to reproduce in a Console Application):

private void Tester_Click(object sender, RoutedEventArgs e)
{
    string copyFolderToThisPath = @"C:\Users\xxx\Desktop\xxxx\xxxx_xxx - Copia";
    string copyAndDeleteThisFolder = @"C:\Users\xxx\Desktop\xxxx\Prov\Nova pasta (3)";

    //copy the directory recursively: works
    CopyOrDeleteDirectory(new DirectoryInfo(copyAndDeleteThisFolder), copyFolderToThisPath);

    //delete the directory recursively: fails at the third file of the main folder - always
    CopyOrDeleteDirectory(new DirectoryInfo(copyAndDeleteThisFolder), null);
}

Recursive copy or delete:
(I know that Directory.Delete(path, true) exists, but it also fails, I created recursive deletion to check what was going on)

/// <summary>
/// Copies or deletes a directory recursively - Use copyToPath == null to delete
/// </summary>
/// <param name="copyToPath">Destination to copy. If null, will delete the directory</param>
/// <returns>true if all operations with this directory were successful</returns>
private bool CopyOrDeleteDirectory(DirectoryInfo directory, string copyToPath)
{
    bool isCopy = !string.IsNullOrEmpty(copyToPath); //defines if the method will copy or delete

    FileInfo[] files = null;
    DirectoryInfo[] dirs = null;

    //try get files and subdirectories
    try
    {
        files = directory.GetFiles();
        dirs = directory.GetDirectories();

        if (isCopy)
            Directory.CreateDirectory(copyToPath);
    }
    catch (Exception e)
    {
        MessageBox.Show("Could not enumerate folder " + directory.Name);
        return false;
    }
    

    bool success = true;

    //copy or delete files
    foreach (FileInfo file in files)
    {
        try
        {
            if (isCopy)
                file.CopyTo(System.IO.Path.Combine(copyToPath, file.Name));
            else
                file.Delete(); //exactly at the third iteration it will crash the application
        }
        catch (Exception e) //the exception will NEVER be thrown!! Catch block is not reached
        {
            MessageBox.Show("Failed to operate file " + file.Name);
            success = false;
        }
    }


    //copy or delete subdirectories
    foreach (DirectoryInfo d in dirs)
    {
        try
        {
            string subPath = isCopy ? System.IO.Path.Combine(copyToPath, d.Name) : null;
            bool subDirSuccess = CopyOrDeleteDirectory(d, subPath);

            if (!subDirSuccess)
                success = false;
        }
        catch (StackOverflowException ex)
        {
            MessageBox.Show("StackOverflow in recursive function");
            success = false;
        }
    }

    if (success && (!isCopy))
    {
        try
        {
            directory.Delete();
        }
        catch (Exception e)
        {
            MessageBox.Show("Failed to delete directory " + directory.Name);
            success = false;
        }
    }

    return success;
}

Important details:

  • This is a "bug reproduction" code. The original application is bigger, and there is interaction with the user between the copy and the deletion. This "copy and delete" is not the normal flow of the application, but the user may do this by calling two different commands of the application
  • There is a time interval with the application fully responsive between the user clicking copy and clicking delete. The copy operation is completed before the user can do anything else.
  • The problem does not happen if only the delete command is called, it will happen if there is a copy first
  • I tried freeing the resources, but it doesn't seem that it's possible for FileInfo and DirectoryInfo. Anyway I tried setting everything to null everywhere as soon as possible, no success.
  • No Exception is thrown, the application fully crashes
  • All files are accessible, none of them are read only
  • Windows 10
  • WPF application with C#
  • Visual Studio 2017 debugging (The problem happens either stepping or not)
Daniel Möller
  • 84,878
  • 18
  • 192
  • 214
  • Anything interesting in the Event Viewer? – Victor Wilson Jun 20 '21 at 02:18
  • I tried the same code and it is working for me. Only difference is I am using VS2019. Can you let us know why you are calling same method two time. This can be done in single call only. – Amit Verma Jun 20 '21 at 02:26
  • Is there a requirement to copy and then delete? You can just use `MoveTo`, which will surely simplify your code – Timur Umerov Jun 20 '21 at 02:39
  • Have you turned on "Break when thrown" in the Debug menu>>Exception settings (put a tick next to CLR). My guess is some background worker thread is getting an exception and you're not seeing the "Exception has been thrown by the target of an invocation", it's just killing the app – Caius Jard Jun 20 '21 at 04:04
  • For those asking "why" I'm doing it like this, it's well explained in the question. – Daniel Möller Jun 20 '21 at 13:41
  • Have you tried putting a `try/catch` *outside* the `foreach`? My guess is that deleting is messing up the enumeration. You may need to fully read the list of files first. – Charlieface Jun 20 '21 at 19:51
  • @VictorWilson, I don't think I have an "Events Viewer", is it something only available in "pro" versions? I use a community version. – Daniel Möller Jun 21 '21 at 03:35
  • 1
    @DanielMöller Sorry, I meant the Windows Event Viewer. It has proven to be very useful in debugging these kind of full-crash problems. – Victor Wilson Jun 21 '21 at 17:44
  • Did you ever get a resolution to this? I'm having this exact problem. We have a windows service that FTPs a file and then deletes the local and it kills the services on the third attempt without catching anywhere. – Joe Schmeltzer Dec 03 '21 at 21:17
  • Sorry, @JoeSchmeltzer , I never got a solution. But I didn't try the event viewer suggestion, though. It sounded too complex to learn for something that would happen very rarely in my case. – Daniel Möller Dec 03 '21 at 21:38

1 Answers1

1

This could help perhaps:

C# app exits without exception when deleting a temp file

I had the same problem, always on the third file. The moment I disabled Trend Micro everything worked.

stefan
  • 31
  • 4
  • 1
    Very interesting. Indeed the machine where I saw the problem had Trend Micro running. Unfortunately I cannot test this anymore, but you might have found the answer to my problem as well – Daniel Möller Apr 04 '22 at 17:13
  • Too bad you cannot test it anymore but this could have been the answer. Never found out why Trend Micro was just killing the application without an exception though – stefan Apr 05 '22 at 10:02