validity of a pointer

  • Follow


finding the validity of the address pointed to by a pointer,
how this can be done.

a pointer "ptr" having a value of 0x808 is obviosuly not a
valid value. At the same time a value of 0xffffffff or 0x0000000
is inavalid and if a process address space is inbetween x and y;
any pointer value "< x" or "> y" would be invalid.
Is it possible to write this kind of checking in c
under linux platform.

 thanks
0
Reply sinbad.sinbad (155) 1/27/2009 9:21:46 AM

sinbad wrote:

> a pointer "ptr" having a value of 0x808 is obviosuly not a
> valid value.

Say's who?

> At the same time a value of 0xffffffff or 
> 0x0000000 is inavalid and if a process address space is
> inbetween x and y; any pointer value "< x" or "> y" would be
> invalid.

First read the pointer FAQ. Then you must understand, that the
only "invalid" pointer in terms of C is the null pointer, with
the value 0.

Any terms of additional validity/invalidity are imposed by the
operating system, so you've to check through this.

> Is it possible to write this kind of checking in c 
> under linux platform.

Sure. Open '/proc/self/maps'. It tells you exactly the memory
layout of the process. Read accessing any of the shown ranges
will expose well defined behaviour. In the maped areas with
write access you can also write without causing a SIGSEGV, but I
strongly discourage it, as it will probably corrupt vital
process data, especially if you write to the uppermost addresses
of the '[stack]' mapping.

Wolfgang

0
Reply wdraxinger (404) 1/27/2009 9:50:58 AM


sinbad wrote:
> finding the validity of the address pointed to by a pointer,
> how this can be done.
> 
> a pointer "ptr" having a value of 0x808 is obviosuly not a
> valid value. At the same time a value of 0xffffffff or 0x0000000
> is inavalid and if a process address space is inbetween x and y;
> any pointer value "< x" or "> y" would be invalid.
> Is it possible to write this kind of checking in c
> under linux platform.

The range of valid addresses is implementation-specific. Linux has been 
successfully ported to a very wide variety of platforms; I'd be somewhat 
surprised if your description of valid pointers were correct on all of 
them - though I'm not ruling out that possibility.

The only validity check you can perform in portable code is ptr!=NULL. 
For any more comprehensive validity check you need to use 
implementation-specific methods. You'll get better responses to such a 
question on a newsgroup devoted to your implementation. If there is a 
single answer that works on all Linux implementations, then you should 
be able to find it on a Linux newsgroup.

The only implementation-specific answers you'll get on this newsgroup 
will be from trolls, some of whom will give you incorrect answers out of 
incompetence, and one of whom has a history of giving deliberately 
incorrect answers, apparently just for the fun of watching people post 
messages correcting him.
0
Reply jameskuyper (5157) 1/27/2009 11:45:45 AM

Wolfgang Draxinger wrote:

> First read the pointer FAQ. Then you must understand, that the
> only "invalid" pointer in terms of C is the null pointer, with
> the value 0.

An indeterminate pointer is more invalid than a null pointer.

-- 
pete
0
Reply pfiland (6613) 1/27/2009 4:06:24 PM

pete <pfiland@mindspring.com> writes:

> Wolfgang Draxinger wrote:
>
>> First read the pointer FAQ. Then you must understand, that the
>> only "invalid" pointer in terms of C is the null pointer, with
>> the value 0.
>
> An indeterminate pointer is more invalid than a null pointer.

Where are the hosts of people not understanding, while scratching their
beards, what "value 0" means in pointer speak?
0
Reply rgrdev_ (1087) 1/27/2009 4:20:28 PM

On 27 Jan 2009 at  9:21, sinbad wrote:
> a pointer "ptr" having a value of 0x808 is obviosuly not a valid
> value. At the same time a value of 0xffffffff or 0x0000000 is inavalid
> and if a process address space is inbetween x and y; any pointer value
> "< x" or "> y" would be invalid.  Is it possible to write this kind of
> checking in c

If a pointer variable contains garbage, then either you didn't
initialize it, or your program is somehow overwriting the memory
locations where the pointer variable is stored.

In either case, you have a bug. The solution is not to try to check at
runtime whether a particular pointer has been clobbered or not, but to
fix the bug.

For the first case, you can use a memory checker tool: an excellent free
one for Linux is valgrind. The checker intercepts calls to malloc() and
free() to keep track of what memory is being allocated where, and alerts
you to reads from uninitialized memory (and also writes outside
allocated memory, and memory leaks).

For the second type of bug, where you overwrite memory you do actually
own, you can fire up your debugger, set a watch at the address of the
pointer variable, and see where it's getting clobbered. Often you'll
find it's an out-by-one error or bounds overflow for a static or
automatic array.

0
Reply nospam59 (9760) 1/27/2009 6:10:53 PM

sinbad <sinbad.sinbad@gmail.com> writes:

> finding the validity of the address pointed to by a pointer,
> how this can be done.
>
> a pointer "ptr" having a value of 0x808 is obviosuly not a
> valid value. At the same time a value of 0xffffffff or 0x0000000
> is inavalid and if a process address space is inbetween x and y;
> any pointer value "< x" or "> y" would be invalid.
> Is it possible to write this kind of checking in c
> under linux platform.

This isn't really a good question for comp.lang.c, since it doesn't have
much to do with the C language per se, it's really about Linux.
Crossposted and followups set to comp.os.linux.devel.applications

I think before answering this question, you should think about what you
mean by "valid", and why you want to know whether a pointer is "valid"
or not.  What are you going to do with this information?

Other people have mentioned using /proc/self/maps to see if the pointer
points into a region of memory that the process has mapped.  Certainly a
pointer that's not in one of these regions isn't very valid, since it
can't point to any object in your program and will cause a segfault if
dereferenced.  But even if it is in one of these regions, there's other
reasons it might be pointing to the "wrong" place.  Maybe you expect it
to point to an integer containing a number of lines, but it actually
points to the string "Hello world".

Also, regarding /proc/self/maps, doing this check is not very useful,
because what will you do if it fails?  Abort the program?  If you just
use the pointer, a segfault will do this for you.  Clean up first, or
longjmp to some other part of the program?  Then put this code in a
SIGSEGV handler.  You're really just duplicating a check that the
hardware is already doing.

Sometimes people ask questions like this because they have a function
which takes a pointer as an argument, and, wanting to be careful
defensive programmers, they want to verify the pointer somehow before
they use it.  Verifying that arguments make sense is generally a good
idea, but in the case of pointers it isn't really possible.  The
function just doesn't know enough about the rest of the program to be
able to check that the calling function is doing what it wants to.  In
this case you have to trust the caller.  Just use the pointer.  If it is
wrong, you'll find out when the program breaks, and that's when you turn
to your debugger to figure out what's going on in the rest of the
program.
0
Reply nate14 (514) 1/27/2009 6:36:43 PM

>finding the validity of the address pointed to by a pointer,
>how this can be done.

One way you can *try* is to dereference the pointer.  If the
program segfaults, it was an invalid value.  If it doesn't,
it might have been an invalid value.

>a pointer "ptr" having a value of 0x808 is obviosuly not a
>valid value. 

Under CP/M it is quite likely to be a valid value, where programs
start loading at 0x100.

>At the same time a value of 0xffffffff or 0x0000000
>is inavalid 

You don't have a guarantee of that, although NULL is not
guaranteed to be represented as 0xdeadbeef even on 32-bit
systems.

>and if a process address space is inbetween x and y;
>any pointer value "< x" or "> y" would be invalid.

It is quite possible that the program is loaded in several discontiguous
areas.  For example, stack (if there is one) and dynamically allocated
memory often grow towards each other, particularly in uni-threaded
programs.

Some systems deliberately randomize load addresses of the same
program in consecutive invocations in order to make it harder for
buffer-overflow attacks to actually do anything malicious.

>Is it possible to write this kind of checking in c
>under linux platform.

It's going to be VERY system-specific.

0
Reply gordonb.j1ghp (1) 1/27/2009 7:20:54 PM

On 2009-01-27, pete <pfiland@mindspring.com> wrote:
> Wolfgang Draxinger wrote:
>
>> First read the pointer FAQ. Then you must understand, that the
>> only "invalid" pointer in terms of C is the null pointer, with
>> the value 0.
>
> An indeterminate pointer is more invalid than a null pointer.

Yes; something invalid is much more invalid that something valid.
0
Reply kkylheku (2499) 1/27/2009 9:00:25 PM

On Tue, 27 Jan 2009 18:10:53 +0000 (UTC), Antoninus Twink
<nospam@nospam.invalid> wrote:

>On 27 Jan 2009 at  9:21, sinbad wrote:
>> a pointer "ptr" having a value of 0x808 is obviosuly not a valid
>> value. At the same time a value of 0xffffffff or 0x0000000 is inavalid
>> and if a process address space is inbetween x and y; any pointer value
>> "< x" or "> y" would be invalid.  Is it possible to write this kind of
>> checking in c
>
>If a pointer variable contains garbage, then either you didn't
>initialize it, or your program is somehow overwriting the memory
>locations where the pointer variable is stored.
>
>In either case, you have a bug. The solution is not to try to check at
>runtime whether a particular pointer has been clobbered or not, but to
>fix the bug.
>
>For the first case, you can use a memory checker tool: an excellent free
>one for Linux is valgrind. The checker intercepts calls to malloc() and
>free() to keep track of what memory is being allocated where, and alerts
>you to reads from uninitialized memory (and also writes outside
>allocated memory, and memory leaks).
>
>For the second type of bug, where you overwrite memory you do actually
>own, you can fire up your debugger, set a watch at the address of the
>pointer variable, and see where it's getting clobbered. Often you'll
>find it's an out-by-one error or bounds overflow for a static or
>automatic array.

While this is good advice in some contexts it is problematic in
others.  Yes, you want to fix the bug.  Sometimes using a
debugger is just the ticket and sometimes not.  Frex, how are you
going to set a watch at the address of the pointer variable
unless you know the pointer variable was clobbered?  What do you
do if the customers are off-site, perhaps running an OS variant
that you don't have in house or feeding proprietary data to the
program that they won't share with you.  Can you reproduce the
operator's fat fingering, etc.

For production software it is often best to assume that the nice
tools won't be relevant and that you have to debug from the
information the program provides to you.  Extensive error checks
and extensive error reports are your friends.



Richard Harter, cri@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
0
Reply cri (1432) 1/27/2009 9:40:12 PM

pete wrote:

> Wolfgang Draxinger wrote:
> 
>> First read the pointer FAQ. Then you must understand, that the
>> only "invalid" pointer in terms of C is the null pointer, with
>> the value 0.
> 
> An indeterminate pointer is more invalid than a null pointer.

In terms of C a null pointer is not something invalid in the term, that it
may not be there. However dereferencing a null pointer is invalid, thus I
wrote the word "invalid" in quotations marks, to designate it as being
meant in the OPs intention.

Any pointer with a value not being null can be dereferenced legally, as long
as we'te talking in terms of the language.

In terms of a specific implementation there might be further values, that
are invalid for a given pointer type (e.g. pointer values are alignment
constrained).

And then there is the classification of a pointer being valid or not by the
(operating system). Today one can cheaply build a 32 bits machine with 4GiB
memory (costs about 100$). Without a operating system, memory protection
and a paging system the physical memory can be addressed linearily. In this
situation, 32 bit CPU and 4GiB of memory running a single program in
physically addressing mode, virtually every pointer can be dereferenced
without raising a bus error exception.

But the C language deliberately doesn't specify anything about the low level
details that are implied by pointers. The only thing that's granted is,
that a pointer with the value 0 cannot be dereferenced and thus may be
considered invalid.

Wolfgang

P.S.: That I gave some detailed information on how to check a pointer for
validity under Linux is, that there's IMHO no sensible newsgroup for such
questions. The closest match would be comp.os.linux.development.apps, but
the guys there are focused on things like GUI and stuff like that. The
other Linux devel NG is comp.os.linux.development.system, which focuses on
the kernel and there a whole set of other rules apply.

0
Reply wdraxinger (404) 1/27/2009 9:50:10 PM

Kaz Kylheku <kkylheku@gmail.com> writes:
> On 2009-01-27, pete <pfiland@mindspring.com> wrote:
>> Wolfgang Draxinger wrote:
>>
>>> First read the pointer FAQ. Then you must understand, that the
>>> only "invalid" pointer in terms of C is the null pointer, with
>>> the value 0.
>>
>> An indeterminate pointer is more invalid than a null pointer.
>
> Yes; something invalid is much more invalid that something valid.

A null pointer is invalid for some purposes (i.e., dereferencing).  An
indeterminate is invalid for those purposes plus others.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
Reply kst-u (21469) 1/27/2009 9:54:32 PM

Wolfgang Draxinger wrote:
> pete wrote:
> 
>> Wolfgang Draxinger wrote:
>>
>>> First read the pointer FAQ. Then you must understand, that the
>>> only "invalid" pointer in terms of C is the null pointer, with
>>> the value 0.
>> An indeterminate pointer is more invalid than a null pointer.
> 
> In terms of C a null pointer is not something invalid in the term, that it
> may not be there. However dereferencing a null pointer is invalid, thus I
> wrote the word "invalid" in quotations marks, to designate it as being
> meant in the OPs intention.
> 
> Any pointer with a value not being null can be dereferenced legally, as long
> as we'te talking in terms of the language.

No.
A pointer that points one past an object,
is valid for purposes of pointer arithmetic,
but is not valid for dereferncing.

> In terms of a specific implementation there might be further values, that
> are invalid for a given pointer type (e.g. pointer values are alignment
> constrained).
> 
> And then there is the classification of a pointer being valid or not by the
> (operating system). Today one can cheaply build a 32 bits machine with 4GiB
> memory (costs about 100$). Without a operating system, memory protection
> and a paging system the physical memory can be addressed linearily. In this
> situation, 32 bit CPU and 4GiB of memory running a single program in
> physically addressing mode, virtually every pointer can be dereferenced
> without raising a bus error exception.
> 
> But the C language deliberately doesn't specify anything about the low level
> details that are implied by pointers. The only thing that's granted is,
> that a pointer with the value 0 cannot be dereferenced and thus may be
> considered invalid.

Considering three different kinds of operations on a pointer:
1   reading
2   pointer arithmetic
3   dereferencing

An indeterminate pointer is not valid for reading,
nor for pointer arithmetic, nor for dereferencing.

A null pointer is valid for reading;
but not for pointer arithmetic, nor for dereferencing.

A one past pointer is valid for reading.
and for pointer arithmetic.
But not for dereferencing.

A pointer to an object, is valid for reading,
for pointer arithmetic, and also for dereferencing.

-- 
pete
0
Reply pfiland (6613) 1/27/2009 10:09:45 PM

pete wrote:

>> Any pointer with a value not being null can be dereferenced legally, as
>> long as we'te talking in terms of the language.
> 
> No.
> A pointer that points one past an object,
> is valid for purposes of pointer arithmetic,
> but is not valid for dereferncing.

Yes, but that imposes no constraint on the values a pointer can assume.
Maybe I should have written ...may be dereferenced legally, if its value
points to a object." In special circumstances a object can take up the
entire value range a pointer can assume (except 0 of course). Thus the
language can effetivly imply no _value constraints_ other than '0' on the
validity of dereferencabilty, as in such case a pointer can assume
virtually any value not being 0. However implementations may reserve
certain values as invalid and use those to conserve the behavioue you
pointed out below. Or they simply buffer under-/overrun, which is the usual
case.

> Considering three different kinds of operations on a pointer:
> 1   reading
> 2   pointer arithmetic
> 3   dereferencing
> 
> An indeterminate pointer is not valid for reading,
> nor for pointer arithmetic, nor for dereferencing.

Right, but how do you tell an pointer is definitely indeterminate: You leave
it uninitialized. But then the same rule also applies to any other
uninitialized value, though those will only yield undefined behaviour.

> A null pointer is valid for reading;
> but not for pointer arithmetic, nor for dereferencing.
>
> A one past pointer is valid for reading.
> and for pointer arithmetic.
> But not for dereferencing.
>
> A pointer to an object, is valid for reading,
> for pointer arithmetic, and also for dereferencing.

....as long as it stays within the bounds of the object.

Wolfgang

0
Reply wdraxinger (404) 1/27/2009 10:57:47 PM

Wolfgang Draxinger wrote:

>> A pointer to an object, is valid for reading,
>> for pointer arithmetic, and also for dereferencing.
> 
> ...as long as it stays within the bounds of the object.

I meant the arithmetic part.

Wolfgang

0
Reply wdraxinger (404) 1/27/2009 11:16:51 PM

Wolfgang Draxinger wrote:
....
> Any pointer with a value not being null can be dereferenced legally, as long
> as we'te talking in terms of the language.

Not if it points one past the end of an array.

Not if the value of the pointer is indeterminate. To be more specific:
    Not if it points at an object whose lifetime is ended.
        In particular, not if it points at dynamically allocated
memory which has since been free()d.
    Not if it it's a FILE* for a stream that has been fclose()d.
0
Reply jameskuyper (5157) 1/28/2009 12:29:37 AM

Keith Thompson wrote:

> A null pointer is invalid for some purposes (i.e.,
> dereferencing).  An indeterminate is invalid for those purposes
> plus others.

Which still remains the question: How does one determine if a
pointer is indetermined. You can't do it by it's value using
solely the functionality provided by C.

Okay, because some people seem to have misunderstood me another
branch of this thread: I didn't say, that there aren't other
invalidities like null pointers. I just wanted to point out,
that any value one finds in a pointer, except 0, should be
considered possibly valid. And on certain implementations
virtually any pointer value (except 0) could be valid, though
not neccesarily dereferencable, like the value of a pointer
pointing just one element beyond the bounds of an array.

Wolfgang

0
Reply wdraxinger (404) 1/28/2009 12:32:43 AM

Wolfgang Draxinger wrote:
> Keith Thompson wrote:
>
> > A null pointer is invalid for some purposes (i.e.,
> > dereferencing).  An indeterminate is invalid for those purposes
> > plus others.
>
> Which still remains the question: How does one determine if a
> pointer is indetermined. You can't do it by it's value using
> solely the functionality provided by C.

No, the only thing you can do is examine your code for possible causes
of indeterminacy. If the pointer comes in from outside your code, such
checks will, unfortunately, be inadequate.

> Okay, because some people seem to have misunderstood me another
> branch of this thread: I didn't say, that there aren't other
> invalidities like null pointers. I just wanted to point out,
> that any value one finds in a pointer, except 0, should be
> considered possibly valid.

You should only consider it possibly valid if you've made sure that
your own code has gone out of it's way, if necessary, to ensure that
none of the situations that can render a pointer value indeterminate
have occurred to this pointer value. If your code is linked to other
people's code, the best you can do is hope that they have been equally
careful, but that's not the same as always considering that any non-
null pointer is valid.
0
Reply jameskuyper (5157) 1/28/2009 12:46:04 AM

Wolfgang Draxinger <wdraxinger@darkstargames.de> writes:
> Keith Thompson wrote:
>
>> A null pointer is invalid for some purposes (i.e.,
>> dereferencing).  An indeterminate is invalid for those purposes
>> plus others.
>
> Which still remains the question: How does one determine if a
> pointer is indetermined.

Right.

>                          You can't do it by it's value using
> solely the functionality provided by C.

And there's your answer.  There *might* be a system-specific way to
determine whether a pointer is "valid", for whatever meaning of the
word "valid" you'd like to apply -- or there might not.

> Okay, because some people seem to have misunderstood me another
> branch of this thread: I didn't say, that there aren't other
> invalidities like null pointers. I just wanted to point out,
> that any value one finds in a pointer, except 0, should be
> considered possibly valid. And on certain implementations
> virtually any pointer value (except 0) could be valid, though
> not neccesarily dereferencable, like the value of a pointer
> pointing just one element beyond the bounds of an array.

Sure, any non-null pointer value *could* be valid, in the sense that
it might point to an object within your program.  But even if you
could test for that, it's really not enough.  The important question
is whether the pointer value is correct; does it point to the *right*
object?  That's a question that depends intimately on your program
logic.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
Reply kst-u (21469) 1/28/2009 12:47:51 AM

Wolfgang Draxinger wrote:
> Keith Thompson wrote:
> 
>> A null pointer is invalid for some purposes (i.e.,
>> dereferencing).  An indeterminate is invalid for those purposes
>> plus others.
> 
> Which still remains the question: How does one determine if a
> pointer is indetermined. You can't do it by it's value using
> solely the functionality provided by C.
> 
> Okay, because some people seem to have misunderstood me another
> branch of this thread: I didn't say, that there aren't other
> invalidities like null pointers. I just wanted to point out,
> that any value one finds in a pointer, except 0, should be
> considered possibly valid. And on certain implementations
> virtually any pointer value (except 0) could be valid, though
> not neccesarily dereferencable, like the value of a pointer
> pointing just one element beyond the bounds of an array.

I sometimes form a specific pointer for the purpose of having a
NULL equivalent that is distinguishable from NULL.  There is an
example in my hashlib package, used to keep track of deleted
entries, which cannot be replaced with a NULL pointer.

-- 
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: <http://cbfalconer.home.att.net>
            Try the download section.
0
Reply cbfalconer (19183) 1/28/2009 1:09:31 AM

Wolfgang Draxinger wrote:
> Keith Thompson wrote:
> 
>> A null pointer is invalid for some purposes (i.e.,
>> dereferencing).  An indeterminate is invalid for those purposes
>> plus others.
> 
> Which still remains the question: How does one determine if a
> pointer is indetermined. You can't do it by it's value using
> solely the functionality provided by C.
> 
> Okay, because some people seem to have misunderstood me another
> branch of this thread: I didn't say, that there aren't other
> invalidities like null pointers. I just wanted to point out,
> that any value one finds in a pointer, except 0, should be
> considered possibly valid. And on certain implementations
> virtually any pointer value (except 0) could be valid, though
> not neccesarily dereferencable, like the value of a pointer
> pointing just one element beyond the bounds of an array.

There exist some systems where zero is a "valid" pointer, e.g. in MS DOS 
it's a pointer to the interrupt vector table.

There is no portable way to test for "indeterminate" pointers, and even 
if your OS provides a non-portable function to perform a test, 
technically calling it can invoke UB because an argument must be 
evaluated to be passed, and examining an indeterminate pointer (not just 
dereferencing it) causes UB...

S

-- 
Stephen Sprunk        "Stupid people surround themselves with smart
CCIE #3723           people.  Smart people surround themselves with
K5SSS          smart people who disagree with them."  --Isaac Jaffe
0
Reply stephen (1124) 1/28/2009 1:55:06 AM

Stephen Sprunk <stephen@sprunk.org> writes:

> There is no portable way to test for "indeterminate" pointers, and
> even if your OS provides a non-portable function to perform a test,
> technically calling it can invoke UB because an argument must be
> evaluated to be passed, and examining an indeterminate pointer (not
> just dereferencing it) causes UB...

Presumably such a system would define the undefined behavior
appropriately.  For example, it might document that there are no trap
representations for pointer types (which is commonly the case anyway).


0
Reply nate14 (514) 1/28/2009 2:35:03 AM

On 2009-01-28, Nate Eldredge <nate@vulcan.lan> wrote:
> Stephen Sprunk <stephen@sprunk.org> writes:
>
>> There is no portable way to test for "indeterminate" pointers, and
>> even if your OS provides a non-portable function to perform a test,
>> technically calling it can invoke UB because an argument must be
>> evaluated to be passed, and examining an indeterminate pointer (not
>> just dereferencing it) causes UB...
>
> Presumably such a system would define the undefined behavior
> appropriately.

Not in a way that can magically reach back into the standard language
and make it defined there. :)

It would be ``defined in this dialect of C'', not 
``defined in standard C''.
0
Reply kkylheku (2499) 1/28/2009 2:57:42 AM

Kaz Kylheku <kkylheku@gmail.com> writes:

> On 2009-01-28, Nate Eldredge <nate@vulcan.lan> wrote:
>> Stephen Sprunk <stephen@sprunk.org> writes:
>>
>>> There is no portable way to test for "indeterminate" pointers, and
>>> even if your OS provides a non-portable function to perform a test,
>>> technically calling it can invoke UB because an argument must be
>>> evaluated to be passed, and examining an indeterminate pointer (not
>>> just dereferencing it) causes UB...
>>
>> Presumably such a system would define the undefined behavior
>> appropriately.
>
> Not in a way that can magically reach back into the standard language
> and make it defined there. :)
>
> It would be ``defined in this dialect of C'', not 
> ``defined in standard C''.

Yes.  But standard C also doesn't provide an `is_valid_pointer'
function.  So any implementation that did the latter could (should) also
do the former.  Of course a program using these features would cease to
be portable standard C.
0
Reply nate14 (514) 1/28/2009 3:00:32 AM

Stephen Sprunk <stephen@sprunk.org> writes:
[...]
> There exist some systems where zero is a "valid" pointer, e.g. in MS
> DOS it's a pointer to the interrupt vector table.
>
> There is no portable way to test for "indeterminate" pointers, and
> even if your OS provides a non-portable function to perform a test,
> technically calling it can invoke UB because an argument must be
> evaluated to be passed, and examining an indeterminate pointer (not
> just dereferencing it) causes UB...

If your OS provides such a function, your C implementation probably
also guarantees (or *could* guarantee) that examining an indeterminate
pointer value doesn't cause an unhappy situation.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
Reply kst-u (21469) 1/28/2009 3:08:50 AM

Wolfgang Draxinger said:

> Keith Thompson wrote:
> 
>> A null pointer is invalid for some purposes (i.e.,
>> dereferencing).  An indeterminate is invalid for those purposes
>> plus others.
> 
> Which still remains the question: How does one determine if a
> pointer is indetermined. You can't do it by it's value using
> solely the functionality provided by C.

Right - and this is a perfect question for comp.lang.c, because it's 
a question that is about ISO C but which actually can't be answered 
(adequately) merely by reference to the Standard. Of course, this 
is bound to mean that there isn't any single right answer, and 
opinions are going to vary wildly, but it still bears discussing.

My own strategy for dealing with this problem is to make sure that 
no pointer has an indeterminate value for any longer than necessary 
(and ideally an indeterminate pointer should be made determinate in 
the very next statement). I'm not saying I follow this strategy 
perfectly, but I do consider any departure from it to be a bug 
which I will endeavour to fix upon discovering it.

So for example, let's say we're defining a pointer object. The 
"rule" is - give it a proper value or give it NULL. Hence:

T *new = malloc(sizeof *new); /* for example... */

or:

T *new = NULL;

If we're making a pointer indeterminate, we fix it right away:

free(*old);
*old = NULL;

By adopting this strategy both in library code and in program code, 
we can be reasonably confident that we won't hit any indeterminate 
pointers. A test for NULL becomes adequate.

Having followed this strategy carefully (albeit not perfectly) for 
some time, I can now be reasonably (albeit not perfectly) confident 
that I have a substantial (albeit not perfect) collection of 
library routines which provide me with important functionality 
without introducing any determinacy problems into my programs.

-- 
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
0
Reply rjh (10789) 1/28/2009 5:02:40 AM

Wolfgang Draxinger wrote:
> pete wrote:

>> An indeterminate pointer is not valid for reading,
>> nor for pointer arithmetic, nor for dereferencing.
> 
> Right, but how do you tell an pointer is definitely indeterminate: You leave
> it uninitialized. But then the same rule also applies to any other
> uninitialized value, though those will only yield undefined behaviour.

Freed pointers are also indeterminate.
The only way to know if a pointer is indeterminate,
is by knowing the pointer's history.

-- 
pete
0
Reply pfiland (6613) 1/28/2009 6:10:25 AM

Wolfgang Draxinger wrote:
> Wolfgang Draxinger wrote:
> 
>>> A pointer to an object, is valid for reading,
>>> for pointer arithmetic, and also for dereferencing.
>> ...as long as it stays within the bounds of the object.
> 
> I meant the arithmetic part.

I didn't mean a pointer to an object type.
I meant a pointer to an object, with "pointer to"
having the same meaning as in:
"The malloc function returns either a null pointer
  or a pointer to the allocated space."

-- 
pete
0
Reply pfiland (6613) 1/28/2009 6:18:54 AM

Stephen Sprunk wrote:

> There exist some systems where zero is a "valid" pointer, e.g.
> in MS DOS it's a pointer to the interrupt vector table.

I fell for the same misconception until a few months ago (when
Keith Thompson and a few others had the patience, to explain it
to me, thanks again guys). The value of a pointer in C may be
something completely different from what is actually stored in
the machine. If your architecture consideres 0xdeadbeef as a
null pointer, then the C standard states, that

void *p = something;
if( p == 0 ) { ... }

is actually compiled to a comparision of p against 0xdeadbeef.

If you wonder how to access things like the interrupt vector
table then. Well, you need a compiler that has been writen for
that system (e.g. by applying a offset of -0x1000 to all pointer
values found in the range 0x1000...0x2000 if dereferenced and
the inverse if casted to an int). And you declare your pointer
extern (and constant).

extern void * const intvec;

And then in the linker you direct intvec to point to the correct
location.

The funny thing is: C is much more high level then most
implementations make people think. One could perfectly compile C
into interpreted bytecode.

Wolfgang

0
Reply wdraxinger (404) 1/28/2009 10:06:17 AM

jameskuyper wrote:

> same as always considering that any non- null pointer is valid.

I wouldn't consider any pointer valid, but one can't be sure if a
given pointer value is valid or not. 0 is the only exception. If
a pointer is 0 you know it's invalid.

Any saying "any pointer values should be considered valid" does
not mean, you should write something like:

#include <stdint.h>
uintptr_t j;
for(j = 0; j < UINTPTR_MAX ; ++j) {
        putc( *((char*)j) );
}

The statement means, that the following is not reasonable,
without knowing details of the implementation (in this case
r_min, r_max).

#include <stdint.h>
extern uintptr_t r_min, r_max;
extern void *p;
if( (uintptr_t)p < r_min || (uintptr_t)p > r_max ) {
        printf("pointer p is invalid");
}

You don't know if it's valid or invalid. And on some systems
(like DOS) dereferencing a invalid pointer will not raise a bus
error, if you don't address nonexisting memory. And on such
systems, where programs share the address space, you should
assume a safe strategy, considering every pointer you've no
track of as being valid, and unknowingly touching it may couse
severe trouble in other parts of the system. So saying "consider
every pointer valid" does not mean "do with it what ever you
want" but instead: "treat it carefully, you don't know, what it
might do, if you don't. It could be even the trigger of a
doomsday device..."

Wolfgang

0
Reply wdraxinger (404) 1/28/2009 10:24:34 AM

Wolfgang Draxinger wrote:

> The funny thing is: C is much more high level then most
> implementations make people think. One could perfectly compile C
> into interpreted bytecode.

That's not a test of high-level-ness, since one could compile
assembly code into interpreted bytecode.

-- 
"It's just the beginning we've seen."           - Colosseum, /Tomorrow's Blues/

Hewlett-Packard Limited     Cain Road, Bracknell,                registered no:
registered office:          Berks RG12 1HN                       690597 England

0
Reply chris.dollin (1683) 1/28/2009 10:30:22 AM

Wolfgang Draxinger wrote:
> only "invalid" pointer in terms of C is the null pointer, with
> the value 0.
Just 2 cents:
"with the value defined in headers".
I guess that any well written code (not referring to 0) should work with 
null redefined to MAX_INT (as long it's not in it's allocatable address 
range)
0
Reply Francois 1/28/2009 1:51:42 PM

Wolfgang Draxinger wrote:
> Stephen Sprunk wrote:
> 
>> There exist some systems where zero is a "valid" pointer, e.g.
>> in MS DOS it's a pointer to the interrupt vector table.
> 
> I fell for the same misconception until a few months ago (when
> Keith Thompson and a few others had the patience, to explain it
> to me, thanks again guys). The value of a pointer in C may be
> something completely different from what is actually stored in
> the machine. If your architecture consideres 0xdeadbeef as a
> null pointer, then the C standard states, that
> 
> void *p = something;
> if( p == 0 ) { ... }
> 
> is actually compiled to a comparision of p against 0xdeadbeef.
> 
> If you wonder how to access things like the interrupt vector
> table then. Well, you need a compiler that has been writen for
> that system (e.g. by applying a offset of -0x1000 to all pointer
> values found in the range 0x1000...0x2000 if dereferenced and
> the inverse if casted to an int). And you declare your pointer
> extern (and constant).

Yes, an implementation is allowed to use such an approach; but that's 
not what was done in the case Stephen was describing. A pointer to 
address 0 was treated as a null pointer; the undefined behavior that 
occurred as a result of dereferencing such a null pointer was that it 
produced a reference to start of the piece of memory containing the 
interrupt vector table.
0
Reply jameskuyper (5157) 1/28/2009 2:30:27 PM

Francois Cartegnie wrote:
> Wolfgang Draxinger wrote:
>> only "invalid" pointer in terms of C is the null pointer, with
>> the value 0.
> Just 2 cents:
> "with the value defined in headers".
> I guess that any well written code (not referring to 0) should work with 
> null redefined to MAX_INT (as long it's not in it's allocatable address 
> range)

Well written code can assume that null isn't even defined; it certainly 
doesn't need to be able to cope with null pre-defined to the same value 
as MAX_INT. The following is perfectly legal code that would become a 
syntax error with that definition:

char null[] = "NULL is not the same thing as null.";

If you were actually talking aboue NULL (rather than null), then your 
statement is still incorrect. NULL cannot legally be defined to have a 
value of MAX_INT, and well-written code therefore need not consider the 
possibility that it is. NULL can't legally be defined as (void*)MAX_INT, 
either, though it is permissible for (void*)MAX_INT to be null, in which 
case it must compare equal to NULL.

I suspect that some of my statements above will sound meaningless, 
nonsensical, or contradictory to you. If so, please identify which ones, 
and I'll explain further.
0
Reply jameskuyper (5157) 1/28/2009 2:41:43 PM

On Wed, 28 Jan 2009 14:41:43 +0000, James Kuyper wrote:
> [...] NULL can't legally be defined as (void*)MAX_INT,
> either, though it is permissible for (void*)MAX_INT to be null, in which
> case it must compare equal to NULL.

If NULL is defined as ((void*)MAX_INT), which requirement of the standard 
has the implementation not met if a program cannot tell ((void*)0) apart 
from ((void*)MAX_INT)? The one thing I can think of is that (void*)0 can 
be implicitly converted to a function pointer type, but implicit 
conversions between object and function pointer types are somewhat 
commonly supported already anyway.
0
Reply truedfx (1926) 1/28/2009 4:04:35 PM

Harald van Dijk wrote:
> On Wed, 28 Jan 2009 14:41:43 +0000, James Kuyper wrote:
>> [...] NULL can't legally be defined as (void*)MAX_INT,
>> either, though it is permissible for (void*)MAX_INT to be null, in which
>> case it must compare equal to NULL.
> 
> If NULL is defined as ((void*)MAX_INT), which requirement of the standard 
> has the implementation not met if a program cannot tell ((void*)0) apart 
> from ((void*)MAX_INT)?

It has certainly not met the requirement that NULL expand to a null 
pointer constant. However, the only way to verify that would be by 
stringizing the macro using the # operator:

#define STRING(a) STR(a)
#define STR(a) #a
#include <stdlib.h>
#include <string.h>

int main(void)
{
     return strcmp(STRING(NULL), "((void*)MAX_INT)")
         ? EXIT_SUCCESS : EXIT_FAILURE;
}

There has been considerable disagreement expressed on comp.std.c about 
whether it something really is a conformance violation, if the only way 
to detect the violation is to convert the expansion of a standard macro 
to a string. However, it seems to me that a strict interpretation of the 
standard renders the above program strictly conforming, and guarantees 
that that the program will indicate a successful termination when it is 
translated and executed by any conforming implementation.
0
Reply jameskuyper (5157) 1/28/2009 4:52:55 PM

Wolfgang Draxinger wrote:
> Stephen Sprunk wrote:
>> There exist some systems where zero is a "valid" pointer, e.g.
>> in MS DOS it's a pointer to the interrupt vector table.
> 
> I fell for the same misconception until a few months ago (when
> Keith Thompson and a few others had the patience, to explain it
> to me, thanks again guys). The value of a pointer in C may be
> something completely different from what is actually stored in
> the machine. If your architecture consideres 0xdeadbeef as a
> null pointer, then the C standard states, that
> 
> void *p = something;
> if( p == 0 ) { ... }
> 
> is actually compiled to a comparision of p against 0xdeadbeef.

I am now aware that (void*)0 is not necessarily the same as (void*)zero. 
  However, on all DOS compilers I'm aware of, NULL was all-bits zero, 
and was indeed a "valid" pointer, for sufficiently loose definitions of 
"valid".  One could claim that the IVT was not a C "object" due to its 
location, but there quite certainly was an array of pointers-to-function 
at that address...

(Above assumes const int zero = 0;)

S

-- 
Stephen Sprunk        "Stupid people surround themselves with smart
CCIE #3723           people.  Smart people surround themselves with
K5SSS          smart people who disagree with them."  --Isaac Jaffe
0
Reply stephen (1124) 1/28/2009 5:08:59 PM

Francois Cartegnie <NOSPAM@371b8a65dbbbe45a3b6ad5b7af1cf904.mail> writes:
> Wolfgang Draxinger wrote:
>> only "invalid" pointer in terms of C is the null pointer, with
>> the value 0.
> Just 2 cents:
> "with the value defined in headers".
> I guess that any well written code (not referring to 0) should work
> with null redefined to MAX_INT (as long it's not in it's allocatable
> address range)

As James pointed out, you meant NULL, not null, and you probably meant
((void*)INT_MAX).

I believe that redefining a macro defined in a standard header invokes
undefined behavior, but we'll ignore that for now.

What you're saying, I think, is that if a well-written program used
some unique non-null pointer value as a null pointer, then it would
still work as long as it *consistently* uses this unique value.  Let's
say it defines, in some header:
    #define MY_NULL ((void*)INT_MAX)
and used MY_NULL everywhere in place of NULL.

This could be made to work, but you'd have to watch out for references
to null pointers that don't use the NULL macro:

    void *ptr = 0;   /* sets ptr to NULL, not MY_NULL */
    if (ptr) { ... } /* compares ptr to NULL, not MY_NULL */

But the biggest problem is that the standard library uses actual null
pointers in many places.  You'd have to compare the result of fopen()
to NULL, but compare the result of your own foo() to MY_NULL.

The choice of which pointer representation to set aside as a null
pointer value is largely an arbitrary one, and you can change it as
long as you do so consistently.  (I think that was the point you were
trying to make.)  But changing it consistently requires changing the
compiler, the standard runtime library, any additional libraries
provided by the OS or by third parties, *and* your own program.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
Reply kst-u (21469) 1/28/2009 5:31:19 PM

On Wed, 28 Jan 2009 16:52:55 +0000, James Kuyper wrote:
> Harald van Dijk wrote:
>> On Wed, 28 Jan 2009 14:41:43 +0000, James Kuyper wrote:
>>> [...] NULL can't legally be defined as (void*)MAX_INT, either, though
>>> it is permissible for (void*)MAX_INT to be null, in which case it must
>>> compare equal to NULL.
>> 
>> If NULL is defined as ((void*)MAX_INT), which requirement of the
>> standard has the implementation not met if a program cannot tell
>> ((void*)0) apart from ((void*)MAX_INT)?
> 
> It has certainly not met the requirement that NULL expand to a null
> pointer constant. However, the only way to verify that would be by
> stringizing the macro using the # operator:

That's not something a strictly conforming program can do, because the 
expansion is allowed to contain backslashes that do not start an escape 
sequence, and the expansion is allowed to be too long to be stringised. 
4000 opening parentheses, a plain old 0, and 4000 closing parentheses 
make a valid null pointer constant.

[example snipped]
0
Reply truedfx (1926) 1/28/2009 5:47:11 PM

Richard Heathfield wrote:
> 
.... snip ...
> 
> If we're making a pointer indeterminate, we fix it right away:
> 
> free(*old);
> *old = NULL;
> 
> By adopting this strategy both in library code and in program
> code, we can be reasonably confident that we won't hit any
> indeterminate pointers. A test for NULL becomes adequate.

The problem with this, which we don't really notice [1], is that we
have to keep track of which pointers are secured from malloc, and
which are not.  Except for NULL, the only ones that can be passed
to free are those secured via malloc and friends.

[1] I think the reason is that we are so used to it, and we tend to
keep malloced pointers in a separate mental class.

-- 
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: <http://cbfalconer.home.att.net>
            Try the download section.
0
Reply cbfalconer (19183) 1/28/2009 9:55:14 PM

CBFalconer said:

> Richard Heathfield wrote:
>> 
> ... snip ...
>> 
>> If we're making a pointer indeterminate, we fix it right away:
>> 
>> free(*old);
>> *old = NULL;
>> 
>> By adopting this strategy both in library code and in program
>> code, we can be reasonably confident that we won't hit any
>> indeterminate pointers. A test for NULL becomes adequate.
> 
> The problem with this, which we don't really notice [1], is that
> we have to keep track of which pointers are secured from malloc,
> and
> which are not.

It's true that one has to do this, but not for the reason you claim. 
One has to know which pointers have been returned by malloc because 
one has to free them.

> Except for NULL, the only ones that can be passed
> to free are those secured via malloc and friends.

Yes. How is that a problem with what I wrote?

> [1] I think the reason is that we are so used to it, and we tend
> [to
> keep malloced pointers in a separate mental class.

I have nothing to say about the above statement. 

-- 
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
0
Reply rjh (10789) 1/28/2009 10:50:36 PM

James Kuyper <jameskuyper@verizon.net> writes:
> sinbad wrote:
>> finding the validity of the address pointed to by a pointer,
>> how this can be done.
>>
>> a pointer "ptr" having a value of 0x808 is obviosuly not a
>> valid value. At the same time a value of 0xffffffff or 0x0000000
>> is inavalid and if a process address space is inbetween x and y;
>> any pointer value "< x" or "> y" would be invalid.
>> Is it possible to write this kind of checking in c
>> under linux platform.
>
> The range of valid addresses is implementation-specific. Linux has
> been successfully ported to a very wide variety of platforms; I'd be
> somewhat surprised if your description of valid pointers were correct
> on all of them - though I'm not ruling out that possibility.

From my limited experience of the linux kernel, most drivers (which 
make up most of the bulk of the kernel code) use a RAII model, use
reference counting whereever pointers are shared, and are never in 
a state where their pointers are in an indeterminate state. (They
may be invalid C pointers, but something in the structure as a whole
indicates that those pointers are indeed invalid.)

The (virtual) memory manager may be entirely different, but that's
a) a minuscule part of the elephantine kernal
b) intrinsically platform specific

Phil
-- 
I tried the Vista speech recognition by running the tutorial. I was 
amazed, it was awesome, recognised every word I said. Then I said the 
wrong word ... and it typed the right one. It was actually just 
detecting a sound and printing the expected word! -- pbhj on /.
0
Reply thefatphil_demunged (1558) 1/29/2009 6:45:29 AM

James Kuyper <jameskuyper@verizon.net> writes:

> Harald van Dijk wrote:
> > On Wed, 28 Jan 2009 14:41:43 +0000, James Kuyper wrote:
> >> [...] NULL can't legally be defined as (void*)MAX_INT,
> >> either, though it is permissible for (void*)MAX_INT to be null, in which
> >> case it must compare equal to NULL.
> > 
> > If NULL is defined as ((void*)MAX_INT), which requirement of the standard 
> > has the implementation not met if a program cannot tell ((void*)0) apart 
> > from ((void*)MAX_INT)?
> 
> It has certainly not met the requirement that NULL expand to a null 
> pointer constant. However, the only way to verify that would be by 
> stringizing the macro using the # operator:
> 
> #define STRING(a) STR(a)
> #define STR(a) #a
> #include <stdlib.h>
> #include <string.h>
> 
> int main(void)
> {
>      return strcmp(STRING(NULL), "((void*)MAX_INT)")
>          ? EXIT_SUCCESS : EXIT_FAILURE;
> }
> 
> There has been considerable disagreement expressed on comp.std.c about 
> whether it something really is a conformance violation, if the only way 
> to detect the violation is to convert the expansion of a standard macro 
> to a string. However, it seems to me that a strict interpretation of the 
> standard renders the above program strictly conforming, and guarantees 
> that that the program will indicate a successful termination when it is 
> translated and executed by any conforming implementation.

This argument uses circular reasoning.  The given program is
strictly conforming only if an implementation is not allowed
to define its own null pointer constants for NULL, but that
question is the very question under consideration.  Nothing
is proven one way or the other by this argument.

(I assume most people are reading 'MAX_INT' to mean INT_MAX, not that
that difference changes the comments in any material way.)
0
Reply txr (1104) 2/12/2009 1:16:10 AM

42 Replies
25 Views

(page loaded in 0.507 seconds)


Reply: