C objects

E

E. Robert Tisdale

Mabden said:
But I am assured this is not the case! You may NOT use the word "ALL".

Please cite an example of a standard conforming C compiler
that does *not* use all-bits-zero for NULL.
 
C

CBFalconer

E. Robert Tisdale said:
Please cite an example of a standard conforming C compiler
that does *not* use all-bits-zero for NULL.

Any one for the 8086/8 in normal segmented mode. Writing to the
interrupt vector table is considered poor technique.

Now please cease the trolling.
 
K

Keith Thompson

CBFalconer said:
Any one for the 8086/8 in normal segmented mode. Writing to the
interrupt vector table is considered poor technique.

How would using all-bits-zero for null pointers result in writing to
the interrupt vector table? Are you saying that code that
*accidentally* attempts to write through a null pointer will clobber
the interrupt vector table, thus messing up the system rather than
just crashing the offending program? (I'm not familiar with the
systems in question.)
 
B

Ben Pfaff

CBFalconer said:
Any one for the 8086/8 in normal segmented mode. Writing to the
interrupt vector table is considered poor technique.

Every MS-DOS compiler I used had null pointers as all-bits-zero.
What did yours use, and which compiler was it?
 
R

RCollins

CBFalconer said:
Any one for the 8086/8 in normal segmented mode. Writing to the
interrupt vector table is considered poor technique.

Now please cease the trolling.

Trolling or not, it's a good question. Just because 0:0 was an
interrupt table, doesn't mean the common C compilers of the day
used a different NULL constant.

So, just off hand, does anyone remember what NULL was defined to
be on any of those compilers: Turbo C, Power C, etc?
 
B

Ben Pfaff

Keith Thompson said:
How would using all-bits-zero for null pointers result in writing to
the interrupt vector table?

In real mode on an x86, the interrupt table is at the bottom of
physical memory. Real mode has a 1:1 mapping from virtual to
physical addresses, so writing through a null pointer will indeed
modify the interrupt vector table.
Are you saying that code that *accidentally* attempts to write
through a null pointer will clobber the interrupt vector table,
thus messing up the system rather than just crashing the
offending program? (I'm not familiar with the systems in
question.)

It's actually worse than that. The first few interrupts in the
table aren't all that important (e.g. the first one is the
"divide by zero" exception vector), so it's possible that writing
to a null pointer won't even mess up the system *quickly*.
 
K

Keith Thompson

Ben Pfaff said:
In real mode on an x86, the interrupt table is at the bottom of
physical memory. Real mode has a 1:1 mapping from virtual to
physical addresses, so writing through a null pointer will indeed
modify the interrupt vector table.


It's actually worse than that. The first few interrupts in the
table aren't all that important (e.g. the first one is the
"divide by zero" exception vector), so it's possible that writing
to a null pointer won't even mess up the system *quickly*.

So using a non-all-bits-zero value for the null pointer (on the system
in question) is a mechanism for defending the system against buggy
code. Cool.

(Of course, if somebody uses memset() to set a pointer to
all-bits-zero, assuming that it's a null pointer, and then
accidentally writes through it, it's going to clobber the system
anyway. Presumably anyone who would do such a thing won't be allowed
anywhere near the system.)
 
R

RCollins

Keith said:
So using a non-all-bits-zero value for the null pointer (on the system
in question) is a mechanism for defending the system against buggy
code. Cool.

(Of course, if somebody uses memset() to set a pointer to
all-bits-zero, assuming that it's a null pointer, and then
accidentally writes through it, it's going to clobber the system
anyway. Presumably anyone who would do such a thing won't be allowed
anywhere near the system.)

There are millions of ways to clobber a system ... writing to an
invalid memory address is just one of them.

Who would do such a thing? Well, (need I say it?), none of us are
perfect, I'm sure we've all made our share of bone-headed errors.
(That weekend in Tiajuana ... well, never mind).
 
C

CBFalconer

Keith said:
How would using all-bits-zero for null pointers result in writing to
the interrupt vector table? Are you saying that code that
*accidentally* attempts to write through a null pointer will clobber
the interrupt vector table, thus messing up the system rather than
just crashing the offending program? (I'm not familiar with the
systems in question.)

The pointers consist of seg:eek:ffset, combined as 16*seg+offset =
address in the 0 to 1 meg range. If those are all 0's the result
is absolute address 0, which is where the int 0 interrupt vector
resides. There is no memory protection whatsoever in '86 or '186,
nor, I believe, in the x86 at boot time, when they come up in real
mode.
 
C

CBFalconer

Ben said:
Every MS-DOS compiler I used had null pointers as all-bits-zero.
What did yours use, and which compiler was it?

I _never_ write through a NULL pointer :) It might be an
experiment to get Borlands TC from the museum and run it through
some experiments on pure MsDOS. I expect int0 will be affected.
A virtual MsDos on W98 won't do.
 
D

Dan Pop

In said:
I had assumed that "-W -Wall" enabled some required diagnostics, but
if you say "-ansi -pedantic" suffices, I'll take your word for it.

You don't have to, it's well documented in the gcc man page.
(Using "-W -Wall" as well is generally a good idea, but that's not
necessarily related to conformance.)

It is -Wall -O that is a good idea. -Wall fails to identify the usage
of uninitialised variables if optimisation is not turned on and -W
generates objectionable warnings (that's why its functionality was
not included into -Wall in the first place).

-W is fine for experienced people who understand the underlying issues
and agree with them. Its diagnostics, however, could be confusing
to newbies and lead them to break perfectly good code, in order to
shut them up.

I wouldn't recommend -W to newbies or to anyone else who doesn't have a
clear understanding of its effects (and those who do, don't need anyone
else's recommendations in order to decide whether to use it or not).

Dan
 
J

Joe Wright

CBFalconer said:
I _never_ write through a NULL pointer :) It might be an
experiment to get Borlands TC from the museum and run it through
some experiments on pure MsDOS. I expect int0 will be affected.
A virtual MsDos on W98 won't do.

I have not snipped anything from Chuck's post. I fear we are
wandering off point if not off topic. In no particular order I offer
various considerations for the null pointer value being zero.

1. It is useful to have functions return an error indication if the
function fails. Consider malloc(). It returns the address of
allocated memory if it succeeds. What shall we have it do if there
is no memory available? Return a value which cannot be a valid address.

2. Given an address, perhaps stored in a pointer, how might we
examine it to determine its validity? Sadly, we can't. C programmers
see pointer values as unsigned integers with no upper bound.

So, if we need a single pointer value within the domains of unsigned
integers of various widths, we are limited to the lower bound, 0.

This is not a bad choice. Usually 0 is an important address to the
underlying OS and we shouldn't write to it in any case. Reserving
address 0 for our NULL pointer constant is perfect. We are warned
that writing or even reading address zero might cause your house to
burn down, and so we don't do it.

Tell me why any C implementation would have a null pointer other
than zero? So that writing through NULL might be safer? Nonsense.
Writing through NULL is the ultimate sin. So why?
 
K

Keith Thompson

Joe Wright said:
Tell me why any C implementation would have a null pointer other than
zero? So that writing through NULL might be safer? Nonsense. Writing
through NULL is the ultimate sin. So why?

In a typical system, there are huge numbers of invalid pointer values;
the null pointer is only of them. But since it's easy to generate a
null pointer in a C program, a given invalid pointer is more likely to
have the value null than any other value. Therefore, a buggy program
that writes through an invalid pointer is more likely to write through
a null pointer than through any other invalid pointer value. If the
system happens to have world-writable critical data at address
all-bits-zero, such that a buggy program can damage the system by
clobbering it, can be made somewhat more secure by using a value other
than all-bits-zero as a null pointer.

Of course, bug-free programs aren't affected by this -- which is fine
if you only run bug-free programs on your system. (The best way to do
that is to pull the power plug.)

If reading or writing through address all-bits-zero is guaranteed to
cause a trap that affects the offending program, then all-bits-zero is
probably an excellent value for the null pointer. But if the
all-bits-zero address doesn't trap (say, because there's real memory
there), and some other address does (say, because it points to memory
that doesn't exist), then the trapping value is probably a better choice.

Many years ago, I worked on a 68K-based system programmed in Pascal
(no C compiler). It used the value 1 for the nil pointer because an
attempt to deference an odd address would cause a trap. (Of course,
Pascal doesn't have all the confusion caused by C's use of a literal 0
to represent a null pointer; it just uses the "nil" keyword.)
 
C

CBFalconer

Joe said:
.... snip ...

So, if we need a single pointer value within the domains of unsigned
integers of various widths, we are limited to the lower bound, 0.

not so, see below.
This is not a bad choice. Usually 0 is an important address to the
underlying OS and we shouldn't write to it in any case. Reserving
address 0 for our NULL pointer constant is perfect. We are warned
that writing or even reading address zero might cause your house to
burn down, and so we don't do it.

Tell me why any C implementation would have a null pointer other
than zero? So that writing through NULL might be safer? Nonsense.
Writing through NULL is the ultimate sin. So why?

I remember one system that used the value 1 for the NULL pointer.
Conceded, it was not a C system, however the same reasons apply.
I forget the details, but it was essential in the architecture.

Using any such value is perfectly possible, it is only necessary
that the system never assign that space to anything, including
statics, automatics, malloced, and even code (which may be needed
for constants and/or immediate addressing instructions).
 
C

CBFalconer

Keith said:
.... snip ...

Of course, bug-free programs aren't affected by this -- which is fine
if you only run bug-free programs on your system. (The best way to do
that is to pull the power plug.)

Doesn't work on most laptops.
.... snip ...

Many years ago, I worked on a 68K-based system programmed in Pascal
(no C compiler). It used the value 1 for the nil pointer because an
attempt to deference an odd address would cause a trap. (Of course,
Pascal doesn't have all the confusion caused by C's use of a literal 0
to represent a null pointer; it just uses the "nil" keyword.)

That was UCSD Pascal, which is not representative.
 
K

Keith Thompson

CBFalconer said:
Keith Thompson wrote: [...]
Many years ago, I worked on a 68K-based system programmed in Pascal
(no C compiler). It used the value 1 for the nil pointer because an
attempt to deference an odd address would cause a trap. (Of course,
Pascal doesn't have all the confusion caused by C's use of a literal 0
to represent a null pointer; it just uses the "nil" keyword.)

That was UCSD Pascal, which is not representative.

(Actually it was a derivative of UCSD Pascal.)

Not representative of what?
 
J

junky_fellow

CBFalconer said:
Doesn't work on most laptops.

That was UCSD Pascal, which is not representative.

on 68k processor, i think at location all-bits-zero there lies
"initial stack pointer" which is used only at boot time.
Similarly, on PowerPC 8260, there lie HRCW (Hard Reset Configuration
Word) at location all-bits-zero which is only used at boot time.

So, writing at null-pointer won't harm the running system , i suppose.
i am a newbie so i maybe wrong as well.

My doubt is that, since we have placed something valid "HRCW in case
of PowerPC" (take the example of an embedded system, where application
has been linked with kernel ) at location all-bits-zero, so isn't it
possible that null pointer may compare equal (because we have some
valid object
at location all-bits-zero).
This may sound very illogical or absurd to the experts, but
this is the picture that i have in my mind.
 
F

Flash Gordon

On 19 Aug 2004 04:08:07 -0700
(e-mail address removed) (junky_fellow) wrote:

My doubt is that, since we have placed something valid "HRCW in case
of PowerPC" (take the example of an embedded system, where application
has been linked with kernel ) at location all-bits-zero, so isn't it
possible that null pointer may compare equal (because we have some
valid object
at location all-bits-zero).
This may sound very illogical or absurd to the experts, but
this is the picture that i have in my mind.

I'm not completely sure of your meaning, so I'll go through all the
interpretations I can think of.

1) If the implementation might place an object (i.e. a variable or
malloced region) at location all bits 0 then it has to use something
other than all bits zero as the NULL pointer. It also has to do compile
time magic so that things like "ptr == 0" work as you would expect
"ptr == NULL" to work. I.e. if ptr is all bits zero the result is false.

2) If the implementation might place the start of a function at all bits
0 then I believe 1 above applies again because a pointer to a function
has has to be distinct from the null pointer.

3) If there is some resource stored at all bits 0 that you have to be
able to access then the compiler has to (as a Quality of Implementation
issue, not a standards conformance issue) provide some non-standard
method of accessing it. This could be allowing you to dereference the
null pointer to get at it (although I would not like that) or some other
mechanism such as letting you use *__HRCW to access it (using compiler
magic) and having the null pointer be something other than all bits 0.
My preferred method would be for the compiler to provide symbols like
__HRCW (which is in the implementation name space so providing it does
not break standards conformance), but that does not mean they do it this
way.
 
K

Keith Thompson

My doubt is that, since we have placed something valid "HRCW in case
of PowerPC" (take the example of an embedded system, where application
has been linked with kernel ) at location all-bits-zero, so isn't it
possible that null pointer may compare equal (because we have some
valid object
at location all-bits-zero).
This may sound very illogical or absurd to the experts, but
this is the picture that i have in my mind.

If there is a valid C object at location all-bits-zero, the C
implementation should not use all-bits-zero as a null pointer. Any C
object declaration, or any call to malloc() and friends, should
*never* allocate an object at whatever address the implementation has
chosen for the null pointer; if it does, it indicates a bug in the
compiler or in the malloc() implementation.

If there's some system object (outside the scope of the C language,
but potentially accessible from a C program) at location
all-bits-zero, or at whatever location the implementation has chosen
for null pointers, there is no portable way to access that object. In
fact, there's no portable way to access any object at a specified
address. (You can convert an integer to a pointer, but the result is
implementation-defined.)

An implementation may permit access to a system object at location
all-bits-zero, even if the null pointer is all-bits-zero. Such access
is likely to involve derferencing a null pointer, which of course
invokes undefined behavior -- but an implementation is free to
document the effects of instances of undefined behavior.

For example:

#include <stdio.h>
int main(void)
{
unsigned char *ptr = NULL;
printf("The value stored at address %p is %d\n",
(void*)ptr, (int)*ptr);
return 0;
}

This program invokes undefined behavior, but the effect of that
undefined behavior might be to print the value of whatever is stored
at address all-bits-zero. If the implementation documents this, the
above is a valid program *for that implementation*. Port it to
another implementation and it will likely blow up in your face.
 
K

Keith Thompson

Flash Gordon said:
2) If the implementation might place the start of a function at all bits
0 then I believe 1 above applies again because a pointer to a function
has has to be distinct from the null pointer.
[...]

A small quibble:

A function pointer doesn't necessarily contain the address of the
start of the function. It could be, for example, an index into a
table. Also, a null function pointer doesn't have to have the same
representation as a null object pointer. You could have null object
pointers represented as all-bits-zero, null function pointers
represented as all-bits-one, and a valid function (main?) starting at
address all-bits-zero. (And of course code and data could be in
separate address spaces.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,146
Messages
2,570,832
Members
47,374
Latest member
anuragag27

Latest Threads

Top