Lock disposal of separate gdi+ objects under different threads since this prevents malloc heap corruption seen under Ubuntu 10.04.1 and 11.04 - probably a libcairo issue

In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
the native malloc heap can become corrupted, possibly due to a double free().  This may be due to
bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX.  These problems were
seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1.  They go away if disposal is perfomed
under lock.
integration
Justin Clark-Casey (justincc) 2012-08-22 23:04:17 +01:00
parent 568de9313a
commit 1369058280
1 changed files with 43 additions and 27 deletions

View File

@ -308,36 +308,44 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
try try
{ {
if (alpha == 256) // XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb); // the native malloc heap can become corrupted, possibly due to a double free(). This may be due to
else // bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were
bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); // seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed
// under lock.
graph = Graphics.FromImage(bitmap); lock (this)
// this is really just to save people filling the
// background color in their scripts, only do when fully opaque
if (alpha >= 255)
{ {
using (SolidBrush bgFillBrush = new SolidBrush(bgColor)) if (alpha == 256)
{ bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
graph.FillRectangle(bgFillBrush, 0, 0, width, height); else
} bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
}
for (int w = 0; w < bitmap.Width; w++) graph = Graphics.FromImage(bitmap);
{
if (alpha <= 255) // this is really just to save people filling the
// background color in their scripts, only do when fully opaque
if (alpha >= 255)
{ {
for (int h = 0; h < bitmap.Height; h++) using (SolidBrush bgFillBrush = new SolidBrush(bgColor))
{ {
bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h))); graph.FillRectangle(bgFillBrush, 0, 0, width, height);
} }
} }
for (int w = 0; w < bitmap.Width; w++)
{
if (alpha <= 255)
{
for (int h = 0; h < bitmap.Height; h++)
{
bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h)));
}
}
}
GDIDraw(data, graph, altDataDelim);
} }
GDIDraw(data, graph, altDataDelim);
byte[] imageJ2000 = new byte[0]; byte[] imageJ2000 = new byte[0];
try try
@ -355,11 +363,19 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
} }
finally finally
{ {
if (graph != null) // XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
graph.Dispose(); // the native malloc heap can become corrupted, possibly due to a double free(). This may be due to
// bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were
if (bitmap != null) // seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed
bitmap.Dispose(); // under lock.
lock (this)
{
if (graph != null)
graph.Dispose();
if (bitmap != null)
bitmap.Dispose();
}
} }
} }