[comp.sys.dec] strcat

wggabb@sdrc.COM (Rob Gabbard) (06/11/91)

A call to strcat with NULL as the second argument core dumps with a memory 
fault on Ultrix.  Why would anyone want to do this anyway ? How about....

	strcat(foo,getenv("FOO"))

		instead of

	if (getenv("FOO")) strcat(foo,getenv("FOO"));

Actually, just coding strcat(foo,NULL) will dump.  Anyone run into this ?
Am I doing a no-no here.

-- 
The statements above are my own and do not neccesarily reflect the opinion of 
my employer.
-------------------------------------------------------------------------------
Rob Gabbard 				    wggabb@sdrc.sdrc.com
Technical Development Engineer
Structural Dynamics Research Corporation

lwm@bronze.ucs.indiana.edu (Larry Meehan) (06/12/91)

In <966@sdrc.COM> wggabb@sdrc.COM (Rob Gabbard) writes:

>A call to strcat with NULL as the second argument core dumps with a memory 
>fault on Ultrix.
...
>Actually, just coding strcat(foo,NULL) will dump.  Anyone run into this ?
>Am I doing a no-no here.

You must be on one of the MIPS-based DEC systems.  Due to a quirk of the VAX
port of ULTRIX, you can get by with what you are trying to do, but you are,
strictly speaking, doing a no-no.  The thing to remember is that NULL is not
the same thing as "", since strcat(foo,"") will work just fine.  This program
will fail too for *exactly* the same reason:
	main()
	{
		char *p, c;

		p = (char *) 0;
		c = *p;
	}
If you look in /usr/include/stdio.h, you will see that NULL is really just 0,
so our programs are trying to access location 0 which is legal on a VAX, but
not on the MIPS implementation of Ultrix.  A lot of "bug-free" code broke
when it was moved from VAX to non-VAX systems.  The little program above dumps
core on a MIPS CPU and runs without errors on a VAX.  The program is at fault,
not Ultrix.  Hope this helps.

-- 
	 Larry Meehan			University Computing Services
	 lwm@ucs.indiana.edu		Indiana University

	("Industry without art is brutality." -- Ananda Coomaraswamy)
-- 
	 Larry Meehan			University Computing Services
	 lwm@ucs.indiana.edu		Indiana University

	("Industry without art is brutality." -- Ananda Coomaraswamy)

diamond@jit533.swstokyo.dec.com (Norman Diamond) (06/12/91)

In article <966@sdrc.COM> wggabb@sdrc.COM (Rob Gabbard) writes:
>A call to strcat with NULL as the second argument core dumps with a memory 
>fault on Ultrix.  Why would anyone want to do this anyway ? How about....
>	strcat(foo,getenv("FOO"))
>		instead of
>	if (getenv("FOO")) strcat(foo,getenv("FOO"));

The behavior is undefined according to the C standard.  Core dumps are
a common result (although they used to be less common when one particular
hardware architecture used to be more common).

If you want to change the C language (including the standard library), wait
for the ANSI committee to begin preparing the next revision of the language,
and make your suggestions to them.  It probably won't be a long wait;
proceedings for the 1989 standard began around 8 years ago.  They have
probably heard this one before, so you will probably have to get a lot
of people on your side to join the committee and vote for your proposal.

>Actually, just coding strcat(foo,NULL) will dump.  Anyone run into this ?

Yes.  Mostly new programmers, and also some irresponsible (i.e. experienced
enough to know better, but lazy -- they know who they are) ones.

>Am I doing a no-no here.

Yes.
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.
Permission is granted to feel this signature, but not to look at it.

grr@cbmvax.commodore.com (George Robbins) (06/12/91)

In article <966@sdrc.COM> wggabb@sdrc.COM (Rob Gabbard) writes:
> A call to strcat with NULL as the second argument core dumps with a memory 
> fault on Ultrix.  Why would anyone want to do this anyway ? How about....
> 
> Actually, just coding strcat(foo,NULL) will dump.  Anyone run into this ?
> Am I doing a no-no here.

You is doing a no-no.  NULL is not a defined to be a usable pointer
value, it is only a flag that no meaningful value is being provided
for the argument.  Of course, with many compilers, NULL is kinda
equivalent to "" (a null string), but this isn't guaranteed.

-- 
George Robbins - now working for,     uucp:   {uunet|pyramid|rutgers}!cbmvax!grr
but no way officially representing:   domain: grr@cbmvax.commodore.com
Commodore, Engineering Department     phone:  215-431-9349 (only by moonlite)

diamond@jit533.swstokyo.dec.com (Norman Diamond) (06/12/91)

In article <1991Jun12.040043.24091@bronze.ucs.indiana.edu> lwm@bronze.ucs.indiana.edu (Larry Meehan) writes:

[First an explanation of why dereferencing NULL is illegal, which was correct,
but had not yet arrived at this site when I previously replied.  But then...]

>If you look in /usr/include/stdio.h, you will see that NULL is really just 0,
>so our programs are trying to access location 0

Sorry, but you can't see that from looking in /usr/include/stdio.h.
When a source program uses an integer constant 0 as a pointer, the compiler
must recognize it as a null pointer constant.  However, a null pointer
constant does not have to be address 0 at execution time.  If the source
program uses 0 for an integer, its binary value has to consist of 0-bits,
but for a null pointer it does not have to do so.

For example, in some implementations, a byte of storage might be allocated
somewhere and never used for anything legal, but the implementation will
use its address as a null pointer.  For another example, on some Intel
processors, it would be very nice to use address (some segment):FFFF as a
null pointer, so that the hardware would trap some illegal dereferences.
In these cases, a 0 in the source program, compiled to a null pointer
constant, accesses a location other than 0.

These topics come up frequently in newsgroups comp.lang.c and comp.std.c.

The C programming language is confusing in this and in other ways.  It was
not designed for friendliness to mortals.

>which is legal on a VAX,

No.  (Personal opinion, not the company's opinion.)
It was uncaught (usually) and benign (usually), but illegal since day 1,
even before K&R-1.

>but not on the MIPS implementation of Ultrix.

Not anywhere.  Well, hypothetically an implementation could define an
extension to the language, and the program would be legal on such an
implementation, but I don't think any real implementation specifies this.
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.
Permission is granted to feel this signature, but not to look at it.

ltf@ncmicro.lonestar.org (Lance Franklin) (06/13/91)

In article <966@sdrc.COM> wggabb@sdrc.COM (Rob Gabbard) writes:
}A call to strcat with NULL as the second argument core dumps with a memory 
}fault on Ultrix.  Why would anyone want to do this anyway ? How about....
}
}	strcat(foo,getenv("FOO"))
}
}		instead of
}
}	if (getenv("FOO")) strcat(foo,getenv("FOO"));

 Try:   if ((s=getenv("FOO"))) strcat(foo,s);

 Where s is defined as (char *).

}
}Actually, just coding strcat(foo,NULL) will dump.  Anyone run into this ?
}Am I doing a no-no here.

Yup...figure it out, why put up with a lot of overhead on error checking
on string handling routines where 95% of the calls are of the type:

    strcat(foo,"string");

After all, if you check for NULL on strcat, you might as well do it in
all the other str* routines...that's a lot of error checking in a set of
routines you would prefer to be as fast as possible.

Lance


-- 
Lance T. Franklin            +----------------------------------------------+
(ltf@ncmicro.lonestar.org)   | "You want I should bop you with this here    |
NC Microproducts, Inc.       |    Lollipop?!?"                 The Fat Fury |
Richardson, Texas            +----------------------------------------------+

lwm@bronze.ucs.indiana.edu (Larry Meehan) (06/13/91)

In article <1991Jun12.040043.24091@bronze.ucs.indiana.edu> lwm@bronze.ucs.indiana.edu (Larry Meehan) writes:

>which is legal on a VAX,

What I meant was that it results in a legal memory reference.

In <1991Jun12.062045.13467@tkou02.enet.dec.com> diamond@jit533.swstokyo.dec.com (Norman Diamond) writes:

>When a source program uses an integer constant 0 as a pointer, the compiler
>must recognize it as a null pointer constant.  However, a null pointer
>constant does not have to be address 0 at execution time.  If the source
>program uses 0 for an integer, its binary value has to consist of 0-bits,
>but for a null pointer it does not have to do so.

I always knew that NULL could have a non-zero value, depending on
implementation details, but I didn't realize it could be specified
as 0 in the source and that the compiler would translate this to the
"correct" value.

I have always tried to avoid writing code that assumes anything about the
value of NULL.  I have always felt uneasy about constructs like
			while (*argv)
and avoided them myself.  It sounds from what you say like this is a very
dangerous (non-portable) line of code.  I mean, is the compiler expected
to translate this to
			while (*argv != NULL)
on systems that have a non-zero value for NULL?

I realize this newsgroup is not about C programming, but this issue will
probably continue to bite DEC customers who move from VAX to RISC, so it
is probably good for it to appear here once in a while.

-- 
	 Larry Meehan			University Computing Services
	 lwm@ucs.indiana.edu		Indiana University

	("Industry without art is brutality." -- Ananda Coomaraswamy)
-- 
	 Larry Meehan			University Computing Services
	 lwm@ucs.indiana.edu		Indiana University

	("Industry without art is brutality." -- Ananda Coomaraswamy)

diamond@jit533.swstokyo.dec.com (Norman Diamond) (06/13/91)

In article <1991Jun12.214124.24990@bronze.ucs.indiana.edu> lwm@bronze.ucs.indiana.edu (Larry Meehan) writes:
>In <1991Jun12.062045.13467@tkou02.enet.dec.com> diamond@jit533.swstokyo.dec.com (Norman Diamond) writes:
>>When a source program uses an integer constant 0 as a pointer, the compiler
>>must recognize it as a null pointer constant.  However, a null pointer
>>constant does not have to be address 0 at execution time.  If the source
>>program uses 0 for an integer, its binary value has to consist of 0-bits,
>>but for a null pointer it does not have to do so.

>I have always tried to avoid writing code that assumes anything about the
>value of NULL.  I have always felt uneasy about constructs like
>			while (*argv)
>and avoided them myself.  It sounds from what you say like this is a very
>dangerous (non-portable) line of code.

No.  This is perfectly portable and not dangerous.

>I mean, is the compiler expected to translate this to
>			while (*argv != NULL)
>on systems that have a non-zero value for NULL?

   while (*argv)
   while (*argv != 0)
   while (*argv != (void *) 0)
   while (*argv != NULL)
   while (*argv != (char *) 0)  /* only because  *argv  has type  (char *) */
are all equivalent.  The compiler is required to translate all of these to
   compare *argv to run-time representation of a null pointer
   if equal, jump out of the loop
   [contents of loop]
   jump back to the compare
The run-time representation might or might not be binary zeroes.
If the source code has integer constant 0, (void *) 0, or NULL,
(or, as in while (*argv), an implied occurrence of one of these),
in a place where it must be a pointer,
then the compiler is required to translate it to the run-time representation
of a null pointer.

However, for example,
   while ((int) *argv != 0)   /* casting pointer to int, and comparing ints */
   while ((unsigned long) *argv != 0)  /* approximately the same */
are unportable and dangerous.

>I realize this newsgroup is not about C programming, but this issue will
>probably continue to bite DEC customers who move from VAX to RISC, so it
>is probably good for it to appear here once in a while.

It will bite anyone who wrote code for an implementation represents null
pointers by all 0-bits (too many, IMHO, because all 1-bits would be easy
to trap on many Intel processors), or more accurately where fetching from
the location addressed by a null pointer does not trap, and then moves to
an implementation where it does trap.  I once read that some vendor had
changed their kernel to waste a page of (virtual and real) storage for
every process, because that was easier than fixing applications that came
from a certain irresponsible organization that should have known better.

Follow-ups are directed to comp.lang.c because it really is a language issue.
(Readers of comp.std.c probably don't want to be bothered by it again.)
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.
Permission is granted to feel this signature, but not to look at it.