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.
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
Gracias por señalar esto, fue un error al editar el código publicarlo aquí, ahora está arreglado. – floyd73
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 –