Re: strcpy versus strncpy

der Mouse (mouse@RODENTS.MONTREAL.QC.CA)
Wed, 04 Mar 1998 09:56:56 -0500

> What's wrong with using the following [...]?
> It's not MT safe, but other than that I can't see any problems.

> char *sstrcpy(char *dst, size_t n, const char *src) {
> if (strlen(src) > (n - 1)) {

Can you count on src being NUL-terminated? If not, calling strlen on
it is unsafe; you could run off the end of VM and segfault.

> errno = ENOSPC;

This is exactly as thread-safe as errno itself is.

> return NULL;
> }
> strcpy(dst, src);
> dst[n - 1] = '\0';

This assignment is unnecessary, unless src was changed between the
strlen and the strcpy - and in that case, all alleged safety goes out
the window anyway.

> return dst;
> }

Aside from errno (and the caveat about src being changed asynchronously
wrt sstrcpy), I can't see any reason it wouldn't be fully thread-safe -
unless of course strlen or strcpy is somehow thread-unsafe.

Incidentally, a while ago strnlen was mentioned (I think it was on
bugtraq, though I could be misremembering), and I saw at least two
suggested implementations that amount to

int strnlen(const char *s, int maxlen)
{
const char *np;

np = memchr(s,0,maxlen);
return(np?np-s:maxlen);
}

This is not OK; memchr is allowed to access any subset it pleases of
the block of memory described by its first and third arguments.
strnlen should not access memory beyond the NUL, if there is one (or at
least it should behave "as if" that were the case; on some
architectures, for example, it may be possible to read multiple bytes
at once anyway).

If you still don't see how can it make a difference, consider this
example: suppose VM ends at 0x100000, and the arguments passed to
strnlen are 0xffff0 and 128, but there is a NUL present at 0xffff9.
memchr as called above would be within its interface contract to
segfault instead of returning 0xffff9, but strnlen wouldn't.

der Mouse

mouse@rodents.montreal.qc.ca
7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B