From 1369058280c4cf399d46df1508b80cad99f1247e Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Wed, 22 Aug 2012 23:04:17 +0100
Subject: 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.
---
 .../Scripting/VectorRender/VectorRenderModule.cs   | 68 +++++++++++++---------
 1 file changed, 42 insertions(+), 26 deletions(-)

(limited to 'OpenSim/Region')

diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
index ca320e1..c48a703 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
@@ -308,36 +308,44 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
 
             try
             {
-                if (alpha == 256)
-                    bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
-                else
-                    bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
-
-                graph = Graphics.FromImage(bitmap);
-    
-                // this is really just to save people filling the 
-                // background color in their scripts, only do when fully opaque
-                if (alpha >= 255)
+                // XXX: 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.
+                lock (this)
                 {
-                    using (SolidBrush bgFillBrush = new SolidBrush(bgColor))
+                    if (alpha == 256)
+                        bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
+                    else
+                        bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
+    
+                    graph = Graphics.FromImage(bitmap);
+        
+                    // this is really just to save people filling the 
+                    // background color in their scripts, only do when fully opaque
+                    if (alpha >= 255)
                     {
-                        graph.FillRectangle(bgFillBrush, 0, 0, width, height);
+                        using (SolidBrush bgFillBrush = new SolidBrush(bgColor))
+                        {
+                            graph.FillRectangle(bgFillBrush, 0, 0, width, height);
+                        }
                     }
-                }
-    
-                for (int w = 0; w < bitmap.Width; w++)
-                {
-                    if (alpha <= 255) 
+        
+                    for (int w = 0; w < bitmap.Width; w++)
                     {
-                        for (int h = 0; h < bitmap.Height; h++)
+                        if (alpha <= 255) 
                         {
-                            bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h)));
+                            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];
     
                 try
@@ -355,11 +363,19 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
             }
             finally
             {
-                if (graph != null)
-                    graph.Dispose();
-
-                if (bitmap != null)
-                    bitmap.Dispose();
+                // XXX: 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.
+                lock (this)
+                {
+                    if (graph != null)
+                        graph.Dispose();
+    
+                    if (bitmap != null)
+                        bitmap.Dispose();
+                }
             }
         }
         
-- 
cgit v1.1