Parámetro de estructura dañado en la llamada de función

Tengo problemas para rastrear la causa de un comportamiento extraño al pasar una estructura como parámetro.

La estructura en cuestión, structFoo, tiene la siguiente declaración:

typedef struct _structFoo {
    int id;
    BSTR szDescription;
    VARIANT vData;
    BOOL bTransient;
} structFoo;

Tengo dos módulos, A y B. El módulo A llama a B::foo( int id, uint filter, structFoo sF ). En A, antes de la llamada, la estructura structFoo se forma correctamente y se llena con datos válidos. Sin embargo, una vez que se realiza la llamada de función a B::foo(), el parámetro structFoo contiene datos basura. Tras un examen más detallado, resulta que la dirección de la estructura copiada se coloca en el campo de identificación y szDescription apunta a la cadena utilizada más recientemente. Los otros parámetros son correctos después de la llamada a la función.

No estoy seguro de la razón de esta desalineación, o lo que sea que esté sucediendo, pero me parece que hasta que se realiza la llamada a la función, todo está en su lugar correcto. Aquí está el desmontaje que conduce a la llamada de función:

0000000006003211  lea         rdi,[rsp+230h] 
0000000006003219  lea         rsi,[sAttPairId] 
0000000006003221  mov         ecx,30h 
0000000006003226  rep movs    byte ptr [rdi],byte ptr [rsi] 
0000000006003228  mov         rax,qword ptr [piConstruct] 
0000000006003230  mov         rax,qword ptr [rax] 
0000000006003233  lea         r9,[rsp+230h] 
000000000600323B  mov         r8d,800h 
0000000006003241  mov         edx,dword ptr [iHighNodeId] 
0000000006003248  mov         rcx,qword ptr [piConstruct] 
0000000006003250  call        qword ptr [rax+60h] 

Y aquí está el desmontaje después de la llamada a la función:

0000000004B72470  mov         qword ptr [rsp+20h],r9 
0000000004B72475  mov         dword ptr [rsp+18h],r8d 
0000000004B7247A  mov         dword ptr [rsp+10h],edx 
0000000004B7247E  mov         qword ptr [rsp+8],rcx 
0000000004B72483  push        rsi  
0000000004B72484  push        rdi  
0000000004B72485  sub         rsp,0A8h 
0000000004B7248C  mov         rdi,rsp 
0000000004B7248F  mov         rcx,2Ah 
0000000004B72499  mov         eax,0CCCCCCCCh 
0000000004B7249E  rep stos    dword ptr [rdi] 
0000000004B724A0  mov         rcx,qword ptr [rsp+0C0h] 
0000000004B724A8  mov         qword ptr [rsp+90h],0FFFFFFFFFFFFFFFEh

Una vez que el sub rsp, 0A8h todos los parámetros están configurados con datos, pero el parámetro sF tiene la dirección de la información correcta de structFoo en su campo de identificación, en lugar de usar esta dirección como su propio puntero. Cualquier orientación para resolver esto es muy apreciada.

Como nota al margen, lamentablemente no es una opción cambiar B::foo() para que tome la dirección de la estructura en lugar de la estructura en sí. Una gran parte del código heredado se basa en esta función que no tengo la autoridad para cambiar.

¡Gracias!

preguntado el 12 de junio de 12 a las 17:06

¿Puedes mostrar el código para B::foo( int id, uint filter, structFoo sF ) ? -

hay no hay necesidad para declarar estructuras como typedef struct TAG_NAME {} REAL_NAME; en C++. Solo haz struct REAL_NAME {}; -

@ahenderson: esto suele ser un remanente de C. -

¿Se compilan los dos módulos con argumentos de compilación idénticos? ¿Quizás cada uno de ellos se está compilando con una alineación diferente, por lo que el diseño físico de la estructura es diferente dentro de cada módulo? -

Solo adivina: ¿tal vez tienes una violación de ODR (por ejemplo, debido a alguna macro que afecta la definición de la estructura)? -

2 Respuestas

supongo, módulos A y B se compilan con diferentes convenciones de llamadas. Módulo A pasa estructuras a funciones por referencia/puntero, mientras que módulo B espera recibir estructuras en la pila, por valor.

Puede haber un modificador en Barchivo de encabezado de, así:

__weird_call void B::foo( int id, uint filter, structFoo sF );

Tal vez el compilador del módulo. A no lo entiende, o algún otro archivo de encabezado lo define (#define __weird_call /* nothing */), o algo por el estilo.

Respondido el 12 de junio de 12 a las 18:06

Me topé con esta página mientras buscaba una respuesta a un problema similar al que me enfrenté. Aunque no pude encontrar respuesta en internet, comparto la experiencia de depuración.

La siguiente estructura se pasó por referencia de una función a otra, y el receptor encontraría que los datos recibidos eran inesperados:

typedef struct
{
    char time_st[30];
    char pipe_no;
    float loss;
    float power[4];
    int   mode;
    int   count;
}Parameters;

Otro hallazgo fue que si defino la función de receptor en el mismo archivo que la función de llamador, el problema desaparecería.

Tras la depuración, se descubrió que la causa raíz era el uso espagueti de "#pragma pack" en archivos .h heredados en el sistema que causan problemas de empaquetamiento de estructuras, debido a la inclusión de varios archivos de encabezado heredados en el archivo .c de la función de llamada. , la estructura estaba empaquetada, pero en el archivo .c de la función receptora (que se escribió de nuevo durante la actividad del proyecto), la estructura se trató como desempaquetada.

Resolución: agregue suficiente relleno para alinear la palabra de estructura

typedef struct
{
    char time_st[30];
    char pad;
    char pipe_no;
    float loss;
    float power[4];
    int   mode;
    int   count;
}Parameters;

Respondido 03 Jul 14, 06:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.