Skip to content

Commit 4077c4b

Browse files
rolfbjarneCopilot
andauthored
[tests] Fix BitmapContextTest.CreateAdaptive_3/_4 crash due to undersized buffer (#24920)
CreateAdaptive_3 and CreateAdaptive_4 used a hardcoded 512-byte buffer for a 256x256 adaptive bitmap context. When ToImage() called CGBitmapContextCreateImage, CoreGraphics tried to copy the bitmap data from this tiny buffer, reading past the allocation and causing a SIGSEGV. Fix CreateAdaptive_3 by computing the buffer size from parameters.AlignedBytesPerRow * parameters.Height (matching CreateAdaptive_2). Fix CreateAdaptive_4 by using a 1MB buffer, large enough for any 256x256 adaptive bitmap format. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent fcc6c07 commit 4077c4b

File tree

1 file changed

+59
-58
lines changed

1 file changed

+59
-58
lines changed

tests/monotouch-test/CoreGraphics/BitmapContextTest.cs

Lines changed: 59 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ public void CreateAdaptive_3 ()
205205
var calledOnLockPointer = false;
206206
var calledOnUnlockPointer = false;
207207
var calledOnReleaseInfo = false;
208-
const int renderingBufferProviderSize = 512;
209208

210209
var calledOnResolve = false;
211210
var calledOnAllocate = false;
@@ -225,10 +224,11 @@ public void CreateAdaptive_3 ()
225224
(ref CGContentInfo info, ref CGBitmapParameters parameters) => {
226225
// TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#3 info={info} parameters={parameters}");
227226
calledOnAllocate = true;
227+
var renderingBufferProviderSize = checked(parameters.AlignedBytesPerRow * parameters.Height);
228228
var renderingBufferProvider = CGRenderingBufferProvider.Create (IntPtr.Zero, renderingBufferProviderSize,
229229
lockPointer: (info) => {
230230
calledOnLockPointer = true;
231-
var rv = Marshal.AllocHGlobal (renderingBufferProviderSize);
231+
var rv = Marshal.AllocHGlobal (checked((nint) renderingBufferProviderSize));
232232
// TestRuntime.NSLog ($"CreateAdaptive3 () OnLockPointer#3 (0x{info:x}) => 0x{rv:x}");
233233
return rv;
234234
},
@@ -280,69 +280,70 @@ public void CreateAdaptive_4 ()
280280
var calledOnLockPointer = false;
281281
var calledOnUnlockPointer = false;
282282
var calledOnReleaseInfo = false;
283-
const int renderingBufferProviderSize = 512;
283+
CGRenderingBufferProvider? externalBufferProvider = null;
284284

285285
using (var pool = new NSAutoreleasePool ()) {
286-
using (var renderingBufferProvider = CGRenderingBufferProvider.Create (IntPtr.Zero, renderingBufferProviderSize,
287-
lockPointer: (info) => {
288-
calledOnLockPointer = true;
289-
var rv = Marshal.AllocHGlobal (renderingBufferProviderSize);
290-
// TestRuntime.NSLog ($"CreateAdaptive () OnLockPointer#4 (0x{info:x}) => 0x{rv:x}");
291-
return rv;
286+
var calledOnResolve = false;
287+
var calledOnAllocate = false;
288+
var calledOnFree = false;
289+
var calledOnError = false;
290+
var options = new CGAdaptiveOptions () {
291+
MaximumBitDepth = CGComponent.Float16Bit,
292+
};
293+
294+
using (var context = CGBitmapContext.Create (width, height, options,
295+
(ref CGContentInfo info, ref CGBitmapParameters parameters) => {
296+
// TestRuntime.NSLog ($"CreateAdaptive () OnResolve#4 info={info} parameters={parameters}");
297+
calledOnResolve = true;
298+
return true;
292299
},
293-
unlockPointer: (info, pointer) => {
294-
// TestRuntime.NSLog ($"CreateAdaptive () OnUnlockPointer#4 (0x{info:x}, 0x{pointer:x})");
295-
calledOnUnlockPointer = true;
296-
Marshal.FreeHGlobal (pointer);
300+
(ref CGContentInfo info, ref CGBitmapParameters parameters) => {
301+
// TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#4 info={info} parameters={parameters}");
302+
calledOnAllocate = true;
303+
var renderingBufferProviderSize = checked(parameters.AlignedBytesPerRow * parameters.Height);
304+
externalBufferProvider = CGRenderingBufferProvider.Create (IntPtr.Zero, renderingBufferProviderSize,
305+
lockPointer: (info) => {
306+
calledOnLockPointer = true;
307+
var rv = Marshal.AllocHGlobal (checked((nint) renderingBufferProviderSize));
308+
// TestRuntime.NSLog ($"CreateAdaptive () OnLockPointer#4 (0x{info:x}) => 0x{rv:x}");
309+
return rv;
310+
},
311+
unlockPointer: (info, pointer) => {
312+
// TestRuntime.NSLog ($"CreateAdaptive () OnUnlockPointer#4 (0x{info:x}, 0x{pointer:x})");
313+
calledOnUnlockPointer = true;
314+
Marshal.FreeHGlobal (pointer);
315+
},
316+
releaseInfo: (info) => {
317+
// TestRuntime.NSLog ($"CreateAdaptive () OnReleaseInfo#4 (0x{info:x})");
318+
calledOnReleaseInfo = true;
319+
}
320+
);
321+
return externalBufferProvider;
322+
},
323+
(CGRenderingBufferProvider renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => {
324+
// TestRuntime.NSLog ($"CreateAdaptive () OnFree#4 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}");
325+
calledOnFree = true;
297326
},
298-
releaseInfo: (info) => {
299-
// TestRuntime.NSLog ($"CreateAdaptive () OnReleaseInfo#4 (0x{info:x})");
300-
calledOnReleaseInfo = true;
301-
}
302-
)) {
303-
Assert.That (renderingBufferProvider, Is.Not.Null, "RenderingBufferProvider");
304-
305-
var calledOnResolve = false;
306-
var calledOnAllocate = false;
307-
var calledOnFree = false;
308-
var calledOnError = false;
309-
var options = new CGAdaptiveOptions () {
310-
MaximumBitDepth = CGComponent.Float16Bit,
311-
};
312-
313-
using (var context = CGBitmapContext.Create (width, height, options,
314-
(ref CGContentInfo info, ref CGBitmapParameters parameters) => {
315-
// TestRuntime.NSLog ($"CreateAdaptive () OnResolve#4 info={info} parameters={parameters}");
316-
calledOnResolve = true;
317-
return true;
318-
},
319-
(ref CGContentInfo info, ref CGBitmapParameters parameters) => {
320-
// TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#4 info={info} parameters={parameters}");
321-
calledOnAllocate = true;
322-
return renderingBufferProvider;
323-
},
324-
(CGRenderingBufferProvider renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => {
325-
// TestRuntime.NSLog ($"CreateAdaptive () OnFree#4 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}");
326-
calledOnFree = true;
327-
},
328-
(NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => {
329-
// TestRuntime.NSLog ($"CreateAdaptive () OnError#4 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}");
330-
calledOnError = true;
331-
})) {
332-
333-
Assert.NotNull (context, "Context#4");
334-
335-
using var img = context.ToImage ();
336-
Assert.NotNull (img, "ToImage");
337-
}
338-
339-
Assert.That (calledOnResolve, Is.True, "calledOnResolve#4");
340-
Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#4");
341-
Assert.That (calledOnFree, Is.True, "calledOnFree#4");
342-
Assert.That (calledOnError, Is.False, "calledOnError#4");
327+
(NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => {
328+
// TestRuntime.NSLog ($"CreateAdaptive () OnError#4 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}");
329+
calledOnError = true;
330+
})) {
331+
332+
Assert.NotNull (context, "Context#4");
333+
334+
using var img = context.ToImage ();
335+
Assert.NotNull (img, "ToImage");
343336
}
337+
338+
Assert.That (calledOnResolve, Is.True, "calledOnResolve#4");
339+
Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#4");
340+
Assert.That (calledOnFree, Is.True, "calledOnFree#4");
341+
Assert.That (calledOnError, Is.False, "calledOnError#4");
344342
}
345343

344+
// Explicitly dispose the buffer provider to verify releaseInfo is called.
345+
externalBufferProvider?.Dispose ();
346+
346347
Assert.That (calledOnLockPointer, Is.True, "calledOnLockPointer#4");
347348
Assert.That (calledOnUnlockPointer, Is.True, "calledOnUnlockPointer#4");
348349
Assert.That (calledOnReleaseInfo, Is.True, "calledOnReleaseInfo#4");

0 commit comments

Comments
 (0)