Dangerous convertion?

R

Richard Bos

Tom St Denis said:
strncpy and/or write your own that checks bounds.

Anyone who suggests using strncpy() as a replacement for strcpy() is a
loony.

If you want to copy a string with a maximum length, use strncat(),
_never_ strncpy(), which has undesirable side effects. If you want to
copy a string of which you _already_ know its maximum length, and you
know that it fits, using anything but strcpy() is daft.

Richard
 
R

Richard Bos

Malcolm McLean said:
Assuming sane naming conventions, this is safe.

You're talking about Microsoft, here. Sane naming conventions? I
wouldn't count on it.

For example, how do you _know_ that a CString is something that can
safely be cast to a char *?

Richard
 
K

Kaz Kylheku

strncpy and/or write your own that checks bounds.

strncpy is a retardation that belongs in the same bin as gets.

Any function that begins with ``str'' but can leave an array non-null-terminated
is a design ``non-str-ter''.

But when space is available, strncpy goes nuts! Not only does it write one null
byte, it writes as many of them as will fit into the target buffer, no matter
how much smaller the string is.

It's as if it's trying to atone for all the times it created a non-string
object in the array.
 
A

Alexander Bartolich

Kaz said:
[...]
assert (sizeof foo->name >= sizeof "foo");

This assertion can be done at compile time, i.e. the check will be
performed only once by the compiler, not every time the program runs.

{ typedef int Assert[sizeof(foo->name) >= sizeof("foo") ? +1 : -1]; }
memcpy(foo->name, "foo", sizeof("foo"));
[...]
/* c) */
strcpy(foo->name, "foo");

Well, solution c) is equivalent to

memcpy(foo->name, "foo", strlen(foo) + 1));

That is, it makes a superflous call of strlen.
Why do you program in C if you don't care about performance?
 
K

Kaz Kylheku

Look, I'll break it down for you.

You should never use strcpy. Ever.

Loonie alert!

Pop Quiz.

1. Given the following declaration, what is the best style
for initializing the name field in a dynamic instance of the struct?

struct foo {
char name[128]; /* will never, ever be any smaller */
};

/*...*/

{
struct foo *f = malloc(sizeof *foo);
/* ... null check ... */

/* a) */
assert (sizeof foo->name >= sizeof "foo");
memcpy(foo->name, "foo", sizeof "foo");
DEBUG_PRINTF(("sizeof foo->name = %ld\n", (long int) sizeof foo->name));
DEBUG_PRINTF(("sizeof \"foo\" = %ld\n", (long int) sizeof "foo"));

/* b) */
foo->name[0] = 'f';
foo->name[1] = 'o';
foo->name[2] = 'o';
foo->name[3] = '\0';

/* c) */
strcpy(foo->name, "foo");
}

d) AAAARGH! You said strcpy! I need my medication, NOW!
 
K

Keith Thompson

Alexander Bartolich said:
Kaz Kylheku wrote: [...]
/* c) */
strcpy(foo->name, "foo");

Well, solution c) is equivalent to

memcpy(foo->name, "foo", strlen(foo) + 1));

That is, it makes a superflous call of strlen.
Why do you program in C if you don't care about performance?

It's logically equivalent, but what makes you think it's equally
inefficient? strcpy() traverses the source and target arrays exactly
once, terminating when it finds a '\0' in the source. Your
"equivalent" code first traverse the source to find the '\0', then
traverses the source and target again, terminating after copying a
specified number of characters.

Even given constant lengths and character counts:
char target[12];
char source[] = "hello world";
it's not obvious which of
strcpy(target, source);
or
memcpy(target, source, 12);
will be faster.
 
A

Alexander Bartolich

Keith said:
[...]
Even given constant lengths and character counts:
char target[12];
char source[] = "hello world";
it's not obvious which of
strcpy(target, source);
or
memcpy(target, source, 12);
will be faster.

$ nl -ba m.c
1 #include <string.h>
2
3 char target[12];
4 char source[] = "hello world";
5
6 int main()
7 {
8 strcpy(target, source);
9 memcpy(target, source, 12);
10 return 0;
11 }
12

$ gcc -Wall -O2 -S m.c && sed -ne '/main:/,/ret/p' m.s
main:
..LFB14:
subq $8, %rsp
..LCFI0:
movl $source, %esi
movl $target, %edi
call strcpy
movq source(%rip), %rax
movq %rax, target(%rip)
movl source+8(%rip), %eax
movl %eax, target+8(%rip)
xorl %eax, %eax
addq $8, %rsp
ret

The invocation of memcpy was completely inlined by gcc 4.3.2,
i.e. replaced by move instructions.
 
J

jameskuyper

Alexander Bartolich wrote:
....
Well, solution c) is equivalent to

memcpy(foo->name, "foo", strlen(foo) + 1));

That is, it makes a superflous call of strlen.

Why do you think that? Why do a separate pass to determine the end of
the string? I'd expect strcpy(p,q) to be translated into machine code
that does something similar to the following:

char *strcpy(char * restrict s1, const char * restrict s2)
{
char* retval = s1;
while(*s1++ = *s2++);

return retval;
}

I've worked on machines in which that loop could be translated into a
single instruction, and execute much faster than the strlen()/memcpy()
combination you mentioned above. I'd be surprised to find any standard
library implementation where strcpy() wasted time in the fashion you
describe. Not as surprised as I'd like to be :-( - but surprised,
nonetheless.
 
K

Keith Thompson

Alexander Bartolich said:
Keith said:
[...]
Even given constant lengths and character counts:
char target[12];
char source[] = "hello world";
it's not obvious which of
strcpy(target, source);
or
memcpy(target, source, 12);
will be faster.

$ nl -ba m.c [snip]

$ gcc -Wall -O2 -S m.c && sed -ne '/main:/,/ret/p' m.s
main:
.LFB14:
subq $8, %rsp [snip]

The invocation of memcpy was completely inlined by gcc 4.3.2,
i.e. replaced by move instructions.

I didn't say one or the other *wouldn't* be faster, I said it's not
obvious which is faster.
 
A

Alexander Bartolich

Keith said:
Alexander Bartolich said:
[...]
The invocation of memcpy was completely inlined by gcc 4.3.2,
i.e. replaced by move instructions.

I didn't say one or the other *wouldn't* be faster, I said it's
not obvious which is faster.

Well, a compiler that can inline
memcpy(target, "hello world", sizeof("hello world"));
might produce identical code for
strcpy(target, "hello world");

Though the task gets a bit harder for
static const source[] = "hello world";
strcpy(target, source);

However, in your fine example you emitted the "const". So it actually
is obvious that strcpy cannot be optimized while

memcpy(target, source, sizeof(source))

can make maximum use of the size of a register.

That is, strcpy must search a for a single terminating byte, and
thus copy byte by byte, while memcpy called with a constant size
can divide it by sizeof(long) and copy more bytes per instruction.
 
A

Alexander Bartolich

Keith said:
Alexander Bartolich said:
[...]
The invocation of memcpy was completely inlined by gcc 4.3.2,
i.e. replaced by move instructions.

I didn't say one or the other *wouldn't* be faster, I said it's
not obvious which is faster.

Well, a compiler that can inline
memcpy(target, "hello world", sizeof("hello world"));
might produce identical code for
strcpy(target, "hello world");

Though the task gets a bit harder for
static const source[] = "hello world";
strcpy(target, source);

However, in your fine example you omitted the "const". So it actually
is obvious that strcpy cannot be optimized by the compiler while

memcpy(target, source, sizeof(source))

can make maximum use of the size of a register.

That is, strcpy must search for a single terminating byte, and
thus copy byte by byte, while memcpy called with a constant size
can divide it by sizeof(long) and copy more bytes per instruction.
 
P

Phil Carmody

Alexander Bartolich said:
Kaz said:
[...]
assert (sizeof foo->name >= sizeof "foo");

This assertion can be done at compile time, i.e. the check will be
performed only once by the compiler, not every time the program runs.

{ typedef int Assert[sizeof(foo->name) >= sizeof("foo") ? +1 : -1]; }

Such tricks are an abomination, IMHO.
However, they highlight the fact that the C standard still needs
augmenting with useful features, such as improved compile-time
assertions.
memcpy(foo->name, "foo", sizeof("foo"));
[...]
/* c) */
strcpy(foo->name, "foo");

Well, solution c) is equivalent to

memcpy(foo->name, "foo", strlen(foo) + 1));

That is, it makes a superflous call of strlen.
Codswallop.

Why do you program in C if you don't care about performance?

Why do you post 'corrections' to a newsgroup if you don't care
about correctness?

Phil
 
W

Willem

Alexander Bartolich wrote:
)> /* c) */
)> strcpy(foo->name, "foo");
)
) Well, solution c) is equivalent to
)
) memcpy(foo->name, "foo", strlen(foo) + 1));

Yes.

) That is, it makes a superflous call of strlen.

No.
Where did you go from 'is equivalent to' to 'makes the same calls as' ?

stcrpy(to, from) is also equivalent to:

while (*to = *from) ;

See ? No call to strlen() there.

Especially for short strings, strcpy() can often be faster than memcpy().
(Depending on implementation of course).


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
C

Curtis Dyer

Alexander Bartolich wrote:
)> /* c) */
)> strcpy(foo->name, "foo");
)
) Well, solution c) is equivalent to
)
) memcpy(foo->name, "foo", strlen(foo) + 1));

Yes.

) That is, it makes a superflous call of strlen.

No.
Where did you go from 'is equivalent to' to 'makes the same
calls as' ?

stcrpy(to, from) is also equivalent to:

while (*to = *from) ;

Did you mean to write

while (*to++ = *from++) ;

?

<snip>
 
E

Eric Sosman

Alexander said:
Kaz said:
[...]
/* c) */
strcpy(foo->name, "foo");

Well, solution c) is equivalent to

memcpy(foo->name, "foo", strlen(foo) + 1));

That is, it makes a superflous call of strlen.

It's *possible* that strcpy() could be implemented as
a strlen() plus a memcpy(), just as it's *possible* it might
be implemented as sprintf(target, "%s", source).

But I'm having a hard time imagining a machine where a
sane implementor would choose either of these. Where have
you encountered a strcpy() that calls strlen()?
Why do you program in C if you don't care about performance?

Because the machines I'm writing code for don't have
JOVIAL compilers.
 
W

Willem

<snip>

Curtis Dyer wrote:
) Did you mean to write
)
) while (*to++ = *from++) ;
)
) ?

Yes. Right. Sorry.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
K

Kaz Kylheku

Kaz said:
[...]
assert (sizeof foo->name >= sizeof "foo");

This assertion can be done at compile time, i.e. the check will be
performed only once by the compiler, not every time the program runs.

{ typedef int Assert[sizeof(foo->name) >= sizeof("foo") ? +1 : -1]; }
memcpy(foo->name, "foo", sizeof("foo"));
[...]
/* c) */
strcpy(foo->name, "foo");

Well, solution c) is equivalent to

memcpy(foo->name, "foo", strlen(foo) + 1));

That is, it makes a superflous call of strlen.
Why do you program in C if you don't care about performance?

Fool, yes, people can program in C for reasons other than performance.
The main function of a hosted C program is often written for reasons other
than performance, for example, even when the bulk of the execution time
is spent in other functions.

Why do you use a braindead compiler to translate your C, if you wrote it for
performance reasons?

Code:

#include <string.h>

typedef struct foo {
char name[128];
int dummy;
} foo;

int main(void)
{
extern struct foo *global_f;
strcpy(global_f->name, "foo");
return 0;
}

Compiler: gcc 3.4.3 (quite old)

Output:

main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl global_f, %eax
movl $7303014, (%eax)
andl $-16, %esp
subl $16, %esp
xorl %eax, %eax
leave
ret

See? The four byte string "foo" turns into a four byte little-endian integer,
which is just moved to the target memory location.

I don't see any call to strlen or memcpy.
 
J

jameskuyper

io_x said:
The above is wrong because it has to return the len of the array.

I'm curious - have you written any code which relies on that
misconception? How well did it work?. See xection 7.21.2.3:

"Synopsis
#include <string.h>
char *strcpy(char * restrict s1,
const char * restrict s2);

Description

The strcpy function copies the string pointed to
character) into the array pointed to by s1. If copying
overlap, the behavior is undefined.

Returns

The strcpy function returns the value of s1."

Notice: the value of s1 is a pointer; it is NOT "the len of the
array".
 
F

Flash Gordon

Alexander said:
Eric Sosman wrote:


IMHO "does not amount to much" is the ultimate argument in this case.
It beats me why benchmark results were neither presented nor demanded.

I'm sure we've been round the bouye on whether strcpy or memcpy was
faster before here, and found that on some implementations for some
lengths strcpy was faster.
Well, that's a another can of worms. I prefer strdup to statically
sized buffers just because of the flexibility. One natural consequence
is that string assignment is reduced to pointer assignment (and keeping
track of who is responsible for releasing the buffer again).

Well, using strdup (apart from it being non-standard but easy to
implement) *does* require doing a strlen (or equivalent) before the copy!
 
A

Antoninus Twink

Assuming sane naming conventions, this is safe.

Are you sure?

I thought the C in LPCTSTR stands for const, in which case casting it
away *might* be dangerous.
 

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,756
Messages
2,569,535
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top