jbm@eos.UUCP (Jeffrey Mulligan) (07/17/89)
It has been pointed out that there should be no assumptions
about what addresses are valid; is there any way to get
a guaranteed INVALID address?
I commonly do this sort of thing:
struct foobar { /* some stuff */};
static struct foobar *fb1=NO_FOOBAR;
struct foobar *get_a_foobar()
{
if( can_allocate_memory_and_initialize )
return( a_pointer_to_a_foobar );
else
return( NO_FOOBAR );
}
/* somewhere else */
if( fb1==NO_FOOBAR ) /* initial state */
if( (fb1=get_a_foobar()) == NO_FOOBAR )
complain_loudly();
So, the question is, how should NO_FOOBAR be defined?
#define NO_FOOBAR ((struct foobar *) -1 ) is what I use, but...
I note that malloc(3) returns NULL (0) on failure [on the sun], indicating
that 0 could never be a valid address returned from malloc.
Sorry if this is the wrong newsgroup.
--
Jeff Mulligan (jbm@aurora.arc.nasa.gov)
NASA/Ames Research Ctr., Mail Stop 239-3, Moffet Field CA, 94035
(415) 694-6290
scs@adam.pika.mit.edu (Steve Summit) (07/17/89)
In article <4348@eos.UUCP> jbm@eos.UUCP (Jeffrey Mulligan) writes: >It has been pointed out that there should be no assumptions >about what addresses are valid; is there any way to get >a guaranteed INVALID address? >I commonly do this sort of thing: > >static struct foobar *fb1=NO_FOOBAR; > >So, the question is, how should NO_FOOBAR be defined? NULL, or the equivalent 0, is precisely the right thing to use in this situation. The null pointer is, by definition, guaranteed not to point to any object. Using the intermediate NO_FOOBAR is still a good idea, by the way, because it helps insulate the calling application from the implementation details of the "foobar" code. For instance, my programs contain things like #include "graph.h" graphd gd = grph_alloc(...); if(gd == NOGRAPH) ... where graphd is a "graph descriptor" type defined with a typedef in graph.h . The caller is not supposed to know what kind of a type graphd is (that's why it's a typedef). If a graphd is a pointer, NOGRAPH is 0, but if it's a small-integer descriptor (like Unix file descriptors) NOGRAPH is -1. >Sorry if this is the wrong newsgroup. Actually, it is, and I'd redirect followups to comp.lang.c, except that they're generally pretty tired of the NULL topic over there. (And yes, unadorned 0 is a guaranteed acceptable #definition for NULL, so let's not start that discussion here.) Steve Summit scs@adam.pika.mit.edu
smb@ulysses.homer.nj.att.com (Steven M. Bellovin) (07/17/89)
In article <4348@eos.UUCP>, jbm@eos.UUCP (Jeffrey Mulligan) writes: > It has been pointed out that there should be no assumptions > about what addresses are valid; is there any way to get > a guaranteed INVALID address? > > I commonly do this sort of thing: > > struct foobar { /* some stuff */}; > > static struct foobar *fb1=NO_FOOBAR; .... > So, the question is, how should NO_FOOBAR be defined? From the C Reference Manual, section 7.7, ``Equality Operators'': A pointer may be compared to an integer only if the integer is the constant 0. A pointer to which 0 has been assigned is guaranteed not to point to any object and will appear to be equal to 0. In conventional usage, such a pointer is considered to be null. In other words, NO_FOOBAR should be defined as 0. And this is a strong hint to those who think that dereferencing 0 is legal. --Steve Bellovin
bzs@bu-cs.BU.EDU (Barry Shein) (07/17/89)
From: jbm@eos.UUCP (Jeffrey Mulligan) >It has been pointed out that there should be no assumptions >about what addresses are valid; is there any way to get >a guaranteed INVALID address? > >I commonly do this sort of thing: > >struct foobar { /* some stuff */}; > >static struct foobar *fb1=NO_FOOBAR; >... >So, the question is, how should NO_FOOBAR be defined? > >#define NO_FOOBAR ((struct foobar *) -1 ) is what I use, but... A perfectly good solution is: struct foobar no_foobar; #define NO_FOOBAR (&no_foobar) being as no_foobar will be the only thing assigned this address it is unique and solves your problem. This of course works for your example where you test for a return value of NO_FOOBAR, doing it by causing a signal to occur (eg. SEGV) is another problem entirely. -- -Barry Shein Software Tool & Die, Purveyors to the Trade 1330 Beacon Street, Brookline, MA 02146, (617) 739-0202 Internet: bzs@skuld.std.com UUCP: encore!xylogics!skuld!bzs or uunet!skuld!bzs
debra@alice.UUCP (Paul De Bra) (07/17/89)
In article <4348@eos.UUCP> jbm@eos.UUCP (Jeffrey Mulligan) writes: } }It has been pointed out that there should be no assumptions }about what addresses are valid; is there any way to get }a guaranteed INVALID address? }... }So, the question is, how should NO_FOOBAR be defined? } }#define NO_FOOBAR ((struct foobar *) -1 ) is what I use, but... } }I note that malloc(3) returns NULL (0) on failure [on the sun], indicating }that 0 could never be a valid address returned from malloc. According to the (new) K&R book NULL (0) is indeed guaranteed not to be a valid data (or text or stack) address. Furthermore, the only meaningful comparisons between pointers are comparison between pointers to elements of the same string and comparison between a pointer and NULL. Paul. -- ------------------------------------------------------ |debra@research.att.com | uunet!research!debra | ------------------------------------------------------
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/17/89)
In article <4348@eos.UUCP> jbm@eos.UUCP (Jeffrey Mulligan) writes:
-It has been pointed out that there should be no assumptions
-about what addresses are valid; is there any way to get
-a guaranteed INVALID address?
A null pointer is guaranteed not to match any valid object address.
-#define NO_FOOBAR ((struct foobar *) -1 ) is what I use, but...
This is not portable. Just use NULL.
richm@cbnewsm.ATT.COM (richard.a.miani) (07/17/89)
Why is this discussion on dereferencing NULL pointers in comp.UNIX.wizards and not in comp.lang.c ? Rich -- Rich Miani ram@lcuxlm.att.com Other Paths: ram%lcuxlm@research.att.com ...arpa!lcuxlm!ram
jik@athena.mit.edu (Jonathan I. Kamens) (07/21/89)
In article <34785@bu-cs.BU.EDU> bzs@bu-cs.BU.EDU (Barry Shein) writes: >A perfectly good solution is: > > struct foobar no_foobar; > #define NO_FOOBAR (&no_foobar) > >being as no_foobar will be the only thing assigned this address it is >unique and solves your problem. struct foobar no_foobar; #define NO_FOOBAR (&no_foobar) struct foobar foo_array[50]; struct foobar *ptr; ... ptr = &foo_array[0]; ptr = ptr - 1; Now, the last line above is obviously not something that should be encouraged :-), but fencepost errors of that type happen commonly inside loops et al. You can't assume that just because you've allocated a particular spot in memory be declaring a variable to sit in that spot, nothing else will ever try to access that spot. The already-mentioned assignment of NO_FOOBAR to 0 is a better solution. Jonathan Kamens USnail: MIT Project Athena 432 S. Rose Blvd. jik@Athena.MIT.EDU Akron, OH 44320 Office: 617-253-4261 Home: 216-869-6432
bzs@bu-cs.BU.EDU (Barry Shein) (07/21/89)
>In article <34785@bu-cs.BU.EDU> bzs@bu-cs.BU.EDU (Barry Shein) writes: >>A perfectly good solution is: >> >> struct foobar no_foobar; >> #define NO_FOOBAR (&no_foobar) >> >>being as no_foobar will be the only thing assigned this address it is >>unique and solves your problem. > >struct foobar no_foobar; >#define NO_FOOBAR (&no_foobar) >struct foobar foo_array[50]; >struct foobar *ptr; > >... > >ptr = &foo_array[0]; >ptr = ptr - 1; > >Now, the last line above is obviously not something that should be >encouraged :-), but fencepost errors of that type happen commonly >inside loops et al. You can't assume that just because you've >allocated a particular spot in memory be declaring a variable to sit >in that spot, nothing else will ever try to access that spot. > >The already-mentioned assignment of NO_FOOBAR to 0 is a better >solution. > >Jonathan Kamens USnail: The issue is a *unique* spot to test against versus one which is guaranteed to cause a core dump or some other fault, perhaps. Although in theory a pointer of zero should cause some sort of fault we all should know by now that some of the most popular unix platforms will treat it as legally as any other address, does the person want the theoretical answer or one which will work for his/her software on a variety of platforms? In fact as I remember this is exactly what the original question was alluding to, he was well aware of using a zero pointer but felt he needed some alternative (he was using -1.) Some people suggested just calling malloc(n) and using that and that indeed is equivalent to my suggestion other than set-up costs (why not just set it up statically at load time?) The advantage to this sort of approach is you can have more than one of them (eg. to be able to type the invalid pointer.) I believe the only sure way to get a pointer which is guaranteed to cause a fault on a wide variety of platforms if de-referenced is going to involve machine-dependent ifdef's in a header, it will vary from machine to machine. Obvious attacks are 0 on many (but not all) systems, a pointer into text space on others (eg. the address of a function), even that depends on certain load options being used but we'll assume that's under control of the author, setting some magic bit (eg. pointing into the wrong P space on a VAX), others? In fact on some machines there may be no pointer guaranteed to produce a fault when dereferenced (at least not without changing the operating system which I am sure someone here will suggest as a counter-example, wrongo, not w/in the stated constraints.) I believe an example of that would be a PDP-11 with separate I&D space and all data space (64K) legally allocated, NOT an unusual situation (tho PDP-11s are somewhat unusual in this day and age.) The S/370 using 24 bit addressing may be another example depending on the host O/S, same for a '286? (not exactly rare and peculiar machines.) Trying to write into the space of course makes the problem easier, but most would like an address which faults if read (can't just destroy memory to see if a pointer is valid.) It's an interesting question and repeating zero adds nothing. -- -Barry Shein Software Tool & Die, Purveyors to the Trade 1330 Beacon Street, Brookline, MA 02146, (617) 739-0202 Internet: bzs@skuld.std.com UUCP: encore!xylogics!skuld!bzs or uunet!skuld!bzs
gnb@bby.oz (Gregory N. Bond) (07/28/89)
In article <35077@bu-cs.BU.EDU> bzs@bu-cs.BU.EDU (Barry Shein) writes:
Obvious attacks are 0 on many (but not all) systems, a pointer into
text space on others (eg. the address of a function), even that
depends on certain load options being used but we'll assume that's
under control of the author, setting some magic bit (eg. pointing into
the wrong P space on a VAX), others?
For word-aligned machines, (e.g. 680x0), (int *)1. In fact, in one
application involving humungous collections of 2D linked lists (linked
plains??) I used (struct foo *)0 as uninitialised pointer, and (struct
foo *)1 as initialised-to-invalid-address pointer. Both dumped core
when dereferenced, and help track down obscure bugs. Especialy as I
could do (struct foo *)(2*n+1) for any n, and work out which
assignment was generating the pointer that was dereferenced. This
method could give a very large class of distinguishable invalid
pointers, (provided they weren't (char *)'s).
Not a general solution, but neat for the problem I had.
Greg.
(No comp.lang.c in Australia. Lucky, hey?)
--
Gregory Bond, Burdett Buckeridge & Young Ltd, Melbourne, Australia
Internet: gnb@melba.bby.oz.au non-MX: gnb%melba.bby.oz@uunet.uu.net
Uucp: {uunet,pyramid,ubc-cs,ukc,mcvax,prlb2,nttlab...}!munnari!melba.bby.oz!gnb