bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: string types


From: Tim Rühsen
Subject: Re: string types
Date: Mon, 6 Jan 2020 11:34:35 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.3.1


On 12/31/19 10:53 AM, Bruno Haible wrote:
> Hi Tim,
> 
>>>   - providing primitives for string allocation reduces the amount of buffer
>>>     overflow bugs that otherwise occur in this area. [1]
>>> [1] https://lists.gnu.org/archive/html/bug-gnulib/2019-09/msg00031.html
> 
>> here is a string concatenation function without ellipsis, analogue to
>> writev() and struct iovec - just a suggestion. Instead of 'struct
>> strvec' a new string_t type would be handy.
>>
>> #include <stddef.h>
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <string.h>
>>
>> struct strvec {
>>   char *strv_base;
>>   size_t strv_len;
>> };
>>
>> __attribute__ ((nonnull (1)))
>> char *concat_stringv(const struct strvec *strv)
>> {
>>   const struct strvec *str;
>>   size_t len = 0;
>>   char *buf;
>>
>>   for (str = strv; str->strv_base; str++)
>>     len += str->strv_len;
>>
>>   if (!(buf = malloc(len + 1)))
>>     return buf;
>>
>>   len = 0;
>>   for (str = strv; str->strv_base; len += str->strv_len, str++)
>>     memcpy(buf + len, str->strv_base, str->strv_len);
>>
>>   buf[len] = 0;
>>
>>   return buf;
>> }
>>
>> void main(void)
>> {
>>   char *s = concat_stringv((struct strvec []) {
>>     { "a", 1 },
>>     { "b", 1 },
>>     { NULL }
>>   });
> 
> This looks good. It brings us one step closer to the stated goal [1].
> 
> Would you like to contribute such a 'string-alloc' module that, together with
> 'strdup' and 'asprintf', removes most needs to create a string's contents
> "by hand"?

When time allows, I would like to make up a module.

Though IMO the design of the function doesn't allow to reuse an existing
buffer (e.g. a scratch buffer on the stack). Since malloc() etc are
pretty costly, you often want to avoid it as much as possible.

Like e.g.

/* Use given stack buffer, fallback to malloc() if too short */
char sbuf[256];
char *s = concat_stringv_stack(sbuf, sizeof (sbuf), (struct strvec []) {
    { "a", 1 },
    { "b", 1 },
    { NULL }
  });

... do things with s ...

if (s != sbuf)
  free (s);

Sometimes you want to reuse an existing malloc'ed buffer:

/* Use existing heap buffer, use realloc() if too short */
char *buf = malloc(N);
char *buf = concat_stringv_reuse(buf, N, (struct strvec []) {
    { "a", 1 },
    { "b", 1 },
    { NULL }
  });

... do things with s ...

free (buf);

You might also be interested in the size of the created string to avoid
a superfluous strlen(). So the need for more specialized functions makes
it all more and more complex.

During the development of Libwget/Wget2 we needed all of the above (and
more) and finally came up with a good compromise (well, good for us).

We created a 'catch them all' string/buffer type plus API. It is a good
compromise for all kinds of situations, works like a memory buffer but
is guaranteed 0-terminated, allows custom stack buffers with fallback to
heap if to small.

$ cloc buffer.c
Language             files          blank        comment           code
-----------------------------------------------------------------------
C                        1             49            327            195

https://gitlab.com/gnuwget/wget2/blob/master/libwget/buffer.c


There also is a sprintf functionality (glibc compatible) using these
buffers - and the operation is well faster than glibc's sprintf-like
functions for all format strings tested (tested back a few years). The
code is also much smaller (380 C code lines), the return values are
size_t. It doesn't support float/double.

$ cloc buffer_printf.c
Language             files          blank        comment           code
-----------------------------------------------------------------------
C                        1             74            120            380

https://gitlab.com/gnuwget/wget2/blob/master/libwget/buffer_printf.c

If there is serious interest, I could prepare modules for gnulib.


Regards, Tim

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]