[comp.sys.ibm.pc.programmer] NULL pointer error

reilly@bnlux0.bnl.gov (kevin reilly) (07/13/90)

After exiting my program DOS writes an error to the screen
NULL pointer error R6001
I understand the meaning of the error message but how do I go about
debugging the program to find what is causing it.
From reading the documentation from MicroSoft (QC2.5) the program will
compile and link error free. But when run and then exited that is when
the error will appear.
The program ran error free up until I linked in the menu.obj file that
came with the compiler.
I guess the question is: What memory address do I watch when stepping
through the program?
Thank you in advance!
reilly@bnlux0.bnl.gov

weisen@eniac.seas.upenn.edu (Neil Weisenfeld) (07/14/90)

In article <2008@bnlux0.bnl.gov> reilly@bnlux0.bnl.gov (kevin reilly) writes:
[NULL ptr stuff deleted]
>I guess the question is: What memory address do I watch when stepping
>through the program?

If the program is attempting to write to a NULL pointer, you could
try watching address 0x0000:0x0000 as this is where the "NULL" pointer
points.

Neil



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Neil I.  Weisenfeld                    | InterNet: weisen@eniac.seas.upenn.edu
Dept. of Computer and Info. Sciences   | USPS: I dunno, I'm moving...
University of Pennsylvania             | PENNmail: Don't even try it...
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

steve@taumet.com (Stephen Clamage) (07/16/90)

weisen@eniac.seas.upenn.edu (Neil Weisenfeld) writes:
>If the program is attempting to write to a NULL pointer, you could
>try watching address 0x0000:0x0000 as this is where the "NULL" pointer
>points.

Sadly, it's not this simple.  The NULL pointer error is reported for
a range about about 128 bytes starting at data address zero.  In a small
data model program, this is not 0x0000:0x0000, but addresses DS:0x0000 -
DS:0x007F.  I don't believe this error can be reliably reported for
other-model programs, since there is no place to put the checksummed data
for comparison at program exit.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

trier@cwlim.CWRU.EDU (Stephen C. Trier) (07/16/90)

Debugging a null pointer error is a little simpler than it may seem.  The
most likely two locations to watch are DS:0000 and DS:0008.  The first is
NULL and the second is where a malloc'ed pointer will point if it is
mistakenly typecast to a near pointer.

With Turbo C, the low memory area checked is filled with the Borland
Copyright.  It is checksummed as part of the exit code and the error
message is printed if the checksum is incorrect.

_Any_ write to that area should be considered a bug.

Note that another common cause of null pointer errors is code like the
following:

	int a;
	scanf("%d", a);

"a" will be interpreted as a pointer, causing a random write into memory
corresponding to whatever is in "a" when scanf is called.  If "a" is 0,
you will receive a null pointer error.

-- 
Stephen Trier                              Case Western Reserve University
Home: sct%seldon@scl.cwru.edu              Information Network Services
Work: trier@cwlim.ins.cwru.edu
                 I do _not_ speak for the University.

venkat@matrix.UUCP (D Venkatrangan) (07/16/90)

In article <27092@netnews.upenn.edu> weisen@eniac.seas.upenn.edu.UUCP (Neil Weisenfeld) writes:
>In article <2008@bnlux0.bnl.gov> reilly@bnlux0.bnl.gov (kevin reilly) writes:
>[NULL ptr stuff deleted]
>>I guess the question is: What memory address do I watch when stepping
>>through the program?
>
>If the program is attempting to write to a NULL pointer, you could
>try watching address 0x0000:0x0000 as this is where the "NULL" pointer
>points.
>
>Neil

If you linked with Microsoft supplied libraries, you probably pulled in their
exit() function definition, and the _nullcheck() function that it calls.
This function actually takes a guess at whether your program changed something
outside of memory using a NULL pointer.  The code for _nullcheck is probably
in your Microsoft compiler/linker software distribution, in a module 
chksum.asm.  The following lines from that module give some insights into
this.  Starting from DS:0, for a length of 0x42, each succesive byte is xor'ed
into the xor'ed result so far.  Then, this value is compared with the value
that is to be expected if none of the bytes were changed when your program ran.
If they are different, the routine assumes that your code accessed data using a
NULL pointer.  This assumption can be incorrect for the following reasons:

1) you accessed a byte within the first 66 bytes of your DS and changed it,
   and also another byte within that same region in such a way that xor'ing
   the new sequence of bytes still gives the same checksum.

2) you changed a byte and the checksum byte as well, so that the change is
   undetectable.

3) you used a NULL pointer as a pointer to a structure and accessed a member
   of the structure that was displaced by more than 66 bytes from the start
   of that structure.  (Fo eg, if struct param { char first[66]; char second; };
   and NULL->second = x;).  Incidentally, this is why you can't just watch
   0x0000:0x0000 as an earlier poster had suggested.

4) you used a different DS and used a NULL pointer.  This can happen if you
   use assembly routines and changed DS somewhere.

Despite these limitations, _nullcheck() does catch quite a few of errant
NULL pointer usage.

/* THIS IS FROM Microsoft's CHKSUM.ASM module */
chkpt	db	8 dup(0)		; for null pointer assignment
	CHKSUM= 11h			; has to be correct or error
	db	'MS Run-Time Library - Copyright (c) 1988, Microsoft Corp'
chkb	db	CHKSUM			; checksum byte
	db	0			; leaves al = 0
chkln=		$ - chkpt		; length to checksum

cProc	_nullcheck,<PUBLIC>,<>
cBegin	nogen				; no arguments - so no frame


	push	si

	xor	si,si			; start at DS:0
	mov	cx,chkln
	xor	ah,ah
	cld

chkloop:				; loop to 1 past end of copyrt. string
	lodsb
	xor	ah,al			; accumulate xor total in AH
	loop	chkloop

	xor	ah,BIAS 		; XOR out the initial BIAS
	jz	setzero

	call	_FF_MSGBANNER		; (1) "\r\n" to stderr
					; (2) FORTRAN $DEBUG file/line
					;     if _Fline is set (not in C)
	                    		; (3) "run-time error" banner
	mov	ax,1			; null pointer assignment message no.
	push	ax
	call	_NMSG_WRITE		; write message out
	mov 	ax,1			; indicate error occurred

;	ax = 0 if the checksum is OK

setzero:
	pop	si



	ret

cEnd	nogen

---------------------------------------------------------------------------
D. Venkatrangan
Matrix Computer Systems, Inc.           7 1/2 Harris Rd, Nashua, NH 03062
suneast!venkat   uunet!matrix!venkat    (603) 888-7790
---------------------------------------------------------------------------

geiser@apollo.HP.COM (Wayne Geiser) (07/16/90)

In article <2008@bnlux0.bnl.gov>, reilly@bnlux0.bnl.gov (kevin reilly) writes:
|> After exiting my program DOS writes an error to the screen
|> NULL pointer error R6001
|> I understand the meaning of the error message but how do I go about
|> debugging the program to find what is causing it.
|> From reading the documentation from MicroSoft (QC2.5) the program will
|> compile and link error free. But when run and then exited that is when
|> the error will appear.
|> The program ran error free up until I linked in the menu.obj file that
|> came with the compiler.
|> I guess the question is: What memory address do I watch when stepping
|> through the program?
|> Thank you in advance!
|> reilly@bnlux0.bnl.gov

What I have done in my Microsoft C programs to help find such problems is to
add the following line at the end of each routine:

assert(_nullcheck());

If you don't want the assertion there in released code, put a #ifdef around it.
This line will call the Microsoft runtime routine to check the section of
memory everyone's been describing here and tell you the file and line number
when it does occur.

Just pointing a finger at the offending routine is usually enough to elicit an
"Oh yea!  Boy was that stupid!" (at least for me).

Wayne Geiser
Apollo Computer, Inc. - A subsidiary of Hewlett Packard
geiser@apollo.hp.com

"The holy passion of Friendship is of so sweet and steady and loyal and
 enduring a nature that it will last through a whole lifetime - if not
 asked to lend money."

    - Mark Twain.

kdq@demott.COM (Kevin D. Quitt) (07/17/90)

In article <2008@bnlux0.bnl.gov> reilly@bnlux0.bnl.gov (kevin reilly) writes:
>After exiting my program DOS writes an error to the screen
>NULL pointer error R6001
>I understand the meaning of the error message but how do I go about
>debugging the program to find what is causing it.
>From reading the documentation from MicroSoft (QC2.5) the program will
>compile and link error free. But when run and then exited that is when
>the error will appear.
>The program ran error free up until I linked in the menu.obj file that
>came with the compiler.
>I guess the question is: What memory address do I watch when stepping
>through the program?

    Microsoft C reserves the first chunk of your data segment (starting
at DS:0) to help protect you against yourself.  If you look at a link
map, you will see a segment called NULL. 

    The NULL segment contains the Microsoft copyright and some other
miscellaneous non-junk.  When your program exits, the MS library checks
to see if you've corrupted this area (generally by using a null pointer)
and reports the R6001 error if you have. 

    If you're using codeview, you can look for uninitialized pointers,
or pointers that get clobbered.  You can also look at DS:0 to see if you
recognize the data there.  Good Luck

-- 
 _
Kevin D. Quitt         demott!kdq   kdq@demott.com
DeMott Electronics Co. 14707 Keswick St.   Van Nuys, CA 91405-1266
VOICE (818) 988-4975   FAX (818) 997-1190  MODEM (818) 997-4496 PEP last

                96.37% of all statistics are made up.

apn@Apple.COM (Alex Novickis) (07/17/90)

In article <27092@netnews.upenn.edu> weisen@eniac.seas.upenn.edu.UUCP (Neil Weisenfeld) writes:
>In article <2008@bnlux0.bnl.gov> reilly@bnlux0.bnl.gov (kevin reilly) writes:
>[NULL ptr stuff deleted]
>>I guess the question is: What memory address do I watch when stepping
>>through the program?
>
>If the program is attempting to write to a NULL pointer, you could
>try watching address 0x0000:0x0000 as this is where the "NULL" pointer
>points.
>
>Neil
>
>

try watching DS:0000, thats where the MSC null-pointer-error-checking
routine places some test data to check for this condition. Look through
your startup source files, microsoft distrubutes these!


-- 
Alex P. Novickis, Real Time systems demi-guru.  (W)   408-370-4541
ALINK:alex.n                                    (PAGE)    989-6678
UUCP:{amdahl,claris,pyramid,sun,decwrl,well,ubvax,ames}!apn@apple.com,apn@nonvon
"I think... I think it's in my basement. Let me go upstairs and check"-Escher.

weisen@eniac.seas.upenn.edu (Neil Weisenfeld) (07/17/90)

In article <4ba0b259.20b6d@apollo.HP.COM> geiser@apollo.HP.COM (Wayne Geiser) writes:
>
>What I have done in my Microsoft C programs to help find such problems is to
>add the following line at the end of each routine:
>
>assert(_nullcheck());
>
>If you don't want the assertion there in released code, put a #ifdef around it.
>This line will call the Microsoft runtime routine to check the section of
>memory everyone's been describing here and tell you the file and line number
>when it does occur.

Why not just use the ifdef that's there?  The assert macro expands
to a call with #ifdef NDEBUG around it.  Defining NDEBUG will keep
the assertion from being compiled in.

Neil


P.S. -- Thanks for the _nullcheck tip.



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Neil I.  Weisenfeld                    | InterNet: weisen@eniac.seas.upenn.edu
Dept. of Computer and Info. Sciences   | USPS: I dunno, I'm moving...
University of Pennsylvania             | PENNmail: Don't even try it...
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=