Two Questions about "strlen", "strcat" and "strcpy"

G

Gene Wirchenko

I also have 2 questions:

1. Posting homework questions to usenet frequently returns
misinformation and insults. Why is this more appropriate than actual
answers?

2. Would there be any advantage in having you do your own homework?

Those sound suspiciously like homework questions (perhaps in a
course on computing ethics).

Sincerely,

Gene Wirchenko

Computerese Irregular Verb Conjugation:
I have preferences.
You have biases.
He/She has prejudices.
 
C

CBFalconer

Michael said:
.... snip ...

Ugh. That's what I get for posting over-hastily. I thought I had
a counter-example, but you're right; they're only safe if you know
both how large your buffer is and how much data you're copying in,
and given that information, it's just as safe to chain them as not.
(And, of course, there are no results to be checked from strcpy and
strcat.)

There are results to be checked in strlcat and strlcpy. See:

<http://cbfalconer.home.att.net/download/strlcpy.zip>

(No noises about reserved identifiers please. Covered in the ref)

--
Some useful references:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://www.eskimo.com/~scs/C-faq/top.html>
<http://benpfaff.org/writings/clc/off-topic.html>
<http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
<http://www.dinkumware.com/refxc.html> C-library
 
D

Dan Pop

In said:
He makes many of his announcements on comp.compilers.lcc. That is
a low traffic group. Bug reports also show up there, which he
usually seems to repair very quickly.

If you manage to convince him that they are bugs...

Dan
 
D

Default User

Flash said:
Matt wrote:
2. Would there be any advantage in having strcat and strcpy
return a pointer to the "end" of the destination string rather
than returning a pointer to its beginning?

No. It returns the pointer to the start so you can chain calls:


char str[80];

strcat(strcpy(str, "Hello "), "World!");

This would also work if strcpy was specified as returning a pointer to
the end of the string.

Yes, but only because it's strcat(). Not so if you wanted to use
strlen) or strstr() or other string functions that need a pointer to
the beginning of the string, or if you were passing the result to a
home-grown function. My example wasn't the best.



Brian Rodenborn
 
D

Default User

CBFalconer said:
Default said:
Matt wrote:
.... snip ...
2. Would there be any advantage in having strcat and strcpy
return a pointer to the "end" of the destination string rather
than returning a pointer to its beginning?

No. It returns the pointer to the start so you can chain calls:

char str[80];

strcat(strcpy(str, "Hello "), "World!");

However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));


I'm confused, you said my way was poor usage, then showed some other
usage altogether, one dependent on order of evaluation of function
arguments. Mine had no such dependency.

You could just as well show:

int i;

printf("%d%d\n", i, i = 10);


Then claim that means assigning to integers is bad.



Brian Rodenborn
 
C

CBFalconer

Default said:
CBFalconer said:
Default said:
Matt wrote:
.... snip ...

2. Would there be any advantage in having strcat and strcpy
return a pointer to the "end" of the destination string rather
than returning a pointer to its beginning?

No. It returns the pointer to the start so you can chain calls:

char str[80];

strcat(strcpy(str, "Hello "), "World!");

However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));

I'm confused, you said my way was poor usage, then showed some
other usage altogether, one dependent on order of evaluation of
function arguments. Mine had no such dependency.

No, my point is that the fact that strcpy returns a pointer to its
first argument encourages such evil usage by the unaware.
strlcpy, on the other hand, returns a length, so cannot be used in
such a manner, and forces proper separate evaluation. I guess I
was unclear again.

USE worldnet address!
 
D

Default User

[ removed CLCM from the distribution ]

CBFalconer wrote:

However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));

I'm confused, you said my way was poor usage, then showed some
other usage altogether, one dependent on order of evaluation of
function arguments. Mine had no such dependency.

No, my point is that the fact that strcpy returns a pointer to its
first argument encourages such evil usage by the unaware.
strlcpy, on the other hand, returns a length, so cannot be used in
such a manner, and forces proper separate evaluation. I guess I
was unclear again.

But what is wrong with the usage you show then? If you removed the
first usage of buff, then you'd have:

printf("%s\n", strcpy(buff, "foo"));


That works just fine, causes no problems and does just what you'd think.



Brian Rodenborn
 
C

CBFalconer

Default said:
CBFalconer said:
However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));

I'm confused, you said my way was poor usage, then showed some
other usage altogether, one dependent on order of evaluation of
function arguments. Mine had no such dependency.

No, my point is that the fact that strcpy returns a pointer to its
first argument encourages such evil usage by the unaware.
strlcpy, on the other hand, returns a length, so cannot be used in
such a manner, and forces proper separate evaluation. I guess I
was unclear again.

But what is wrong with the usage you show then? If you removed the
first usage of buff, then you'd have:

printf("%s\n", strcpy(buff, "foo"));

That works just fine, causes no problems and does just what you'd think.

Yes, but try what I wrote, and you won't get what you might
expect.
 
D

Default User

CBFalconer wrote:

However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));
Yes, but try what I wrote, and you won't get what you might
expect.


I got one of the two possible results. Why would I not expect that? As
I said, as far as I can see all your example does is illustrate
something about order of evaluation of arguments.

If you think it demonstrates something else, just assume I'm too stupid
to figure it out and explain it.



Brian Rodenborn
 
E

Eric Sosman

Default said:
CBFalconer said:
However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));
Yes, but try what I wrote, and you won't get what you might
expect.

I got one of the two possible results. Why would I not expect that? As
I said, as far as I can see all your example does is illustrate
something about order of evaluation of arguments. [...]

I think there's only one possible result. Regardless
of order of evaluation, the second and third arguments to
the printf() call have the same value, to wit, `&buff[0]'.
Also, there's a sequence point just before printf() starts
to execute, so when printf() uses those two pointers it
must find that they both point to "foo". Unless I've
missed something really fundamental, the above code *must*
output "foofoo\n". No (ahem) two ways about it.
 
R

red floyd

Eric said:
Default said:
CBFalconer said:
However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));
I think there's only one possible result. Regardless
of order of evaluation, the second and third arguments to
the printf() call have the same value, to wit, `&buff[0]'.
Also, there's a sequence point just before printf() starts
to execute, so when printf() uses those two pointers it
must find that they both point to "foo". Unless I've
missed something really fundamental, the above code *must*
output "foofoo\n". No (ahem) two ways about it.

I don't think that you can guarantee anything. Given the snippet above,
aren't you invoking UB, since "foofoo\n" overruns the inital allocation
of buff (which I suspect should be 5 characters)?
 
E

Eric Sosman

red said:
Eric said:
Default said:
CBFalconer wrote:

However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));

I think there's only one possible result. Regardless
of order of evaluation, the second and third arguments to
the printf() call have the same value, to wit, `&buff[0]'.
Also, there's a sequence point just before printf() starts
to execute, so when printf() uses those two pointers it
must find that they both point to "foo". Unless I've
missed something really fundamental, the above code *must*
output "foofoo\n". No (ahem) two ways about it.

I don't think that you can guarantee anything. Given the snippet above,
aren't you invoking UB, since "foofoo\n" overruns the inital allocation
of buff (which I suspect should be 5 characters)?

printf() sends output to the `stdout' stream, not
to an in-memory buffer.

(Oddly enough, my first glance at the code came up
with exactly the same mis-reading! I guess the name
`buff' carries more suggestive power than expected.)
 
R

red floyd

Eric said:
(Oddly enough, my first glance at the code came up
with exactly the same mis-reading! I guess the name
`buff' carries more suggestive power than expected.)

Yep. I misread it as sprintf().

<EMILY-LATELLA> Never Mind </EMILY-LATELLA>
 
C

CBFalconer

Default said:
CBFalconer said:
However it is a bad habit to use it in that manner. Consider:

char buff[] = "blah";

printf("%s%s\n", buff, strcpy(buff, "foo"));
Yes, but try what I wrote, and you won't get what you might
expect.

I got one of the two possible results. Why would I not expect that?
As I said, as far as I can see all your example does is illustrate
something about order of evaluation of arguments.

If you think it demonstrates something else, just assume I'm too
stupid to figure it out and explain it.

There is only one possible result. It is NOT "blahfoo". Both
arguments load a pointer to the buffer buff. Both are evaluated
before printf is called. The strcpy makes buff hold "foo" as a
side effect. The output should be "foofoo".
 
D

Default User

CBFalconer wrote:

There is only one possible result. It is NOT "blahfoo". Both
arguments load a pointer to the buffer buff. Both are evaluated
before printf is called. The strcpy makes buff hold "foo" as a
side effect. The output should be "foofoo".

I see what you are getting at. But again, it really only demonstrates a
problem using side-effects when using pointers multiple times in a
function call parameter list.

It has little to do with using the return value of the str* functions
in other calls, which was the original assertion. Unless they returned
void, you could demonstrate the same thing.



Brian Rodenborn
 
C

CBFalconer

Default said:
I see what you are getting at. But again, it really only demonstrates
a problem using side-effects when using pointers multiple times in a
function call parameter list.

It has little to do with using the return value of the str* functions
in other calls, which was the original assertion. Unless they returned
void, you could demonstrate the same thing.

It presents an easily overlooked means of injecting stinging
insects into a program. Better designed routines, such as strlcpy
and strlcat, do not return the pointer but a useful entity, i.e.
the resultant length. Thus they never lure the programmer into
this mistake. I for one would dearly love the next standard, or
even some intermediate thing equivalent to C95, to include these
routines.

See the whole story about them on my site:

<http://cbfalconer.home.att.net/download/strlcpy.zip>
 
D

Default User

CBFalconer said:
It presents an easily overlooked means of injecting stinging
insects into a program. Better designed routines, such as strlcpy
and strlcat, do not return the pointer but a useful entity, i.e.
the resultant length. Thus they never lure the programmer into
this mistake. I for one would dearly love the next standard, or
even some intermediate thing equivalent to C95, to include these
routines.

Well, that's your opinion and that's fine and all. I just don't see
that it's really that big of a deal.

What really happens in your example is a confusion based on the fact
that the first argument passed to printf() is a pointer to an entity
that is changed via side-effect in another argument. That would happen
with your strlcpy as well.


The usual usage of the nested str* calls is something like this:

size t len;
char buff[40] = "Hello";

len = strlen(strcat(buff, " World!");



Brian Rodenborn
 
C

CBFalconer

Default said:
CBFalconer said:
Default User wrote:

It presents an easily overlooked means of injecting stinging
insects into a program. Better designed routines, such as strlcpy
and strlcat, do not return the pointer but a useful entity, i.e.
the resultant length. Thus they never lure the programmer into
this mistake. I for one would dearly love the next standard, or
even some intermediate thing equivalent to C95, to include these
routines.

Well, that's your opinion and that's fine and all. I just don't see
that it's really that big of a deal.

What really happens in your example is a confusion based on the
fact that the first argument passed to printf() is a pointer to
an entity that is changed via side-effect in another argument.
That would happen with your strlcpy as well.

The usual usage of the nested str* calls is something like this:

size t len;
char buff[40] = "Hello";

len = strlen(strcat(buff, " World!");

Using strlcpy that would be (safely):

len = strlcat(buff, " World!", sizeof buff);

assuming buff is local so sizeof works. Otherwise supply that
constant. Notice there is only one function call involved.
Insufficient space is detectable after the call.
 
C

Charlie Gordon

Matt said:
I have 2 questions:

1. strlen returns an unsigned (size_t) quantity. Why is an unsigned
value more approprate than a signed value? Why is unsighned value less
appropriate?

You have a very good point here.
The obvious but simplistic reason is that negative string lengths are
meaningless. But then wouldn't it make sense for strlen(NULL) to be -1 ?
With the current C spec, it is undefined behaviour, and most implementations
will crash...
The decent but somewhat optimistic explanation is that it allows for strings
to be as large as the largest object (size_t). But I have seen
implementations where the largest objects were larger than size_t could
handle, and strings were still limited to 64KB.
On a 32 bit system, defining strlen as returning an int would make it
inconsistent with C99 but would prevent signed/unsigned clashes resulting in
hard to find bugs such as this one:

int n = -1;
const char *str = "Hello, world\n";
if (strlen(str) > n) {
// why does this test fail?
printf("OK\n");
}
2. Would there be any advantage in having strcat and strcpy return a
pointer to the "end" of the destination string rather than returning a
pointer to its beginning?

For some uses, it would be advantageous for strcpy or strcat to return a
pointer to the end of the string, or the length of the string, or nothing at
all. People can define their own alternatives and some are quite common
albeit not standard. The C string functions were defined a LONG time ago,
changing the semantics is impossible without breaking millions of lines of
existing code.

Chqrlie

PS: talking about string functions, I strongly advise against any use of
strncpy and strncat, whose semantics are IMHO quite broken and *very* error
prone.
 
D

Douglas A. Gwyn

Charlie said:
The obvious but simplistic reason is that negative string lengths are
meaningless. But then wouldn't it make sense for strlen(NULL) to be -1 ?

No, NULL doesn't denote a string, and even if it did,
a length of -1 would "make sense" only if it pertained
to going backward from the given starting location.
 

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
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top