strncpy() fails to copy

D

David Resnick

Ah fair enough.  So strncpy is full of failure for MULTIPLE reasons.
That's impressive.

char *strncpy(char *dest, const char *src, size_t n)
{
   char *tmp = dest;
   while (*src && n-- > 1) {
      *dest++ = *src++;
   }
   *dest = 0;
   return tmp;

}

Is that really that hard?

Tom

Given a choice, I'd personally rather use a standard library function
for a task where one is available and works. Might be more efficient
in some way, use assembly/etc. And everyone knows what it is without
looking at it. Your function is called "strncpy" but doesn't do what
the standard requires of the function named that. I wish the
requirements said strncpy does what your function above does. But
they don't.

-David
 
T

Tom St Denis

Given a choice, I'd personally rather use a standard library function
for a task where one is available and works.  Might be more efficient
in some way, use assembly/etc.  And everyone knows what it is without
looking at it.  Your function is called "strncpy" but doesn't do what
the standard requires of the function named that.  I wish the
requirements said strncpy does what your function above does.  But
they don't.

If I had the time I'd just implement that as a "safe_strncpy" and
replace all calls to strncpy with it in my app. As shipment is coming
up soon I'd rather not, so I make due...

What would be cooler is to just suck it up and fix strncat/strncpy
broken apps be damned. Too much legacy shit gets propagated because
inept committees come up with designs.

Tom
 
D

David Resnick

If I had the time I'd just implement that as a "safe_strncpy" and
replace all calls to strncpy with it in my app.  As shipment is coming
up soon I'd rather not, so I make due...

What would be cooler is to just suck it up and fix strncat/strncpy
broken apps be damned.  Too much legacy shit gets propagated because
inept committees come up with designs.

Tom

Existing strncpy has some legitimate use. For example, if you are
sending a fixed size buffer over a wire, using strncpy is correct if
you do want to 0 out the rest of the buffer, and you may not care
about nul terminating either where your string exactly fills the
region. May be the right thing for database fields as well. Fringe
uses perhaps. But it is not unreasonable to expect that the semantics
of your existing standard library functions will not change when you
upgrade your library. I'd go for adding the strlxxx family and
depricating the old ones myself rather than screwing over people
correctly using the existing functions.

-David
 
K

Keith Thompson

Tom St Denis said:
What happens here?

It appears that servIP is allocated immediately after myport in memory.

Also the correct usage of strncpy [sadly] is this

memset(dest, 0, sizeof dest);
strncpy(dest, src, sizeof(dest) - 1);

Which is really F'ing stupid IMHO. A call to strncpy(dest, src,
sizeof dest) should guarantee that dest is NUL terminated...

It's not a bug, it's a feature. No, really.

strncy's source buffer is expected to contain an ordinary C string,
consisting of a sequence of non-null characters terminated by and
including a null character (with zero or more bytes of ignored
garbage following the terminator).

The target buffer, however, contains a data structure that's similar
to a C string, but subtly different. It consists of a sequence of
non-null characters foolowed by zero or more null characters, padding
to the end of the buffer. If there are one or more terminating
null characters, this can be treated as a string; if not, it can't.

This data structure is not used very often, but it is used sometimes,
which is why strncpy() exists. For example, I believe that early
Unix systems used it to store file names.

The real problem is that the name strncpy() implies that it has the
same relationship to strcpy() that strncat() has to strcat() (namely
that strncat() is a "safer" version of strcat() that lets you specify
the maximum size of the destination buffer). But strncpy() is *not*
a safer strcpy(); it's a function that does something similar,
but in a way that makes it very easy to shoot yourself in the foot.

If you don't specifically need to deal with this particular data
structure, don't use strncpy(). (Most programmers can safely ignore
all but the last three words of that sentence.)

It would have been nice if we had a standard strncpy() function
that actually does what a lot of people expect it to do, and if
the strncpy() we have were either given a different name or removed
from the standard. But it's about 20 years too late for that.

[...]
N.B. The man page for strncpy in Ubuntu has a typo ... the string is
nul terminated not null ... :)

That's not a typo; "null terminated" is correct. ("nul terminated"
would also be correct.) It means that the string is terminated
by a null character, a term used by the C standard. (The man page
uses the term "null byte", which is also valid.)
 
K

Keith Thompson

Tom St Denis said:
What would be cooler is to just suck it up and fix strncat/strncpy
broken apps be damned. Too much legacy shit gets propagated because
inept committees come up with designs.

That would break the (few) applications that use strncpy *correctly*
for the narrow purpose for which it was designed.

As I said elsethread, the main problem with strncpy() is its misleading
name.
 
K

Keith Thompson

Tom St Denis said:
The character '\0' is not a NULL it's NUL as in ASCII zero.

Correct. Fortunately, the man page doesn't mention NULL.
NULL in most programming contexts means a pointer,

In particular, that's what it means in C.
'null' [lower case]
means an empty set. 'nul' means the zero char [or terminator].

C doesn't have a set data type, and "null" doesn't *only* refer to
the empty set. "null" is widely used in the C standard to refer
to both "null pointers" and "null characters". There is nothing
wrong with the man page's use of the term.
 
B

Ben Bacarisse

Tom St Denis said:
On Sep 14, 11:02 am, Ben Bacarisse <[email protected]> wrote:
Not sure what you mean now.  My Ubuntu man page (for strncpy) has no
"nul" in it at all -- it looks fine to me.

The character '\0' is not a NULL it's NUL as in ASCII zero.

NULL in most programming contexts means a pointer, 'null' [lower case]
means an empty set. 'nul' means the zero char [or terminator].

Using NULL would be wrong, but the page does not do that. Advocating
the use of the lowercase version of the abbreviated ASCII name ('nul')
seems to me perverse. The character defined by ANSI X3.4-1963 is called
NULL in the original table (with an annotation "Null/Idle") and the name
Null persists right into ISO 640. The three-letter names (like NUL and
BEL) are abbreviations; not the real names of the characters.

In C, '\0' is the null character. Strings are "null terminated" or have
a "terminating null character". This is both common usage and the
language used in the C standard. I can't see any reason to object to
it.
 
T

Tom St Denis

That would break the (few) applications that use strncpy *correctly*
for the narrow purpose for which it was designed.

As I said elsethread, the main problem with strncpy() is its misleading
name.

Fair enough and I appreciate you taking the time to explain it.
Thanks.

Tom
 
S

Shao Miller

Rich said:
... ... ...
A better function to uses is strncat, it has much more useful
semantics.
dest[0] = '\0';
strncat(dest, src, sizeof(dest));

will handle the problem perfectly..

Or
strncpy(dest, src, LEN_DEST)[LEN_DEST - 1] = '\0';

Wouldn't sizeof(dest) be the size of a pointer to char?

Perhaps it depends on the type of 'dest'. If 'dest' in the example was
an array, 'sizeof dest' would return the number of bytes in the array.
If 'dest' in the example was a pointer, then 'sizeof dest' would return
the number of bytes in the pointer.
 
J

Jeffrey Walton

What happens here?
It appears that servIP is allocated immediately after myport in memory.

Also the correct usage of strncpy [sadly] is this

memset(dest, 0, sizeof dest);
strncpy(dest, src, sizeof(dest) - 1);

Which is really F'ing stupid IMHO.  A call to strncpy(dest, src,
sizeof dest) should guarantee that dest is NUL terminated...
strcpy_s. The safe string functions were standardized in ISO/IEC TR
24731 and guarantees NULL termination. But the Linux gate keepers
refuse to incorporate them into the runtimes (yet another Ulrich
Drepper controversy).

In the meantime, the Linux crowd should use the following (taken from
Apple's Secure Coding Guide [1], p 38):
strcat -> strlcat
strcpy -> strlcpy
strncat -> strlcat
strncpy -> strlcpy
sprintf -> snprintf
vsprintf -> vsnprintf
gets -> fgets

[SNIP]

Jeff

[1] http://developer.apple.com/documentation/Security/Conceptual/SecureCodingGuide/SecureCodingGuide.pdf
 
I

Ian Collins

strcpy_s. The safe string functions were standardized in ISO/IEC TR
24731 and guarantees NULL termination. But the Linux gate keepers
refuse to incorporate them into the runtimes (yet another Ulrich
Drepper controversy).

I don't think a non-normative technical report counts as standardisation.

If I remember correctly, the POSIX group didn't think much of them
either. They certainly don't appear in the standard library on any Unix
system I know.
 
P

Peter Nilsson

David Resnick said:
Again, because strncpy has a design second flaw for
general purpose string usage,

The fact that the specs and usage don't match your
expectation does not mean it is a design flaw. Note
that %s does not require a terminated string if a
precision is specified. Also note that strncmp does
not require null terminated strings. So one could
argue that it's actually strncat that is the irregular
function, not strncpy!
that it internally does a stupid memset that can be
QUITE costly if the target buffer is big and the
string to be copied is small.

The flaw, if any, is that you cannot choose the padding
character.
 
N

Nick Keighley

So as you correctly pointed out (and David Resnick got wrong) you need
to -1 the sizeof of the buffer.
Yep, oops.  Don't use either much at this point.  Still thing strncpy
is awful tho.
Since you still have to use -1 on strncat how is it any different than
dest[sizeof(dest)-1] = 0;
strncpy(dest, src, ...);
It's basically the same code at that point.
It'd be nice if all strn*() functions guaranteed that within n-bytes
of the dest there is a NUL and just truncate as required.  But that
would require a bit of forethought on the standard C library designers
part.
Tom
Again, because strncpy has a design second flaw for general purpose
string usage, that it internally does a stupid memset that can be
QUITE costly if the target buffer is big and the string to be copied
is small.
In my current app I'm more worried about buffer overflows or corrupt
[uninitialized] strings than a few microseconds of performance.
But as I said you *could* just set the n-1'th byte to 0 and get the
same effect.

I guess I somehow wasn't thinking about your current app (how could I
have been?), but rather was making a general point that the semantics
of strncpy make it unwise to use.  I put it down there in the category
of functions like strtok that I avoid in any real program.  But YMMV.

the point about strncpy() is that isn't really a string function. Its
designed to operate on fixed length char arrays, things that I believe
were common on early unix systems. It doesn't do what you think it
does so read the documentation and use it when it does what you want
(hardly ever!).

If you want a limited strcpy() then write your own ncpystr() or
whatever. You could have written an entire string library in the time
you've spent debating strncpy()
 
J

Jeffrey Walton

What happens here?
It appears that servIP is allocated immediately after myport in memory.

Also the correct usage ofstrncpy[sadly] is this

memset(dest, 0, sizeof dest);strncpy(dest, src, sizeof(dest) - 1);

Which is really F'ing stupid IMHO.  A call to strncpy(dest, src,
sizeof dest) should guarantee that dest is NUL terminated...
strcpy_s. The safe string functions were standardized in ISO/IEC TR
24731 and guarantees NULL termination. But the Linux gate keepers
refuse to incorporate them into the runtimes (yet another Ulrich
Drepper controversy).

In the meantime, the Linux crowd should use the following (taken from
Apple's Secure Coding Guide [1], p 38):
strcat -> strlcat
strcpy -> strlcpy
strncat -> strlcat
strncpy -> strlcpy
sprintf -> snprintf
vsprintf -> vsnprintf
gets -> fgets

[SNIP]

My apologies if this received twice.Google Groups seems to be having
more technical difficulties.

Jeff

[1] http://developer.apple.com/documentation/Security/Conceptual/SecureCodingGuide/SecureCodingGuide.pdf
 
P

Peter Nilsson

People's desire to use functions without reading the specs
is also an impressive failure for multiple reasons.

What would be cooler is to just suck it up and fix
strncat/strncpy broken apps be damned.

You seem to mean working apps be damned too.
Too much legacy shit gets propagated because inept
committees come up with designs.

Neither C nor the vast majority of the Standard Library
were designed by WG14. That wasn't their job.
 
E

Edward A. Falk

You seem to mean working apps be damned too.

Maybe he means working apps that would *become* broken
apps.

Changing the behavior of these functions would be a
support catastrophe of the first order. We'd be finding
and fixing broken apps for decades.

But creating *new* functions, e.g. strlcat/strlcpy would
be an excellent solution. Remember, though, that nobody
would dare use them until they were in libc and installed
on 100% of the machines in the wild.
 
J

Jeffrey Walton

I don't think a non-normative technical report counts as standardisation.
Agreed. ISO/IEC TR 24731 is a Technical Report of type 2. ... [without
an] immediate possibility of an agreement on an International Standard
[1].
If I remember correctly, the POSIX group didn't think much of
them either.
Its unfortunate that a safer, near drop in replacement was punned. But
POSIX comes up with some brain dead ideas. For example, assert calls
SIGABRT. The behavior has many developers either (1) not using asserts
or (2) commenting out useful asserts because they can't continue when
an assert fires (and are too lazy to look up how to install a new
handler). I would argue that an assert, as a debug tool, would be much
more useful if it raised a SIGTRAP so that default behavior would be a
console message without a debugger, and a break under a debugger. I'd
go out on a limb and claim that SIGTRAP should be default behavior.

But hey, what do I know? Linus is a bastard who has a strong dislike
or hatred for debuggers [2], thinks GCC is crap because it warns a
programmer who erroneously compares an unsigned to less than zero [3],
and who many folks blindly follow because its 'Linus'.
 They certainly don't appear in the standard library on any
Unix system I know.
Again unfortunate. I'm a big fan of a unified code base, which I don't
have because of the controversies and pissing contests. And on Linux,
I'm no closer to a set of safe string functions. Crashing and calling
perror() leaves something to be desired for me.

Jeff

[1] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1172.pdf
[2] http://lkml.indiana.edu/hypermail/linux/kernel/0009.0/1148.html
[3] http://linux.derkeiler.com/Mailing-Lists/Kernel/2006-11/msg08316.html
 
I

Ian Collins

I don't think a non-normative technical report counts as standardisation.
Agreed. ISO/IEC TR 24731 is a Technical Report of type 2. ... [without
an] immediate possibility of an agreement on an International Standard
[1].
If I remember correctly, the POSIX group didn't think much of
them either.
Its unfortunate that a safer, near drop in replacement was punned. But
POSIX comes up with some brain dead ideas.

The preferred fixing problems rather than papering over them with
Elastoplast functions.
For example, assert calls
SIGABRT. The behavior has many developers either (1) not using asserts
or (2) commenting out useful asserts because they can't continue when
an assert fires (and are too lazy to look up how to install a new
handler).

If developers are this slack, they deserve all they get.
I would argue that an assert, as a debug tool, would be much
more useful if it raised a SIGTRAP so that default behavior would be a
console message without a debugger, and a break under a debugger. I'd
go out on a limb and claim that SIGTRAP should be default behavior.

Which is exactly what an abort does on every system I've used.
But hey, what do I know? Linus is a bastard who has a strong dislike
or hatred for debuggers [2], thinks GCC is crap because it warns a
programmer who erroneously compares an unsigned to less than zero [3],
and who many folks blindly follow because its 'Linus'.

What does Linus have to do with POSIX?
Again unfortunate. I'm a big fan of a unified code base, which I don't
have because of the controversies and pissing contests. And on Linux,
I'm no closer to a set of safe string functions. Crashing and calling
perror() leaves something to be desired for me.

You could easily write your own.
 

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
474,083
Messages
2,570,591
Members
47,212
Latest member
RobynWiley

Latest Threads

Top