News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Help: Checking whether memory is readable/allocated

Started by Sean1337, May 20, 2008, 02:14:24 AM

Previous topic - Next topic

Sean1337

Hi,

I was wondering if there was some way of verifying whether or not a particular memory region has been allocated or not.

I need to know how to do this because I'm get exceptions in parts of my code where I check the value a particular address with [eax] where eax is the address and if address is in a region which has not been allocated any memory, then it generates an exception.

So yea I was wondering if there was a way to check whether that address (eax) falls in a memory region that has been allocated memory.

Thanks alot,
-Sean

hutch--

Sean,

At a guess these things happen due to an incorrect level of indirection (1 too many, 1 too few etc ...). It will depend on how yopu obtained the address in the first place and whether it is still a valid address when you try and read it.

If you can extract a bit of the code so we can have a look at it we may be able to help you.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

japheth

Hi,

functions IsBadReadPtr() or VirtualQuery() may be helpful.

evlncrn8

or VirtualQuery...

IsBad*Ptr is generally now 'frowned upon' by microsoft...

"Many older applications have used functions such as IsBadReadPtr and IsBadWritePtr to validate call parameters. These functions are not supported on Windows Vista. Applications that rely on these functions to validate parameters will fail.

The preferred method to provide Safe Exception Handling (SEH) is to provide adequate error-checking routines in the application itself rather than relying on Windows to handle application exceptions."

the api's still exist, but to get logo certification your program must NOT use those api's...

http://technet.microsoft.com/en-us/library/bb490276.aspx

Sean1337

Hey guys, I got a SEH working, however, it slows down the application drastically. So, I was thinking about trying to use VirtualQuery.

However, I am not sure what parameter that is returned in the buffer to check.

The following is returned in my buffer:

typedef struct _MEMORY_BASIC_INFORMATION {
  PVOID BaseAddress;
  PVOID AllocationBase;
  DWORD AllocationProtect;
  SIZE_T RegionSize;
  DWORD State;
  DWORD Protect;
  DWORD Type;
} MEMORY_BASIC_INFORMATION,
*PMEMORY_BASIC_INFORMATION;


Which parameter in the struct should I check to see whether or not the address is writable/readable?

Thanks,
-Sean

zooba

Quote from: Sean1337 on May 21, 2008, 06:06:04 AM
Hey guys, I got a SEH working, however, it slows down the application drastically.

That should be expected. SEH should make no performance difference if an exception is never thrown. If you are expecting an exception in normal operation, you need to change your algorithm.

I would follow Hutch's advice. Find out exactly where the address is coming from. If you have complete control over it from start to finish (which you probably do) then you are able to code in such a way that you don't even need to check for a null pointer before using it. It is possible to guarantee that the address is valid. If it isn't, then something catastrophic has occured and SEH is the best option.

Cheers,

Zooba :U

Rockoon

Initializing an exceptoin handler certainly isnt free, so I just dont get the no performance impact claim.

The penalty can certainly be ammortized over many calls, but that breaks some encapsulation practices for whos duty is it to catch this exception.. the caller or the callee? Sometimes its "supposed" to be the callee and thats where the performance impact can be greatest
When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

zooba

Quote from: Rockoon on May 21, 2008, 01:51:14 PM
Initializing an exceptoin handler certainly isnt free, so I just dont get the no performance impact claim.

A few pushes and an immediate->memory move. It may technically not be 'free', but it's not "drastic", as was claimed.

In terms of who should provide the exception handler, I would (and do) argue that it is whoever provides the address. If the caller allocates the memory, the callee should assume that the memory is allocated. If it isn't, the caller should have dealt with that already or should be able to deal with it when everything dies.

Checking to make sure memory is allocated is as simple as checking the return value of HeapAlloc/LocalAlloc/malloc/whatever. If the memory is not allocated, zero is returned, otherwise the memory is fine. If the allocation function breaks this contract, there is something wrong with the operating system that the application is (probably) not responsible for - dealing with something this catastrophic is unreasonable.

Cheers,

Zooba :U

Rockoon

Quote from: zooba on May 22, 2008, 01:30:28 AM
Quote from: Rockoon on May 21, 2008, 01:51:14 PM
Initializing an exceptoin handler certainly isnt free, so I just dont get the no performance impact claim.

A few pushes and an immediate->memory move. It may technically not be 'free', but it's not "drastic", as was claimed.

It can be drastic. How big is the function?

I would argue that many common functions that take a pointer as input, are also short functions. Example: a string compare normally exits very early. Setting up an exception handler becomes a significant chunk of total time. Given that a string compare needs an exception handler anyways (could over-run the allocated buffers) then you've just added even more time by creating two when you only needed one.

Quote from: zooba on May 22, 2008, 01:30:28 AM
In terms of who should provide the exception handler, I would (and do) argue that it is whoever provides the address.

This assumes that the caller is the only guy with the address. This assumption is often less true than we would like to believe, often we pretend that it "cant happen" when really it can, and simply fail non-gracefully. Many pointers are known to many. Some of them other threads, and some of them other processes. If the function is truely generic, it really does handle cases where the caller doesnt own the pointer its passing. Often we skip the "truely" part, but that doesnt make it right to do so.

Quote from: zooba on May 22, 2008, 01:30:28 AM
If the caller allocates the memory, the callee should assume that the memory is allocated.

...usualy...
When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

zooba

A string compare can (and should) make part of its contract that either the strings are null-terminated or the correct lengths are provided. If the caller gets these right, there's no problem. If the caller gets them wrong, there's clearly a bug somewhere in the caller, since it is supposed to provide strings according to the callee's contract. Is the string compare function supposed to catch the exception and return ERROR_BUG_IN_CALLER?

If another thread or process owns the memory what is the string compare function supposed to do about it? At some point the caller must obtain the pointer from somewhere. It either allocates it directly or is passed a pointer. If the caller does not have some way of controlling the lifespan of this memory it should make a copy. It is horribly poor programming to simply use pointers without understanding and having some control over them. If memory can be randomly freed without warning then what right does the caller have to be using it to begin with?

You have to skip the "truly" part of "truly generic". It is impossible to create a function that can handle every single known and unknown case gracefully (mostly because I can always invent a new case that is not handled). "Very" generic functions tend to be bloated. Requiring the caller to use the function properly (as above) is a much easier way of writing widely usable functions.

Cheers,

Zooba :U

Rockoon

Quote from: zooba on May 22, 2008, 05:51:20 AM
A string compare can (and should) make part of its contract that either the strings are null-terminated or the correct lengths are provided. If the caller gets these right, there's no problem. If the caller gets them wrong, there's clearly a bug somewhere in the caller, since it is supposed to provide strings according to the callee's contract. Is the string compare function supposed to catch the exception and return ERROR_BUG_IN_CALLER?

How does the caller verify that all strings which are read from a binary file are null terminated? Perhaps by calling a function? Does that function have an exception handler? You see where this is going, right? You have just placed the responsibility on another function, the problem didnt magically disappear.

Quote from: zooba on May 22, 2008, 05:51:20 AM
If another thread or process owns the memory what is the string compare function supposed to do about it? At some point the caller must obtain the pointer from somewhere. It either allocates it directly or is passed a pointer. If the caller does not have some way of controlling the lifespan of this memory it should make a copy.

Making a copy by calling a function, perhaps? Shifting the responsibility again without actualy handling the problem.

Your arguement also assumes that we want a copy and not a realtime value.

Quote from: zooba on May 22, 2008, 05:51:20 AM
It is horribly poor programming to simply use pointers without understanding and having some control over them.

You never have control of a pointer from another process. Your arguement is easily undermined by pointing out that you insisted that the callee does not have control of them, which means the callee under your definition is poorly programmed. The very thing you are fighting for, you are also fighting against.

Quote from: zooba on May 22, 2008, 05:51:20 AM
If memory can be randomly freed without warning then what right does the caller have to be using it to begin with?

Rights are meaningless. In practice, we use pointers handed to us from APIs, other processes, etc, ALL THE TIME. Its common practice. You can argue that its bad programming but that just reveals the problem for what it really is.. a problem!

Quote from: zooba on May 22, 2008, 05:51:20 AM
You have to skip the "truly" part of "truly generic". It is impossible to create a function that can handle every single known and unknown case gracefully (mostly because I can always invent a new case that is not handled). "Very" generic functions tend to be bloated. Requiring the caller to use the function properly (as above) is a much easier way of writing widely usable functions.

Thats just it.. thay arent widely usable.. you just declared them to be when really you meant 'widely efficient', which isnt the same thing.
When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

zooba

Quote from: Rockoon on May 22, 2008, 06:06:02 AM
How does the caller verify that all strings which are read from a binary file are null terminated? Perhaps by calling a function? Does that function have an exception handler? You see where this is going, right? You have just placed the responsibility on another function, the problem didnt magically disappear.

The second side to the contract is what the callee guarantees. If ReadFile guarantees that the string will be null-terminated, it will be. If it doesn't guarantee that, the caller has to do it somehow. Many of the C runtime functions and earlier Windows API functions didn't guarantee null-termination. They did, however, allow a maximum length to be specified. This is about documentation. If you (general you, not personal you) can't be bothered to read up on how to use a function, that doesn't mean that the function has to catch all of your mistakes.

To specifically answer your example, presumably at some point there will be an exception handler. That doesn't justify having an exception handler at every point. If the function that buffers chunks of the file into memory has an exception handler, the function that copies part of that chunk into a local buffer doesn't need one.

Quote from: Rockoon on May 22, 2008, 06:06:02 AM
Your arguement also assumes that we want a copy and not a realtime value.

Your argument assumes that the data we're operating on might disappear or change while we're partway through the operation. I can't think of any operation that I would want to silently handle the input data changing during an operation. And what if input data that has already been processed now changes? The results are completely invalid. Even if we want a realtime value, we still need to prevent that from changing while we operate on it. Either by making a (temporary) copy or using synchronisation.

Quote from: Rockoon on May 22, 2008, 06:06:02 AM
You never have control of a pointer from another process. Your arguement is easily undermined by pointing out that you insisted that the callee does not have control of them, which means the callee under your definition is poorly programmed. The very thing you are fighting for, you are also fighting against.

Again, it comes down to contracts. When you call CreateWindowEx you are given a handle. CreateWindow guarantees that the handle will remain valid until the window is destroyed. That is the contract. If you work within that there is no problem. If you try and use the handle after the window has been destroyed you are breaking your half of the contract. This is a bug in the caller, not the callee.

Quote from: Rockoon on May 22, 2008, 06:06:02 AM
Rights are meaningless. In practice, we use pointers handed to us from APIs, other processes, etc, ALL THE TIME. Its common practice. You can argue that its bad programming but that just reveals the problem for what it really is.. a problem!

Again, contracts solve this, but it requires diligence on the part of both developers. Microsoft has this -- 99.9% of their functions performs precisely according to contract. A much lower percentage of other developers have this diligence.

Quote from: Rockoon on May 22, 2008, 06:06:02 AM
Thats just it.. thay arent widely usable.. you just declared them to be when really you meant 'widely efficient', which isnt the same thing.

If you pass 00000001h as the pointer to window text to CreateWindowEx it will crash. This is obviously a stupid thing to do, however, your definition of "generic" seems to imply that CreateWindowEx should fail gracefully here. Does this make CreateWindowEx a widely efficient function but not widely usable? Where do you draw the line? A string length function that has 2 lines of code to count the number of characters and 1000 lines checking for invalid pointers?

A crash indicates a problem that should never occur. It also forces the developer to fix it rather than wondering why it doesn't work properly and (incorrectly) blaming "the other guy".

Cheers,

Zooba :U

hutch--

I personally come down on the side of no error handling unless very specific conditions are expected to be encountered, usually those of an external hardware nature where some variables cannot be known. I agree with zooba on the documentation area as there is no point in asuming that the end user is so stupid they cannot understand the documentation if it is done properly.

The problem is an old one, now matter how safe you think you have made a function, there will always be a better idiot who can defeat it. My own view is don't bother trying, document the function properly, add any economical testing that makes it easier to use and fully gut the function to make sure there is no un-necessary overhead.

Anyone who reembers the joys of dialups on win9x knows what hardware crashes are about and it is here that SEH and similar mechanisims come into play. If you are calling a function or relying on information where you absolutely cannot garrantee what comes back, error handling including SEH is the sensible approach in this context.

Have a look at the guts of NTOSKRNL or HAL.DLL and you will see that they are not full of crap like multiple nested SEH or similar, once you get under the consumer level of API functions, you get down to the bare bones of the OS that must be fast and must have correct arguments passed to it every time.

I remember with some humour developing the in memory dialog system for masm32 in win98se and you could forget about blue screens of death, the instand black screen of death did not even tell you the OS had crashed, you just pushed the reset button and started again.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php