🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: rec.games.programmer
Article #2035

Re: bug#15 ddj p124

#2035
From: Jos A. Horsmeier
Date: Fri, 01 Sep 1995 08:18
77 lines
3447 bytes
In article <4263mu$7ib@ub.d.umn.edu>, cbusch@ub.d.umn.edu (Christopher G 
Busch) wrote:

|>----a1.cpp---
|>extern int *a;
|>void initialize(int*);
|>
|>int main()
|>{
|>   initialize(a);
|>}
|>
|>----a2.cpp----
|>int a[10];
|>void initialize(int *p)
|>{
|>   for(int i=0;i<10;i++) p[i]=i;
|>}
|>
|>I noticed that the type declarations for "a" didnt match, do I figured the
|>problem was there.  'extern int *a' should be changed to 'extern int a[]'
|>to avoid seg faults.   I have noticed this bug before in C/C++ programming
|>and have been careful about it.
|>
|>My question is this:  Why is it, when C/C++ treats arrays as pointers that
|>the above bug will occur?  If *a and a[10] were different, why would it
|>link together correctly?  Shouldnt you get duplicate identifiers or some
|>error?
|>
|>What exactly happens on the machine level?

A short answer is: those two translation units (a1.cpp and a2.cpp)
actually lied to the compiler and most linkers nowadays are way too
stupid to detect that an object with a certain type, defined in one
module,  is used as if it were an object of another type in another
module. Linkers simply find addresses of chunks of memory and sticks
those addresses in the right places in your object code and data.

A more elaborate answer is: when compiling translation unit a1.cpp,
the compiler is told that there exists a piece of memory somewhere
(the user named it 'a') and this piece of memory happens to be an
address of an int: 'extern int* a'. The call to function initialize()
in function main() grabs the value (an address) from this location
(the user called 'a') and passes it to function initialize().

The second translation unit a2.cpp tells the compiler to reserve ten
slots of memory (each of sizeof(int) bytes) and name this chunk of
memory 'a'. 

Suppose this chunk of memory is located in the memory map at an arbitrary
address, say, 0xDEADBEEF. Ten slots of size sizeof(int) reside there,
each initialized to all bits zero. 

Here comes the (stupid) linker: the first compiled module wants to
know the location (the user named it 'a') of a certain external
object; the second module knows where this object 'a' resides: at 
location 0xDEADBEEF. The linker simply resolves this external reference
and the resulting machine code of the second compiled module looks
something like this:

	- load contents of address 0xDEADBEEF (as if it were an int*)
        - push it on a stack
        - call function initialize

The first few bytes (sizeof(int*) bytes actually) of the array 'a'
are treated as if they were a valid address pointing to an int.
On most machines (note: not all machines) all bits zero actually
_is_ a NULL pointer value, or, most likely, it's not a valid pointer
value. Hence the segmentation violation and a well deserved core dump.

Does this clarify things a bit?

kind regards,

Jos aka jos@and.nl
-- 
Atnwgqkrl gy zit vgksr, ug qshiqwtzoeqs!         
Technical Details
Message-ID: <426fl0$9u9@beach.and.nl>
Path: arc1-ca.pugleaf.net!beach.and.nl!usenet
References: <4263mu$7ib@ub.d.umn.edu>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!beach.and.nl!usenet
From: jos@and.nl (Jos A. Horsmeier)
Newsgroups: rec.games.programmer,comp.lang.c,comp.lang.c++
Subject: Re: bug#15 ddj p124
Date: 1 Sep 1995 08:18:40 GMT
Organization: AND Software B.V. Rotterdam
Message-ID: <426fl0$9u9@beach.and.nl>
References: <4263mu$7ib@ub.d.umn.edu>
NNTP-Posting-Host: klepzeiker.and.nl
Mime-Version: 1.0
Content-Type: Text/Plain; charset=ISO-8859-1
X-Newsreader: WinVN 0.99.5