From 4d248b37278ffd09d5322196fdec5cf708349f4a Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Tue, 28 Oct 2008 15:34:29 +0000 Subject: [PATCH] Add the k5buf string module to libkrb5support ticket: 6200 status: open git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20929 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/k5-buf.h | 117 +++++++++ src/include/k5-int.h | 3 + src/util/support/Makefile.in | 25 +- src/util/support/k5buf-int.h | 51 ++++ src/util/support/k5buf.c | 144 +++++++++++ src/util/support/libkrb5support-fixed.exports | 8 + src/util/support/t_k5buf.c | 238 ++++++++++++++++++ 7 files changed, 585 insertions(+), 1 deletion(-) create mode 100644 src/include/k5-buf.h create mode 100644 src/util/support/k5buf-int.h create mode 100644 src/util/support/k5buf.c create mode 100644 src/util/support/t_k5buf.c diff --git a/src/include/k5-buf.h b/src/include/k5-buf.h new file mode 100644 index 000000000..2fe1d1d89 --- /dev/null +++ b/src/include/k5-buf.h @@ -0,0 +1,117 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * include/k5-buf.h + * + * Copyright 2008 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * k5buf string buffer module interface + */ + +#ifndef K5_BUF_H +#define K5_BUF_H + +#if defined(_MSDOS) || defined(_WIN32) +#include +#endif +#ifndef KRB5_CALLCONV +#define KRB5_CALLCONV +#define KRB5_CALLCONV_C +#endif + +#include +#include + +/* The k5buf module is intended to allow multi-step string + construction in a fixed or dynamic buffer without the need to check + for a failure at each step (and without aborting on malloc + failure). If an allocation failure occurs or if the fixed buffer + runs out of room, the error will be discovered when the caller + retrieves the C string value or checks the length of the resulting + buffer. + + k5buf structures are stack-allocated, but are intended to be + opaque, so do not access the fields directly. This is a tool, not + a way of life, so do not put k5buf structure pointers into the + public API or into significant internal APIs. */ + +/* We must define the k5buf structure here to allow stack allocation. + The structure is intended to be opaque, so the fields have funny + names. */ +struct k5buf { + int xx_buftype; + char *xx_data; + size_t xx_space; + size_t xx_len; +}; + +/* Initialize a k5buf using a fixed-sized, existing buffer. SPACE + must be more than zero, or an assertion failure will result. */ +void krb5int_buf_init_fixed(struct k5buf *buf, char *data, size_t space); + +/* Initialize a k5buf using an internally allocated dynamic buffer. + The buffer contents must be freed with krb5int_free_buf. */ +void krb5int_buf_init_dynamic(struct k5buf *buf); + +/* Add a C string to BUF. */ +void krb5int_buf_add(struct k5buf *buf, const char *data); + +/* Add a counted set of bytes to BUF. If is okay for DATA[0..LEN-1] + to contain null bytes if you are prepared to deal with that in the + output (use krb5int_buf_len to retrieve the length of the output). */ +void krb5int_buf_add_len(struct k5buf *buf, const char *data, size_t len); + +/* Truncate BUF. LEN must be between 0 and the existing buffer + length, or an assertion failure will result. */ +void krb5int_buf_truncate(struct k5buf *buf, size_t len); + +/* Retrieve the byte array value of BUF, or NULL if there has been an + allocation failure or the fixed buffer ran out of room. + + The byte array will be a C string unless binary data was added with + krb5int_buf_add_len; it will be null-terminated regardless. + Modifying the byte array does not invalidate the buffer, as long as + its length is not changed. + + For a fixed buffer, the return value will always be equal to the + passed-in value of DATA at initialization time if it is not NULL. + + For a dynamic buffer, any buffer modification operation except + krb5int_buf_truncate may invalidate the byte array address. */ +char *krb5int_buf_cstr(struct k5buf *buf); + +/* Retrieve the length of BUF, or -1 if there has been an allocation + failure or the fixed buffer ran out of room. The length is equal + to strlen(krb5int_buf_cstr(buf)) unless binary data was added with + krb5int_buf_add_len. */ +ssize_t krb5int_buf_len(struct k5buf *buf); + +/* Free the storage used in the dynamic buffer BUF. The caller may + choose to take responsibility for freeing the return value of + krb5int_buf_cstr instead of using this function. If BUF is a fixed + buffer, an assertion failure will result. It is unnecessary + (though harmless) to free a buffer after an error is detected; the + storage will already have been freed in that case. */ +void krb5int_free_buf(struct k5buf *buf); + +#endif /* K5_BUF_H */ diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 574c8c87c..3052d7be8 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -176,6 +176,9 @@ typedef INT64_TYPE krb5_int64; /* Get error info support. */ #include "k5-err.h" +/* Get string buffer support. */ +#include "k5-buf.h" + /* Error codes used in KRB_ERROR protocol messages. Return values of library routines are based on a different error table (which allows non-ambiguous error codes between subsystems) */ diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in index d931a1f02..5ffe4e9ed 100644 --- a/src/util/support/Makefile.in +++ b/src/util/support/Makefile.in @@ -41,6 +41,7 @@ STLIBOBJS= \ init-addrinfo.o \ plugins.o \ errors.o \ + k5buf.o \ gmt_mktime.o \ fake-addrinfo.o \ $(STRLCPY_ST_OBJ) \ @@ -52,6 +53,7 @@ LIBOBJS= \ $(OUTPRE)init-addrinfo.$(OBJEXT) \ $(OUTPRE)plugins.$(OBJEXT) \ $(OUTPRE)errors.$(OBJEXT) \ + $(OUTPRE)k5buf.$(OBJEXT) \ $(OUTPRE)gmt_mktime.$(OBJEXT) \ $(OUTPRE)fake-addrinfo.$(OBJEXT) \ $(STRLCPY_OBJ) \ @@ -68,11 +70,13 @@ SRCS=\ $(srcdir)/threads.c \ $(srcdir)/init-addrinfo.c \ $(srcdir)/errors.c \ + $(srcdir)/k5buf.c \ $(srcdir)/gmt_mktime.c \ $(srcdir)/fake-addrinfo.c \ $(srcdir)/strlcpy.c \ $(srcdir)/printf.c \ - $(srcdir)/mkstemp.c + $(srcdir)/mkstemp.c \ + $(srcdir)/t_k5buf.c SHLIB_EXPDEPS = # Add -lm if dumping thread stats, for sqrt. @@ -117,6 +121,19 @@ libkrb5support.exports: $(srcdir)/libkrb5support-fixed.exports Makefile ##DOS## $(RM) libkrb5support.exports ##DOS## $(MV) new-exports libkrb5support.exports +T_K5BUF_OBJS= t_k5buf.o k5buf.o + +t_k5buf: $(T_K5BUF_OBJS) + $(CC_LINK) -o t_k5buf $(T_K5BUF_OBJS) + +TEST_PROGS= t_k5buf + +check-unix:: $(TEST_PROGS) + ./t_k5buf + +clean:: + $(RM) t_k5buf.o t_k5buf + @lib_frag@ @libobj_frag@ @@ -138,6 +155,9 @@ init-addrinfo.so init-addrinfo.po $(OUTPRE)init-addrinfo.$(OBJEXT): \ errors.so errors.po $(OUTPRE)errors.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-platform.h \ $(SRCTOP)/include/k5-thread.h errors.c supp-int.h +k5buf.so k5buf.po $(OUTPRE)k5buf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-platform.h \ + $(SRCTOP)/include/k5-thread.h k5buf-int.h k5buf.c gmt_mktime.so gmt_mktime.po $(OUTPRE)gmt_mktime.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(SRCTOP)/include/k5-gmt_mktime.h \ gmt_mktime.c @@ -155,3 +175,6 @@ printf.so printf.po $(OUTPRE)printf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ mkstemp.so mkstemp.po $(OUTPRE)mkstemp.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \ mkstemp.c +t_k5buf.so t_k5buf.po $(OUTPRE)t_k5buf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-platform.h \ + $(SRCTOP)/include/k5-thread.h k5buf-int.h t_k5buf.c diff --git a/src/util/support/k5buf-int.h b/src/util/support/k5buf-int.h new file mode 100644 index 000000000..20aefc367 --- /dev/null +++ b/src/util/support/k5buf-int.h @@ -0,0 +1,51 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ + +/* + * k5buf-int.h + * + * Copyright 2008 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Internal declarations for the k5buf string buffer module. + */ + +#ifndef K5BUF_INT_H +#define K5BUF_INT_H + +#include "k5-platform.h" +#include "k5-buf.h" + +/* The k5buf structure has funny field names to discourage callers + from violating the abstraction barrier. Define less funny names + for them here. */ +#define buftype xx_buftype +#define data xx_data +#define space xx_space +#define len xx_len + +#define DYNAMIC_INITIAL_SIZE 128 +#define SPACE_MAX (SIZE_MAX / 2) /* rounds down, since SIZE_MAX is odd */ + +/* Buffer type values. */ +enum { FIXED, DYNAMIC, ERROR }; + +#endif /* K5BUF_INT_H */ diff --git a/src/util/support/k5buf.c b/src/util/support/k5buf.c new file mode 100644 index 000000000..747490280 --- /dev/null +++ b/src/util/support/k5buf.c @@ -0,0 +1,144 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ + +/* + * k5buf.c + * + * Copyright 2008 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Implement the k5buf string buffer module. + */ + +/* Can't include krb5.h here, or k5-int.h which includes it, because + krb5.h needs to be generated with error tables, after util/et, + which builds after this directory. */ +#include "k5buf-int.h" +#include + +/* Structure invariants: + + buftype is FIXED, DYNAMIC, or ERROR + if buftype is not ERROR: + space > 0 + space <= floor(SIZE_MAX / 2) (to fit within ssize_t) + len < space + data[len] = '\0' +*/ + +/* Make sure there is room for LEN more characters in BUF, in addition + to the null terminator and what's already in there. Return true on + success. On failure, set the error flag and return false. */ +static int ensure_space(struct k5buf *buf, size_t len) +{ + size_t new_space; + char *new_data; + + if (buf->buftype == ERROR) + return 0; + if (buf->space - 1 - buf->len >= len) /* Enough room already. */ + return 1; + if (buf->buftype == FIXED) /* Can't resize a fixed buffer. */ + goto error_exit; + assert(buf->buftype == DYNAMIC); + new_space = buf->space * 2; + while (new_space <= SPACE_MAX && new_space - buf->len - 1 < len) + new_space *= 2; + if (new_space > SPACE_MAX) + goto error_exit; + new_data = realloc(buf->data, new_space); + if (new_data == NULL) + goto error_exit; + buf->data = new_data; + buf->space = new_space; + return 1; + + error_exit: + if (buf->buftype == DYNAMIC) + free(buf->data); + buf->buftype = ERROR; + return 0; +} + +void krb5int_buf_init_fixed(struct k5buf *buf, char *data, size_t space) +{ + assert(space > 0); + buf->buftype = FIXED; + buf->data = data; + buf->space = space; + buf->len = 0; + buf->data[0] = '\0'; +} + +void krb5int_buf_init_dynamic(struct k5buf *buf) +{ + buf->buftype = DYNAMIC; + buf->space = DYNAMIC_INITIAL_SIZE; + buf->data = malloc(buf->space); + if (buf->data == NULL) { + buf->buftype = ERROR; + return; + } + buf->len = 0; + buf->data[0] = '\0'; +} + +void krb5int_buf_add(struct k5buf *buf, const char *data) +{ + krb5int_buf_add_len(buf, data, strlen(data)); +} + +void krb5int_buf_add_len(struct k5buf *buf, const char *data, size_t len) +{ + if (!ensure_space(buf, len)) + return; + memcpy(buf->data + buf->len, data, len); + buf->len += len; + buf->data[buf->len] = '\0'; +} + +void krb5int_buf_truncate(struct k5buf *buf, size_t len) +{ + if (buf->buftype == ERROR) + return; + assert(len <= buf->len); + buf->len = len; + buf->data[buf->len] = '\0'; +} + + +char *krb5int_buf_cstr(struct k5buf *buf) +{ + return (buf->buftype == ERROR) ? NULL : buf->data; +} + +ssize_t krb5int_buf_len(struct k5buf *buf) +{ + return (buf->buftype == ERROR) ? -1 : (ssize_t) buf->len; +} + +void krb5int_free_buf(struct k5buf *buf) +{ + if (buf->buftype == ERROR) + return; + assert(buf->buftype == DYNAMIC); + free(buf->data); +} diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports index 225c54ac0..dfc560a68 100644 --- a/src/util/support/libkrb5support-fixed.exports +++ b/src/util/support/libkrb5support-fixed.exports @@ -29,3 +29,11 @@ krb5int_free_error krb5int_clear_error krb5int_set_error_info_callout_fn krb5int_gmt_mktime +krb5int_buf_init_fixed +krb5int_buf_init_dynamic +krb5int_buf_add +krb5int_buf_add_len +krb5int_buf_truncate +krb5int_buf_cstr +krb5int_buf_len +krb5int_free_buf diff --git a/src/util/support/t_k5buf.c b/src/util/support/t_k5buf.c new file mode 100644 index 000000000..d76398a96 --- /dev/null +++ b/src/util/support/t_k5buf.c @@ -0,0 +1,238 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ + +/* + * t_k5buf.c + * + * Copyright 2008 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Test the k5buf string buffer module. + */ + +#include "k5buf-int.h" +#include +#include + +static void fail_if(int condition, const char *name) +{ + if (condition) { + fprintf(stderr, "%s failed\n", name); + exit(1); + } +} + +/* Test the invariants of a buffer. */ +static void check_buf(struct k5buf *buf, const char *name) +{ + fail_if(buf->buftype != FIXED && buf->buftype != DYNAMIC + && buf->buftype != ERROR, name); + if (buf->buftype == ERROR) + return; + fail_if(buf->space == 0, name); + fail_if(buf->space > SPACE_MAX, name); + fail_if(buf->len >= buf->space, name); + fail_if(buf->data[buf->len] != 0, name); +} + +static void test_basic() +{ + struct k5buf buf; + char storage[1024], *s; + ssize_t len; + + krb5int_buf_init_fixed(&buf, storage, sizeof(storage)); + krb5int_buf_add(&buf, "Hello "); + krb5int_buf_add_len(&buf, "world", 5); + check_buf(&buf, "basic fixed"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(!s || strcmp(s, "Hello world") != 0 || len != 11, "basic fixed"); + + krb5int_buf_init_dynamic(&buf); + krb5int_buf_add_len(&buf, "Hello", 5); + krb5int_buf_add(&buf, " world"); + check_buf(&buf, "basic dynamic"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(!s || strcmp(s, "Hello world") != 0 || len != 11, "basic dynamic"); + krb5int_free_buf(&buf); +} + +static void test_realloc() +{ + struct k5buf buf; + char data[1024], *s; + ssize_t i, len; + + for (i = 0; i < sizeof(data); i++) + data[i] = 'a'; + + /* Cause the buffer size to double from 128 to 256 bytes. */ + krb5int_buf_init_dynamic(&buf); + krb5int_buf_add_len(&buf, data, 10); + krb5int_buf_add_len(&buf, data, 128); + fail_if(buf.space != 256, "realloc 1"); + check_buf(&buf, "realloc 1"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(!s || len != 138 || memcmp(s, data, len) != 0, "realloc 1"); + + /* Cause the same buffer to double in size to 512 bytes. */ + krb5int_buf_add_len(&buf, data, 128); + fail_if(buf.space != 512, "realloc 2"); + check_buf(&buf, "realloc 2"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(!s || len != 266 || memcmp(s, data, len) != 0, "realloc 2"); + krb5int_free_buf(&buf); + + /* Cause a buffer to increase from 128 to 512 bytes directly. */ + krb5int_buf_init_dynamic(&buf); + krb5int_buf_add_len(&buf, data, 10); + krb5int_buf_add_len(&buf, data, 256); + fail_if(buf.space != 512, "realloc 3"); + check_buf(&buf, "realloc 3"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(!s || len != 266 || memcmp(s, data, len) != 0, "realloc 3"); + krb5int_free_buf(&buf); + + /* Cause a buffer to increase from 128 to 1024 bytes directly. */ + krb5int_buf_init_dynamic(&buf); + krb5int_buf_add_len(&buf, data, 10); + krb5int_buf_add_len(&buf, data, 512); + fail_if(buf.space != 1024, "realloc 4"); + check_buf(&buf, "realloc 4"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(!s || len != 522 || memcmp(s, data, len) != 0, "realloc 4"); + krb5int_free_buf(&buf); + + /* Cause a reallocation to fail by exceeding SPACE_MAX. */ + krb5int_buf_init_dynamic(&buf); + krb5int_buf_add_len(&buf, data, 10); + krb5int_buf_add_len(&buf, NULL, SPACE_MAX); + check_buf(&buf, "realloc 5"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(buf.buftype != ERROR || s != NULL || len != -1, "realloc 5"); + krb5int_free_buf(&buf); + + /* Cause a reallocation to fail by integer overflow. */ + krb5int_buf_init_dynamic(&buf); + krb5int_buf_add_len(&buf, data, 100); + krb5int_buf_add_len(&buf, NULL, SPACE_MAX * 2); + check_buf(&buf, "realloc 6"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(buf.buftype != ERROR || s != NULL || len != -1, "realloc 6"); + krb5int_free_buf(&buf); +} + +static void test_overflow() +{ + struct k5buf buf; + char storage[10], *s; + ssize_t len; + + /* Cause a fixed-sized buffer overflow. */ + krb5int_buf_init_fixed(&buf, storage, sizeof(storage)); + krb5int_buf_add(&buf, "12345"); + krb5int_buf_add(&buf, "12345"); + check_buf(&buf, "overflow 1"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(buf.buftype != ERROR || s != NULL || len != -1, "overflow 1"); + + /* Cause a fixed-sized buffer overflow with integer overflow. */ + krb5int_buf_init_fixed(&buf, storage, sizeof(storage)); + krb5int_buf_add(&buf, "12345"); + krb5int_buf_add_len(&buf, NULL, SPACE_MAX * 2); + check_buf(&buf, "overflow 2"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(buf.buftype != ERROR || s != NULL || len != -1, "overflow 2"); +} + +static void test_error() +{ + struct k5buf buf; + char storage[1], *s; + ssize_t len; + + /* Cause an overflow and then perform actions afterwards. */ + krb5int_buf_init_fixed(&buf, storage, sizeof(storage)); + krb5int_buf_add(&buf, "1"); + fail_if(buf.buftype != ERROR, "error"); + check_buf(&buf, "error"); + krb5int_buf_add(&buf, "test"); + check_buf(&buf, "error"); + krb5int_buf_add_len(&buf, "test", 4); + check_buf(&buf, "error"); + krb5int_buf_truncate(&buf, 3); + check_buf(&buf, "error"); + fail_if(buf.buftype != ERROR, "error"); +} + +static void test_truncate() +{ + struct k5buf buf; + char *s; + ssize_t len; + + krb5int_buf_init_dynamic(&buf); + krb5int_buf_add(&buf, "abcde"); + krb5int_buf_add(&buf, "fghij"); + krb5int_buf_truncate(&buf, 7); + check_buf(&buf, "truncate"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(!s || len != 7 || strcmp(s, "abcdefg") != 0, "truncate"); +} + +static void test_binary() +{ + struct k5buf buf; + char *s, data[] = { 'a', 0, 'b' }; + ssize_t len; + + krb5int_buf_init_dynamic(&buf); + krb5int_buf_add_len(&buf, data, 3); + krb5int_buf_add_len(&buf, data, 3); + check_buf(&buf, "binary"); + s = krb5int_buf_cstr(&buf); + len = krb5int_buf_len(&buf); + fail_if(!s || len != 6, "binary"); + fail_if(s[0] != 'a' || s[1] != 0 || s[2] != 'b', "binary"); + fail_if(s[3] != 'a' || s[4] != 0 || s[5] != 'b', "binary"); +} + +int main() +{ + test_basic(); + test_realloc(); + test_overflow(); + test_error(); + test_truncate(); + test_binary(); + return 0; +} -- 2.26.2