 |
|
 |
Problems guaranteed, that is, if you end up calling IsBadWritePtr().
You will feel like a fool because on reading the MSDN you are told that not only are these functions not thread-safe, they recommend you wrap calls in some kind of critical-section or whatever.
Reason being, on further search, is that IsBadWritePtr() ACTUALLY WRITES BYTES and then restores their original values, but if you're multithreading the "restores their original values" part is what will make you tear your hair out. Your other thread will read a trash value, but then you look again and the value is fine, and upon ultimately tracking it down you find the "momentary corruption" was caused by IsBadWritePtr(), and THEN you find out that MSDN effectively "told you so"
With "IsBadReadPtr()", obviously the function can't be writing bytes so you might be OK there, but anyway after this RTFM experience I am searching CodeProject for alternatives and didn't see a warning in this highly-rated article.
pg--az
|
|
|
|
 |
|
 |
See http://msdn2.microsoft.com/en-us/library/aa366713.aspx and http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx
for explanation, but essentially if you call these functions (via these macros) then you can cause your perfectly valid program to crash later on (i.e. at a time well after you've called the function) because your stack fails to grow when it should, i.e. by calling these functions, the automatic growth of your own stack may fail.
E.g. call one of these functions then allocate a large array on the stack might fail!
Aaron
|
|
|
|
 |
|
 |
As you may notice, these functions are obsolete by now. The article was written in 2002 when Windows 95 was still widely used and application security was just a faint thought of some weirdos.
Leon[^] - Enterprise Anti-Spam Server
|
|
|
|
 |
|
 |
They are not supported on Windows Vista. Any thoughts? VirtualQuery perhaps?
|
|
|
|
 |
|
 |
can u tell me how can i do _asm in evc4.0
I really need this
hillolsarker@yahoo.com
|
|
|
|
 |
|
|
 |
|
 |
When executing the following code, I would expect it to fire an assertion
char* pSomething = new char[200];
delete[] pSomething;
VERIFY_ISWRITEDATA(pSomething, 200);
Or am I wrong?
|
|
|
|
 |
|
 |
No it does not. Simply because it does not make heap/stack checks. And so far the pSomething pointer is pointing to a valid memory area, except if it happens that your memory manager really frees the block where your 200 chars are located. May happen, may not happen.
You must add extra heap checking code for this kind of errors.
[edit]
It will however work when you use functions like GlobalAlloc()/GlobalFree() for your memory allocations instead of new/delete or malloc/free.
[/edit]
I don't think this is a serious possesion, and the evil most likely comes from your hand. Colin J Davies, The Lounge
|
|
|
|
 |
|
 |
BTW, most programmers take the habit of adding pSomething = 0; after the delete, to clearly mark it as invalid.
It may not be necessary if the pointer goes out of scope just after that, but still, somebody can add code just after it, before the end of the scope...
|
|
|
|
 |
|
 |
Yes, which unfortunately is optimized away in a release build. But for debug builds its a great help.
A nice value is also 0xdeadbeef, 0xbaadf00d or similar
I don't think this is a serious possesion, and the evil most likely comes from your hand. Colin J Davies, The Lounge
|
|
|
|
 |
|
 |
Am I completely missing something here, or does sizeof(LPDWORD) not always return 4 (the size of a pointer is always 4 bytes)
|
|
|
|
 |
|
 |
Not necessarily. It is, right now, under Win32. But what will it be tomorrow? What, if you compile it under Win64 ? Is it still 4 bytes?
Never mind, with sizeof() you are always on the right side as long as you recompile the source for any new target.
PS: Also, never assume that a char is 1 byte, or a unicode char is 2 bytes. Never ever.
I keep submitting “VB” as a Priority-1 bug, but apparently no one here knows how to fix it. Nick Hodapp, Semicolon
|
|
|
|
 |
|
 |
Thats right, but my point is that if you use sizeof() as used in these macros, the function 'IsBadReadPtr(a, sizeof(LPDWORD))' will only test the memory located from where pointer 'a' starts, and check 4 bytes ahead, it will not check the rest of the memory.
Eg. you might have read acces to the first 123 bytes of the pointer location but not the rest.
|
|
|
|
 |
|
 |
Thats what the other macro is here for. It checks an area of a given size for read or write access.
The POINTER macro is exactly only for verifying a pointer. This might be a char**, LPVOID* or a RPC pointer for example. Or, the function just has no idea about the length of the area and just wants to verify that the actual first bytes are accessible.
I keep submitting “VB” as a Priority-1 bug, but apparently no one here knows how to fix it. Nick Hodapp, Semicolon
|
|
|
|
 |
|
 |
Okay now I get it, I missed the macro with the length parameter. The macro with only one parameter is obviously only for checking the actual pointer address, sorry
|
|
|
|
 |
|
 |
Actually, isn't a char guaranteed to be 1 byte?
|
|
|
|
 |
|
 |
No. It is guaranteed to be at least 8 bit! Same for int (min. 16 bit), long (min 32 bit) etc.
I keep submitting “VB” as a Priority-1 bug, but apparently no one here knows how to fix it. Nick Hodapp, Semicolon
|
|
|
|
 |
|
 |
By "byte" I do not necessarily mean 8 bits. I mean the size of a "storage unit". In other words, sizeof(char) == 1 always. From K&R, second edition : "The sizeof operator yields the number of bytes required to store an object of the type of its operand.... When sizeof is applied to a char, the result is one...."
|
|
|
|
 |
|
 |
A byte is (normally) 8 bits, this means that sizeof(char) is guaranteed to return at least 1. I think that there are currently very few systems where it is bigger than 1. Personally I've never seen one.
I keep submitting “VB” as a Priority-1 bug, but apparently no one here knows how to fix it. Nick Hodapp, Semicolon
|
|
|
|
 |
|
 |
No, even if chars are more than 8 bits, sizeof(char) will always return 1 as long as the compiler conforms to the standard. I even quoted K&R. Do you dare refute K&R?;)
|
|
|
|
 |
|
 |
Anonymous wrote:
Do you dare refute K&R?
Ok, I've looked into the specs and yes, you are right. For some historical reasons sizeof(char) always returns 1. My apologies.
So I can only add that you can use 1 as size for char's but only if you really use the C/C++ type char instead of the recommended TCHAR which might be a wchar_t or a char (or whatever is fashion tomorrow).
I keep submitting “VB” as a Priority-1 bug, but apparently no one here knows how to fix it. Nick Hodapp, Semicolon
|
|
|
|
 |
|
 |
You can remove MFC dependency by replace ASSERT() with
_asm { int 3 } }. Ex :
#define ASSERT_ISWRITEDATA(a, l){ if(::IsBadWritePtr(a, l)) \
{ ::OutputDebugString(_T("Parameter ") _T(#a) _T(" is not a valid write area\r\n")); _asm { int 3 } };}}.
It has many advantages over MFC's style : you get break right in place your code went wrong not in somewhere in an MFC .h file.
Moreover, you can add a macro to check for a string validity by using IsBadStringPtr().
And last, you should remove the VERIFY_....
VERIFY in MFC means "break the code in both Debug and Release" but your code means "ALWAYS NOT break".
Nguyen Binh
|
|
|
|
 |
|
 |
This is the coolest thing I read here.;)
|
|
|
|
 |
|
 |
Well then, nothing stops you from doing the following:
#undef ASSERT
#define ASSERT _asm { int 3 }
The nice thing about ASSERT is that is is defined as a macro. Anyway, under Windows you should use the correct and do a ::DebugBreak() instead of trying to be clever and inserting assembly code by hand.
Nguyen Binh wrote:
VERIFY in MFC means "break the code in both Debug and Release"
VERIFY is never breaking the code, but indicating an error condition when in debug mode. In release it just executes the expression. And again, its a #define'd macro.
The pointer verification is definitely not meant to be a complete and thorough validity check for any passed pointer. This is a bit more work and very specific to each function.
I keep submitting “VB” as a Priority-1 bug, but apparently no one here knows how to fix it. Nick Hodapp, Semicolon
|
|
|
|
 |
|
 |
OK. we can do
#undef ASSERT
#define ASSERT _asm { int 3 }
But why get dirt with that #undef?
"The nice thing about ASSERT is that is is defined as a macro."
Well, then _asm { int 3 } can be defined as a macro too.
Anyway, under Windows you should use the correct and do a ::DebugBreak() instead of trying to be clever and inserting assembly code by hand.
OK. Do you know how MFC ASSERT() do?
It call CustomDebugBreak()
And
//-----Code from debug.h in VC.NET SDK
// by default, debug break is asm int 3, or a call to DebugBreak, or nothing
#if defined(_M_IX86)
#define CustomDebugBreak() _asm { int 3 }
#else
#define CustomDebugBreak() DebugBreak()
#endif
#define TRACE ::Trace
#define THIS_FILE __FILE__
#define ASSERT(f) \
do \
{ \
if (!(f) && AssertFailedLine(THIS_FILE, __LINE__)) \
CustomDebugBreak(); \
} while (0) \
//-----End
So after a bunch of check for line number, some thread synx, etc... ASSERT() do call _asm { int 3 } to break the code flow.
And I really don't need such work. I need to see a break point where my code go wrong.
And yeah, you are right about VERIFY.
I've been using _asm { int 3 } for a long time and every thing go OK on any X86 system. I don't know about others.
B.R
Nguyen Binh
|
|
|
|
 |