Error extraño de MSC 8.0: “El valor de ESP no se guardó correctamente en una llamada de función …”

Recientemente, intentamos separar algunos de nuestros proyectos de Visual Studio en bibliotecas, y todo pareció comstackrse y comstackrse en un proyecto de prueba con uno de los proyectos de la biblioteca como una dependencia. Sin embargo, al intentar ejecutar la aplicación nos dio el siguiente mensaje de error desagradable en tiempo de ejecución:

Error de comprobación en tiempo de ejecución # 0: el valor de ESP no se guardó correctamente en una llamada a función. Esto suele ser el resultado de llamar a un puntero de función declarado con una convención de llamada diferente.

Nunca hemos especificado convenciones de llamadas (__cdecl, etc.) para nuestras funciones, dejando todos los comstackdores activados por defecto. Revisé y la configuración del proyecto es consistente para llamar a convenciones en la biblioteca y probar proyectos.

Actualización: uno de nuestros desarrolladores cambió la configuración del proyecto “Comprobaciones de tiempo de ejecución básico” de “Ambos (/ RTC1, equiv. A / RTCsu)” a “Predeterminado” y el tiempo de ejecución desapareció, dejando el progtwig ejecutándose aparentemente correctamente. No confío en esto en absoluto. ¿Fue esta una solución adecuada o un truco peligroso?

Este error de depuración significa que el registro del puntero de stack no se devuelve a su valor original después de la llamada a la función, es decir, que el número de pulsaciones antes de la llamada de función no fue seguido por el mismo número de saltos después de la llamada.

Hay 2 razones para esto que sé (ambas con bibliotecas cargadas dinámicamente). # 1 es lo que VC ++ está describiendo en el mensaje de error, pero no creo que esta sea la causa más frecuente del error (vea el n. ° 2).

1) Convenciones de llamadas no coincidentes:

La persona que llama y la persona que llama no tienen un acuerdo adecuado sobre quién hará qué. Por ejemplo, si llama a una función DLL que es _stdcall , pero por algún motivo la ha declarado como _cdecl (predeterminada en VC ++) en su llamada. Esto pasaría mucho si estás usando diferentes idiomas en diferentes módulos, etc.

Debería inspeccionar la statement de la función infractora y asegurarse de que no se declare dos veces y de forma diferente.

2) Tipos no coincidentes:

La persona que llama y la llamada no se comstackn con los mismos tipos. Por ejemplo, un encabezado común define los tipos en la API y ha cambiado recientemente, y un módulo fue recomstackdo, pero el otro no, es decir, algunos tipos pueden tener un tamaño diferente en la persona que llama y en el destinatario.

En ese caso, la persona que llama empuja los argumentos de un tamaño, pero el destinatario (si usa _stdcall donde el destinatario limpia la stack) muestra el tamaño diferente. El ESP no es, por lo tanto, devuelto al valor correcto.

(Por supuesto, estos argumentos, y otros debajo de ellos, parecerían distorsionados en la función llamada, pero a veces puede sobrevivir sin un fallo visible).

Si tiene acceso a todo el código, simplemente vuelva a comstackrlo.

Lo leí en otro foro

Estaba teniendo el mismo problema, pero simplemente lo arreglé. Estaba obteniendo el mismo error del siguiente código:

 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. 

Después de algunas investigaciones, cambié una de las líneas a:

 typedef bool (WINAPI*tSetSuspendStateSig)(BOOL, BOOL, BOOL); 

que resolvió el problema Si echas un vistazo al archivo de encabezado donde se encuentra SetSuspendState (powrprof.h, parte del SDK), verás que el prototipo de la función se define como:

 BOOLEAN WINAPI SetSuspendState(BOOLEAN, BOOLEAN, BOOLEAN); 

Entonces ustedes están teniendo un problema similar. Cuando llama a una función determinada desde un archivo .dll, su firma probablemente esté desactivada. (En mi caso, era la palabra clave WINAPI que faltaba).

Espero que ayude a cualquier persona en el futuro! 🙂

Aclamaciones.

Silenciar el cheque no es la solución correcta. Tienes que descubrir qué está mal con tus convenciones de llamadas.

Existen bastantes formas de cambiar la convección de llamada de una función sin especificarla explícitamente. Extern “C” lo hará, STDMETHODIMP / IFACEMETHODIMP también lo hará, otras macros podrían hacerlo también.

Creo que si ejecutas tu progtwig en WinDBG ( http://www.microsoft.com/whdc/devtools/debugging/default.mspx ), el tiempo de ejecución debería romperse en el punto en que llegas a ese problema. Puede mirar la stack de llamadas y descubrir qué función tiene el problema y luego ver su definición y la statement que usa la persona que llama.

Vi este error cuando el código intentó llamar a una función en un objeto que no era del tipo esperado.

Entonces, jerarquía de clases: Padres con hijos: Child1 y Child2

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

Estaba obteniendo un error similar para las API de AutoIt que estaba llamando desde el progtwig VC ++.

  typedef long (*AU3_RunFn)(LPCWSTR, LPCWSTR); 

Sin embargo, cuando cambié la statement que incluye WINAPI, como se sugirió anteriormente en el hilo, el problema desapareció.

El código sin ningún error se ve así:

 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); } 

Obtuve este error llamando a una función en un archivo DLL que se compiló con una versión anterior a 2005 de Visual C ++ desde una versión más nueva de VC (2008). La función tenía esta firma:

 LONG WINAPI myFunc( time_t, SYSTEMTIME*, BOOL* ); 

El problema fue que el tamaño de time_t es de 32 bits en la versión anterior a 2005, pero de 64 bits desde VS2005 (se define como _time64_t ). La llamada de la función espera una variable de 32 bits pero obtiene una variable de 64 bits cuando se llama desde VC> = 2005. Como los parámetros de las funciones se pasan a través de la stack al usar la convención de llamadas WINAPI , esto corrompe la stack y genera el mensaje de error mencionado anteriormente (“Error de comprobación en tiempo de ejecución # 0 …”).

Para solucionar esto, es posible

 #define _USE_32BIT_TIME_T 

antes de incluir el archivo de encabezado de la DLL o – mejor – cambie la firma de la función en el archivo de encabezado dependiendo de la versión VS (las versiones anteriores a 2005 no conocen _time32_t !):

 #if _MSC_VER >= 1400 LONG WINAPI myFunc( _time32_t, SYSTEMTIME*, BOOL* ); #else LONG WINAPI myFunc( time_t, SYSTEMTIME*, BOOL* ); #endif 

Tenga en cuenta que necesita usar _time32_t lugar de time_t en el progtwig de llamada, por supuesto.

¿Está creando libs estáticas o DLL? Si son DLL, ¿cómo se definen las exportaciones? ¿Cómo se crean las bibliotecas de importación?

¿Los prototipos de las funciones en las libs son exactamente los mismos que las declaraciones de funciones donde se definen las funciones?

¿Tiene algún prototipo de función typedef’d (por ejemplo, int (* fn) (int a, int b))

si dom, es posible que haya obtenido el prototipo incorrecto.

ESP es un error en la llamada de una función (¿puede decir cuál en el depurador?) Que tiene una falta de coincidencia en los parámetros, es decir, la stack ha vuelto al estado en el que comenzó cuando llamó a la función.

También puede obtener esto si está cargando funciones de C ++ que necesitan ser declaradas externas. C – C usa cdecl, C ++ usa convención de llamadas stdcall por defecto (IIRC). Coloque algunos envoltorios de C externos alrededor de los prototipos de función importados y puede solucionarlos.

Si puede ejecutarlo en el depurador, verá la función de inmediato. Si no, puede configurar DrWtsn32 para crear un minivolcado que pueda cargar en windbg para ver el callstack en el momento del error (sin embargo, necesitará símbolos o un mapfile para ver los nombres de las funciones).

Otro caso en el que esp puede dañarse es con un desbordamiento inadvertido del búfer, generalmente a través del uso erróneo de punteros para trabajar más allá del límite de una matriz. Digamos que tiene alguna función C que se parece a

 int a, b[2]; 

Escribir en b[3] probablemente cambie a , y en cualquier lugar que pase, es probable que mangue el esp guardado en la stack.

Obtendrá este error si la función se invoca con una convención de llamada diferente a la que está comstackda.

Visual Studio utiliza una configuración de convención de llamada predeterminada que se decaló en las opciones del proyecto. Compruebe si este valor es el mismo en la configuración del proyecto orignal y en las nuevas bibliotecas. Un desarrollador demasiado ambicioso podría haber establecido esto en _stdcall / pascal en el original, ya que reduce el tamaño del código en comparación con el cdecl predeterminado. Entonces, el proceso base usaría esta configuración y las nuevas bibliotecas obtendrían el cdecl predeterminado que causa el problema

Dado que usted ha dicho que no usa ninguna convención de llamadas especiales, esta parece ser una buena probabilidad.

También haga una diferencia en los encabezados para ver si las declaraciones / archivos que el proceso ve son los mismos con los que se comstackn las bibliotecas.

pd: hacer que la advertencia desaparezca es BAAAD. el error subyacente aún persiste.

Esto me sucedió al acceder a un objeto COM (Visual Studio 2010). Pasé el GUID para otra interfaz A en mi llamada a QueryInterface, pero luego proyecté el puntero recuperado como interfaz B. Esto dio como resultado hacer una llamada de función a una con una firma completa, lo que representa la stack (y ESP) hecho un desastre.

Pasar el GUID para la interfaz B solucionó el problema.

Estaba teniendo exactamente el mismo error después de mover las funciones a un dll y cargar dinámicamente el dll con LoadLibrary y GetProcAddress. Había declarado extern “C” para la función en el dll debido a la decoración. Entonces eso cambió la convención de llamadas a __cdecl también. Estaba declarando que los punteros a las funciones son __stdcall en el código de carga. Una vez que cambié el puntero de función de __stdcall a__cdecl en el código de carga, el error de tiempo de ejecución desapareció.

En mi aplicación MFC C ++ estoy experimentando el mismo problema que el reportado en el error Weird MSC 8.0: “El valor de ESP no se guardó correctamente en una llamada a función …” . La publicación tiene más de 42,000 vistas y 16 respuestas / comentarios, ninguno de los cuales culpó al comstackdor como el problema. Al menos en mi caso, puedo demostrar que el comstackdor VS2015 tiene la culpa.

Mi configuración de prueba y desarrollo es la siguiente: tengo 3 PC, todas las cuales ejecutan la versión 10.0.10586 de Win10. Todos están comstackndo con VS2015, pero aquí está la diferencia. Dos de los VS2015 tienen la Actualización 2, mientras que el otro tiene la Actualización 3 aplicada. La PC con la Actualización 3 funciona, pero las otras dos con la Actualización 2 fallan con el mismo error que se informó en la publicación anterior. El código de mi aplicación MFC C ++ es exactamente el mismo en las tres PC.

Conclusión: al menos en mi caso para mi aplicación, la versión del comstackdor (Actualización 2) contenía un error que rompió mi código. Mi aplicación hace un uso intensivo de std :: packaged_task así que espero que el problema esté en ese código de comstackción bastante nuevo.

Vale la pena señalar que esto también puede ser un error de Visual Studio.

Tengo este problema en VS2017, Win10 x64. Al principio tenía sentido, ya que estaba haciendo cosas raras lanzando esto a un tipo derivado y envolviéndolo en una lambda. Sin embargo, revertí el código a una confirmación previa y todavía obtuve el error, aunque no estaba allí antes.

Intenté reiniciar y luego reconstruir el proyecto, y luego desapareció el error.

ESP es el puntero de la stack. Entonces, de acuerdo con el comstackdor, su puntero de stack se está arruinando. Es difícil decir cómo (o si) podría estar sucediendo sin ver algún código.

¿Cuál es el segmento de código más pequeño que puede obtener para reproducir esto?

Si está utilizando funciones de callback con la API de Windows, deben declararse utilizando CALLBACK y / o WINAPI . Eso aplicará las decoraciones apropiadas para que el comstackdor genere código que limpia la stack correctamente. Por ejemplo, en el comstackdor de Microsoft, agrega __stdcall .

Windows siempre ha usado la convención __stdcall ya que conduce a un código (ligeramente) más pequeño, con la limpieza ocurriendo en la función llamada en lugar de en cada sitio de llamada. Sin embargo, no es compatible con las funciones varargs (porque solo quien llama sabe cuántos argumentos presionaron).

Aquí hay un progtwig reducido de C ++ que produce ese error. Comstackdo usando (Microsoft Visual Studio 2003) produce el error mencionado anteriormente.

 #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(); } 

ERROR: "Error de comprobación en tiempo de ejecución # 0: el valor de ESP no se guardó correctamente en una llamada de función. Esto es generalmente el resultado de llamar a una función declarada con una convención de llamada con un puntero de función declarado con una convención de llamada diferente".

Tuve el mismo problema aquí en el trabajo. Estaba actualizando un código muy antiguo que llamaba a un puntero de función FARPROC. Si no lo sabe, los FARPROC son punteros de función con seguridad de tipo ZERO. Es el equivalente en C de un puntero de función tipdef’d, sin la comprobación de tipo de comstackdor. Entonces, por ejemplo, supongamos que tiene una función que toma 3 parámetros. Le apuntas un FARPROC y luego lo llamas con 4 parámetros en lugar de 3. El parámetro extra extrajo más basura en la stack, y cuando aparece, ESP ahora es diferente de cuando comenzó. Así que lo resolví eliminando el parámetro adicional a la invocación de la llamada a la función FARPROC.

No es la mejor respuesta pero acabo de volver a comstackr mi código desde cero (reconstruir en VS) y luego el problema desapareció.