strcpy implementation

I

iC and iC++

I found this code in a very old book about pointers and I started
playing with it and I have a question.


#include <stdio.h>
#include <string.h>

main()
{
char x[5];
strcpy(x, "COMPILER");

printf("%s, %u, %d, \n", x, &x, sizeof(x));

getchar();
}

How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array? In other words, where are the extra bytes
stored and how is memory for them allocated. I looked at it while
debugging and there were no clues there.

thanks
 
B

Ben Bacarisse

iC and iC++ said:
I found this code in a very old book about pointers and I started
playing with it and I have a question.

What's its name?
#include <stdio.h>
#include <string.h>

main()

int main(void) is better.
{
char x[5];
strcpy(x, "COMPILER");

See below for my comments on this.
printf("%s, %u, %d, \n", x, &x, sizeof(x));

Only one of the formats (%s) matches the type of supplied argument and
even that one (because of the strcpy error) won't necessarily print
correctly. What does the book claim is being illustrated here?
getchar();

There should be a return statement here.
}

How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array? In other words, where are the extra bytes
stored and how is memory for them allocated. I looked at it while
debugging and there were no clues there.

There are two ways to look at this. You can work out what happens on
one particular machine when the code is compiled with one particular
compiler and linked with one particular library; or you can look at it
is an incorrect program whose behaviour is not specified by the language
it appears to be written in.

The first can be useful but I don't think it will be in this case. The
second makes you focus on what constructs have well-defined meanings and
that is usually more productive. Here the lesson is that strcpy must
always have somewhere to cpy the str to.
 
I

iC and iC++

iC said:
I found this code in a very old book about pointers and I started
playing with it and I have a question.
#include <stdio.h>
#include <string.h>
main()
   {
   char x[5];
   strcpy(x, "COMPILER");
   printf("%s, %u, %d, \n", x, &x, sizeof(x));
   getchar();
}
 How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array?

It can't (legally). If you don't provide enough storage in the target
string to keep a copy of the source string, the behaviour of your
program is undefined. In other words, by failing to provide sufficient
storage you are breaking the contract between yourself and the
implementation, and the implementation is therefore free to break the
contract itself in any way it pleases.
In other words, where are the extra bytes
stored and how is memory for them allocated. I looked at it while
debugging and there were no clues there.

A debugger can't teach you the rules of the language! There are no extra
bytes (in the abstract machine) - in practice, strcpy just starts
writing at x[0] and keeps going until it gets to a null character, so
any data stored immediately after x[4] are going to get trashed.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within

Thats what I thought too, but it actually returns "COMPILER". That
definitely more characters than it has been allocated. Why isn't there
an error when there should be one. I am just curious.
 
D

Default User

iC and iC++ said:
I found this code in a very old book about pointers and I started
playing with it and I have a question.


#include <stdio.h>
#include <string.h>

main()
{
char x[5];
strcpy(x, "COMPILER");

printf("%s, %u, %d, \n", x, &x, sizeof(x));

getchar();
}

How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array? In other words, where are the extra bytes
stored and how is memory for them allocated. I looked at it while
debugging and there were no clues there.

It's undefined behavior. There is no defined behavior for undefined
behavior. A possible outcome would be to keep writing until it either
overwrote some other variables or intruded upon storage for which it had no
permission to access, triggering some sort of system response.

I would recommend not using that book.



Brian
 
I

iC and iC++

iC and iC++ said:
I found this code in a very old book about pointers and I started
playing with it and I have a question.

What's its name?
#include <stdio.h>
#include <string.h>

int main(void) is better.
   {
   char x[5];
   strcpy(x, "COMPILER");

See below for my comments on this.
   printf("%s, %u, %d, \n", x, &x, sizeof(x));

Only one of the formats (%s) matches the type of supplied argument and
even that one (because of the strcpy error) won't necessarily print
correctly.  What does the book claim is being illustrated here?
   getchar();

There should be a return statement here.
 How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array? In other words, where are the extra bytes
stored and how is memory for them allocated. I looked at it while
debugging and there were no clues there.

There are two ways to look at this.  You can work out what happens on
one particular machine when the code is compiled with one particular
compiler and linked with one particular library; or you can look at it
is an incorrect program whose behaviour is not specified by the language
it appears to be written in.

The first can be useful but I don't think it will be in this case.  The
second makes you focus on what constructs have well-defined meanings and
that is usually more productive.  Here the lesson is that strcpy must
always have somewhere to cpy the str to.

The point this book is trying to make is as follows:
..."x does not equal "COMPILER". It only returns the memory address
at which the first character in the array is stored. Function that
accept this pointer are programmed to be "smart" and know to quit when
what they are doing after reading the NULL character."

So, even though, x only contains the first 5 bytes, the next 3 are
copied and when printf prints x, it continues past the 5th bit and
does not stop until the NULL is reached, as in this case.
 
B

bart.c

iC said:
iC and iC++ wrote:
char x[5];
strcpy(x, "COMPILER");
printf("%s, %u, %d, \n", x, &x, sizeof(x));
How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array?

It can't (legally). If you don't provide enough storage in the target
Thats what I thought too, but it actually returns "COMPILER". That
definitely more characters than it has been allocated. Why isn't there
an error when there should be one. I am just curious.

It works by chance. Whatever is being overwritten with the extra 4 bytes,
hasn't caused a crash or malfunction in this case (although you might want
to check the files on your hard drive are all still there..)

(Try a much longer string than "compiler". And/or a different compiler.)

C doesn't provide these safeguards except perhaps in certain
implementations.
 
I

iC and iC++

iC said:
iC and iC++ wrote:
   char x[5];
   strcpy(x, "COMPILER");
   printf("%s, %u, %d, \n", x, &x, sizeof(x));
   getchar();
}
 How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array?
[...] in practice, strcpy just starts
writing at x[0] and keeps going until it gets to a null character, so
any data stored immediately after x[4] are going to get trashed.
Thats what I thought too, but it actually returns "COMPILER".

When you break the rules, anything can happen, including what you
observed to happen (but that isn't the only thing that could have happened).
That
definitely more characters than it has been allocated. Why isn't there
an error when there should be one. I am just curious.

There *is* an error. The error is in the code. But this isn't the kind
of error a compiler can catch (in the general case). It's what we know
in the trade as a "bug".

Let's just play pretend for a moment. Let's pretend that memory is laid
out like this:

+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|     |     |     |     |     |     |     |     |     |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+
<-- 5 bytes reserved for x --> <-- 4 bytes reserved
                                    for system time -->

(In practice, no system would be daft enough to keep its timestamp so
close to user memory, but we're just pretending.)

First, let's take a look at our system time:

*) TIME
17:42

Now let's run our program:

*) SILLYSTRCPY

When your program starts its run (on this pretend system), x contains
any old junk, whatever happened to be in memory, and the following four
bytes contain the system time (which, for simplicity, I'll represent in
ASCII).

+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|  d  |  %  |  $  |  `  |  &  |  1  |  7  |  4  |  2  |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+
<-- 5 bytes reserved for x --> <-- 4 bytes reserved
                                    for system time -->

Now we execute our strcpy, and here's what happens to the memory (on
this particular system):

+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|  C  |  O  |  M  |  P  |  I  |  L  |  E  |  R  |  \0 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+
<-- 5 bytes reserved for x --> <-- 4 bytes reserved
                                    for system time -->

We print the string, and printf thinks it's just a string like any
other, so printf prints everything from the start of x up to the first
null character, and you see:

COMPILER

on your monitor. The program then ends, and we are back at the prompt:

*)

We are curious to know again what the time is, so we do this:

*) TIME

and the result is:

LER

The program has trashed an important component of the system by
violating the bounds of its memory. Lesson: Don't Do That.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within

you have been understood.

thanks
 
J

Jens Thoms Toerring

iC and iC++ said:
I found this code in a very old book about pointers and I started
playing with it and I have a question.
#include <stdio.h>
#include <string.h>
main()
{
char x[5];
strcpy(x, "COMPILER");
printf("%s, %u, %d, \n", x, &x, sizeof(x));

How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array? In other words, where are the extra bytes
stored and how is memory for them allocated. I looked at it while
debugging and there were no clues there.

You won't find anything because this use of strcpy() just in-
vokes undefined behaviour. As a programmer you have to ensure
that the buffer you pass to strcpy() as the target is large
enough to hold the string you want to copy to it. In this pro-
gram this isn't the case and the consequences could be anything
- from looking as if everything works fine, a crash of your pro-
gram to your hard disk getting reformatted. So this example
program simply is buggy and should be marked with "Don't do
this at home. kids".

strcpy() simply doesn't have any means of checking if the
source string will fit into the target buffer - all it gets
is two pointers with no information about the sizes of the
buffers. So it has to blindly trust you that you have got
it right and copies everything, including the trailing '\0'
char, from the source string to the destination. If the desti-
nation buffer is too short printf() will blissfully ignorant
of what may be the consequences overwrite the memory following
the end of the destination buffer. If there's something im-
portant to your program (or even the operating system) you
just overwrote it and there's no way to get it back. strcpy()
also can only deduce from the trailing '\0' in the source
buffer when to stop, so if you pass it a char array that
doesn't contain a '\0' (so it's not a string) then you're also
screwed since it won't stop at the end of the source buffer
but happily continues until it finds some '\0' in the memory
following the end of the source buffer.

Perhaps that gets even more clear if you consider a possible
implemention of strcpy():

char *strcpy( char *dest, const char *src )
{
char *ret = dest;
while ( *dest++ = *src++ );
return ret;
}

This is (I think) a perfectly legal implementation of strcpy().
So you will be in trouble when

a) 'dest' is a NULL pointer or does not point to memory you own
b) 'src' is a NULL pointer or does not point to memory you own
c) 'src' isn't a pointer to a string, i.e. there's no '\0'
within the elements of the char array pointed to by 'src'
d) the char array 'dest' is pointing to isn't large enough
to hold all the chars from 'src' up to and including
the terminating '\0; char

So YOU have to take care that this can't happen. You pro-
bably will be careless a few times and will have to spend
a god deal of time figuring out where things went wrong.
In the long run it will make you either a much more careful
programmer or you will switch to a language where this can't
happen. It's like with cooking - things are a lot more fun
if you have really sharp knifes but you have to be on your
toes or you will shed some of your blood (or even lose parts
of your fingers;-)

By the way, also this line is problematic:
printf("%s, %u, %d, \n", x, &x, sizeof(x));

since the type of 'sizeof(x) isn't necessarily an int
(as you are promising printf() by using the '%d' format
specifier). The result of 'sizeof' is an unsigned integer
type of 'size_t' (note the 'integer' in contrast to 'int'),
so it would be prudent to use '%lu' as the format specifier
and cast the result of 'sizeof' to 'unsigned long' (or use
whatever is the largest unsigned integer type on your machine
unless you have a C99 compliant compiler where there's the
special format specifier of '%z' that tells printf() that it
has to expect a type of 'size_t' as the corresponding argument).

Regards, Jens
 
I

iC and iC++

On Wed, 2 Jun 2010 15:57:34 -0700 (PDT), "iC and iC++"

 What is the title of this book and who is the author?

Mastering C Pointers: Tools for programming power by Robert J.
Traister.. 1990

I am writing a tutorial on C pointers and this is one of the better
books I've found..
 
S

Seebs

#include <stdio.h>
#include <string.h>

main()
{
char x[5];
strcpy(x, "COMPILER");

printf("%s, %u, %d, \n", x, &x, sizeof(x));

getchar();
}
How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array?

By overwriting other stuff, probably. This is certainly welcome to blow up
spectacularly, and will on some hardware.

-s
 
S

Seebs

I am writing a tutorial on C pointers and this is one of the better
books I've found..

If you are at a level of expertise where you have to ask these questions,
I respectfully submit that you are probably not the right person to be
writing a tutorial on C pointers.

-s
 
K

Keith Thompson

iC and iC++ said:
iC said:
I found this code in a very old book about pointers and I started
playing with it and I have a question.
#include <stdio.h>
#include <string.h>
main()
   {
   char x[5];
   strcpy(x, "COMPILER");
   printf("%s, %u, %d, \n", x, &x, sizeof(x));
   getchar();
}
 How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array?
[snip]

Thats what I thought too, but it actually returns "COMPILER". That
definitely more characters than it has been allocated. Why isn't there
an error when there should be one. I am just curious.

There was an error. It just wasn't detected.

But I think what you meant was "Why isn't there an error *message*".

Many errors in C are classified as "undefined behavior". This means
that it's something you shouldn't do, but the implementation is not
obligated to diagnose, or even detect, the problem. Almost all
languages have such things; C has more than most. It can make C
programming tricky. Trial and error can often lead you astray;
a program that appears to work can still have serious errors.
 
B

Ben Bacarisse

There is always the possibility the code or its purpose have not been
accurately described.
Mastering C Pointers: Tools for programming power by Robert J.
Traister.. 1990

From the Amazon page:

Customers Who Bought This Item Also Bought

C: The Complete Reference, 4th Ed. by
Herbert Schildt
 
K

Keith Thompson

iC and iC++ said:
you have been understood.

thanks

When you post a followup, please trim the quoted text, keeping
only enough for your followup to be reasonably clear to someone
who hasn't read the parent article. In particular, please don't
quote signatures (the 4 or so lines following the "-- " marker)
unless you're actually commenting on them.

See most of the articles in this newsgroup for good examples of
how to do this.
 
K

Keith Thompson

Geoff said:
You MIGHT spot the bug in debug when your program prints garbage due
to an unterminated string if you used strncpy(), example:

strncpy(x, "COMPILER", sizeof(x));

But even strncpy won't save you if the memory allocated to x was
zero-filled prior to the copy operation.

Short answer, forget strcpy exists. Use strncpy with care and remember
if the buffer size is LESS than the string to be copied strncpy won't
properly terminate the destination string.

I suggest that that's bad advice.

strncpy(), in contrast to most of the other standard strn*()
functions, is *not* just a safer version of strcpy() that lets you
specify a maximum length. It's designed for a very specific (and,
these days, unusual) data structure: a fixed size characters array
consisting of some number of data characters followed by zero or
more trailing null characters. (Some early Unix systems stored
file names this way, with an upper bound of 14 characters.)

If the source string is short, the target array is padded with
unnecessary extra null characters. If the source is long, the
target array will not contain a string, which will almost certainly
cause problems later on. (Whether those problems will be detected
is another matter.)

If you're able to exercise enough care to use strncpy() safely,
you're able to exercise enough care to use strcpy() safely.

strcpy() is not *inherently* dangerous. It's possible to shoot
yourself in the foot with it (as the original example demonstrates),
but with care it can be used safely; you just have to ensure,
by whatever means you like, that the target array is big enough.
 
K

Keith Thompson

Seebs said:
#include <stdio.h>
#include <string.h>

main()
{
char x[5];
strcpy(x, "COMPILER");

printf("%s, %u, %d, \n", x, &x, sizeof(x));

getchar();
}
How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array?

By overwriting other stuff, probably. This is certainly welcome to blow up
spectacularly, and will on some hardware.

It's also welcome to quietly do what you expected it to do. This is
arguably a much worse outcome than blowing up spectacularly.
 
S

Seebs

I respectfully disagree. Writing a tutorial is a great way to learn
something. If you think about it you'll probably even agree with me.

No, no, I've thought about it a great deal and I still strongly disagree.
I would bet that you learned a great deal about shell scripting by writing
a book about the subject.

Yes. But I *started* as an experienced shell programmer who knew the
topic better than most people. And I was writing a book which, no matter
what the marketing people thought, was aimed at reasonably experienced
people.

A decent tutorial is MUCH harder to write. It's aimed at people who haven't
got the background or skills to recognize any errors you make, and who are
unequipped to evaluate the quality of your work -- and they are fairly likely
to imprint on whatever mistakes you make.
There are certainly people that know even less about pointers than iC,
and so tutorial could even be helpful.

A book or tutorial written by someone even moderately experienced, but not
an expert, can often be fairly harmful -- it's too easy to teach people
errors.

-s
 
K

Keith Thompson

Seebs said:
No, no, I've thought about it a great deal and I still strongly disagree.

I suggest that *writing* a tutorial might be a good way to learn
something. *Distributing* it (other than to experts for feedback)
might not be such a good idea.

Of course, once you've written a tutorial it might be hard to resist
the temptation to share it -- which could explain the preponderance
of lousy tutorials out there.
 
N

Nick Keighley

On Wed, 2 Jun 2010 15:22:39 -0700 (PDT), "iC and iC++"
I found this code in a very old book about pointers and I started
playing with it and I have a question.
#include <stdio.h>
#include <string.h>
main()
   {
   char x[5];
   strcpy(x, "COMPILER");
   printf("%s, %u, %d, \n", x, &x, sizeof(x));
   getchar();
}
How deos strcpy assign all the characters in the code if x is only
defines as a 5 byte array? In other words, where are the extra bytes
stored and how is memory for them allocated. I looked at it while
debugging and there were no clues there.

This is a fine example of why strcpy is unsafe.

only you and Microsoft think strcpy() is unsafe. Like many other C
functions strcpy() can be used in an unsafe manner. Either don't do
that or use a safer language.
The results you get will depend on your platform and compiler
implementation as well as your choice of optimizations. On x86 in
debug mode on Windows you would have to look closely to see the bug
waiting to bite you.

5 bytes are reserved for x[] but strcpy will write 8 characters plus a
zero termination for the string (9 chars). Overwriting something
adjacent to x[] and on x86 that would be in the stack frame for the
main() function. Classic buffer overrun and stack smash waiting to
happen. If the second argument to strcpy was dependent on user input,
you would be in a world of hurt when the blackhats want to hit you.

My compiler reserves 8 bytes for the 5 chars due to alignment
requirements.

You MIGHT spot the bug in debug when your program prints garbage due
to an unterminated string if you used strncpy(), example:

        strncpy(x, "COMPILER", sizeof(x));

But even strncpy won't save you if the memory allocated to x was
zero-filled prior to the copy operation.

Short answer, forget strcpy exists. Use strncpy with care and remember
if the buffer size is LESS than the string to be copied strncpy won't
properly terminate the destination string.- Hide quoted text -

no. Forget strncpy() exists. This is my strncpy() boilerplate response

the semantics of strncpy() are non-intuitive (it's broken). So
generally
*don't* use strncpy.

/* what is wrong with this? */
char sbuff[5];
strncpy(sbuff, "bomb", 4);
printf ("%s\n", buff);

/* how many characters are written to bbuff? */
char bbuff [1000000];
strncpy(bbuff, "bomb", 1000000);

See FAQ 13.2 "Why does strncpy() not always place a '\0'
terminator in the destination string?
 
S

Seebs

I suggest that *writing* a tutorial might be a good way to learn
something. *Distributing* it (other than to experts for feedback)
might not be such a good idea.

That may be a good point.

My experience has been that trying to teach something before I understand
it well enough tends to make me firm up bad ideas, though, because I have
to talk as though they're known truths rather than speculations...

-s
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top