什么会导致 SysFreeString 遇到 Int 3 断点?

发布于 2024-09-12 17:05:48 字数 928 浏览 1 评论 0原文

我有一些代码在 Delphi 2007 下运行良好,但在 D2010 下崩溃。它涉及传入一个字符串,将其转换为 PWideChar(具体来说,是 WideString 指针,而不是 UnicodeString 指针),进行一些处理,然后对其调用 SysFreeString。它工作正常,直到传入一个空白字符串,然后 SysFreeString 中断。它调用了一堆东西,最终在 NTDLL.DLL 内引发了 Int 3 断点。继续经过这一点会导致

项目引发异常类 $C0000005 带有消息“访问” 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,并且没有 非空白时出现双重释放错误 字符串被传入。不幸的是,我 无法真正发布代码示例 因为这是第三方 受版权保护的组件。 (和 我无法请求他们的支持,因为 它不再受支持。基本上, 整件事一团糟。)

I've got some code that worked fine under Delphi 2007 but breaks under D2010. It involves passing in a string, converting it to a PWideChar (specifically, a WideString pointer, not a UnicodeString pointer), doing some processing, and then calling SysFreeString on it. It works fine until a blank string is passed in, then SysFreeString breaks. It calls a bunch of things that end up raising an Int 3 breakpoint inside NTDLL.DLL. Continuing past this point results in

Project raised exception class
$C0000005 with message 'access
violation at 0x7747206e: read of
address 0x539b8dba'.

Which, if you look closely, is not the standard Access Violation message.

The top of the stack trace when it hits the Int 3 looks like this:

: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

Does anyone have any idea what's going on here?

Edit (from the comments):

This isn't a WideString, though. It's
a PWideChar generated by
StringToOleStr, and there are no
double-free errors when a non-blank
string is passed in. Unfortunately, I
can't really post a code sample
because this is a third-party
component that's under copyright. (And
I can't ask them for support because
it's no longer supported. Basically,
the whole thing's one big mess.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

橘味果▽酱 2024-09-19 17:05:48

如果不查看实际代码,很难进行诊断,但是当 WideString 超出范围时,它会自动调用 SysFreeString()。听起来您的代码可能正在对已释放的内存进行第二次调用 SysFreeString() 。 WideString 本身在 D2007 和 D2010 之间根本没有改变,但 Delphi 字符串处理的其他方面却发生了变化。也许您没有正确管理字符串。您能显示您的实际代码吗?

It is hard to diagnose without seeing your actual code, however WideString automatically calls SysFreeString() when it goes out of scope. It sounds like your code may be making a second call to SysFreeString() on memory that has already been freed. WideString itself has not changed at all between D2007 and D2010, but other aspects of Delphi's string handling have. Maybe you are not managing the strings correctly. Can you please show your actual code?

玩世 2024-09-19 17:05:48

我要尝试心灵调试。您的应用程序中存在某种堆损坏,而 SysFreeString 是不幸的受害者(如果没有操作系统符号,很难判断,您可能应该为您的操作系统安装 MSFT 符号包)。

尝试为您的应用程序启用应用程序验证程序(特别是页面堆),看看它是否会更早崩溃。

I'm going to try psychic debugging. You've got some kind of heap corruption in your application and SysFreeString is the unfortunate victim (it's hard to tell without OS symbols, you should probably install the MSFT symbol packages for your OS).

Try enabling application verifier (in particular pageheap) for your app and see if it crashes earlier.

⒈起吃苦の倖褔 2024-09-19 17:05:48

一个简单的测试表明,您需要非常小心按顺序执行操作。

那么:即使您无法发布一个小示例,您能否更详细地说明您正在做什么?

调试不好;忽略下面的事情;见评论。

Allocate() 调用结束时调用 SysFreeString(),即使它返回 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”,因为内存尚未被覆盖。

<罢工>--杰罗恩

A simple test shows that you need to be really careful on what you do in which order.

So: even though you cannot post a small example, can you indicate what you are doing in a bit more detail?

Bad debugging; ignore the things below; see comment.

The SysFreeString() is being called at the end of the the Allocate() call, even though it returns a 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.

Note the console still outputs 'Foo' because the memory has not been overwritten yet.

--jeroen

寄意 2024-09-19 17:05:48

此类错误可能有不同的原因:

  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() 在不同的可疑地方,您可以非常快速地定位损坏的地方。

It can be different reasons of such kind of errors:

  1. You try to free with SysFreeString a memory which are allocated not with SysAllocString, but for example with CoTaskMemAlloc.
  2. You have heap correct.

Heap corruptions are difficult to localize. The function HeapSetInformation can be very helpful. For example you can use

HeapSetInformation(NULL,HeapEnableTerminationOnCorruption,NULL,0);

Other good way is usage of HeapValidate function. For example you can define a function which verify all heaps pf the process (code in C, which can be easy rewritten in 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;
}

The usage of this function can be like following:

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

With respect of inserting MyHeapValidate() in different suspected places you can very quickly local the place of corruption.

想挽留 2024-09-19 17:05:48

拉里·奥斯特曼的回答+1。

某些 Windows 内存函数在调试器下的行为略有不同:如果它们检测到某种误用 - 它们会触发断点以通知调试器。所以,基本上,你的代码做错了什么。

您可以在 SysAllocString/SysFreeString 上安装挂钩,并将它们重定向到内存管理器(应处于完全调试模式)以收集更多信息。或者,您可以将这些调用传递给原始函数,仅安装一个过滤器来监视内存操作。

您可以安装调试符号来获取还有更多信息(我不确定 Delphi 调试器是否可以使用它,但 Process Explorer - 可以。您可以将其连接到您的进程并查看调用堆栈)。

+1 for Larry Osterman's answer.

Some Windows memory functions behave slightly different under debugger: if they detect some kind of misuse - they trigger breakpoint to notify debugger. So, basically, your code is doing something wrong.

You can install hooks on SysAllocString/SysFreeString and redirect them to your memory manager (which should be in full debug mode) to collect more info. Or you can just pass these calls through to original functions, installing only a filter, which watches for memory actions.

And you can install debug symbols to get more info too (I'm not sure if Delphi debugger can use it, but Process Explorer - can. You can connect it to your process and see call stack).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文