please help!
in my vstudio 2005 solution i recieve an error when i start
without debugging.
it's an unhandled excpetion - access voilation - reading from 0x0000
- inside NTDLL.DLL
1. what is/does ntdll.dll?
2. how should i resolve/debug this error???
i have little or no experience in debugging, especially
in vc++ and winXP, so please tell me how to debug this
and other things! years ago i worked in motorola and pentium assembly,
and i knew how to debug it, but not inside vstudio 2005.
regards,
marc k.
In 99.99% of the cases, a problem in ntdll.dll is a consequence of
a programming error in the application, that causes the internal state
of the runtime in ntdll.dll to get corrupted.
First thing that would come to mind is a heap corruption.
If you could get good symbols for the OS binaries, and post a stack,
maybe few people could be able to help.
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Use of any included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm
"marco 2" <rebel...@planet.nl> wrote in message
news:43d0111d$0$12831$ba62...@text.nova.planet.nl...
1. where/how do i get good symbols for the OS binaries?
i have installed windows symbols from microsoft.com (debugging),
but i don't see them in my disassembly.
2. and what means "posting a stack"? do you mean,
putting a message in the newsgroup with a copy of the call stack?
3. what means "thunk" in: "....and thunk against the native calls......"?
regards,
mk
"Ivan Brugiolo [MSFT]" <Ivan.B...@online.microsoft.com> schreef in
bericht news:%23VU91CV...@TK2MSFTNGP14.phx.gbl...
c:\debugger>symchk %windir%\system32\ntdll.dll /s
SRV*e:\temp*http://msdl.microsoft.com/download/symbols /os /od
SYMCHK: ntdll.dll PASSED - PDB:
e:\temp\ntdll.pdb\9385FE43F2EB4DCAAEB1EF2D2CF13E272\ntdll.pdb DBG:
<N/A>
SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 1
#2 assuming you have cdb/ntsd/windbg, a stack would look like [see below]
I belice that that CallStack toolwindow in VS has a Select-All & Copy
function,
that would produce somewhat identical results.
#3 A think is normally a piece of code that calls one other.
Each CPU / architecture might have a different mechanism to call the kernl.
This abstraction (int 2e, sysenter, syscall) is kept in ntdll.dll
0:000> r
rax=000000000000ff00 rbx=fffffffffffffff0 rcx=0000000000000000
rdx=0000000011000103 rsi=00000000019d0000 rdi=00000000019d02c8
rip=0000000078edcc6d rsp=00000000000ae280 rbp=0000000000000000
r8=0000000000000a58 r9=0000000000000a08 r10=0000000078ed6416
r11=0000000078fa55e0 r12=00000000019d0000 r13=00000000000000a8
r14=0000000000000000 r15=0000000001100003
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b
efl=00010202
ntdll!RtlAllocateHeapSlowly+0xa50:
00000000`78edcc6d 0fb74308 movzx eax,word ptr [rbx+0x8]
ds:ffffffff`fffffff8=????
0:000> k
Child-SP RetAddr Call Site
00000000`000ae280 00000000`78f60ff7 ntdll!RtlAllocateHeapSlowly+0xa50
00000000`000ae560 00000000`78f3b758 ntdll!RtlDebugAllocateHeap+0xe7
00000000`000ae610 00000000`78edd036 ntdll!RtlAllocateHeapSlowly+0x74
00000000`000ae8f0 00000000`78f5e636 ntdll!RtlAllocateHeap+0x1292
00000000`000aeb40 00000000`78f5a985 ntdll!RtlpDphNormalHeapAllocate+0x36
00000000`000aeb70 00000000`78f60f50 ntdll!RtlpDebugPageHeapAllocate+0x6d8
00000000`000aee90 00000000`78f3b758 ntdll!RtlDebugAllocateHeap+0x40
00000000`000aef40 00000000`78edd036 ntdll!RtlAllocateHeapSlowly+0x74
00000000`000af220 000007ff`7fd34858 ntdll!RtlAllocateHeap+0x1292
00000000`000af470 000007ff`7fd34a3b RPCRT4!rc4_safe_startup+0x28
00000000`000af4b0 00000000`78edef73 RPCRT4!_InitializeDLL+0xb4
00000000`000af4e0 00000000`78ed6380 ntdll!LdrpRunInitializeRoutines+0x4d7
00000000`000af6c0 00000000`78ed6416 ntdll!LdrpInitializeProcess+0x1bb6
00000000`000af9d0 00000000`78ef3925 ntdll!_LdrpInitialize+0x18f
00000000`000afab0 00000000`78d59630 ntdll!KiUserApcDispatch+0x15
00000000`000affa8 00000000`00000000 kernel32!BaseProcessStart
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Use of any included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm
"marco 2" <rebel...@planet.nl> wrote in message
news:43d02854$0$12834$ba62...@text.nova.planet.nl...
Why can't you simply debug your application in debug mode to see what's
wrong ?
--
Vladimir
"marco 2" <rebel...@planet.nl> wrote in message
news:43d02854$0$12834$ba62...@text.nova.planet.nl...
mk
"Scherbina Vladimir" <vladimir....@gmail.com> schreef in bericht
news:uwHdbyYH...@TK2MSFTNGP10.phx.gbl...
i have found the error.
it was loadbitmapfile().
1. the problem is the result of stepping up from iostream.h
to iostream. i haven't yet changed my original iostreamh-code.
for use with iostream. any suggestions????
2. can anyone explain to me the problems and ins and outs
of different working directories????
mk
"marco 2" <rebel...@planet.nl> schreef in bericht
news:43d12944$0$12839$ba62...@text.nova.planet.nl...
i have upgraded my solution from vs6 to vs2005.
i had to replace iostream.h with iostream.
now it results in an error in LoadBitmapFile(),
(a Null Pointer or something like that.
JIT passes an access voilation reading from adress 0x0000.)
though it worked perfectly in vs6.
how do i solve this?
what should you change when upgrading
to <iostream> from <iostream.h>???
mk
"marco 2" <rebel...@planet.nl> schreef in bericht
news:43d1a35a$0$12837$ba62...@text.nova.planet.nl...
------------
THIS IS THE FUCTION:
unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER
*_bitmapInfoHeader)
{
FILE *filePtr; // the file pointer
BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
unsigned char *bitmapImage; // bitmap image data
int imageIdx = 0; // image index counter
unsigned char tempRGB; // swap variable
// open filename in "read binary" mode
filePtr = fopen(filename, "rb");
if (filePtr == NULL)
return NULL;
// read the bitmap file header
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// verify that this is a bitmap by checking for the universal bitmap id
if (bitmapFileHeader.bfType != BITMAP_ID)
{
fclose(filePtr);
return NULL;
}
// read the bitmap information header
fread(_bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// move file pointer to beginning of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// allocate enough memory for the bitmap image data
THIS IS WHERE THE ERROR OCCURS:
bitmapImage = (unsigned char*)malloc(_bitmapInfoHeader->biSizeImage);
--------
THE CALLSTACK:
ntdll.dll!_RtlpCoalesceFreeBlocks@16() + 0x124e bytes
ntdll.dll!_RtlpExtendHeap@8() + 0xa1 bytes
ntdll.dll!_RtlAllocateHeap@12() + 0x16a2 bytes
prophecy city.exe!malloc(unsigned int size=196608) Line 163 + 0x63 bytes
C
> prophecy city.exe!LoadBitmapFile(char * filename=0x00000024,
> tagBITMAPINFOHEADER * _bitmapInfoHeader=0x00364d42) Line 3498 + 0x9 bytes
> C++
user32.dll!77d21324()
[Frames below may be incorrect and/or missing, no symbols loaded for
user32.dll]
prophecy city.exe!int_textures() Line 8696 + 0xd bytes C++
user32.dll!77d21324()
prophecy city.exe!main_int() Line 8730 C++
prophecy city.exe!WinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__
* hPrevInstance=0x00000000, char * lpCmdLine=0x00162354, int nShowCmd=5)
Line 8862 C++
prophecy city.exe!__tmainCRTStartup() Line 315 + 0x1c bytes C
kernel32.dll!_BaseProcessStart@4() + 0x23 bytes
----------------------------
"marco 2" <rebel...@planet.nl> schreef in bericht
news:43d26fa1$0$12840$ba62...@text.nova.planet.nl...
mk
"marco 2" <rebel...@planet.nl> schreef in bericht
news:43d2b412$0$12842$ba62...@text.nova.planet.nl...
See this thread for more details:
--
This posting is provided "AS IS" with no warranties, and confers no
rights.
"marco 2" wrote:
>i know now where things go wrong
> but i can't actually solve the error?!?!?!
> can anyone help?
> see former messages......
>
marc
"Pavel Lebedinsky [MSFT]" <pa...@online.microsoft.com> schreef in bericht
news:%23SsKY$6HGHA...@TK2MSFTNGP12.phx.gbl...
marc k.
"marco 2" <rebel...@planet.nl> schreef in bericht
news:43d4226f$0$12833$ba62...@text.nova.planet.nl...
m.
"marco 2" <rebel...@planet.nl> schreef in bericht
news:43d4226f$0$12833$ba62...@text.nova.planet.nl...
>> ntdll.dll!_RtlpCoalesceFreeBlocks@16() + 0x124e bytes
>> ntdll.dll!_RtlpExtendHeap@8() + 0xa1 bytes
>> ntdll.dll!_RtlAllocateHeap@12() + 0x16a2 bytes
>> prophecy city.exe!malloc(unsigned int size=196608) Line 163 + 0x63
>> bytes C
>>> prophecy city.exe!LoadBitmapFile(char * filename=0x00000024,
>>> tagBITMAPINFOHEADER * _bitmapInfoHeader=0x00364d42) Line 3498 + 0x9
>>> bytes C++
Here filename is not a valid pointer, however the failure indicates that
fopen succeeded, therefore it seems the arguments area of your stack has
been overwritten.... this will lead to failures accessing _bitmapInfoHeader
I don't see anything wrong with the code after a cursory inspection, so you
will be debugging...
>> ------------
>>
>> THIS IS THE FUCTION:
>> unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER
>> *_bitmapInfoHeader)
Use this prototype instead (safer!)
unsigned char *LoadBitmapFile(const char* const filename, BITMAPINFOHEADER*
const _bitmapInfoHeader)
>>
>> {
Put a breakpoint [here]!
Check your arguments. Add the following code (use your favorite
logging/reporting mechanism in place of MessageBox):
if ((NULL == filename) || IsBadStringPtr(filename, _MAX_PATH)) {
MessageBox(...);
}
if ((NULL == _bitmapInfoHeader) || IsBadWritePtr(_bitmapInfoHeader, sizeof
*_bitmapInfoHeader)) {
MessageBox(...);
}
Then recompile and launch in debug mode. When the debugger breaks, visually
inspect the arguments (make sure the filename is reasonable, etc.).
Now added both arguments to the watch list and begin stepping through the
function (use step over).
Find out what line causes filename to get corrupted. Watch to see if
_bitmapInfoHeader also changes.
>>
>> FILE *filePtr; // the file pointer
>>
>> BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
>>
>> unsigned char *bitmapImage; // bitmap image data
>>
>> int imageIdx = 0; // image index counter
>>
>> unsigned char tempRGB; // swap variable
>>
>> // open filename in "read binary" mode
>>
>> filePtr = fopen(filename, "rb");
>>
>> if (filePtr == NULL)
>>
>> return NULL;
tested return value.... check
>>
>> // read the bitmap file header
>>
>> fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
Check return value!
>>
>>
>> // verify that this is a bitmap by checking for the universal bitmap id
>>
>> if (bitmapFileHeader.bfType != BITMAP_ID)
>>
>> {
>>
tested value.... check
>> fclose(filePtr);
>>
>> return NULL;
>>
>> }
>>
>> // read the bitmap information header
>>
>> fread(_bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
>>
Check return value!
>> // move file pointer to beginning of bitmap data
>>
>> fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
>>
Check return value!
>> // allocate enough memory for the bitmap image data
>>
>> THIS IS WHERE THE ERROR OCCURS:
>>
>> bitmapImage = (unsigned char*)malloc(_bitmapInfoHeader->biSizeImage);
>>
If any of the above reads fail then _bitmapInfoHeader->biSizeImage is
meaningless.
Don't use IsBadWritePtr, it's considered both pointless and
harmfull.
"Should I check the parameters to my function?"
http://blogs.msdn.com/larryosterman/archive/2004/05/18/134471.aspx
Sounds like bugs in IsBadWritePtr... it should be a little smarter and not
extend the stack. And that's not an expensive check! You don't have to
check for guard pages or anything like that... check against ESP and EBP --
no user buffer should be allowed to overlap with the scratch space of
IsBadWritePtr. Basically.... if ptr < ESP && ptr + size > EBP then bad
pointer. Or maybe I've got the stack registers backwards. Of course
IsBadWritePtr checks for pointer overflow.... right? If I have
char* ptr = NULL;
IsBadWritePtr(&ptr[-10], 500);
I would hope it fails *without* needing to touch memory.
For a debug build, it would even be worthwhile to virtually unwind the stack
and make sure the buffer doesn't overlap any reserved stack areas in any
frame (i.e. return address, saved registers, etc.)
>
IsBad<Read|Write>Ptr does exactlty what is says - it
reads/writes memory starting with specified pointer for
specified length. I can't see how otherwise you would be
able to check readability/writability of memory if not by
actually reading or writing. The point of Larry Osterman's
blog article is: if you're going to crash anyway, then at
least do it explicitly and at right moment, so developer
will be able to debug it at once.
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Use of any included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm
"Alex Blekhman" <tkfx....@yahoo.com> wrote in message
news:uMrtlkxM...@TK2MSFTNGP10.phx.gbl...
I actually suggested two other ways...please comment.
By my definition, IsBadReadPtr/IsBadWritePtr shouldn't be limited to
indicating whether the CPU MMU will permit the operation, they should
indicate whether the memory lies within a user buffer.
First, if the pointer overflows.
char* ptr = NULL;
IsBadWritePtr(&ptr[-10], 500);
This is clearly a bad pointer, and shouldn't SEH to determine that.
Secondly, since stack grows downward any access to the stack region below
EBP/ESP is invalid. If I'm not mistaken, this check will eliminate the
"guard page" bug, because the guard page is an unused stack page strictly
below EBP and ESP.
(Isn't ESP the stack pointer on entry to the function, and EBP the base of
the function's stack space? Or do I have that reversed, or is one of them
adjusted by argument space, etc? And is this behavior different between
i686 vs x86_64? Of course that's why APIs are OS-provided, so they can be)
Someone might rationally want to overwrite several stack variables at once.
But no one (except maybe an exception handler) should ever be writing into
the areas managed by prolog/epilog, i.e. return address and saved registers.
This information is available to a debugger, so why not check that too?
Although a stack walk might be slow enough you would want to explicitly
enable it.
Of course, these features (knowing the stack base and maximum stack size,
advanced knowledge about the composition of stack frames) would require
compiler support. There might have to be different keywords depending on
whether the buffer can lie in the local stack frame, i.e. no caller buffer
should overlap my stack frame, but if I declare an object, and get a pointer
returned from one of its member functions, it should be allowed to lie in my
stack frame. Then the following compiler primitives:
__isbadwriteptr
__isbadreadptr
__isbadstringptr
__isbadcallerwriteptr
__isbadcallerreadptr
__isbadcallerstringptr
__isbadcodeptr
And a compiler option to enable stack-walking instead of checking against
the current frame.
OK. Let's assume that IsBadReadPtr is written in
straightforward manner like this:
BOOL IsBadReadPtr(const VOID* lp, UINT_PTR ucb)
{
__try
{
for(UINT_PTR i = 0; i < ucb; ++i)
{
BYTE bt = *(((PBYTE)lp) + i);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return FALSE;
}
return TRUE;
}
> By my definition, IsBadReadPtr/IsBadWritePtr shouldn't be
> limited to indicating whether the CPU MMU will permit the
> operation, they should indicate whether the memory lies
> within a user buffer.
> First, if the pointer overflows.
> char* ptr = NULL;
> IsBadWritePtr(&ptr[-10], 500);
>
> This is clearly a bad pointer, and shouldn't SEH to
> determine that.
So, now we have something like that inside:
BOOL IsBadReadPtr(const VOID* lp, UINT_PTR ucb)
{
if(IsInBadRange(lp)) // Platform specific!
return FALSE;
// rest of function...
}
And we have to implement platform specific IsInBadRange.
> Secondly, since stack grows downward any access to the
> stack region below EBP/ESP is invalid. If I'm not
> mistaken, this check will eliminate the "guard page" bug,
> because the guard page is an unused stack page strictly
> below EBP and ESP.
So, IsBadReadPtr becomes:
BOOL IsBadReadPtr(const VOID* lp, UINT_PTR ucb)
{
// 2 - check up to 2 levels upward:
// 1st - IsBadReadPtr itself
// 2nd - caller of IsBadReadPtr
if(IsBadStack(lp, ucb, 2)) // Platform specific!
return FALSE;
if(IsInBadRange(lp)) // Platform specific!
return FALSE;
// rest of function...
}
And we have to implement platform specific IsBadStack, too.
(Mind you that we don't discuss here another whole issue of
what the bad stack is under different platforms. For
example, look for Itanium's stack madness:
"The Itanium's so-called stack"
http://blogs.msdn.com/oldnewthing/archive/2005/04/21/410397.aspx)
Now, we also should handle correctly __declspec( naked ) and
__declspec( noreturn ) functions. Also, IsBadStack should
know about its callers stack frames to check them, i.e.
should know how to walk stack upwards.
> Someone might rationally want to overwrite several stack
> variables at once. But no one (except maybe an exception
> handler) should ever be writing into the areas managed by
> prolog/epilog, i.e. return address and saved registers.
You cannot assume it with __declspec( naked ) functions.
> This information is available to a debugger, so why not
> check that too? Although a stack walk might be slow
> enough you would want to explicitly enable it.
This will require additional parameter for IsBadReadPtr. So,
IsBadReadPtr cannot be used anymore due to backward
compatibility. We'll need IsBadReadPtrEx, for instance. Now
we have:
BOOL IsBadReadPtrEx(const VOID* lp, UINT_PTR ucb, DWORD
dwFlags)
{
// 2 - check up to 2 levels upward:
// 1st - IsBadReadPtr itself
// 2nd - caller of IsBadReadPtr
if((dwFlags & IBP_CHECKSTACK) && IsBadStack(lp, ucb, 2))
return FALSE;
if(IsInBadRange(lp)) // Platform specific!
return FALSE;
// rest of function...
}
> Of course, these features (knowing the stack base and
> maximum stack size, advanced knowledge about the
> composition of stack frames) would require compiler
> support. There might have to be different keywords
> depending on whether the buffer can lie in the local
> stack frame, i.e. no caller buffer should overlap my
> stack frame, but if I declare an object, and get a
> pointer returned from one of its member functions, it
> should be allowed to lie in my stack frame.
Many of these checks already exist. See:
"Compiler Security Checks In Depth"
http://msdn.microsoft.com/library/en-us/dv_vstechart/html/vctchCompilerSecurityChecksInDepth.asp
Now, let's summarize what we have after refurbishing
IsBadReadPtr:
1. Two platform specific and non-trivial functions should be
written.
2. Additional parameter should be added for IsBadReadPtr,
making it IsBadReadPtrEx. (I.e., documentation updates,
support, marking IsBadReadPtr as deprecated, etc..).
3. IsBadReadPtrEx is heavy and complex stack-walking hog. To
make it light you need to combine flags for it, then you'll
get equivalent of old IsBadReadPtr.
4. You gained exactly nothing considering pointers security.
That's why:
a) The address you pass to IsBadReadPtrEx can be
unmapped by other thread immediately after you return from
the function. So, you checked nothing.
b) Making IsBadReadPtrEx walking your stack guarantees
safety for your thread only. Nothing prevents me to write
code like that:
char* p = 0x00BAAADD; // arbitrary address
IsBadReadPtrEx(p, 1024);
There is no way to know for IsBadReadPtrEx where `p'
comes from. It can be on heap, it can be other thread's
guard page, too. Oops! Back to guard page problem again.
Well, we made so many drastic changes to gain tiny ammount
of additional cases. Was it worthwhile? I don't think so.