如果我分配一些内存使用malloc()
是否有一种方法来标记它只读.因此,如果有人试图写入memcpy()会失败吗?
这与错误的api设计有关,用户错过了使用由GetValue()
大型内存结构的一部分的方法返回的const指针 .由于我们希望避免复制大块内存,因此我们将实时指针返回到具有特定格式的结构化内存中.现在的问题是,有些用户通过直接写入这个内存来找到hack来实现工作,并避免使用SetValue()调用来进行分配并正确处理我们开发的内存二进制格式.虽然有时会破解工作,但有时它会因为用户已覆盖的控制标志的错误解释而导致内存访问冲突.
教育用户是一项任务,但我们现在要说,我们希望代码失败.
我只是想知道我们是否可以简单地防止这种情况.
为了类比,假设有人从sqlite语句中获取blob列,然后回写它.虽然在sqlite的情况下,它没有意义,但在我们的情况下这有点讨厌.
我的程序抛出一个错误,它无法通过catch(Exception e)
块处理然后崩溃:
访问冲突已损坏的状态异常.
这是奇怪的事情,因为,据我所知,从非托管代码抛出了损坏的状态异常,而在这里我在调用StringBuilder方法时得到了这个异常.
代码在后台线程中运行并且不时崩溃,这是不容易再现的.所以我将WinDbg附加到进程并具有以下异常堆栈:
000000001dabd8c8 000007feea129a1d [HelperMethodFrame: 000000001dabd8c8]
000000001dabda00 000007fee90cfce8 System.Text.StringBuilder.ExpandByABlock(Int32)
000000001dabda40 000007fee90cfba4 System.Text.StringBuilder.Append(Char*, Int32)
000000001dabdaa0 000007fee9102955 System.Text.StringBuilder.Append(System.String, Int32, Int32)
000000001dabdaf0 000007ff00bf5ce3 MineUtils.Common.Strings.Strings.Replace(System.String, System.String, System.String, Boolean, Boolean)
000000001dabdb90 000007ff00bf5a59 MineUtils.Common.Strings.Strings.RemoveSubstrings(System.String, System.String, System.String, Boolean) [D:\Programs\Visual Studio 2005 Projects\MineUtils.Common\Strings\Strings.Common-Main.cs @ 1481
Run Code Online (Sandbox Code Playgroud)
WinDbg显示发生此异常:
EXCEPTION_RECORD: ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 000007feea129a1d (clr!WKS::gc_heap::find_first_object+0x0000000000000092)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000000
Parameter[1]: 0000000000003d80
Attempt to read from address 0000000000003d80
Run Code Online (Sandbox Code Playgroud)
我读过这样的异常可以使用方法属性[HandleProcessCorruptedStateExceptions]来处理,但是如果我只使用StringBuilder,为什么会发生这种异常呢?
这是之前的WinDbg分析(StringBuilder.ToString()
导致异常):
*******************************************************************************
* * …
Run Code Online (Sandbox Code Playgroud) 使用C++,今天在演示期间发现我正在遭受损坏的堆(但仅在重要场合!!).我在SO上发现了一些帖子,并决定下载Application Verifier和Debugging工具.我目前正在运行Visual Studio 2010.
所以,现在我已经安装了调试工具,我得到一个名为Windows Kits的文件夹.在文件夹中我有一个名为WinDbg的应用程序,我试图打开我的应用程序并运行它.它被罚款但我无法获得有关我的堆损坏的任何信息.然后我安装了验证器,它只给我留下了一个头文件和一个.dll文件,我不知道该怎么办.
所以,任何人都可以告诉我如何使用这个工具,这样我就不会再遭受这样的尴尬时刻了吗?一直在论坛上搜索,因为我甚至不知道如何打开验证器,当我阅读说明如何使用它时,我真的迷失了(从2009年开始)
我是Windows编程的新手,我只是"迷失"两个小时寻找一个每个人都知道的错误:你不能在DLL中创建一个对象并在另一个DLL(或主程序)中销毁它.
我几乎可以肯定,在Linux/Unix上,情况并非如此(如果是的话,请说出来,但我很确定我做了数千次而没有问题......).
在这一点上,我有几个问题:
1)静态链接的DLL使用与主程序不同的堆吗?
2)静态链接的DLL是否映射在主程序的同一进程空间中?(我很确定这里的答案是一个很大的问题,否则将主程序中的函数指针传递给DLL中的函数是没有意义的.)
我说的是普通/常规DLL,而不是COM/ATL服务
编辑:通过"静态链接"我的意思是我不使用LoadLibrary加载DLL但我链接到存根库
我睡不着!:)
我在Windows上有一个相当大的项目,遇到了一些堆损坏问题.我已阅读所有SO,包括这个好主题:如何调试堆损坏错误?但是没有什么比开箱即用更能帮助我了.Debug CRT
和BoundsChecker
检测到堆损坏,但地址总是不同的,并且检测点总是远离实际存储器重写.我没有睡到半夜,并制作了以下黑客:
DWORD PageSize = 0;
inline void SetPageSize()
{
if ( !PageSize )
{
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
PageSize = sysInfo.dwPageSize;
}
}
void* operator new (size_t nSize)
{
SetPageSize();
size_t Extra = nSize % PageSize;
nSize = nSize + ( PageSize - Extra );
return Ptr = VirtualAlloc( 0, nSize, MEM_COMMIT, PAGE_READWRITE);
}
void operator delete (void* pPtr)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(pPtr, &mbi, sizeof(mbi));
// leave pages in reserved state, but free …
Run Code Online (Sandbox Code Playgroud) 我的多线程托管程序中存在堆损坏.做一些测试我发现只有当程序中的后台线程处于活动状态时(它们是可切换的)才会发生损坏.线程使用一些第三方组件.
在检查了线程和第三方组件的代码(使用.NET Reflector)后,我发现它们都是托管的,即没有 "不安全"或"DllImportAttribute"或"P/Invoke".似乎纯托管代码导致堆损坏,这可能吗?
UPDATE
除了使用Marshal类之外,是否有可能在线程未正确同步的情况下破坏堆?一个例子将非常感激.
在一个生产站点上,我们的应用程序(*)反复崩溃,但不可重现.分析崩溃转储清楚地表明它是一个堆损坏:崩溃位于不同的位置,但始终访问kernel32!HeapFree
/ 内部的违规ntdll!RtlpLowFragHeapFree
.Win Dbg !analyze -v
还报告堆损坏.
到目前为止我们尝试的是使用GFlags选项Page Heap运行应用程序.问题是页面堆的内存开销使应用程序不再运行(达到32位进程的虚拟内存限制).
所以,我们不能使用Page Heap.添加哪些其他标志对我们要么有用
HeapFree
?我们正在尝试标志:
希望下一个崩溃转储包含更多关于出错的信息.
我考虑过这些标志,但暂时将它们排除在外:
我(也)遇到的一个问题是,我不确定这些标志在发生内存损坏时如何起作用.当某些内容写入保护页面时,页面堆显然会产生访问冲突,但其他标志如何运行?
我是否必须使用Application Verifier运行应用程序以获取其他标志以帮助您?或者在检查代码检测到某些内容时会引发异常?
这些标志的哪种组合最有意义,以便应用程序仍可以在生产中以良好的性能和内存消耗运行?
(*):它是工业自动化中的32位Windows桌面应用程序.在这种情况下运行在Win7 64bit上(它在许多其他站点上运行得很好).
在堆损坏的情况下,可以new
扔?
如果我理解正确,在堆损坏的情况下,所有赌注都会关闭,任何事情都可能发生.它是否正确?
我有一个c ++ dll,它为我的主要c#应用程序提供一些功能.在这里,我尝试读取文件,将其加载到内存,然后将一些信息(如指针加载数据和内存块计数)返回到c#.Dll成功将文件读取到内存,但在返回主应用程序时,程序因堆损坏而崩溃(检测到严重错误c0000374).
代码非常简单明了,之前我做过类似的事情没有问题,但是我无法弄清楚是什么原因导致问题,我尝试使用"new,malloc和GlobalAlloc"分配内存,但都没有帮助.代码如下:
C++ MyDll:
typedef unsigned long U32;
extern "C" __declspec(dllexport) int ReadFile(LPSTR Path, U32** DataPtr, U32* Count)
{
FILE *fp;
U32 *Data;
CString tempStr(Path);
long fSize;
if(!(fp = fopen(tempStr, "rb"))) {
return 0;
}
// Obtain File Size;
fseek(fp, 0, SEEK_END);
fSize = ftell(fp);
rewind(fp);
Data = (U32 *)GlobalAlloc(0, fSize);
if(Data == NULL) {
fclose(fp);
return -1;
}
// Copy file into the buffer.
if(!(*Count = fread(Data, sizeof(U32), fSize / sizeof(U32), fp))) {
fclose(fp);
free(Data);
return -2; …
Run Code Online (Sandbox Code Playgroud) 我正在调试GC堆损坏,并且我想尝试在WinDbg + PageHeap + AppVerifier + GCStress下运行程序.
我在文章软件崩溃中找到了:故障模块mscorwks.dll,版本1.1.4322.2379我可以像这样启用GCStress:
reg.exe add "HKLM\SOFTWARE\Microsoft\.NETFramework" /f /v HeapVerify /t REG_DWORD /d 1
reg.exe add "HKLM\SOFTWARE\Microsoft\.NETFramework" /f /v StressLog /t REG_DWORD /d 1
reg.exe add "HKLM\SOFTWARE\Microsoft\.NETFramework" /f /v GCStress /t REG_DWORD /d 3
reg.exe add "HKLM\SOFTWARE\Microsoft\.NETFramework" /f /v FastGcStress /t REG_DWORD /d 2
Run Code Online (Sandbox Code Playgroud)
(我正在尝试这种方法.它会永远启动程序.我从注册表中删除了最后两个条目以使其工作,可能是方法本身出了问题.)
或者gc_heap :: garbage_collect中没有非托管模块的.NET 4 Runtime中的文章访问冲突描述了另一种方法:
(DWORD) StressLog = 1
(DWORD) LogFacility = 0xffffffff
(DWORD) StressLogSize = 65536
Run Code Online (Sandbox Code Playgroud)
哪种方式是正确的还是有另一种正确的方法?
heap-corruption ×10
c++ ×5
c# ×3
windows ×3
.net ×2
c ×2
debugging ×2
dll ×2
windbg ×2
.net-4.0 ×1
gflags ×1
heap ×1
heap-memory ×1
linux ×1
malloc ×1
virtualalloc ×1
visual-c++ ×1