String handling in krb5

ghudson@MIT.EDU ghudson at MIT.EDU
Thu Oct 23 17:00:54 EDT 2008


Based on the excellent feedback in the previous discussion thread
(http://mailman.mit.edu/pipermail/krbdev/2008-October/006975.html) and
a survey of the current string handling code in krb5, we have arrived
at a tentative resolution.

First, we'll be recommending strdup, asprintf, and snprintf when they
are applicable.  I've added an SNPRINTF_OVERFLOW macro to
k5-platform.h.  It will be the recommended way to check for an
overflow from an snprintf result.  It avoids a signed/unsigned
comparison and handles the case of non-conforming snprintf
implementations returning -1 on overflow.

Second, we'll be changing the build system to ensure that strlcpy and
strlcat are available.  strlcpy will be recommended for simple copies
of a single string into a fixed-sized buffer, but strlcpy/strlcat will
also be an option for multi-step string construction if no other
options are desirable.

Third, we'll be introducing a string buffer module for internal use
only, which I'll call k5buf.  The idea is to allow multi-step string
construction within a dynamic or fixed-sized buffer, without requiring
an error check at each step.  Errors need only be checked when it is
time to retrieve the constructed value.  The 30-second API overview
is:

    void krb5int_buf_init_fixed(struct k5buf *buf, char *data, size_t size);
    void krb5int_buf_init_dynamic(struct k5buf *buf);
    void krb5int_buf_add(struct k5buf *buf, const char *data);
    void krb5int_buf_add_len(struct k5buf *buf, const char *data, size_t len);
    void krb5int_buf_truncate(struct k5buf *buf, size_t len);
    char *krb5int_buf_cstr(struct k5buf *buf); /* returns NULL on error */
    ssize_t krb5int_buf_len(struct k5buf *buf); /* returns -1 on error */
    void krb5int_free_buf(struct k5buf *buf); /* dynamic buffers only */

If a truncation or allocation failure happens, the buffer remembers
that it is in an error state and ignores subsequent modifications.
The caller will detect the failure when it calls krb5int_buf_cstr().

The k5buf module will typically only be used for the most complicated
cases of string construction which cannot be reduced to asprintf() or
snprintf() or simpler.  These cases are not terribly common; I found
20-25 of them in the code base during my survey.  k5buf is not
intended to become part of the krb5 API or part of the prototype of
any internal function (except maybe a static helper function here or
there).  It's a tool, not a way of life.

Here is what the coding practice section for string handling will look
like:

-----

Dynamically allocated buffers are preferred to fixed-sized
buffers.  When using dynamic buffers:

* Use strdup or asprintf for simple constructions.
* Use the k5buf module for complex constructions.  If this is not
  desirable, strlcpy and strlcat are valid alternatives.

When using fixed-sized buffers:

* Use strlcpy for simple copies.
* Use snprintf for simple compound constructions.  Avoid using
  precision or field width specifiers in snprintf format strings.
* To check for truncation when using snprintf, use the following
  approach:

    result = snprintf(buffer, sizeof(buffer), "format string", ...);
    if (SNPRINTF_OVERFLOW(result, sizeof(buffer))
        handle_overflow_error;

  The SNPRINTF_OVERFLOW macro is defined in k5-platform.h.
* Use the k5buf module for complex constructions.  If this is not
  desirable, strlcpy and strlcat are valid alternatives.



More information about the krbdev mailing list