pointer 32 wraparound

I am doing a check to see if a given VA is within the range described by
a chain of MDL’s. For each MDL in the chain I do:

CurrentVa is the address I am checking (a parameter to this function)
curr_mdl is the current MDL in the chain

PVOID mdl_start_va = MmGetMdlVirtualAddress(curr_mdl);
ULONG mdl_byte_count = MmGetMdlByteCount(curr_mdl);

if ((ULONGLONG)CurrentVa >= (ULONGLONG)mdl_start_va &&
(ULONGLONG)CurrentVa < (ULONGLONG)mdl_start_va + mdl_byte_count)
return TRUE;

I have found though that on a 32 bit system, when CurrentVa =
0xFFFFA000, mdl_start_va = 0xFFFFA000 and mdl_byte_count = 24576, then
the expression evaluates to FALSE.

So obviously(?) mdl_start_va + mdl_byte_count is suffering from 32 bit
wraparound and is evaluating to 0x00000000, even though I had assumed
that my casting would ensure that it evaluated to 0x100000000. But even
then on a 64 bit system, if CurrentVa and mdl_start_va were
0xFFFFFFFFFFFFA000 which I assume isn’t impossible, I would still be
right back where I started.

So what’s the right way to approach this, is it to change the expression
to:

if ((ULONGLONG)CurrentVa >= (ULONGLONG)mdl_start_va &&
(ULONGLONG)CurrentVa <= (ULONGLONG)mdl_start_va + mdl_byte_count - 1)
return TRUE;

or is there a helper function or macro that can help me here?

At a glance, would anyone else have assumed that the above would give
the expected outcome, or is it just me and everyone else knows that
doing such a comparison is dumb? :slight_smile:

Also, maybe I’m wrong about my assumptions as to why I’m seeing this
outcome (hence the (?) at ‘obviously’).

Thanks

James

>

Also, maybe I’m wrong about my assumptions as to why I’m seeing this
outcome (hence the (?) at ‘obviously’).

Hmmm… a pointer appear to be a signed type… that may explain things
a little…

James

James Harper wrote:

I am doing a check to see if a given VA is within the range described by
a chain of MDL's. For each MDL in the chain I do:

CurrentVa is the address I am checking (a parameter to this function)
curr_mdl is the current MDL in the chain

PVOID mdl_start_va = MmGetMdlVirtualAddress(curr_mdl);
ULONG mdl_byte_count = MmGetMdlByteCount(curr_mdl);

if ((ULONGLONG)CurrentVa >= (ULONGLONG)mdl_start_va &&
(ULONGLONG)CurrentVa < (ULONGLONG)mdl_start_va + mdl_byte_count)
return TRUE;

I have found though that on a 32 bit system, when CurrentVa =
0xFFFFA000, mdl_start_va = 0xFFFFA000 and mdl_byte_count = 24576, then
the expression evaluates to FALSE.

How about:

if (CurrentVa >= mdl_start_va && (CurrentVa - mdl_start_va) <
mdl_byte_count) ...

to try to avoid the overflow?

Paul

--

Paul Durrant
Paul Durrant - Amazon Web Services (AWS) | LinkedIn

> >

> Also, maybe I’m wrong about my assumptions as to why I’m seeing this
> outcome (hence the (?) at ‘obviously’).
>

Hmmm… a pointer appear to be a signed type… that may explain
things
a little…

That’s the problem. casting the pointer 0xFFFFA000 to a ULONGLONG makes
it 0xFFFFFFFFFFFFA000 - the value is sign extended because a pointer is
a signed type.

I have typedef’d UINTPTR to be ULONG for a 32 bit build and ULONGLONG
for a 64 bit build. I now just cast the pointer to a UINTPTR and do the
comparisons with that type, making sure to compare the upper value with
‘<= va + len - 1’ to ensure I don’t get a wrap around. Seems to work
perfectly now.

I must find out who decided that a pointer should be a signed value and
ask them a few questions. It’s not that way under linux (or under GCC at
least) which is where I have done previous development which is why I
was initially confused. I can’t think why it would ever make any sense
to have the compiler treat a pointer as a signed value…

James

You should always use ULONG_PTR to cast a pointer types to a value type.
ULONG_PTR is a size_t so this is still 32 bits on a 32 bits system. So
substitute (ULONGLONG) with (ULONGLONG)(ULONG_PTR).

It helps if you narrow these problems by substituting parts of the
expression with other variables.

The compiler should warn you about these problems if you compile with
highest warning levels. You may also find these problems if you compile your
code as cpp.

//Daniel

“James Harper” wrote in message > PVOID
mdl_start_va = MmGetMdlVirtualAddress(curr_mdl);
> ULONG mdl_byte_count = MmGetMdlByteCount(curr_mdl);
>
> if ((ULONGLONG)CurrentVa >= (ULONGLONG)mdl_start_va &&
> (ULONGLONG)CurrentVa < (ULONGLONG)mdl_start_va + mdl_byte_count)
> return TRUE;
>
>

>

You should always use ULONG_PTR to cast a pointer types to a value
type.
ULONG_PTR is a size_t so this is still 32 bits on a 32 bits system.
So
substitute (ULONGLONG) with (ULONGLONG)(ULONG_PTR).

Ah. I always assumed ULONG_PTR was a 32 bit value, but that was an
incorrect assumption.

Thanks for the tip.

James

ULONG_PTR is a unsigned ‘long’ of pointer width.

Mr. Durrant’s suggestion is the one I use. When making stride comparisons
in a number space that ‘wraps’ (what is that Calvin, affine closure?) bias
the comparison by resetting the origin to the starting point. Or as Mr.
Durrant put it, avoid the overlflow.

Good Luck,
Dave Cattley

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of James Harper
Sent: Wednesday, July 08, 2009 8:07 AM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] pointer 32 wraparound

You should always use ULONG_PTR to cast a pointer types to a value
type.
ULONG_PTR is a size_t so this is still 32 bits on a 32 bits system.
So
substitute (ULONGLONG) with (ULONGLONG)(ULONG_PTR).

Ah. I always assumed ULONG_PTR was a 32 bit value, but that was an
incorrect assumption.

Thanks for the tip.

James


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

That method leaves open the option of underflow so the equation might wrap
in the other direction.

//Daniel

“David R. Cattley” wrote in message news:xxxxx@ntdev…
> Mr. Durrant’s suggestion is the one I use. When making stride comparisons
> in a number space that ‘wraps’ (what is that Calvin, affine closure?) bias
> the comparison by resetting the origin to the starting point. Or as Mr.
> Durrant put it, avoid the overlflow.
>
> Good Luck,
> Dave Cattley
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of James Harper
> Sent: Wednesday, July 08, 2009 8:07 AM
> To: Windows System Software Devs Interest List
> Subject: RE: [ntdev] pointer 32 wraparound
>
>>
>> You should always use ULONG_PTR to cast a pointer types to a value
> type.
>> ULONG_PTR is a size_t so this is still 32 bits on a 32 bits system.
> So
>> substitute (ULONGLONG) with (ULONGLONG)(ULONG_PTR).
>
> Ah. I always assumed ULONG_PTR was a 32 bit value, but that was an
> incorrect assumption.
>
> Thanks for the tip.
>
> James
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
>

xxxxx@resplendence.com wrote:

That method leaves open the option of underflow so the equation might
wrap in the other direction.

No it doesn't. If there was going to be underflow in the 2nd clause then
the 1st clause would eval. to FALSE meaning the 2nd clause would never
be evaluated.

Paul

--

Paul Durrant
Paul Durrant - Amazon Web Services (AWS) | LinkedIn

“Paul Durrant” wrote in message news:xxxxx@ntdev…
> No it doesn’t. If there was going to be underflow in the 2nd clause then
> the 1st clause would eval. to FALSE meaning the 2nd clause would never be
> evaluated.
>

That holds true only if there are two conditions to be met to see if the
pointer is within range. While this may work most of the time for pointers,
we can’t say that is as unequivocal.

//Daniel

Also, it does not address the problem of casting the pointer to a value. In
its current form it will not even compile. Even if you want to do the
equation in the other direction you will need to cast the pointer to a value
for which you will need ULONG_PTR.

//Daniel

“David R. Cattley” wrote in message news:xxxxx@ntdev…
> ULONG_PTR is a unsigned ‘long’ of pointer width.
>
> Mr. Durrant’s suggestion is the one I use. When making stride comparisons
> in a number space that ‘wraps’ (what is that Calvin, affine closure?) bias
> the comparison by resetting the origin to the starting point. Or as Mr.
> Durrant put it, avoid the overlflow.
>
> Good Luck,
> Dave Cattley
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of James Harper
> Sent: Wednesday, July 08, 2009 8:07 AM
> To: Windows System Software Devs Interest List
> Subject: RE: [ntdev] pointer 32 wraparound
>
>>
>> You should always use ULONG_PTR to cast a pointer types to a value
> type.
>> ULONG_PTR is a size_t so this is still 32 bits on a 32 bits system.
> So
>> substitute (ULONGLONG) with (ULONGLONG)(ULONG_PTR).
>
> Ah. I always assumed ULONG_PTR was a 32 bit value, but that was an
> incorrect assumption.
>
> Thanks for the tip.
>
> James
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
>

If you want to use well tested code that detects overflow for you, look at safeint.h (UM version) and ntsafeint.h (KM). The flow of the code is a little strained b/c after each operation you need to check for failure, but it works…

d

Sent from my phone with no t9, all spilling mistakes are not intentional.

-----Original Message-----
From: xxxxx@resplendence.com
Sent: Wednesday, July 08, 2009 6:40 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] pointer 32 wraparound

Also, it does not address the problem of casting the pointer to a value. In
its current form it will not even compile. Even if you want to do the
equation in the other direction you will need to cast the pointer to a value
for which you will need ULONG_PTR.

//Daniel

“David R. Cattley” wrote in message news:xxxxx@ntdev…
> ULONG_PTR is a unsigned ‘long’ of pointer width.
>
> Mr. Durrant’s suggestion is the one I use. When making stride comparisons
> in a number space that ‘wraps’ (what is that Calvin, affine closure?) bias
> the comparison by resetting the origin to the starting point. Or as Mr.
> Durrant put it, avoid the overlflow.
>
> Good Luck,
> Dave Cattley
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of James Harper
> Sent: Wednesday, July 08, 2009 8:07 AM
> To: Windows System Software Devs Interest List
> Subject: RE: [ntdev] pointer 32 wraparound
>
>>
>> You should always use ULONG_PTR to cast a pointer types to a value
> type.
>> ULONG_PTR is a size_t so this is still 32 bits on a 32 bits system.
> So
>> substitute (ULONGLONG) with (ULONGLONG)(ULONG_PTR).
>
> Ah. I always assumed ULONG_PTR was a 32 bit value, but that was an
> incorrect assumption.
>
> Thanks for the tip.
>
> James
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
>


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

>

That method leaves open the option of underflow so the equation might
wrap
in the other direction.

In my particular case, the parameters are assumed to be valid. At such a
low level, if someone passes bad parameters to a system function then
they deserve to have a crashed system :slight_smile:

Thanks for the discussion guys.

James