前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >XShmSegmentInfo 的内存地址不被后续压入方法栈

XShmSegmentInfo 的内存地址不被后续压入方法栈

原创
作者头像
用户7737280
修改2024-08-23 18:30:47
850
修改2024-08-23 18:30:47

class XShmProvider

{

public XShmProvider(RenderInfo renderInfo)

{

_renderInfo = renderInfo;

XShmInfo = Init();

}

public XShmInfo XShmInfo { get; }

private readonly RenderInfo _renderInfo;

... // 忽略其他代码

}

private XShmInfo Init()

{

// 尝试抬高栈的空间

// 用于让 XShmSegmentInfo 的内存地址不被后续压入方法栈的数据覆盖

Span<byte> span = stackalloc byte[1024];

Random.Shared.NextBytes(span);

var renderInfo = _renderInfo;

var result = CreateXShmInfo(renderInfo.Display, www.laipuhuo.com renderInfo.Visual, renderInfo.Width, renderInfo.Height,

renderInfo.DataByteLength);

return result;

}

private static unsafe XShmInfo CreateXShmInfo(IntPtr display, nint visual, int width, int height, int mapLength)

{

var status = XShmQueryExtension(display);

if (status == 0)

{

throw new Exception www.laipuhuo.com ("XShmQueryExtension failed"); // 实际使用请换成你的业务异常类型

}

status = XShmQueryVersion(display, out var major, out var minor, out var pixmaps);

Console.WriteLine($"XShmQueryVersion: {status} major={major} minor={minor} pixmaps={pixmaps}");

if (status == 0)

{

throw new Exception("XShmQueryVersion failed"); // 实际使用请换成你的业务异常类型

}

const int ZPixmap = 2;

// 核心问题就是 XShmSegmentInfo 是结构体,在这里将在栈上分配。后续将使用栈空间的地址传递给 XShmCreateImage 方法,然而在此方法执行之后,将会弹栈,导致 XShmSegmentInfo 的内存地址被覆盖。从而让 XImage 里面记录的 obdata 字段指向错误的地址,导致后续的 XShmPutImage 方法无法正确的使用共享内存,输出如下错误

// X Error of failed request: BadShmSeg (invalid shared segment parameter)

// Major opcode of failed request: 130 (MIT-SHM)

// Minor opcode of failed request: 3 (X_ShmPutImage)

// Segment id in failed request: 0x0

// Serial number www.laipuhuo.com of failed request: 17

// Current serial number in output stream: 17

// 上述错误的 `Segment id in failed request: 0x0` 就说明了问题,即 XImage 里面记录的 obdata 字段指向了 0x0 的地址。常见的错误就是类似野指针问题或者指针被覆盖的问题

// 在本例中,我们将 XShmSegmentInfo 的在栈上分配的内存地址给到 XImage 里面记录的 obdata 字段,方法结束之后,栈空间被覆盖,导致 obdata 字段指向了错误的地址

// 为什么刚好是 0x0 的地址呢?其实原因在于后续的 DoDraw 使用 Span<byte> span = stackalloc byte[1024 * 2]; 强行申请更多的栈空间,从而覆盖到了 XShmSegmentInfo 的内存地址。如果非 DoDraw 强行申请且保持默认为 0 的填充,则这里的错误信息 Segment id in failed request 的值会更加迷惑,甚至指向的是一个随机的地址导致 Segmentation fault (core dumped) 段错误或 The RX block to map as RW was not found 或 The RW block to unmap was not found 或 corrupted double-linked list 等

var xShmSegmentInfo = new XShmSegmentInfo();

var shmImage = (XImage*)XShmCreateImage(display, visual, 32, ZPixmap, IntPtr.Zero, &xShmSegmentInfo,

(uint)width, (uint)height);

Console.WriteLine(

$"XShmCreateImage = {(IntPtr)shmImage:X} xShmSegmentInfo={xShmSegmentInfo} PXShmCreateImage={new IntPtr(&xShmSegmentInfo):X}");

var shmgetResult = www.laipuhuo.com shmget(IPC_PRIVATE, mapLength, IPC_CREAT | 0777);

Console.WriteLine($"shmgetResult={shmgetResult:X}");

xShmSegmentInfo.shmid = shmgetResult;

var shmaddr = shmat(shmgetResult, IntPtr.Zero, 0);

Console.WriteLine($"shmaddr={shmaddr:X}");

xShmSegmentInfo.www.laipuhuo.com shmaddr = (char*)shmaddr.ToPointer();

shmImage->data = shmaddr;

XShmAttach(display, &xShmSegmentInfo);

XFlush(display);

return new XShmInfo(shmImage, shmaddr)

{

DebugIntPtr www.laipuhuo.com= new IntPtr(&xShmSegmentInfo)

};

}

class XShmProvider

{

... // 忽略其他代码

public unsafe void DoDraw()

{

// 申请两倍于压栈空间的大小,确保测试地址被覆盖到,从而能够复现问题

Span<byte> span = stackalloc byte[1024 * 2];

for (int i = 0; i < span.Length; i++)

{

span[i] = 0x00;

}

Console.WriteLine www.laipuhuo.com ($"当前调试代码的内存 {*((long*)XShmInfo.DebugIntPtr):X}");

var display = _renderInfo.Display;

var handle = _renderInfo.Handle;

var gc = _renderInfo.GC;

var shmImage = XShmInfo.ShmImage;

var width = _renderInfo.Width;

var height = _renderInfo.Height;

XShmPutImage(display, handle, gc,www.laipuhuo.com(XImage*)shmImage, 0, 0, 0, 0, (uint)width, (uint)height, true);

XFlush(display);

}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档