Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 奇怪的MSC 8.0错误:“;ESP的值在函数调用中未正确保存;_C++_Visual C++_X86_Stack_Calling Convention - Fatal编程技术网

C++ 奇怪的MSC 8.0错误:“;ESP的值在函数调用中未正确保存;

C++ 奇怪的MSC 8.0错误:“;ESP的值在函数调用中未正确保存;,c++,visual-c++,x86,stack,calling-convention,C++,Visual C++,X86,Stack,Calling Convention,我们最近尝试将一些VisualStudio项目拆分为库,在一个测试项目中,所有内容似乎都可以编译并构建良好,其中一个库项目作为依赖项。但是,尝试运行该应用程序时会出现以下严重的运行时错误消息: 运行时检查失败#0-未在函数调用中正确保存ESP的值。这通常是调用使用不同调用约定声明的函数指针的结果 我们甚至从未为函数指定过调用约定(_cdecl等),所有编译器开关都是默认的。我检查了,项目设置与库和测试项目中调用约定一致 更新:我们的一个开发人员将“基本运行时检查”项目设置从“两者(/RTC1,等

我们最近尝试将一些VisualStudio项目拆分为库,在一个测试项目中,所有内容似乎都可以编译并构建良好,其中一个库项目作为依赖项。但是,尝试运行该应用程序时会出现以下严重的运行时错误消息:

运行时检查失败#0-未在函数调用中正确保存ESP的值。这通常是调用使用不同调用约定声明的函数指针的结果

我们甚至从未为函数指定过调用约定(_cdecl等),所有编译器开关都是默认的。我检查了,项目设置与库和测试项目中调用约定一致


更新:我们的一个开发人员将“基本运行时检查”项目设置从“两者(/RTC1,等价于/RTCsu)”更改为“默认”,运行时消失,程序运行明显正常。我一点也不相信这一点。这是正确的解决方案还是危险的黑客行为?

ESP是堆栈指针。因此,根据编译器的说法,堆栈指针被弄乱了。如果没有看到一些代码,很难说这是如何(或是否)发生的


您可以得到的最小代码段是多少来复制此代码段?

取消检查不是正确的解决方案。你必须弄清楚你的通话习惯有什么问题

有很多方法可以在不显式指定的情况下更改函数的调用转换。extern“C”将执行此操作,STDMETHODIMP/IFACEMETHODIMP也将执行此操作,其他宏也可以执行此操作


我相信如果在WinDBG()下运行程序,运行时应该在遇到该问题时中断。您可以查看调用堆栈,找出哪个函数有问题,然后查看其定义和调用方使用的声明。

您是在创建静态库还是DLL?如果是DLL,如何定义导出;导入库是如何创建的


libs中函数的原型是否与定义函数的函数声明完全相同?

是否有任何类型定义的函数原型(例如int(*fn)(int a,int b))

如果你是dom,你可能会把原型弄错了

ESP是调用参数不匹配的函数时出错(您能告诉调试器中的哪一个吗?),即堆栈已恢复到调用该函数时启动的状态

您也可以得到这个,如果您正在加载需要声明的C++函数,C-C使用CDDEL,C++使用默认的STDCULL调用约定(IIrC)。在导入的函数原型周围放置一些extern C包装,您可以修复它


如果您可以在调试器中运行它,您将立即看到该函数。如果没有,您可以设置DrWtsn32以创建一个小型转储,您可以将其加载到windbg中,以便在发生错误时查看调用堆栈(但您需要符号或映射文件才能查看函数名)。

另一种情况是,
esp
可能会出错,这是由于意外的缓冲区溢出,通常通过错误地使用指针来越过数组的边界。假设你有一个C函数

int a, b[2];

写入
b[3]
可能会更改
a
,以及可能会将已保存的
esp
传送到堆栈上的任何位置。

如果您在Windows API中使用任何回调函数,则必须使用
回调
和/或
WINAPI
声明它们。这将应用适当的修饰,使编译器生成正确清理堆栈的代码。例如,它在微软的编译器上添加了
\uu stdcall


Windows一直使用
\uuu stdcall
约定,因为它会导致(稍微)较小的代码,清理工作在被调用函数中进行,而不是在每个调用站点进行。但是,它与varargs函数不兼容(因为只有调用方知道它们推送了多少个参数)。

如果使用调用约定调用函数,而不是使用编译该函数的约定调用函数,则会出现此错误

Visual Studio使用默认的调用约定设置,该设置在项目的选项中贴花。检查此值在原始项目设置和新库中是否相同。一个过于雄心勃勃的开发人员本来可以将其设置为_stdcall/pascal,因为与默认的cdecl相比,它减少了代码大小。因此,基本流程将使用此设置,新库将获得导致问题的默认cdecl

既然您已经说过您不使用任何特殊的调用约定,那么这似乎是一个很好的可能性

还要对头进行区分,以查看进程看到的声明/文件是否与编译库时使用的声明/文件相同


ps:让警告消失是BAAAD。基本错误仍然存在。

当代码试图对非预期类型的对象调用函数时,我看到了此错误

因此,类层次结构:父级和子级:Child1和Child2

Child1* pMyChild = 0;
...
pMyChild = pSomeClass->GetTheObj();// This call actually returned a Child2 object
pMyChild->SomeFunction();          // "...value of ESP..." error occurs here

此调试错误意味着堆栈指针寄存器在函数调用后没有返回到其原始值,即函数调用前的推送次数后面没有跟随调用后相同数量的POP

我知道有两个原因(都是动态加载的库)#1是VC++在错误消息中描述的,但我认为这不是导致错误的最常见原因(请参见#2)

1)不匹配的呼叫约定:

呼叫者和被呼叫者对于谁将做什么没有适当的协议。例如,如果调用的DLL函数是
\u stdcall
,但由于某种原因
HMODULE hPowerFunctions = LoadLibrary("Powrprof.dll");
typedef bool (*tSetSuspendStateSig)(BOOL, BOOL, BOOL);

tSetSuspendState SetSuspendState = (tSuspendStateSig)GetProcAddress(hPowerfunctions, "SetSuspendState");

result = SetSuspendState(false, false, false); <---- This line was where the error popped up. 
typedef bool (WINAPI*tSetSuspendStateSig)(BOOL, BOOL, BOOL);
BOOLEAN WINAPI SetSuspendState(BOOLEAN, BOOLEAN, BOOLEAN);
#include "stdafx.h"
char* blah(char *a){
  char p[1];
  strcat(p, a);
  return (char*)p;
}
int main(){
  std::cout << blah("a");
  std::cin.get();
}
    typedef long (*AU3_RunFn)(LPCWSTR, LPCWSTR);
typedef long (WINAPI *AU3_RunFn)(LPCWSTR, LPCWSTR);

AU3_RunFn _AU3_RunFn;
HINSTANCE hInstLibrary = LoadLibrary("AutoItX3.dll");
if (hInstLibrary)
{
  _AU3_RunFn = (AU3_RunFn)GetProcAddress(hInstLibrary, "AU3_WinActivate");
  if (_AU3_RunFn)
     _AU3_RunFn(L"Untitled - Notepad",L"");
  FreeLibrary(hInstLibrary);
}
LONG WINAPI myFunc( time_t, SYSTEMTIME*, BOOL* );
#define _USE_32BIT_TIME_T
#if _MSC_VER >= 1400
LONG WINAPI myFunc( _time32_t, SYSTEMTIME*, BOOL* );
#else
LONG WINAPI myFunc( time_t, SYSTEMTIME*, BOOL* );
#endif