streamWriterBufferedDataLost MDA

The streamWriterBufferedDataLost managed debugging assistant (MDA) is activated when a StreamWriter is written to, but the Flush or Close method is not subsequently called before the instance of the StreamWriter is destroyed. When this MDA is enabled, the runtime determines whether any buffered data still exists within the StreamWriter. If buffered data does exist, the MDA is activated. Calling the Collect and WaitForPendingFinalizers methods can force finalizers to run. Finalizers will otherwise run at seemingly arbitrary times, and possibly not at all on process exit. Explicitly running finalizers with this MDA enabled will help to more reliably reproduce this type of problem.

Symptoms

A StreamWriter does not write the last 1–4 KB of data to a file.

Cause

The StreamWriter buffers data internally, which requires that the Close or Flush method be called to write the buffered data to the underlying data store. If Close or Flush is not appropriately called, data buffered in the StreamWriter instance might not be written as expected.

The following is an example of poorly written code that this MDA should catch.

// Poorly written code.  
void Write()
{  
    StreamWriter sw = new StreamWriter("file.txt");  
    sw.WriteLine("Data");  
    // Problem: forgot to close the StreamWriter.  
}  

The preceding code will activate this MDA more reliably if a garbage collection is triggered and then suspended until finalizers have finished. To track down this type of problem, you can add the following code to the end of the preceding method in a debug build. This will help to reliably activate the MDA, but of course it does not fix the cause of the problem.

GC.Collect();  
GC.WaitForPendingFinalizers();  

Resolution

Make sure you call Close or Flush on the StreamWriter before closing an application or any code block that has an instance of a StreamWriter. One of the best mechanisms for achieving this is creating the instance with a C# using block (Using in Visual Basic), which will ensure the Dispose method for the writer is invoked, resulting in the instance being correctly closed.

using(StreamWriter sw = new StreamWriter("file.txt"))
{  
    sw.WriteLine("Data");  
}  

The following code shows the same solution, using try/finally instead of using.

StreamWriter sw;  
try
{  
    sw = new StreamWriter("file.txt"));  
    sw.WriteLine("Data");  
}  
finally
{  
    if (sw != null)  
        sw.Close();  
}  

If neither of these solutions can be used (for example, if a StreamWriter is stored in a static variable and you cannot easily run code at the end of its lifetime), then calling Flush on the StreamWriter after its last use or setting the AutoFlush property to true before its first use should avoid this problem.

private static StreamWriter log;  
// static class constructor.  
static WriteToFile()
{  
    StreamWriter sw = new StreamWriter("log.txt");  
    sw.AutoFlush = true;  
  
    // Publish the StreamWriter for other threads.  
    log = sw;  
}  

Effect on the Runtime

This MDA has no effect on the runtime.

Output

A message indicating that this violation occurred.

Configuration

<mdaConfig>  
  <assistants>  
    <streamWriterBufferedDataLost />  
  </assistants>  
</mdaConfig>  

See also