Mailing List Archive

NULL need not be all bits 0
This is portability nitpicking.

It is a little known fact that the representation of a NULL of a
particular pointer type may not have all bits 0. So clearing a chunk
of memory to zero is not guaranteed to initialize any pointer objects
in that memory to NULL.

gnupg-1.0.0/mpi/mpi-mpow.c" line 90:
G = m_alloc_clear( (1<<k) * sizeof *G );

The code assumes that this initializes an array of MPI pointers to
NULL. This works on almost all machines, but is not guaranteed to
work by the C standard.

Hugh Redelmeier
hugh@mimosa.com voice: +1 416 482-8253
Re: NULL need not be all bits 0 [ In reply to ]
"D. Hugh Redelmeier" <hugh@mimosa.com> writes:

> It is a little known fact that the representation of a NULL of a
> particular pointer type may not have all bits 0. So clearing a chunk

I have never seen such an architecure but I am usually aware of this.
AfAIK, the standard says that (char*)0 will be evaluated as false in
an expression and storing a 0 into a char* will result in storing
the machines representation of a NULL-pointer. This ends up that we
don't have to care about it when writing C code ...

> gnupg-1.0.0/mpi/mpi-mpow.c" line 90:
> G = m_alloc_clear( (1<<k) * sizeof *G );

But sure, you are right here - in this case the compiler can't know
that we are going to store 0s in some pointers.

> The code assumes that this initializes an array of MPI pointers to
> NULL. This works on almost all machines, but is not guaranteed to
> work by the C standard.

Okay, so we better do:

G = m_alloc( (1<<k) * sizeof *G );
for(i=0; i < (1<<k); i++ )
g[i] = NULL; /* or 0 */

or use a special m_alloc_clear_array_of_type_G(). I some vendor
builds such a machine he probably has the resources to fic most
software :-)

You will probably find out that I also assume that a byte has 8 bits
;-)


Werner


--
Werner Koch at guug.de www.gnupg.org keyid 621CC013
Re: NULL need not be all bits 0 [ In reply to ]
| From: Werner Koch <wk@gnupg.org>

| > gnupg-1.0.0/mpi/mpi-mpow.c" line 90:
| > G = m_alloc_clear( (1<<k) * sizeof *G );
|
| But sure, you are right here - in this case the compiler can't know
| that we are going to store 0s in some pointers.

That is the case I was talking about. I have used such a machine (but
they are rare).

I've found the problem in three spots in primegen.c too. I've
replaced it with calls to the following macro. The advantage of a
macro is that it can be generic.

#define m_alloc_ptrs_clear(pp, n) { \
int c = (n); \
(pp) = alloc_bytes((n) * sizeof(*(pp)), "m_alloc_ptrs_clear"); \
while (c > 0) (pp)[--c] = NULL; \
}

Hugh Redelmeier
hugh@mimosa.com voice: +1 416 482-8253
Re: NULL need not be all bits 0 [ In reply to ]
"D. Hugh Redelmeier" <hugh@mimosa.com> writes:

> That is the case I was talking about. I have used such a machine (but
> they are rare).

I am curious: What kind of machines are this.

> I've found the problem in three spots in primegen.c too. I've

And there are a lot of other places too: I know that there are a lot
of structures with mixed pointers and integers. They are all
initialized using calloc() or similar or by doing a memset on them.

--
Werner Koch at guug.de www.gnupg.org keyid 621CC013
Re: NULL need not be all bits 0 [ In reply to ]
| From: Werner Koch <wk@gnupg.org>

[.about machines on which a NULL pointer representation does not have
all bits 0]

| > I have used such a machine (but they are rare).
|
| I am curious: What kind of machines are this.

The machine was a CDC Cyber something-or-other. This was not the
traditional CDC 60-bit architecture of the 6600, but a newer 64-bit one
(it did have a switch to run the old code). It had a segmented address
space and "rings" of protection, as in MULTICS.

Each pointer was 64 bits, and included the segment and ring number.
If I remember correctly, ring 0 was the highest level of protection
(this, in fact, is the MULTICS terminology). Loading 0 into an
address register from user code caused a trap for protection
violation. So you didn't want this to be the representation for NULL.

My impression of this machine was that it was the opposite of what
made CDC great. It wasn't fast because it was complicated. Its
design slightly predated the great wave of RISC thinking. I was
involved in an optimizing C compiler project that targeted it around
1985 or so.

I've never looked closely enough at other segmented architectures for
this feature. If I designed one, without thinking of C code, I'd have
the hardware process addresses upon loading a pointer register rather
than waiting until the address is used. There is a lot of processing
to do (fetching segment descriptors etc.) and this would create the
maximum overlap. This overlap would probably be critical to hiding
the overhead of a segmented architecture, allowing it to be
competitive.

I think the C implementation on the traditional Burroughs architecture
throws up its hands and implements (most? all?) C data in One Big
Array. This, of course, throws away the beauty of that architecture.

Somehow I imagine that the Intel 286 architecture survives all-zero
"far" pointers. Otherwise the screams would have deafened us.
Clearly this is true in 8086 mode, where the segment registers just
hold integers-that-are-multiples-of-16, but I infer it must be true in
the full-blown-segment mode too. Or at least the OS can arrange for
it to be true.

The C committee was aware of these issues and took them into account.

Hugh Redelmeier
hugh@mimosa.com voice: +1 416 482-8253