Re: [Code] Strange error.

From: Thomas Arp (t_arp@stofanet.dk)
Date: 01/10/03


From: "The Fungi" <fungi@yuggoth.org>
> On Fri, Jan 10, 2003 at 12:10:37PM -0600, Ronald Fenner wrote:
> > sprintf(temp, "\r\n    &c%s list&n\r\n", guild_types[i]);
> > strcat(buf, temp);
>
> The method I've been using is:
>
>    len += snprintf(buf + len, sizeof(buf) - len,
>     "\r\n    &c%s list&n\r\n", guild_types[i]);
>
> Which will ensure that you never overflow buf so long as you always
> keep len == sizeof(buf), might not even be a bad idea to assert()
> that if there are general-use functions doing this that you're
> afraid your developers might misuse.

Actually the snprintf statement itself will never overflow, period.

len will only be added to if space is left in the string for writing.
Putting in an assert() would be pointless, unless you're doing some
manual additions beside the snprintf().

> A friend of mine even suggested
> making a struct, maybe called checked_string, that associates an int
> for "len" with a fixed-size string.

Making further structs is only necessary if you wish the buffer to
be inherited into the functions below it, and only then if you don't
wish to add a size_t argument to the function.

To illustrate:

void foo(char *buf, size_t max_len) {
  size_t len;
  int i = 10;

  len = snprintf(buf, max_len, "foo list:\r\n");
  while (i--)
    len += snprintf(buf + len, max_len - len, " foo %d\r\n", i);
}

void bar(void) {
  char buffer[100];

  foo(&buffer, sizeof(buffer));

}

The function foo() will never overflow the buffer, since it is passed
the maximum length available. Adding a checked string struct as you
suggested would alter the appearance, but the functionality is about
the same[1]:

typedef struct {
  char *buffer;
  size_t max_len;
} string; /* or checked_string, or whatever */

string *new_string(size_t max_len) {
  string *new;

  CREATE(new, string, 1);
  CREATE(new->buffer, char, max_len);
  new->max_len = max_len;

  return new;
}

void free_string(string *str) {
  if (str->buffer)
    free(str->buffer);
  free(str);
}

void foo(string *str) {
  size_t len;
  int i = 10;

  len = snprintf(str->buffer, str->max_len, "foo list:\r\n");
  while (i--)
    len += snprintf(str->buffer + len, str->max_len - len, " foo %d\r\n",
i);
}

void bar(void) {
  string *str = new_string(100);

  foo(str);

  free_string(str);
}

The only advantage to this approach, as far as I can see, is not
having to make sure you pass the size parameter along with the
char pointer. The downside is having to free_string() all of the
allocated strings.

Welcor

[1] I added the general string handling routines. Everything here
    is mailer code and may not work if compiled.

--
   +---------------------------------------------------------------+
   | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
   | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
   | Newbie List:  http://groups.yahoo.com/group/circle-newbies/   |
   +---------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 06/26/03 PDT