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结构。
错误原因分析
核心逻辑错误:存指针地址而非实际数据
ioStruct.Buffer是指向真实minidump数据的内存指针,当前代码将指针本身的数值转成字节数组存入dumpData,完全没有读取指针指向的内存区域里的有效dump内容,导致dumpBuffer全是无效的内存地址值。数据长度计算错误
unsafe.Sizeof(ioStruct.Buffer)获取的是指针类型的大小(64位系统为8字节),但实际需要复制的是ioStruct.BufferBytes长度的真实数据,这直接导致每次仅复制8字节无效内容,丢失了全部有效dump数据。缓冲区扩容逻辑错误
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
相关产品推荐
相关产品推荐

