Installing KB5006729 Security patch breaks Pen(Brush brush, float width) constructor when width is 0

%3CLINGO-SUB%20id%3D%22lingo-sub-2856820%22%20slang%3D%22en-US%22%3EInstalling%20KB5006729%20Security%20patch%20breaks%20Pen(Brush%20brush%2C%20float%20width)%20constructor%20when%20width%20is%200%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2856820%22%20slang%3D%22en-US%22%3E%3CP%3EHello%2C%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EAfter%20the%20installing%20KB5006729%20Security%20only%20patch%20for%20server%202012R2%26nbsp%3Bit%20breaks%20the%20.Net%20constructor%20for%20public%20Pen(Brush%20brush%2C%20float%20width)%20where%20width%20is%20passed%20as%200f%20value.%3C%2FP%3E%3CP%3E%3CBR%20%2F%3Ethis%20constructor%20calls%26nbsp%3B%20gdiplus.dll%20method%20(the%20bug%20actually%20is%20with%20following%20function)%3C%2FP%3E%3CP%3ESafeNativeMethods.Gdip.GdipCreatePen2(new%20HandleRef((object)%20brush%2C%20brush.NativeBrush)%2C%20width%2C%200%2C%20out%20pen)%3B%3C%2FP%3E%3CP%3Ereturns%20a%20pen%20with%20value%20of%201f%26nbsp%3B%20if%20the%20width%20has%20been%20passed%20in%20as%20zero(0)%20value.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EFor%20example%3A%3C%2FP%3E%3CP%3Evar%20pen%20%3D%20new%20Pen(SystemBrushes.WindowText%2C%200f)%3C%2FP%3E%3CP%3Ethe%20pen.Width%20is%20returned%20as%20value%201.%20So%20the%20returned%20pen%20has%20a%20width%20of%201%20rather%20than%20expected%20value%20of%200.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3Econstructor%20snipped%3A%3C%2FP%3E%3CP%3Efrom%20System.Drawing.Pen%3C%2FP%3E%3CP%3Epublic%20Pen(Brush%20brush%2C%20float%20width)%3CBR%20%2F%3E%7B%3CBR%20%2F%3EIntPtr%20pen%20%3D%20IntPtr.Zero%3B%3CBR%20%2F%3Eif%20(brush%20%3D%3D%20null)%3CBR%20%2F%3Ethrow%20new%20ArgumentNullException(nameof%20(brush))%3B%3CBR%20%2F%3Eint%20pen2%20%3D%20SafeNativeMethods.Gdip.GdipCreatePen2(new%20HandleRef((object)%20brush%2C%20brush.NativeBrush)%2C%20width%2C%200%2C%20out%20pen)%3B%3CBR%20%2F%3Eif%20(pen2%20!%3D%200)%3CBR%20%2F%3Ethrow%20SafeNativeMethods.Gdip.StatusException(pen2)%3B%3CBR%20%2F%3Ethis.SetNativePen(pen)%3B%3CBR%20%2F%3E%7D%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3Efrom%20System.Drawing.SafeNativeMethods.Gdip%3C%2FP%3E%3CP%3E%5BDllImport(%22gdiplus.dll%22%2C%20CharSet%20%3D%20CharSet.Unicode%2C%20SetLastError%20%3D%20true)%5D%3CBR%20%2F%3Einternal%20static%20extern%20int%20GdipCreatePen2(%20HandleRef%20brush%2C%20float%20width%2C%20int%20unit%2C%20out%20IntPtr%20pen)%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIs%20there%20a%20setting%20or%20anything%20we%20can%20add%20so%20this%20security%20patch%20would%20not%20break%20this%20code%3F%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThank%20you%20and%20regards%2C%3C%2FP%3E%3CP%3EDagnis%20Dancitis%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2858550%22%20slang%3D%22en-US%22%3ERe%3A%20Installing%20KB5006729%20Security%20patch%20breaks%20Pen(Brush%20brush%2C%20float%20width)%20constructor%20when%20width%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2858550%22%20slang%3D%22en-US%22%3E%3CP%3EKB5006729%20security%20patch%20also%20breaks%26nbsp%3Bpublic%20Pen(Color%20color%2C%20float%20width)%20with%200%20parameter%20with%20relevant%20GdiPlus.dll%20function%26nbsp%3BSafeNativeMethods.Gdip.GdipCreatePen1(color.ToArgb()%2C%20width%2C%200%2C%20out%20pen)%20returning%20wrong%20pen%20width%20value%20(1f).%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ELogged%20a%20case%20with%20Microsoft%20Tech%20Support.%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EGdiPlus.dll%26nbsp%3B%20version%206.3.9600.20139%2C%20gdi32.dll%206.3.9600.20143%3C%2FP%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F1188608%22%20target%3D%22_blank%22%3E%40Dagnis%3C%2FA%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2860339%22%20slang%3D%22en-US%22%3ERe%3A%20Installing%20KB5006729%20Security%20patch%20breaks%20Pen(Brush%20brush%2C%20float%20width)%20constructor%20when%20width%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2860339%22%20slang%3D%22en-US%22%3EThis%20code%20will%20return%200%20before%20the%20patch.%20This%20code%20will%20return%201%20after%20the%20patch.%3CBR%20%2F%3E%3CBR%20%2F%3Eusing%20System%3B%3CBR%20%2F%3Eusing%20System.Drawing%3B%3CBR%20%2F%3E%3CBR%20%2F%3Enamespace%20ShowPenWidth%3CBR%20%2F%3E%7B%3CBR%20%2F%3Eclass%20Program%3CBR%20%2F%3E%7B%3CBR%20%2F%3Estatic%20void%20Main(string%5B%5D%20args)%3CBR%20%2F%3E%7B%3CBR%20%2F%3EPen%20p%20%3D%20new%20Pen(Color.Transparent%2C%200)%3B%3CBR%20%2F%3EConsole.WriteLine(p.Width)%3B%3CBR%20%2F%3EConsole.ReadLine()%3B%3CBR%20%2F%3E%7D%3CBR%20%2F%3E%7D%3CBR%20%2F%3E%7D%3CBR%20%2F%3E%3C%2FLINGO-BODY%3E
New Contributor

Hello,

 

After the installing KB5006729 Security only patch for server 2012R2 it breaks the .Net constructor for public Pen(Brush brush, float width) where width is passed as 0f value.


this constructor calls  gdiplus.dll method (the bug actually is with following function)

SafeNativeMethods.Gdip.GdipCreatePen2(new HandleRef((object) brush, brush.NativeBrush), width, 0, out pen);

returns a pen with value of 1f  if the width has been passed in as zero(0) value.

 

For example:

var pen = new Pen(SystemBrushes.WindowText, 0f)

the pen.Width is returned as value 1. So the returned pen has a width of 1 rather than expected value of 0.

 

constructor snipped:

from System.Drawing.Pen

public Pen(Brush brush, float width)
{
IntPtr pen = IntPtr.Zero;
if (brush == null)
throw new ArgumentNullException(nameof (brush));
int pen2 = SafeNativeMethods.Gdip.GdipCreatePen2(new HandleRef((object) brush, brush.NativeBrush), width, 0, out pen);
if (pen2 != 0)
throw SafeNativeMethods.Gdip.StatusException(pen2);
this.SetNativePen(pen);
}

 

from System.Drawing.SafeNativeMethods.Gdip

[DllImport("gdiplus.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int GdipCreatePen2( HandleRef brush, float width, int unit, out IntPtr pen);

 

 

Is there a setting or anything we can add so this security patch would not break this code?

 

Thank you and regards,

Dagnis Dancitis 

 

6 Replies

KB5006729 security patch also breaks public Pen(Color color, float width) with 0 parameter with relevant GdiPlus.dll function SafeNativeMethods.Gdip.GdipCreatePen1(color.ToArgb(), width, 0, out pen) returning wrong pen width value (1f).

 

Logged a case with Microsoft Tech Support. 

 

GdiPlus.dll  version 6.3.9600.20139, gdi32.dll 6.3.9600.20143

@Dagnis 

This code will return 0 before the patch. This code will return 1 after the patch.

using System;
using System.Drawing;

namespace ShowPenWidth
{
class Program
{
static void Main(string[] args)
{
Pen p = new Pen(Color.Transparent, 0);
Console.WriteLine(p.Width);
Console.ReadLine();
}
}
}

@Dagnis 

 

As you may have also noticed, I've seen that the Width value can be set after the Constructor to properly set a Width of 0, but of course it requires changes to all existing code. Ideally, an update to restore the correct behavior may be issued quickly, but if not timely -- then I suppose some apps may be able to fix themselves. (With more work, and some ugly code that we'd all hope to be able to rollback soon. : )

   float penWidth = 0f;
   Pen myPen = new Pen( Color.Blue, penWidth );
   myPen.Width = penWidth; // work-around to fix Windows Update issue

 

using (Pen pen = new Pen(Color.Transparent){Width = 0f}){ ... }

 

Its is not about having a workaround to the issue created by this security patch. Easy fix. It's rolling out the soft to all client base. Clients require UAT first, but UAT lives on same box as Live typically. Must have patch but this breaks the Live environment. This time around Microsoft properly threw a spanner in the wheels.

 

As far as I know now, it is a known bug, but there is no hotfix. And it will be fixed second week of November, which is default cumulative patch release date.

Yes, I totally agree -- the Pen ctor should not need work-arounds! (Just mentioned as something I noticed during my own investigation. So in my example -- line #3 should only be temporary.)

But certainly, the recommendation when using managed GDI+ objects backed by native resources is to explicitly release by manually calling the Dispose() method or scope within 'using' blocks. So good to indicate that with your example.

I'd also prefer clients roll-back the update rather than software providers needing to support fixes/work-arounds to the issue. But it may depend on our customers as to whether that's something they can do, or if we really need to provide a direct/temporary fix.

Thank you for posting what you had found, I was curious to see how the community has been responding to this recently introduced issue.