473,587 Members | 2,451 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

strlcpy and strlcat

I wrote these for a hobby project (I wanted to use them, but needed to
be able to build it on systems that don't have them), and it's probably
worth letting CLC rip them to shreds before I call them done.

They implement, modulo bugs, the behavior of the BSD strlcat and
strlcpy functions. Interestingly, the system I'm actually posting from
(SunOS 5.8) fails one of the tests at the bottom when it uses the
versions in the system library.

They're intended to be in the common subset of C90 and C99. Comments
on correctness and clarity are welcome; comments on style will be
tolerated.
dave
strl.h:
--------
#ifndef H_STRL
#define H_STRL

/*Implementation of BSD strlcat and strlcpy, for systems that don't have them.
Written by Dave Vandervies, December 2007.
Placed in the public domain; attribution is appreciated.
*/

#ifdef __cplusplus
extern "C" { /*make C++ compilers play nicely with the linker*/
#endif

#ifndef HAS_STRLFUNCS

/*strlcpy copies a string from src to dest, creating a string at most
maxlen bytes long (including the '\0' terminator).
Returns the length of the string that would be created without
truncation, excluding the '\0' terminator. (So if the return value
is >= maxlen, the result was truncated.)
*/
size_t my_strlcpy(char *dest,const char *src,size_t maxlen);

/*strlcat appends the contents of src to dest, creating a string at
most maxlen bytes long (including the '\0' terminator).
If src is already longer than maxlen bytes long, its contents
are not changed.
Returns the length of the string that would be created without
truncation, excluding the '\0' terminator, or maxlen+strlen(s rc)
if no '\0' is found within maxlen bytes of *dest. (So if the
return value is >= maxlen, the result was truncated.)
*/
size_t my_strlcat(char *dest,const char *src,size_t maxlen);

#ifndef CLC_PEDANTIC
#undef strlcpy
#define strlcpy my_strlcpy
#undef strlcat
#define strlcat my_strlcat
#endif /*CLC_PEDANTIC*/

#else /*HAS_STRLFUNCS*/
#include <string.h>
#endif /*HAS_STRLFUNCS*/

#ifdef __cplusplus
} /*close extern "C"*/
#endif

#endif /*H_STRL #include guard*/
--------
strl.c:
--------
#include <assert.h>
#include <string.h>

#include "strl.c"

/*Implementation of BSD strlcat and strlcpy, for systems that don't have them.
Written by Dave Vandervies, December 2007.
Placed in the public domain; attribution is appreciated.
*/

#ifndef HAS_STRLFUNCS

size_t my_strlcpy(char *dest,const char *src,size_t maxlen)
{
size_t len,needed;

#ifdef PARANOID
assert(dest!=NU LL);
assert(src!=NUL L);
#endif

len=needed=strl en(src)+1;
if(len >= maxlen)
len=maxlen-1;

memcpy(dest,src ,len);
dest[len]='\0';

return needed-1;
}

size_t my_strlcat(char *dest,const char *src,size_t maxlen)
{
size_t src_len,dst_len ;
size_t len,needed;

#ifdef PARANOID
assert(dest!=NU LL);
assert(src!=NUL L);
#endif

src_len=strlen( src);
/*Be paranoid about dest being a properly terminated string*/
{
char *end=memchr(des t,'\0',maxlen);
if(!end)
return maxlen+src_len;
dst_len=end-dest;
}

len=needed=dst_ len+src_len+1;
if(len >= maxlen)
len=maxlen-1;

memcpy(dest+dst _len,src,len-dst_len);
dest[len]='\0';

return needed-1;
}

#endif /*!HAS_STRLFUNCS */

#ifdef UNIT_TEST

#include <stdio.h>

/*
dj3vande@goofy: ~/clc (0) $ gcc -W -Wall -ansi -pedantic -O -DUNIT_TEST -ostrl strl.c
dj3vande@goofy: ~/clc (0) $ ./strl
strlcpy with truncation: Expect `hel'/5: `hel'/5
strlcat with truncation: Expect `help!'/9: `help!'/9
strlcpy without truncation: Expect `help!'/5: `help!'/5
strlcat without truncation: Expect `help!help!'/10: `help!help!'/10
strlcat with maxlen<strlen(d est): Expect `help!help!'/9: `help!help!'/9
dj3vande@goofy: ~/clc (0) $
*/

int main(void)
{
char buf1[256],buf2[256];
unsigned long ret;

#ifdef HAS_STRLFUNCS
#define my_strlcpy strlcpy
#define my_strlcat strlcat
printf("Using system library versions\n");
#endif

ret=my_strlcpy( buf1,"hello",4) ;
printf("strlcpy with truncation: Expect `hel'/5: `%s'/%lu\n",buf1,ret );

ret=my_strlcat( buf1,"p!!!!!",6 );
printf("strlcat with truncation: Expect `help!'/9: `%s'/%lu\n",buf1,ret );

ret=my_strlcpy( buf2,buf1,sizeo f buf2);
printf("strlcpy without truncation: Expect `help!'/5: `%s'/%lu\n",buf2,ret );

ret=my_strlcat( buf2,buf1,sizeo f buf2);
printf("strlcat without truncation: Expect `help!help!'/10: `%s'/%lu\n",buf2,ret );

ret=my_strlcat( buf2,buf1,4);
printf("strlcat with maxlen<strlen(d est): Expect `help!help!'/9: `%s'/%lu\n",buf2,ret );

return 0;
}

#endif /*UNIT_TEST*/
--------
Dec 6 '07 #1
9 6109
dj******@csclub .uwaterloo.ca.i nvalid wrote:
>
I wrote these for a hobby project (I wanted to use them, but
needed to be able to build it on systems that don't have them),
and it's probably worth letting CLC rip them to shreds before I
call them done.

They implement, modulo bugs, the behavior of the BSD strlcat and
strlcpy functions. Interestingly, the system I'm actually
posting from (SunOS 5.8) fails one of the tests at the bottom
when it uses the versions in the system library.

They're intended to be in the common subset of C90 and C99.
Comments on correctness and clarity are welcome; comments on
style will be tolerated.
Take a look at:

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

They are written to be compact and avoid any further use of the
standard library. This improves their usefullness where memory is
tight. I notice yours uses calls to strlen.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home .att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Dec 7 '07 #2
dj******@csclub .uwaterloo.ca.i nvalid wrote:

[...]
(Over 24 hours and only one response? I need to get my sigmonster set
up on this account, then at least Richard H will read my posts.)
I have seen your request, the main reason for not checking this deeper,
has been primary that those strl* interfaces has IMO a design weakness,
which I eliminated in my own implementation.

I think you should put more effort into your test function, perhaps even
provide some self test function with external linkage, at least use
EXIT_FAILURE in case one test case fail. Also, watching the output from
successful tests, can be tiresome in a big project.

I would remove PARANOID, using assert() isn't paranoid. :) The
CLC_PEDANTIC is not needed, we do know these functions invade the
reserved C name space, but the C committee wouldn't use these names for
something different.

The usage of #ifdef's should be minimized in source, and primary used in
header files instead. Because of all these macros, the code became more
hard-to-read, than it should have been.

I will post another followup, if I get time to write a test function
tomorrow.

--
Tor <bw****@wvtqvm. vw | tr i-za-h a-z>
Dec 9 '07 #3
In article <fj**********@r umours.uwaterlo o.ca>,
<dj******@csclu b.uwaterloo.ca. invalidwrote:
>If the inputs are well-formed neither implementation will ever create
an improperly terminated string.
On second thought, the conditional is irrelevant there; neither
implementation will ever change the contents of memory UNLESS the
inputs are well-formed, in which case the new contents of the
destination buffer will be a properly terminated string.
dave
(needs coffee, or sleep, or both)

Dec 9 '07 #4
dj******@csclub .uwaterloo.ca.i nvalid said:

<snip>
(Over 24 hours and only one response? I need to get my sigmonster set
up on this account, then at least Richard H will read my posts.)
You know me too well, Dave.

--
Richard Heathfield <http://www.cpax.org.uk >
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Dec 9 '07 #5
In article <47************ ***@yahoo.com>,
CBFalconer <cb********@mai neline.netwrote :
>dj******@csclu b.uwaterloo.ca. invalid wrote:
>If the dest argument to strlcat does not in fact point to a correctly
terminated string, the BSD implementation will stop looking for a '\0'
after maxlen bytes. This avoids walking through large amounts of
memory (only to read - it wouldn't be written in any case) when it's
given bad input.

I would argue that my technique is better. It will normally cause
an immediate fault during the call, which should leave traces as to
the cause, and be repairable.
Only if it hits unreadable memory and causes a read trap before it
finds a zero byte. I'd expect it to find a zero byte and give
completely bogus results more often than it would cause a trap.

I don't think either is obviously better in general. If you're using
them to make it easier to write safe code (the original motivation for
adding them in OpenBSD, if I'm not mistaken) it makes sense to give
slightly wrong results for incorrect inputs in return for the added
safety, but if you're just treating them as string operations that do
what strncpy and strncat look like they should do, getting the
"expected" result from strlcat when the destination string is longer
than the maxlen argument is probably worth the cost of getting
completely wrong results or maybe a memory protection trap when the
destination string isn't properly terminated.
dave

Dec 10 '07 #6
dj******@csclub .uwaterloo.ca.i nvalid wrote:
CBFalconer <cb********@mai neline.netwrote :
>dj******@csclub .uwaterloo.ca.i nvalid wrote:
>>If the dest argument to strlcat does not in fact point to a
correctly terminated string, the BSD implementation will stop
looking for a '\0' after maxlen bytes. This avoids walking
through large amounts of memory (only to read - it wouldn't be
written in any case) when it's given bad input.

I would argue that my technique is better. It will normally
cause an immediate fault during the call, which should leave
traces as to the cause, and be repairable.

Only if it hits unreadable memory and causes a read trap before
it finds a zero byte. I'd expect it to find a zero byte and give
completely bogus results more often than it would cause a trap.
True. The 'read onward' has at least a chance of blowing on a bad
call. However, the 'stop after maxlen' just gives the 'destination
too small' response, and no sign of a basic error. The natural
reaction is to increase the destination size, and try again. Still
fails (maybe). At any rate, C programmers should be used to having
dire things happen when failing to pass strings to things expecting
strings.

--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home .att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Dec 10 '07 #7
Tor Rustad wrote:
dj******@csclub .uwaterloo.ca.i nvalid wrote:
.... snip ...
>>
Out of curiousity, what is that design weakness, and how did you
fix it?

Many will not check the return value for truncation. There are
cases where this is not a bug, but most of the cases it will be,
and strl* may hurt matters by hiding it.
I gather you consider failing to check the return value is OK and
that writing on unowned (or nonexistant) memory is prefereable to
truncation?

--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home .att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Dec 10 '07 #8
CBFalconer wrote:
Tor Rustad wrote:
>dj******@csclub .uwaterloo.ca.i nvalid wrote:
.... snip ...
>>Out of curiousity, what is that design weakness, and how did you
fix it?
Many will not check the return value for truncation. There are
cases where this is not a bug, but most of the cases it will be,
and strl* may hurt matters by hiding it.

I gather you consider failing to check the return value is OK and
that writing on unowned (or nonexistant) memory is prefereable to
truncation?
Very odd conclusion, what did you think *fail safe* meant?

--
Tor <bw****@wvtqvm. vw | tr i-za-h a-z>
Dec 11 '07 #9
Tor Rustad wrote:
CBFalconer wrote:
>Tor Rustad wrote:
>>dj******@csclub .uwaterloo.ca.i nvalid wrote:
.... snip ...
>>>Out of curiousity, what is that design weakness, and how did you
fix it?

Many will not check the return value for truncation. There are
cases where this is not a bug, but most of the cases it will be,
and strl* may hurt matters by hiding it.

I gather you consider failing to check the return value is OK and
that writing on unowned (or nonexistant) memory is prefereable to
truncation?

Very odd conclusion, what did you think *fail safe* meant?
I came to this conclusion when you recommend not checking the
returned value, which means you cannot detect an undersized
buffer. Either you are using strlcpy and the result is truncated,
or you are using strcpy (or equivalent) and the result is
overwriting. I am not forgiving failure to check the returned
value.

If I am way off please elucidate. Of course strlcpy can't
auto-expand the destination, since it has to operate into arbitrary
buffers.

--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home .att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Dec 11 '07 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

37
8506
by: Shri | last post by:
hi all, i am writing a code in which i have a char buffer "cwdir" which hold the current working directory by calling the function getcwd(). later i change the directory to "/" as i have to make my code Deamon. and later again i want to run some other executable available at the path holded by the "cwdir" using the system() system call....
11
4092
by: Trevor | last post by:
If I have a string that should be NULL terminated, is it good practice to use "sizeof(str)" or "sizeof(str) - 1" when using a function like strncpy? If I have a 'string' that should NOT be NULL terminated, is it good practice to use "sizeof(str) - 1" or "sizeof(str)" when using a function like strncpy? Is this function bug-free? void...
5
2640
by: Aleksandar Milivojevic | last post by:
I had to write implementation of strlcat() (some source from Microsoft I got was using it, and strlcat/strlcpy doesn't exist in my libc). Two quick questions. If NULL is not encountered in first _size_ bytes of _dst_, should strlcat() return _size_ + strlen(_src_), or should it return _size_? Some manual pages I found were not exactly...
81
7263
by: Matt | last post by:
I have 2 questions: 1. strlen returns an unsigned (size_t) quantity. Why is an unsigned value more approprate than a signed value? Why is unsighned value less appropriate? 2. Would there be any advantage in having strcat and strcpy return a pointer to the "end" of the destination string rather than returning a
11
385
by: Vaddina Prakash Rao | last post by:
Good morning everyone, Can someone comment what is wrong with these statements .. #include <stdio.h> #include <stdlib.h> #include <string.h> main() { char *final, *s="abcdefghij"; int count = 9;
27
2209
by: Andreas Klimas | last post by:
Hello, does anybody know about a standardfunction or a simpler way to get this result. int ends_with(char *string, char *has); answer whether string ends with substring has or not.
6
2452
by: RoSsIaCrIiLoIA | last post by:
d_0=32.000000 d_1=38.000000 Test success d_0=34.000000 d_1=42.000000 Test success d_0=1.000000 d_1=0.000000 Test success
2
2776
by: nano2 | last post by:
Hi all, I have the following scenario but strlcpy is not supported in GCC4.1 and that's the C compiler i am using . Does anyone know of a similar way this canbe achieved .. if (strlcpy(addr.spath, options.cpath, sizeof(addr.spath)) >= sizeof(addr.spath)
59
2777
by: BigRelax | last post by:
Hello`` I am a student from chinese. I like C. -- Message posted using http://www.talkaboutprogramming.com/group/comp.lang.c/ More information at http://www.talkaboutprogramming.com/faq.html
0
7920
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7849
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
8215
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
8347
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
0
6626
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5718
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
3844
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3879
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1189
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.