Может ли этот код вызвать повреждение управляемой кучи? - PullRequest
5 голосов
/ 04 октября 2011

Я пытаюсь отладить сбой, который происходит в нашем приложении во время сбора мусора, и, глядя на код, я обнаружил два связанных фрагмента кода, которые, если не являются причиной проблемы, по крайней мере, являются для меня подозрительными:

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

Обратите внимание, что, насколько я понимаю, структура на самом деле имеет размер не менее 98 байт, но объявляется длиной 96 байт (хотя код компилируется).

Второй подозрительный фрагмент кода связанв приведенной выше структуре:

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

, где m_RawData - простой байтовый массив без знака, а TMilbusData - код C ++ (собственный), аналогичный приведенной выше структуре, определяемый как

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

Что яя не уверен в том, что во втором случае преобразование из нативной структуры в управляемый ссылочный тип безопасно (обратите внимание, что MilbusData не объявлен как тип значения).

AsЯ сказал, что сбои, которые мы испытываем, происходят обычно во время сбора мусора, но иногда их чрезвычайно трудно воспроизвести.Я дал более подробную информацию о самой аварии в другом вопросе , но здесь я хочу спросить:

  • Безопасен ли приведенный выше код?
  • А если нет, то может ли это быть причиной управляемой повреждения кучи и объяснить поэтому сбои, которые мы испытываем?

РЕДАКТИРОВАТЬ : я, вероятно, должен был иметьспросил, является ли абсолютно положительным , что проблемы, которые я обнаружил в коде (как несоответствие размеров структуры между собственным и управляемым кодом), могут быть причиной сбоя в GC.Причина для того, чтобы спросить: i) компилятор C # не жалуется на неправильный размер структуры и ii) проблему очень трудно воспроизвести.Я сейчас испытываю трудности в том, чтобы заставить его рухнуть в «старой» версии (где размер структуры неправильный), и я хотел избежать возможного тупика, так как каждое тестирование может занять много дней.

1 Ответ

3 голосов
/ 04 октября 2011

но компилятор не должен видеть, что 96 байт недостаточно для сохранить структуру и увидеть это как ошибку? В любом случае, может ли это в одиночку объяснить сбои во время сборки мусора?

Возможно, вы захотите хранить только определенное количество данных, скажем, первые 16 бит, из 32 бит целого числа.

Говоря, что размер структуры ограничен 96 байтами, если вы попытаетесь разместить в структуре более 96 байтов, вы попытаетесь выйти за пределы памяти, выделенной вами, в зависимости от размера структуры.

Это означает, что вы будете 1) удерживать только 96 байтов в структуре 2) при попытке разместить больше выделенной памяти возникают проблемы с управлением памятью.

Как я уже сказал, в вашем коде нет ничего плохого, он скомпилируется. в данном случае это просто неверно, и структура не объявлена ​​правильно, поэтому вы не должны либо объявлять размер, либо объявлять правильный размер.

РЕДАКТИРОВАТЬ: Я, вероятно, должен был спросить, если это абсолютно положительно, что проблемы, которые я нашел в коде (как несоответствующая структура размеры между собственным и управляемым кодом) может быть причиной сбоя в GC. Причина для того, чтобы спросить, что я) Компилятор C # не жалуется о неправильном размере структуры и II) проблема очень сложная воспроизвести. Я сейчас испытываю трудности в том, чтобы заставить его врезаться в «старая» версия (где размер структуры неправильный), и я хотел чтобы избежать возможного тупика, так как каждое тестирование может занять много дней ..

Все, что я могу вам пообещать, это неправильный размер структуры в 96 байт, я не могу сказать вам, связана ли проблема, связанная с аварийным завершением, с подключенным сборщиком мусора, с подключением к этой структуре. Если эта структура не так, какие другие структуры не так?

Я бы установил размер и удостоверился в том, что тип данных правильный, чтобы соответствовать данным, которые вы получите от вашего устройства.

...