You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未公开KERNELBASE方法致Windows服务崩溃:无效指针读取(访问违例)

纯托管C# Windows服务非托管线程崩溃问题分析与解决

问题背景

我有两个基于纯托管C#编写的不同Windows服务(无第三方库或PInvoke调用),它们会在非托管线程上因相同调用栈随机崩溃,崩溃间隔从数小时到数周不等。该问题仅在生产环境出现,只能通过崩溃转储文件和WinDbg进行调试。

WinDbg异常分析结果

执行!analyze -v得到的异常信息如下:

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 00007ffd56b56700 (ntdll!memcpy+0x0000000000000040)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000000
   Parameter[1]: 000001f76dea0f78
Attempt to read from address 000001f76dea0f78

PROCESS_NAME:  *Removed*
READ_ADDRESS:  000001f76dea0f78 
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_CODE_STR:  c0000005
EXCEPTION_PARAMETER1:  0000000000000000
EXCEPTION_PARAMETER2:  000001f76dea0f78
STACK_TEXT:  

    ntdll!memcpy+0x40
    KERNELBASE!StmWrite+0x72
    KERNELBASE!PerfpAddCounterToStream+0x89
    KERNELBASE!PerfpAddInstanceToStream+0xcf
    KERNELBASE!PerfpAddQueryItemToStream+0x15d
    KERNELBASE!PerfpNotifyAndCollect+0x113
    KERNELBASE!PerfpNotificationCallback+0xa6
    ntdll!TppIopExecuteCallback+0x129
    ntdll!TppWorkerThread+0x3c8
    kernel32!BaseThreadInitThunk+0x14
    ntdll!RtlUserThreadStart+0x21

两个服务业务逻辑完全不同,且均为纯托管代码,无法确定该非托管线程的来源及其执行操作,也找不到KERNELBASE中这些调用方法的官方文档,难以定位崩溃原因。

堆地址信息分析

查看尝试读取的堆地址信息如下:

!heap -i 000001f76dea0f78
Detailed information for block entry 000001f76dea0f78
Assumed heap       : 0x000001f76df60000 (Use !heap -i NewHeapHandle to change)
Header content     : 0x00000000 0x00000000
Owning segment     : 0x000001f76df60000 (offset 0)
Block flags        : 0x0 (free )
Total block size   : 0x0 units (0x0 bytes)
Previous block size: 0x74e units (0x74e0 bytes)
Block CRC          : OK - 0x0  
List corrupted: (Blink->Flink = 0000000000000000) != (Block = 000001f76dea0f88)
Free list entry    : CORRUPTED
Previous block     : 0x000001f76de99a98
Next block         : 0x000001f76dea0f78

定位思路

  • 调用栈中Perfp前缀方法属于Windows性能计数器相关的非托管代码,该线程是系统性能监控的回调线程,用于收集性能数据。
  • 堆地址显示该内存块已被释放且链表结构损坏,说明存在堆内存使用后释放的野指针问题,或内存越界导致堆结构破坏。
  • 虽然服务是纯托管代码,但托管代码可能通过隐式的COM互操作、.NET框架内部调用触发非托管代码执行,需排查服务中是否依赖了系统组件的COM交互(如Windows内置管理类库)。
  • 可通过!dumpheap、!gcroot等命令检查托管堆中是否存在与性能计数器或相关COM对象的引用异常,同时用!lock排查线程同步问题导致的内存访问冲突。

问题最终定位与解决

更新:两个服务均使用了包含AzMan(Windows授权管理器)类型库的DLL,该库依赖COM互操作。自行开发读取AzMan数据的C#库后,崩溃问题不再出现。

微软已宣称AzMan已弃用多年,但自身软件仍在使用,故其仍作为Windows组件保留。特此提醒仍在使用AzMan的开发者。


内容的提问来源于stack exchange,提问作者Brad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 22:47:04