Странное повреждение памяти - PullRequest
2 голосов
/ 07 мая 2011

Эта ошибка возникает только при сборке с компилятором WinmaDK nmake в 'free' (выпуск), который выполняет оптимизацию. Я не могу воспроизвести это в «проверенной» сборке или компиляции с VS.

Вот псевдокод того, что происходит в моем коде:

main()
{
   //variable init and other code
    fprintf(log, "pre nullValue: %lu\n", NULL);  //printf added for debugging
   otherFunc();
   funcWithError(str1, str2, NULL);
    fprintf(log, "post nullValue: %lu\n", NULL); 
    fprintf(log, "post2 nullValue: %lu, %lu, %lu\n", NULL, 0, NULL);
}

BOOL otherFunc()
{
   //variable init and other code
   callToDll();
    //...doing stuff
   libusb_usb_open(var1);    //If I remove this line there is no problem!!
    //...doing more stuff
}

BOOL funcWithError(char* s1, char* s2, FUNC_PTR fp)
{
    fprintf(log, "inFunc nullValue: %lu, %lu\n", NULL, fp);
   if(fp != NULL)
      return FALSE;        //This line is being executed erroneously!!
}

Вывод в лог:
pre nullValue: 0
inFunc nullValue: 0, 251208
post nullValue: 251208
post2 nullValue: 251208, 251208, 251208
Примечание. Повторяющийся номер (251208) - это разное число при каждом запуске программы

Просто изменение этой строки исправляет / вызывает это. Это libusb usb_open вызов.

  1. В конечном счете, мой вопрос - выяснить, как решить проблему (я не могу избежать этого звонка)
  2. Но только на уровне управления стеком / памятью, как вообще возможно иметь значение NULL, отличное от нуля, и иметь буквенное значение '0', печатаемое как ненулевое?

дайте мне знать, какая другая информация может помочь ...

Ответы [ 2 ]

3 голосов
/ 07 мая 2011

Не совсем хлам. Но очень вероятно, что стек становится несбалансированным. В отладчике (да, вы можете отлаживать сборку релиза) проверьте значение регистра ESP до и после вызова. Это должно быть то же самое. Это не будет, если соглашение о вызовах для функции неверно. Как __stdcall против __cdecl.

Это может хорошо спрятаться при сборке программ с помощью nmake.exe, легко забыть включить параметр / RTCs в отладочной сборке, чтобы код проверки стека передавался. И регистр ESP имеет тенденцию восстанавливаться при возврате функции. До тех пор, пока вы не создадите версию выпуска, в которой функции встроены, а использование EBP оптимизировано, поэтому ESP больше не восстанавливается.

0 голосов
/ 11 мая 2011

Обновление: итак, я наконец получил windbg, чтобы взломать dll и изучить некоторые вещи.Это было, как я изначально подозревал, и, как заметил Ганс, повреждение стека, вызванное несоответствующим соглашением о вызовах.

Что было видно только в сборке релиза, так это то, что компилятор оптимизировал значения 0 / Null, чтобы использовать значение регистра ebx вместо передачи 0. В OtherFunc () оптимизации использовали ebx для хранения нескольких других значений, затем вызов Usb_Open () повредил стек, затем, когда OtherFunc () попытался вытолкнуть стек, чтобы восстановить исходное значение ebx, он восстановил мусор, а не «0».Итак, в main () каждая оптимизированная ссылка на NULL использовала это значение мусора.

Примечание: причина, по которой другие вызовы dll не повредили стек, заключалась в том, что они были без параметров.

Итак, в заключение ответы:

  1. Вызовите libusb, используя правильное соглашение (libusb использует соглашение о вызовах __cdecl, NMAKE использует __stdcall по умолчанию)
  2. Даже если NULL и '0' сложнызакодированный в исходном коде, компилятор может оптимизировать использование регистра вместо передачи значения, и регистры могут быть повреждены из-за неверного кода.
...