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

Go中从uintptr复制字节到byte切片偏移位的问题排查

Minidump生成失败问题排查

原始代码

type MINIDUMP_IO_CALLBACK struct {
    Handle      uintptr //not relevant
    Offset      uint64  //The offset for the write operation from the start of the minidump data.
    Buffer      uintptr //A pointer to a buffer that contains the data to be written.
    BufferBytes uint32  //The size of the data buffer, in bytes
}

var dumpBuffer []byte //all bytes should be copied here

func copyDumpBytes(ioStruct *MINIDUMP_IO_CALLBACK) {
    size := unsafe.Sizeof(ioStruct.Buffer)
    dumpData := make([]byte, size)
    binary.LittleEndian.PutUint64(dumpData, uint64(ioStruct.Buffer)) // getting byte slice from pointer
    requiredSize := ioStruct.Offset + uint64(ioStruct.BufferBytes) // calculating required size to write it at the required offset
    if requiredSize > uint64(len(dumpBuffer)) {
        padding := make([]byte, requiredSize)
        dumpBuffer = append(dumpBuffer, padding...) // allocating new space in buffer, if existing is not enough
    }
    copy(dumpBuffer[ioStruct.Offset:], dumpData) //copying bytes itself into the buffer at the required offset
}

问题背景

copyDumpBytes()会被回调多次,目标是把所有回调传来的minidump数据存入dumpBuffer,但写入文件后WinDbg无法识别该minidump结构。


错误原因分析

  1. 核心逻辑错误:存指针地址而非实际数据
    ioStruct.Buffer是指向真实minidump数据的内存指针,当前代码将指针本身的数值转成字节数组存入dumpData,完全没有读取指针指向的内存区域里的有效dump内容,导致dumpBuffer全是无效的内存地址值。

  2. 数据长度计算错误
    unsafe.Sizeof(ioStruct.Buffer)获取的是指针类型的大小(64位系统为8字节),但实际需要复制的是ioStruct.BufferBytes长度的真实数据,这直接导致每次仅复制8字节无效内容,丢失了全部有效dump数据。

  3. 缓冲区扩容逻辑错误
    dumpBuffer = append(dumpBuffer, padding...)会把长度为requiredSize的空切片追加到原缓冲区后,使dumpBuffer总长度变为原长度+requiredSize,远大于实际需要的requiredSize,破坏了minidump的结构完整性。


修正后的代码

import "unsafe"

type MINIDUMP_IO_CALLBACK struct {
    Handle      uintptr //not relevant
    Offset      uint64  //The offset for the write operation from the start of the minidump data.
    Buffer      uintptr //A pointer to a buffer that contains the data to be written.
    BufferBytes uint32  //The size of the data buffer, in bytes
}

var dumpBuffer []byte //all bytes should be copied here

func copyDumpBytes(ioStruct *MINIDUMP_IO_CALLBACK) {
    // 1. 将C风格指针转换为Go切片,直接访问真实dump数据
    dataSize := ioStruct.BufferBytes
    dataSlice := unsafe.Slice((*byte)(unsafe.Pointer(ioStruct.Buffer)), dataSize)
    
    // 2. 按需扩容缓冲区,仅补充缺失的字节数
    requiredSize := ioStruct.Offset + uint64(dataSize)
    if uint64(len(dumpBuffer)) < requiredSize {
        need := requiredSize - uint64(len(dumpBuffer))
        dumpBuffer = append(dumpBuffer, make([]byte, need)...)
    }
    
    // 3. 将真实数据复制到指定偏移位置
    copy(dumpBuffer[ioStruct.Offset:], dataSlice)
}

关键修正说明

  • 用unsafe.Slice(Go 1.17+支持)将Buffer指针转换为[]byte切片,直接读取指针指向的内存数据,这是处理C风格指针的标准方式。
  • 以ioStruct.BufferBytes作为数据长度,确保复制完整的有效dump内容。
  • 扩容时仅追加实际需要的字节数,保证dumpBuffer长度与minidump总大小完全匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:40:28