gets() - dangerous?

J

Jordan Abel

Daniel Rudy said:
Here's something that's really fast:

#include <strings.h>
#include <string.h>

int strscpy(char *dest, const char *src, int dest_size)
{
int str_size; /* size of string to be copied */
int copy_size; /* number of characters to copy */

/* get src string size */
str_size = strlen(src);
/* determine how much to copy */
/* str_size + 1 is based on strlen not including the terminating
null in the size of the string. remove it if your
implementation does */
copy_size = str_size + 1 < dest_size - 1 ? str_size : dest_size - 2;
/* copy */
bcopy(src, dest, copy_size);
/* set last character to null */
dest[dest_size - 1] = 0x00;
/* return to caller with number of characters copied */
return(copy_size);
}

The benifit of this is that all you do is give it the size of the
destination, and because it is using bcopy, it will handle strings that
overlap in memory.

It may be fast, but my system does not provide a bcopy() function...

#define bcopy(a,b,n) memmove(b,a,n)
 
C

Christian Bau

Jordan Abel said:
Daniel Rudy said:
Here's something that's really fast:

#include <strings.h>
#include <string.h>

int strscpy(char *dest, const char *src, int dest_size)
{
int str_size; /* size of string to be copied */
int copy_size; /* number of characters to copy */

/* get src string size */
str_size = strlen(src);
/* determine how much to copy */
/* str_size + 1 is based on strlen not including the terminating
null in the size of the string. remove it if your
implementation does */
copy_size = str_size + 1 < dest_size - 1 ? str_size : dest_size - 2;
/* copy */
bcopy(src, dest, copy_size);
/* set last character to null */
dest[dest_size - 1] = 0x00;
/* return to caller with number of characters copied */
return(copy_size);
}

The benifit of this is that all you do is give it the size of the
destination, and because it is using bcopy, it will handle strings that
overlap in memory.

It may be fast, but my system does not provide a bcopy() function...

#define bcopy(a,b,n) memmove(b,a,n)

Why would anyone define a macro that just calls memmove with its
arguments in the wrong order?
 
K

Keith Thompson

Christian Bau said:
What is bcopy? And what bright spark defined a copy function that has
its argument the other way round than the standard memcpy?

I think bcopy() and memcpy() are of comparable age (bcopy() may even
be older). Bcopy() just wasn't adopted by the ANSI committee.
 
F

Flash Gordon

Christian said:
Why would anyone define a macro that just calls memmove with its
arguments in the wrong order?

Possibly someone who learnt on BSD before memmove was standardised by
ANSI in 1989? bcopy being a "standard" BSD function.

Although looking at this thread
http://groups.google.co.uk/group/co...nk=st&q=bcopy+history&rnum=3#d2fe4a40b4fa421d
and what Chris Torek said in it, even assuming BSD you can't assume
correct handling of overlapping memory regions if using the "real" bcopy
instead of the suggested #define to provide it.

Of course, I would always recommend using the C standard functions
directly rather than using the old BSD functions and #defining them to
the C equivalent on systems that don't have them..
 
J

Jordan Abel

Jordan Abel said:
Here's something that's really fast:

#include <strings.h>
#include <string.h>

int strscpy(char *dest, const char *src, int dest_size)
{
int str_size; /* size of string to be copied */
int copy_size; /* number of characters to copy */

/* get src string size */
str_size = strlen(src);
/* determine how much to copy */
/* str_size + 1 is based on strlen not including the terminating
null in the size of the string. remove it if your
implementation does */
copy_size = str_size + 1 < dest_size - 1 ? str_size : dest_size - 2;
/* copy */
bcopy(src, dest, copy_size);
/* set last character to null */
dest[dest_size - 1] = 0x00;
/* return to caller with number of characters copied */
return(copy_size);
}

The benifit of this is that all you do is give it the size of the
destination, and because it is using bcopy, it will handle strings that
overlap in memory.

It may be fast, but my system does not provide a bcopy() function...

#define bcopy(a,b,n) memmove(b,a,n)

Why would anyone define a macro that just calls memmove with its
arguments in the wrong order?

Because the semantics thus provided are what the historical function
bcopy, whose existence, as I understand it, pre-dates memmove or memcpy,
does.
 
D

Daniel Rudy

At about the time of 1/5/2006 11:47 AM, Flash Gordon stated the following:
Possibly someone who learnt on BSD before memmove was standardised by
ANSI in 1989? bcopy being a "standard" BSD function.

Although looking at this thread
http://groups.google.co.uk/group/co...nk=st&q=bcopy+history&rnum=3#d2fe4a40b4fa421d
and what Chris Torek said in it, even assuming BSD you can't assume
correct handling of overlapping memory regions if using the "real" bcopy
instead of the suggested #define to provide it.

Of course, I would always recommend using the C standard functions
directly rather than using the old BSD functions and #defining them to
the C equivalent on systems that don't have them..

Now this is interesting because I code on a BSD system...FreeBSD to be
exact. So bcopy is not really a part of the standard? I wasn't aware of
that. The man page says the following:

BCOPY(3) FreeBSD Library Functions Manual
BCOPY(3)

NAME
bcopy -- copy byte string

LIBRARY
Standard C Library (libc, -lc)

SYNOPSIS
#include <strings.h>

void
bcopy(const void *src, void *dst, size_t len);

DESCRIPTION
The bcopy() function copies len bytes from string src to string
dst. The
two strings may overlap. If len is zero, no bytes are copied.

SEE ALSO
memccpy(3), memcpy(3), memmove(3), strcpy(3), strncpy(3)

HISTORY
A bcopy() function appeared in 4.2BSD. Its prototype existed
previously
in <string.h> before it was moved to <strings.h> for IEEE Std
1003.1-2001
(``POSIX.1'') compliance.

FreeBSD 6.0 June 4, 1993
FreeBSD 6.0


And for memmove(3):

MEMMOVE(3) FreeBSD Library Functions Manual
MEMMOVE(3)

NAME
memmove -- copy byte string

LIBRARY
Standard C Library (libc, -lc)

SYNOPSIS
#include <string.h>

void *
memmove(void *dst, const void *src, size_t len);

DESCRIPTION
The memmove() function copies len bytes from string src to string dst.
The two strings may overlap; the copy is always done in a
non-destructive
manner.

RETURN VALUES
The memmove() function returns the original value of dst.

SEE ALSO
bcopy(3), memccpy(3), memcpy(3), strcpy(3)

STANDARDS
The memmove() function conforms to ISO/IEC 9899:1990 (``ISO C90'').

FreeBSD 6.0 June 4, 1993
FreeBSD 6.0



So I guess if the standard section doesn't say that it conforms to some
standard, then it doesn't?

--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
D

Daniel Rudy

At about the time of 1/5/2006 2:27 AM, Flash Gordon stated the following:
Yes, it take absolutely no run time at all because it fails to compile.

Really?

strata:/home/dr2867/c/modules 1038 $$$ ->./compile strscpy.c strscpy.o
gcc -W -Wall -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes
-Wnested-externs -Wwrite-strings -Wfloat-equal -Winline -Wtrigraphs
-ansi -std=c89 -pedantic -ggdb3 -c -o strscpy.o strscpy.c

Seems to compile just fine on my system... FreeBSD 6.0-RELEASE

What if the buffer is larger than INT_MAX? Wouldn't size_t be more
appropriate for the size?

What the hell?

It was an EXAMPLE. Going beyond INT_MAX? Who the hell is going to pass
2GB text strings around in memory. Most machines don't HAVE 2GB RAM
installed. Granted, if need be I can use an unsigned long, but again
who is going to need it? I'll be very interesting in hearing your
answer reguarding real world applications..

About the bcopy function. I was not aware that it was not ISO C90.
Here's the corrected version that still uses int.


#include<string.h>

int strscpy(char *dest, const char *src, int dest_size);

int strscpy(char *dest, const char *src, int dest_size)
{
int str_size;
int copy_size;

str_size = strlen(src);
copy_size = str_size + 1 < dest_size - 1 ? str_size : dest_size - 2;
memmove(dest, src, copy_size);
dest[dest_size - 1] = 0x00;
return(copy_size);
}

Now your size_t version:

size_t strscpy(char *dest, const char *src, size_t dest_size);

size_t strscpy(char *dest, const char *src, size_t dest_size)
{
size_t str_size;
size_t copy_size;

str_size = strlen(src);
copy_size = str_size + 1 < dest_size - 1 ? str_size : dest_size - 2;
memmove(dest, src, copy_size);
dest[dest_size - 1] = 0x00;
return(copy_size);
}
In future, please post standard C answers not implementation specifics,
especially when there is a simple standard C way of doing the same
thing. We only deal with standard C here, not the BSD extensions, POSIX
extensions or Windows extensions.

As a programmer, I use what is available on the platform that I code on.
Because my software has to work in the real world, I have to code it so
that it is robust, safe, and secure. Granted, I am still learning, but
I'm doing quite well. I don't get may errors or warnings when my code
compiles. When I do get an error or warning, I track it down and fix it.

--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
K

Keith Thompson

Daniel Rudy said:
Now this is interesting because I code on a BSD system...FreeBSD to be
exact. So bcopy is not really a part of the standard? I wasn't aware of
that. The man page says the following:

BCOPY(3) FreeBSD Library Functions Manual
BCOPY(3) [snip]
HISTORY
A bcopy() function appeared in 4.2BSD. Its prototype existed
previously
in <string.h> before it was moved to <strings.h> for IEEE Std
1003.1-2001
(``POSIX.1'') compliance.
[...]
And for memmove(3):

MEMMOVE(3) FreeBSD Library Functions Manual
MEMMOVE(3) [...]
STANDARDS
The memmove() function conforms to ISO/IEC 9899:1990 (``ISO C90''). [...]
So I guess if the standard section doesn't say that it conforms to some
standard, then it doesn't?

Presumably, but that's really a question about man pages. If the man
pages are accurate, they *should* tell you what standard specifies a
function, but the only really reliable definition of what's in a
standard is the standard itself.

A draft document consisting of the C99 standard plus some later
additions is freely available; search for n1124.pdf.
 
C

Christian Bau

Daniel Rudy said:
At about the time of 1/5/2006 11:47 AM, Flash Gordon stated the following:

Now this is interesting because I code on a BSD system...FreeBSD to be
exact. So bcopy is not really a part of the standard? I wasn't aware of
that. The man page says the following:

You are posting on comp.lang.c. Only the C Standard is on-topic here.
FreeBSD or BSD or whatever is completely off-topic.

Furthermore, having a copying function that has its source and
destination arguments in the opposite order from the Standard C memcpy
and memmove and strcpy functions etc. is _dangerous_.
 
F

Flash Gordon

Daniel said:
At about the time of 1/5/2006 2:27 AM, Flash Gordon stated the following:


Really?

strata:/home/dr2867/c/modules 1038 $$$ ->./compile strscpy.c strscpy.o
gcc -W -Wall -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes
-Wnested-externs -Wwrite-strings -Wfloat-equal -Winline -Wtrigraphs
-ansi -std=c89 -pedantic -ggdb3 -c -o strscpy.o strscpy.c

Seems to compile just fine on my system... FreeBSD 6.0-RELEASE

Yes, really. I have multiple Windows boxes with different versions of MS
Visual Studio and MS Visual C++ (all of which include C compilers) and
*none* of them have the non-standard header you used.
What the hell?

It was an EXAMPLE. Going beyond INT_MAX? Who the hell is going to pass
2GB text strings around in memory. Most machines don't HAVE 2GB RAM
installed. Granted, if need be I can use an unsigned long, but again
who is going to need it? I'll be very interesting in hearing your
answer reguarding real world applications..

Some machines have had 16 bit ints, so that could be 32K. However, the
point is that if you are writing a replacement for a system function
then you should arbitrarily introduce a lower limit on what it can copy
with than the function it is to replace. After all, if you are trying to
write a safer alternative to a standard function is it really a good
thing to introduce another trap for the unwary?

One example, BTW, where one can sometimes end up dealing with very large
strings (larger than you expect), is when something like an RTF document
is stored in a database and the user chooses to be stupid and embed a
high resolution true-colour image in the header of the document (I know
this through experience or what *real* users do, and in our case the
application did *not* crash, but transferring the document over the
network was taking a very long time). If the non-standard 3rd-party DB
library gives it to you as a string and you then have to copy it
somewhere else for use by another non-standard third party library...

Now, it could be argued that the large RTF document should have been
rejected (although where do you place the limit?) but it is certainly
not acceptable (to me) to invoke undefined behaviour just because the
user has been even more stupid that I expect users to be.
About the bcopy function. I was not aware that it was not ISO C90.

Well, you do now.

As a programmer, I use what is available on the platform that I code on.

So do I, and I regularly use things that are not part of C but are
either extensions or third party libraries.
Because my software has to work in the real world, I have to code it so
that it is robust, safe, and secure.

Using a non-standard function when there is a perfectly good standard
function does not help in this. Using your alternative to strcpy or
using strlcpy (another extension) can assist, but that was not the case
here.

Admittedly you did not know bcopy was non-standard, but now you do. If
you've read the link I posted you will also know that there have been
version of bcopy that did *not* copy with overlapping source and
destination.
> Granted, I am still learning, but
I'm doing quite well. I don't get may errors or warnings when my code
compiles. When I do get an error or warning, I track it down and fix it.

It is also useful to know what is standard and what is not. This does
not mean don't use non-standard things, but when you are using them you
should know you are using them.

Personally I don't use any of the b* functions from BSD even when
programming on systems that provide them (which I do regularly) because
there are perfectly good alternatives that are part of the C standard.

Also, knowing what is standard helps you avoid having people complain at
you for using non-standard things in this group ;-)
 
M

Markus Becker

=======
If your man page considers this a bug, it is broken.

My doesn't say it's a bug. Where did you read that in my
posting?
This is not tedious and does not involve strlen(); it is called planning
ahead, a skill all programmers should have but astonishingly few do.

Some programming activity (in the real world) have to deal with
code already existing and 'proven to work, not to be touched,
but to be used..'.

Markus
 
K

Kenny McCormack

(someone else)
Some programming activity (in the real world) have to deal with
code already existing and 'proven to work, not to be touched,
but to be used..'.

Markus

And thus O/T here. As I posted many months ago here, the real world is O/T
in clc. Yes, you can Google for it.

P.S. To continue your thread of discussion - yes, in the real world, quite
often code cannot be fixed, because that would generate results that are
not consistent with the old results. And that would require you to admit
that the old results were wrong.
 
J

Jordan Abel

You are posting on comp.lang.c. Only the C Standard is on-topic here.
FreeBSD or BSD or whatever is completely off-topic.

Furthermore, having a copying function that has its source and
destination arguments in the opposite order from the Standard C memcpy
and memmove and strcpy functions etc. is _dangerous_.

says who? That's like saying that having an output function whose stream
argument is in a different place than fputc [say, fprintf] is dangerous.
you use a function, whether standard or an extension, you are expected
to learn that function. bcopy existed first anyway.
 
C

Christian Bau

Jordan Abel said:
You are posting on comp.lang.c. Only the C Standard is on-topic here.
FreeBSD or BSD or whatever is completely off-topic.

Furthermore, having a copying function that has its source and
destination arguments in the opposite order from the Standard C memcpy
and memmove and strcpy functions etc. is _dangerous_.

says who? That's like saying that having an output function whose stream
argument is in a different place than fputc [say, fprintf] is dangerous.
you use a function, whether standard or an extension, you are expected
to learn that function. bcopy existed first anyway.

Well, it is not in the C Standard, or is it?
 
K

Keith Thompson

Christian Bau said:
You are posting on comp.lang.c. Only the C Standard is on-topic here.
FreeBSD or BSD or whatever is completely off-topic.

Furthermore, having a copying function that has its source and
destination arguments in the opposite order from the Standard C memcpy
and memmove and strcpy functions etc. is _dangerous_.

says who? That's like saying that having an output function whose stream
argument is in a different place than fputc [say, fprintf] is dangerous.
you use a function, whether standard or an extension, you are expected
to learn that function. bcopy existed first anyway.

Well, it is not in the C Standard, or is it?

No, bcopy() is not in the C Standard (I thought we had established
that some time ago). I'm not sure what your point is.

There's nothing fundamentally wrong with bcopy(). A copying function
could sensibly take its arguments in either order; memcpy()'s order
mimics an assignment statement, while bcopy() arguably reflects the
direction in which the bytes are copied. And there are plenty of
examples of inconsistent parameter orders within the standard itself.

The ANSI standard committee had to pick either memcpy() or bcopy() for
inclusion in the standard (I *think* they both existed at the time).
Including both would have been redundant. The choice they made was,
as far as I know, arbitrary.

Some implementations still provide bcopy() for backward compatibility;
*all* conforming implementations provide memcpy(). There is no reason
to use bcopy() in new code -- not because of the order of its
parameters, but simply because it's less portable than memcpy().
 
N

Nils Weller

You are posting on comp.lang.c. Only the C Standard is on-topic here.
FreeBSD or BSD or whatever is completely off-topic.

Furthermore, having a copying function that has its source and
destination arguments in the opposite order from the Standard C memcpy
and memmove and strcpy functions etc. is _dangerous_.

says who? That's like saying that having an output function whose stream
argument is in a different place than fputc [say, fprintf] is dangerous.
you use a function, whether standard or an extension, you are expected
to learn that function. bcopy existed first anyway.

I find it very dangerous as well. I have made the mistake of assuming
dest,src argument order when using the BSD kernel function copyin() in
the past and the only thing that saved me was a compiler diagnostic
about the fact that the destination argument (which I had mistaken for
the source) was const-qualified but the functions parameter wasn't. :)

I'm just so used to dest,src that such mistakes can slip in no matter
how often I read the docs.

As for the fputc()/fprintf() order - at least you always get a crystal
clear diagnostic from the compiler if you swap those incorrectly (the
arguments to bcopy()/copyin()/copyinstr()/etc are pointers to void.)
 
J

Jordan Abel

You are posting on comp.lang.c. Only the C Standard is on-topic here.
FreeBSD or BSD or whatever is completely off-topic.

Furthermore, having a copying function that has its source and
destination arguments in the opposite order from the Standard C memcpy
and memmove and strcpy functions etc. is _dangerous_.

says who? That's like saying that having an output function whose stream
argument is in a different place than fputc [say, fprintf] is dangerous.
you use a function, whether standard or an extension, you are expected
to learn that function. bcopy existed first anyway.

I find it very dangerous as well. I have made the mistake of assuming
dest,src argument order when using the BSD kernel function copyin() in
the past and the only thing that saved me was a compiler diagnostic
about the fact that the destination argument (which I had mistaken for
the source) was const-qualified but the functions parameter wasn't. :)

I'm just so used to dest,src that such mistakes can slip in no matter
how often I read the docs.

That's your problem, not bcopy's or copyin's. The idea that it is
fundamentally dangerous is misplacement of blame - it's always easier to
blame the other guy's code.
 
N

Nils Weller

You are posting on comp.lang.c. Only the C Standard is on-topic here.
FreeBSD or BSD or whatever is completely off-topic.

Furthermore, having a copying function that has its source and
destination arguments in the opposite order from the Standard C memcpy
and memmove and strcpy functions etc. is _dangerous_.

says who? That's like saying that having an output function whose stream
argument is in a different place than fputc [say, fprintf] is dangerous.
you use a function, whether standard or an extension, you are expected
to learn that function. bcopy existed first anyway.

I find it very dangerous as well. I have made the mistake of assuming
dest,src argument order when using the BSD kernel function copyin() in
the past and the only thing that saved me was a compiler diagnostic
about the fact that the destination argument (which I had mistaken for
the source) was const-qualified but the functions parameter wasn't. :)

I'm just so used to dest,src that such mistakes can slip in no matter
how often I read the docs.

That's your problem, not bcopy's or copyin's. The idea that it is
fundamentally dangerous is misplacement of blame - it's always easier to
blame the other guy's code.

Who's blaming anyone's code? The point is that these families of
interfaces carry out an identical function yet take the opposite order
of arguments. I'm saying it is easy to mix those up if you use them
interchangably, and in fact it has happened to me. Seems likely it could
happen to many others as well. BTW, I never mix up the argument order of
fputc()/fprintf() because they are so different. Those families of data
copying functions (the Linux kernel uses dest,src for the equivalents as
well) are much more similar and thus easier to get wrong ...
 
W

websnarf

Its too bad the standard committee doesn't agree.
I suppose my presence in these c.l.c dialogs is a form of masochism but
...

I use gets() everyday!
Why?

[...] I think I get the "dangerous" message
from almost every make I do! Frankly, if I used a gets() alternative
to avoid the "danger" I'd probably end up using a strcpy()
with the same danger!

Again -- why?
You don't need to URL me to the "dangerous" explanation: I used
to design exploits myself. But the fact is, most of the programs I
write
are not for distribution and are run only on my personal machine,
usually with an impermeable firewall. Who's going to exploit me?
My alter ego? My 10-year old daughter? The input to my gets()
is coming from a file I or my software created, and which has
frequent line-feeds. The buffer into which I gets() is ten times
as big as necessary. If one of my data files gets corrupted,
diagnosing
the gets() overrun would be the least of my worries.

This explains why you are not worried about the downside (i.e., you
don't write software for other people to consume, and you have no
concern about the scalability of your software efforts) but it does not
explain what the *upside* of using gets() is.
I'll agree that such coding should be avoided in programs with
unpredictable
input, but there are *lots* and *lots* of code fragments that suffer
from the same "danger" as gets(), so to me the suggestion that gets()
specifically be barred by the compiler seems like a joke. Or do you
think strcpy() should be barred also?

Personally, of course, *I* do. Not just because its dangerous and
unmaintainable -- but because its slower, less functional, less
convenient, typically uses a larger memory footprint and would cause me
to write more code overall than my alternative of choice (I assume
y'all know what that is by now). Same applies to gets().
 
W

websnarf

Chuck said:
You have re-invented strlcpy, without some of the provisions
specified for its action. For details of this see:

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

At any rate, here is the heart code of my implementation. Notice
that it doesn't use the library at all, and thus is suitable for
embedded applications. Since it has to scan the length of the
source string it combines that with the actual transfer, for
noticeable efficiency improvement.

size_t strlcpy(char *dst, const char *src, size_t sz)
{
const char *start = src;

if (src && sz--) {
while ((*dst++ = *src))
if (sz--) src++;
else {
*(--dst) = '\0';
break;
}
}
if (src) {
while (*src++) continue;
return src - start - 1;
}
else if (sz) *dst = '\0';
return 0;
} /* strlcpy */

I am confused by this implementation of successive src tests. Are you
expecting it to be possible to set src = (char *) ((NULL) - (int)k) or
something? The chances that that means something on a platform seems
pretty low. Why wouldn't you just hoist out the "if (src)" test?
(Attention Edward G. Niles: use my second sentence to determine *WHY*
the C compiler cannot do the hoist automatically.)
 

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,951
Messages
2,570,113
Members
46,698
Latest member
alexxx

Latest Threads

Top