2011-10-04 20 views
5

Estoy intentando depurar un bloqueo que ocurre en nuestra aplicación durante la recolección de basura y al mirar el código encontré dos piezas relacionadas de código que, si no es la causa del problema, son al menos sospechosas para mí:¿Puede este código causar una corrupción del montón administrado?

[StructLayout(LayoutKind.Sequential, Size = 96, CharSet = CharSet.Ansi, Pack=1)] 
public class MilbusData 
{ 
    public System.Int64 TimeStamp; 
    public System.Int16 Lane; 
    public System.Int16 TerminalAddress; 
    public System.Int16 TerminalSubAddress; 
    public System.Int16 Direction; 
    public System.Int64 ErrorCounter; 
    public System.Int64 MessageCounter; 
    public System.Int16 RTErrorState;  
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
    public System.UInt16[] Data; 
} 

Tenga en cuenta que, a mi entender, la estructura es en realidad de al menos 98 bytes de tamaño, pero se declara como de 96 bytes de longitud (sin embargo, el código se compila).

La segunda pieza sospechosa de código está relacionada con la estructura anterior:

MilbusData^ ret = nullptr; 
if (m_Stream->Read(m_RawData, 0, sizeof(TMilbusData)) == sizeof(TMilbusData)) 
{ 
    GCHandle pinnedRawData = GCHandle::Alloc(m_RawData, GCHandleType::Pinned); 

    ret = (MilbusData^)Marshal::PtrToStructure(pinnedRawData.AddrOfPinnedObject(), 
              MilbusData::typeid); 

    pinnedRawData.Free(); 
} 

donde m_RawData es un simple matriz de bytes sin signo y TMilbusData es el C++ (nativo) código análogo de la struct arriba, definido como

typedef struct 
{ 
    __int64 TimeStamp; 
    short Lane; 
    short TerminalAddress; 
    short TerminalSubAddress; 
    short Direction; 
    __int64 ErrorCounter; 
    __int64 MessageCounter; 
    short RTErrorState; 
    unsigned char Data[64]; 
} TMilbusData; 

lo que no estoy seguro acerca de en este segundo caso es si la conversión de la estructura nativa de una referencia de tipo gestionado es seguro (tenga en cuenta que MilbusData no se declara como un tipo de valor).

Como dije, los bloqueos que estamos experimentando ocurren normalmente durante la recolección de basura pero a veces son extremadamente difíciles de reproducir. Me dio más detalles sobre el accidente en sí en otro question pero lo que quiero hacer aquí es:

  • es el código de arriba seguro?
  • Y si no puede ser la causa de una corrupción de montón administrada y explicar, por lo tanto, los bloqueos que estamos experimentando?

EDITAR: probablemente debería haber preguntado si es absolutamente positivos que las cuestiones que he encontrado en el código (como el tamaño de la estructura de desajuste entre nativos y código administrado) puede ser la causa de un accidente en el GC. La razón para preguntar es que i) El compilador de C# no se queja sobre el tamaño incorrecto de la estructura y ii) El problema es muy difícil de reproducir. En este momento estoy teniendo dificultades para hacerlo colapsar en la versión "vieja" (donde el tamaño de la estructura es incorrecto) y quería evitar un posible callejón sin salida ya que cada prueba puede llevar muchos días.

+0

Solo un rápido escaneo del código muestra que está redefiniendo el valor 'ret' dentro de la instrucción if de su segundo bloque de código. Eso podría llevar a confusión si nada más. – pstrjds

+0

Gracias por señalar esto, fue un error al editar el código publicarlo aquí, ahora está arreglado. – floyd73

+1

No está creando suficiente espacio en su código administrado. Tu matriz también tiene diferentes tamaños. ¿Ha verificado que la estructura funciona en su tamaño actual, porque en función de lo que publicó, ni siquiera es lo suficientemente grande como para contener todo. Qué estándar militar es este, se ve casi como MIL-STD-1553. ¿Cómo está tu código C# consciente de tu código C++, normalmente tengo que crear una clase contenedora, si estoy tratando con algo como esto –

Respuesta

3

pero no debería el compilador ver que 96 bytes no son suficientes para almacenar la estructura y ver esto como un error? En cualquier caso, ¿podría esto solo explicar los bloqueos durante la recolección de basura?

Es posible que solo desee almacenar una cierta cantidad de datos, por ejemplo, los primeros 16 bits, de los 32 bits de un entero.

Al decir que el tamaño de la estructura está limitado a 96 bytes, si intenta colocar más de 96 bytes en la estructura, intentará salir de la memoria que asignó según el tamaño de la estructura.

Esto significa que va a 1) Solo mantener 96 bytes en la estructura 2) Cuando intente colocar más, la memoria asignada se ejecutará en problemas de administración de memoria.

Como ya he dicho, no hay nada de malo en su código, se compilará.simplemente no es correcto en este caso, y la estructura no está declarada correctamente, por lo que no debe declarar el tamaño ni declarar el tamaño correcto.

EDIT: probablemente debería haber preguntado si es absolutamente positivo que los problemas que he encontrado en el código (como la estructura no coincidente tamaños entre nativos y código administrado) pueden ser la causa de un accidente en el GC. La razón para preguntar es que i) El compilador C# no se queja sobre el tamaño incorrecto de la estructura y ii) El problema es muy difícil para reproducirse. En este momento estoy teniendo dificultades para hacerlo colapsar en la versión "vieja" (donde el tamaño de la estructura es incorrecta) y quería para evitar seguir un posible callejón sin salida ya que cada prueba puede tomar muchos días ..

Todo lo que puedo prometer es el tamaño de la estructura no es correcta en 96 bytes, no se puede saber si el problema que tiene con accidente conectada al recolector de basura, es la conexión a esta estructura. Si esta estructura es incorrecta, ¿qué otras estructuras están equivocadas?

Corregiré el tamaño y me aseguraré de que Data sea del tipo correcto, para que coincida con los datos que recibirá de su dispositivo.

+0

gracias Ramhound, como mencioné en nuestra discusión en los comentarios, actualmente estoy probando si la aplicación falla con la estructura declarada con el tamaño correcto, pero esto puede llevar varios días. Publicaré mis resultados aquí después de la prueba y dejaré la pregunta abierta hasta entonces. – floyd73

+0

@ floyd73 - Debe verificar que ** m_RawData ** tenga el tamaño correcto antes de continuar con la prueba. No creo que Sizeof pueda determinar el tamaño de su matriz si está vacía. –

+0

Acabo de hacer que la aplicación antigua se bloquee nuevamente y ahora probaré el código fijo y veré si no falla en las próximas 24 horas, ¡gracias por su ayuda! (y sobre el m_RawData se asigna solo una vez para que su tamaño sea constante, lo que estoy verificando en la cláusula if es cuántos bytes se leyeron de la transmisión) – floyd73

Cuestiones relacionadas