Что может вызвать SysFreeString для достижения точки останова Int 3? - PullRequest
1 голос
/ 04 августа 2010

У меня есть код, который отлично работал под Delphi 2007, но не работает под D2010. Он включает передачу строки, преобразование ее в PWideChar (в частности, указатель WideString, а не указатель UnicodeString), выполнение некоторой обработки, а затем вызов SysFreeString для нее. Работает нормально, пока не передается пустая строка, затем SysFreeString обрывается. Он вызывает кучу вещей, которые в итоге поднимают точку останова Int 3 внутри NTDLL.DLL. Продолжение после этой точки приводит к

Проект поднял класс исключения $ C0000005 с сообщением 'access нарушение в 0x7747206e: чтение из адрес 0x539b8dba '.

Что, если присмотреться, не является стандартным сообщением о нарушении прав доступа.

Вершина трассировки стека при попадании на Int 3 выглядит следующим образом:

:774e475d ; ntdll.dll
:774afad0 ; ntdll.dll
:774e5de9 ; ntdll.dll
:774a6dff ; ntdll.dll
:76fc1075 ; C:\Windows\system32\ole32.dll
:770e443a ; C:\Windows\system32\oleaut32.dll
:770e3ea3 oleaut32.SysFreeString + 0x4a

Кто-нибудь знает, что здесь происходит?

Редактировать (из комментариев):

Хотя это не WideString. Это PWideChar, сгенерированный StringToOleStr, а там нет ошибки двойного освобождения, когда непустой строка передается. К сожалению, я не могу опубликовать пример кода потому что это сторонний Компонент, который находится под авторским правом. (А также Я не могу попросить их о поддержке, потому что это больше не поддерживается. В принципе, все это один большой беспорядок.)

Ответы [ 5 ]

3 голосов
/ 04 августа 2010

Я собираюсь попробовать психическую отладку. В вашем приложении есть какая-то куча повреждений, и SysFreeString - неудачная жертва (без символов ОС трудно сказать, вам, вероятно, следует установить пакеты символов MSFT для вашей ОС).

Попробуйте включить верификатор приложения (в частности, pageheap) для своего приложения и посмотрите, не произойдет ли оно раньше.

2 голосов
/ 04 августа 2010

Трудно диагностировать, не видя ваш реальный код, однако WideString автоматически вызывает SysFreeString (), когда он выходит из области видимости. Похоже, ваш код выполняет второй вызов SysFreeString () в памяти, которая уже была освобождена. Сама WideString вообще не изменилась между D2007 и D2010, но есть и другие аспекты обработки строк в Delphi. Возможно, вы не правильно управляете строками. Можете ли вы показать свой фактический код?

0 голосов
/ 07 августа 2010

Причины такого рода ошибок могут быть разными:

  1. Вы пытаетесь освободить с помощью SysFreeString память, которая выделена не с SysAllocString, а, например, с CoTaskMemAlloc.
  2. У вас правильная куча.

Повреждения кучи трудно локализовать.Функция HeapSetInformation может быть очень полезна.Например, вы можете использовать

HeapSetInformation(NULL,HeapEnableTerminationOnCorruption,NULL,0);

Другим хорошим способом является использование функции HeapValidate.Например, вы можете определить функцию, которая проверяет все кучи процесса (код на C, который может быть легко переписан на Delphi):

BOOL MyHeapValidate (void)
{
    HANDLE  hProcessHeaps[1024];
    DWORD   i;
    DWORD   dwNumberOfHeaps;
    BOOL    bSuccess = FALSE;

    dwNumberOfHeaps = GetProcessHeaps (sizeof(hProcessHeaps)/sizeof(hProcessHeaps[0]),
                                       hProcessHeaps);
    if (dwNumberOfHeaps > sizeof(hProcessHeaps)/sizeof(hProcessHeaps[0])) {
        MessageBox(NULL, TEXT("GetProcessHeaps()"),
                   TEXT("Error in MyHeapValidate()"), MB_OK);
        return FALSE;
    }

    for (i=0; i<dwNumberOfHeaps; i++) {
        bSuccess = HeapValidate (hProcessHeaps[i], 0, NULL);
        if (!bSuccess)
            return bSuccess;
    }

    return bSuccess;
}

Использование этой функции может быть следующим:

void BadFunction(BSTR bstr)
{
    LPOLESTR psz = OLESTR("Test12");
    lstrcpy (bstr, psz);
}

int main()
{
    LPOLESTR psz = OLESTR("Test");

    BSTR bstr = SysAllocString (psz);

    // verify that before call of BadFunction() all process heaps are OK!
    if (!MyHeapValidate()) {
        _tprintf(TEXT("heap is corrupted after the step 1.\n"));
        return 1;
    }

    BadFunction(bstr);

    if (!MyHeapValidate()) {
        _tprintf(TEXT("heap is corrupted after the step 1.\n"));
        return 1;
    }
    SysFreeString (bstr);

    return 0;
}

В отношении вставки MyHeapValidate() в разные подозрительные места вы можете очень быстро определить место повреждения.

0 голосов
/ 04 августа 2010

Простой тест показывает, что вам нужно быть очень осторожным в том, что вы делаете в каком порядке.

Итак: даже если вы не можете опубликовать небольшой пример, можете ли вы указать, что вы делаете, более подробно?

плохая отладка; игнорировать вещи ниже; см. комментарий.

SysFreeString() вызывается в конце вызова Allocate(), даже если он возвращает PWideChar:

program ShowStringToOleStrBehaviourProject;

{$APPTYPE CONSOLE}

uses
  SysUtils;

function Allocate(const Value: UnicodeString): PWideChar;
begin
  Result := StringToOleStr(Value);
// implicit  SysFreeString(WideChars);
end;

procedure Run;
var
  WideChars: PWideChar;
begin
  WideChars := Allocate('Foo');
  Writeln(WideChars);
end;

begin
  try
    Run();
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Обратите внимание, что консоль все еще выводит 'Foo', потому что память еще не была перезаписана.

- Йерун

0 голосов
/ 04 августа 2010

+ 1 для ответа Ларри Остермана.

Некоторые функции памяти Windows ведут себя немного иначе при отладчике: если они обнаруживают какое-то неправильное использование - они вызывают точку останова, чтобы уведомить отладчик.Так что, в основном, ваш код делает что-то не так.

Вы можете установить хуки в SysAllocString / SysFreeString и перенаправить их в менеджер памяти (который должен находиться в режиме полной отладки) для сбора дополнительной информации.Или вы можете просто передать эти вызовы исходным функциям, установив только фильтр, который отслеживает действия памяти.

И вы можете установить символы отладки , чтобы получить больше информации (яне уверен, может ли отладчик Delphi использовать его, но Process Explorer - может. Вы можете подключить его к своему процессу и увидеть стек вызовов).

...