{"record":{"id":"d01668296d129785","repo":"SubtitleEdit/subtitleedit","slug":"failed-to-lock-global-memory","errorCode":null,"errorMessage":"Failed to lock global memory","messagePattern":"Failed to lock global memory","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/ClipboardHelper.cs","lineNumber":220,"sourceCode":"\n                // Calculate sizes\n                var stride = width * 4; // 4 bytes per pixel (BGRA)\n                var imageSize = stride * height;\n                var headerSize = Marshal.SizeOf<BITMAPINFOHEADER>();\n                var totalSize = headerSize + imageSize;\n\n                // Allocate global memory\n                hGlobal = GlobalAlloc(GMEM_MOVEABLE, new UIntPtr((uint)totalSize));\n                if (hGlobal == IntPtr.Zero)\n                {\n                    throw new InvalidOperationException(\"Failed to allocate global memory\");\n                }\n\n                IntPtr ptr = GlobalLock(hGlobal);\n                if (ptr == IntPtr.Zero)\n                {\n                    GlobalFree(hGlobal);\n                    throw new InvalidOperationException(\"Failed to lock global memory\");\n                }\n\n                try\n                {\n                    // Write BITMAPINFOHEADER\n                    var header = new BITMAPINFOHEADER\n                    {\n                        biSize = (uint)headerSize,\n                        biWidth = width,\n                        biHeight = height, // positive for bottom-up DIB\n                        biPlanes = 1,\n                        biBitCount = 32,\n                        biCompression = BI_RGB,\n                        biSizeImage = (uint)imageSize,\n                        biXPelsPerMeter = 0,\n                        biYPelsPerMeter = 0,\n                        biClrUsed = 0,\n                        biClrImportant = 0","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/ClipboardHelper.cs#L202-L238","documentation":"Thrown in CopyImageToClipboardWindows right after a successful GlobalAlloc: GlobalLock(hGlobal) returned IntPtr.Zero even though the handle was allocated. The code frees the handle before throwing. A zero from GlobalLock is rare and usually indicates the block is invalid/discardable or a low-level memory-manager corruption; in practice it is far less common than the GlobalAlloc failure.","triggerScenarios":"GlobalLock fails on a freshly allocated moveable block: the handle was invalidated between alloc and lock (e.g. by another thread freeing it), memory-manager corruption, or a discarded/discardable block under memory pressure.","commonSituations":"Concurrent clipboard operations racing on the same handle; heap corruption from a native dependency; extreme memory pressure causing the block to be discarded; AV/hook interfering with the global heap.","solutions":["Check Marshal.GetLastWin32Error() to identify the specific Win32 failure.","Ensure the clipboard copy path is not entered concurrently from multiple threads (the _playLock-style discipline).","Retry the alloc/lock sequence once; if it persists, treat as a fatal environment problem and report it.","Investigate native dependencies for heap corruption if the error recurs reliably."],"exampleFix":"// before\nIntPtr ptr = GlobalLock(hGlobal);\nif (ptr == IntPtr.Zero) { GlobalFree(hGlobal); throw new InvalidOperationException(\"Failed to lock global memory\"); }\n\n// after - one retry and a richer error\nIntPtr ptr = IntPtr.Zero;\nfor (int i = 0; i < 2 && ptr == IntPtr.Zero; i++) ptr = GlobalLock(hGlobal);\nif (ptr == IntPtr.Zero)\n{\n    var winErr = Marshal.GetLastWin32Error();\n    GlobalFree(hGlobal);\n    throw new InvalidOperationException($\"Failed to lock global memory (Win32 error {winErr}).\");\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"IntPtr ptr = IntPtr.Zero;\nfor (int i = 0; i < 2 && ptr == IntPtr.Zero; i++) ptr = GlobalLock(hGlobal);\nif (ptr == IntPtr.Zero)\n{\n    var e = Marshal.GetLastWin32Error();\n    GlobalFree(hGlobal);\n    throw new InvalidOperationException($\"Failed to lock global memory (Win32 {e}).\");\n}","preventionTips":["Do not enter the clipboard copy path concurrently from multiple threads.","Retry the lock once before failing.","Investigate native dependencies if GlobalLock reliably fails on a fresh block."],"tags":["clipboard","windows","win32","memory"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}