【发布时间】:2018-01-15 14:42:30
【问题描述】:
尝试运行编译后的 CLANG,MIDL 生成 RPC 客户端代码,但它在服务器端爆炸,因为 MIDL 生成客户端代码的方式以相反的顺序序列化函数参数。
MIDL 被调用为
midl MyRPCInterface.idl /env win32 /out"RPCx32" /char ascii7
函数看起来像
int __cdecl f(int a, int b, int c);
函数的 RPC 客户端代码如下所示
int __cdecl f(int a, int b, int c)
{
CLIENT_CALL_RETURN _RetVal;
_RetVal = NdrClientCall2(
( PMIDL_STUB_DESC )&MyRPCInterface_StubDec,
(PFORMAT_STRING) & MyRPCInterface __MIDL_ProcFormatString.Format[1110],
( unsigned char * )&a);
return ( char * )_RetVal. Simple;
}
MIDL 生成的客户端代码假定内存中的参数是对齐的 [a][b][c],因此它通过获取指向第一个参数 &a 的指针来序列化它们,并假定接下来的变量。
这对于 MSVC 和 BCC32 非常有效,但对于 CLANG 则不行。参数顺序相反。
MSVC 和 BCC32
int* pA = &a;
int* pB = pA + 1;
int* pC = pB + 1;
int* pD = pC + 1;
叮当
int* pD = &d;
int* pC = pD + 1;
int* pB = pC + 1;
int* pA = pB + 1;
在进行一些低级调试后,我可以确认所有 3 个编译器都以正确的顺序传递参数。
当 MSVC 和 BCC32 使用函数体中的参数时,它们通过引用原始堆栈地址直接使用它们。
另一方面,CLANG 创建变量的副本并将它们以相反的顺序存储在内存中,并在请求变量地址时使用该新位置。结果是函数参数未正确序列化,并且服务器因参数无效而崩溃。 尝试了所有优化参数
问题:
是否有命令行开关或关键字/pragma 告诉 CLANG 直接使用堆栈中的变量而不是先复制它们? (为什么会这样,好像是在浪费指令)
是否有 MIDL 命令行开关或关键字/pragma 告诉它反转变量顺序?
谢谢!
这是查看内存顺序的简单测试代码:
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdint>
void fdef(int a, int b, int c, int d)
{
int* pA = &a;
int* pB = &b;
int* pC = &c;
int* pD = &d;
std::cout << " --------------------- " <<" Default call" << std::endl;
std::cout << BytesToHexStr(&a, 12, true, "") << std::endl;
}
void __cdecl fcdecl(int a, int b, int c, int d)
{
std::cout << " --------------------- " <<" __cdecl call" << std::endl;
std::cout << BytesToHexStr(&a, 12, true, "") << std::endl;
}
void __stdcall fstdcall(int a, int b, int c, int d)
{
std::cout << " --------------------- " <<" stdcall call"<< std::endl ;
std::cout << BytesToHexStr(&a, 12, true, "") << std::endl;
}
void __pascal fpascal(int a, int b, int c, int d)
{
std::cout << " --------------------- " <<" pascal call"<< std::endl ;
std::cout << BytesToHexStr(&a, 12, true, "") << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
fdef(1, 2, 3, 4);
fcdecl(1, 2, 3, 4);
fstdcall(1, 2, 3, 4);
fpascal(1, 2, 3, 4);
}
【问题讨论】: