gpt4 book ai didi

c++ - 64 位 Windows API 结构对齐导致命名管道上的访问被拒绝错误

转载 作者:搜寻专家 更新时间:2023-10-31 02:23:15 29 4
gpt4 key购买 nike

我花了两天时间,但我终于缩小了 ERROR_ACCESS_DENIED 的来源范围。 (5) 尝试 CallNamedPipe 时出错作为结构对齐的问题。我们有一个 32 位服务和一个 32 位应用程序,我正在尝试将该服务更新为 64 位服务。奇怪的是,在 32 位模式下一切正常,但在 64 位模式下 CallNamedPipe来自 32 位应用程序的报告访问被拒绝错误。

该服务已经在设置 ​​SECURITY_ATTRIBUTES结构和填充 lpSecurityDescriptor具有正确初始化的成员 PSECURITY_DESCRIPTOR .传递给 CreateNamedPipe 时没有报告任何错误.我仍然不知道为什么它不报告错误;也许糟​​糕的安全属性会默默地回退到默认值而不是失败。

通过多次反复(包括早期一些不完整/不正确的更改结构对齐的尝试 - 调试服务启动代码并不容易),我开始意识到将默认结构对齐设置为 1 字节 (/Zp1) 的项目设置是造成问题。当我终于使用#pragma pack(push,8)在出现所有 #include <windows.h> 之前和 #pragma pack(pop)之后,事情开始奏效了。

我现在的问题是为什么这是必要的。我看到 Windows API 中有许多头文件通过包含 pshpack1.h 显式设置结构对齐方式, pshpack2.h , pshpack4.h , pshpack8.hpoppack.h .我如何知道 Windows API 何时控制自己的打包,以及何时我有责任设置正确的打包级别?难道每个关心结构对齐的 Windows API 声明都不应该设置正确的包装,这样我就不必筛选系统中的所有代码来查找包括 Windows API 头文件在内的任何内容吗?一种替代方法是更改​​项目设置以使用默认结构对齐,但我必须假设这样做是因为我们的系统中依赖 1 字节结构对齐的代码比依赖 Windows API 的代码还要多。

这是服务器端代码的样子:

BOOL OpenMyPipe()
{
SECURITY_ATTRIBUTES sa;
PSECURITY_DESCRIPTOR pSD;

printf("sizeof(SECURITY_ATTRIBUTES) == %d\n", sizeof(SECURITY_ATTRIBUTES));
pSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (pSD == NULL)
return FALSE;

if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
return FALSE;

if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL)NULL, FALSE))
return FALSE;

sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;

char szPipeName[MAX_PATH];
sprintf(szPipeName, "\\\\.\\pipe\\%s%s", "__SQLTST_",
"MAINMR");

hPipe = CreateNamedPipe(szPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, 0, 0, NMPWAIT_WAIT_FOREVER, &sa);

if (hPipe == INVALID_HANDLE_VALUE)
return FALSE;
return TRUE;
}

为了简单起见,我用一个小型 VB.NET 客户端验证了这一点:

Sub Main()
Dim pipes = System.IO.Directory.GetFiles("\\.\pipe\")

Using pipe As New System.IO.Pipes.NamedPipeClientStream(".", "__SQLTST_MAINMR")
Dim message(16) As Byte
pipe.Connect(3000)
Array.Copy(BitConverter.GetBytes(Process.GetCurrentProcess().Id), message, 4)
pipe.Write(message, 0, 16)
End Using
End Sub

我相信只有当服务器端代码在不同的帐户(如 SYSTEM 帐户)下运行时才会发生错误。不过,我不知道如何轻松地测试它。我所知道的是,即使没有 SECURITY_ATTRIBUTES,上面的代码也不会失败。当它都在与常规应用程序代码相同的帐户下运行时设置。另外,当然,您必须将服务器代码中的结构对齐方式设置为 1 字节才能看到错误。

最佳答案

Windows SDK 期望打包为 8 个字节。来自 Using the Windows Headers

Projects should be compiled to use the default structure packing, which is currently 8 bytes because the largest integral type is 8 bytes. Doing so ensures that all structure types within the header files are compiled into the application with the same alignment the Windows API expects. It also ensures that structures with 8-byte values are properly aligned and will not cause alignment faults on processors that enforce data alignment.

这是确保数据结构与系统预期对齐的必要条件。我怀疑不明确这样做的原因是他们想要默认值,所以 why ask for anything else .改变包装的情况相对较少,应仅限于特定情况。如果 Microsoft 在每个头文件中都添加了 #pragma pack(push,8),他们会含蓄地说更改对齐方式是正常的。

未对齐结构节省空间,但会降低性能 alignment faults在访问未对齐的成员时生成。

出于多种原因,Windows SDK 会更改结构的对齐方式。一种可能适用于需要读取 32 位或 64 位数据结构的文件格式。例如,可以使用 IMAGE_THUNK_DATA64IMAGE_THUNK_DATA32 读取 PE 文件格式。前者需要 8 字节填充,而后者需要 4 字节填充。类似地,Wininet.h 将根据它是针对 32 位代码还是针对 64 位代码编译而不同地打包数据结构。这些是包装方面的合法更改,但有特定原因。

关于c++ - 64 位 Windows API 结构对齐导致命名管道上的访问被拒绝错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29518184/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com