1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* util/support/t_k5buf.c - Test the k5buf string buffer module */ 3 /* 4 * Copyright 2008 Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 #include "k5-platform.h" 28 #include "k5-buf.h" 29 #include <stdio.h> 30 #include <stdlib.h> 31 32 static void 33 fail_if(int condition, const char *name) 34 { 35 if (condition) { 36 fprintf(stderr, "%s failed\n", name); 37 exit(1); 38 } 39 } 40 41 /* Test the invariants of a buffer. */ 42 static void 43 check_buf(struct k5buf *buf, const char *name) 44 { 45 fail_if(buf->buftype != K5BUF_FIXED && buf->buftype != K5BUF_DYNAMIC && 46 buf->buftype != K5BUF_ERROR, name); 47 if (buf->buftype == K5BUF_ERROR) { 48 fail_if(buf->data != NULL, name); 49 fail_if(buf->space != 0 || buf->len != 0, name); 50 } else { 51 fail_if(buf->space == 0, name); 52 fail_if(buf->len >= buf->space, name); 53 } 54 } 55 56 static void 57 test_basic() 58 { 59 struct k5buf buf; 60 char storage[1024]; 61 62 k5_buf_init_fixed(&buf, storage, sizeof(storage)); 63 k5_buf_add(&buf, "Hello "); 64 k5_buf_add_len(&buf, "world", 5); 65 check_buf(&buf, "basic fixed"); 66 fail_if(buf.data == NULL || buf.len != 11, "basic fixed"); 67 fail_if(memcmp(buf.data, "Hello world", 11) != 0, "basic fixed"); 68 69 k5_buf_init_dynamic(&buf); 70 k5_buf_add_len(&buf, "Hello", 5); 71 k5_buf_add(&buf, " world"); 72 check_buf(&buf, "basic dynamic"); 73 fail_if(buf.data == NULL || buf.len != 11, "basic dynamic"); 74 fail_if(memcmp(buf.data, "Hello world", 11) != 0, "basic dynamic"); 75 k5_buf_free(&buf); 76 } 77 78 static void 79 test_realloc() 80 { 81 struct k5buf buf; 82 char data[1024]; 83 size_t i; 84 85 for (i = 0; i < sizeof(data); i++) 86 data[i] = 'a'; 87 88 /* Cause the buffer size to double from 128 to 256 bytes. */ 89 k5_buf_init_dynamic(&buf); 90 k5_buf_add_len(&buf, data, 10); 91 k5_buf_add_len(&buf, data, 128); 92 fail_if(buf.space != 256, "realloc 1"); 93 check_buf(&buf, "realloc 1"); 94 fail_if(buf.data == NULL || buf.len != 138, "realloc 1"); 95 fail_if(memcmp(buf.data, data, buf.len) != 0, "realloc 1"); 96 97 /* Cause the same buffer to double in size to 512 bytes. */ 98 k5_buf_add_len(&buf, data, 128); 99 fail_if(buf.space != 512, "realloc 2"); 100 check_buf(&buf, "realloc 2"); 101 fail_if(buf.data == NULL || buf.len != 266, "realloc 2"); 102 fail_if(memcmp(buf.data, data, buf.len) != 0, "realloc 2"); 103 k5_buf_free(&buf); 104 105 /* Cause a buffer to increase from 128 to 512 bytes directly. */ 106 k5_buf_init_dynamic(&buf); 107 k5_buf_add_len(&buf, data, 10); 108 k5_buf_add_len(&buf, data, 256); 109 fail_if(buf.space != 512, "realloc 3"); 110 check_buf(&buf, "realloc 3"); 111 fail_if(buf.data == NULL || buf.len != 266, "realloc 3"); 112 fail_if(memcmp(buf.data, data, buf.len) != 0, "realloc 3"); 113 k5_buf_free(&buf); 114 115 /* Cause a buffer to increase from 128 to 1024 bytes directly. */ 116 k5_buf_init_dynamic(&buf); 117 k5_buf_add_len(&buf, data, 10); 118 k5_buf_add_len(&buf, data, 512); 119 fail_if(buf.space != 1024, "realloc 4"); 120 check_buf(&buf, "realloc 4"); 121 fail_if(buf.data == NULL || buf.len != 522, "realloc 4"); 122 fail_if(memcmp(buf.data, data, buf.len) != 0, "realloc 4"); 123 k5_buf_free(&buf); 124 125 /* Cause a reallocation to fail by integer overflow. */ 126 k5_buf_init_dynamic(&buf); 127 k5_buf_add_len(&buf, data, 100); 128 k5_buf_add_len(&buf, NULL, SIZE_MAX); 129 check_buf(&buf, "realloc 5"); 130 fail_if(buf.buftype != K5BUF_ERROR, "realloc 5"); 131 k5_buf_free(&buf); 132 } 133 134 static void 135 test_overflow() 136 { 137 struct k5buf buf; 138 char storage[10]; 139 140 /* Cause a fixed-sized buffer overflow. */ 141 k5_buf_init_fixed(&buf, storage, sizeof(storage)); 142 k5_buf_add(&buf, "12345"); 143 k5_buf_add(&buf, "123456"); 144 check_buf(&buf, "overflow 1"); 145 fail_if(buf.buftype != K5BUF_ERROR, "overflow 1"); 146 147 /* Cause a fixed-sized buffer overflow with integer overflow. */ 148 k5_buf_init_fixed(&buf, storage, sizeof(storage)); 149 k5_buf_add(&buf, "12345"); 150 k5_buf_add_len(&buf, NULL, SIZE_MAX); 151 check_buf(&buf, "overflow 2"); 152 fail_if(buf.buftype != K5BUF_ERROR, "overflow 2"); 153 } 154 155 static void 156 test_error() 157 { 158 struct k5buf buf; 159 char storage[1]; 160 161 /* Cause an overflow and then perform actions afterwards. */ 162 k5_buf_init_fixed(&buf, storage, sizeof(storage)); 163 k5_buf_add(&buf, "12"); 164 fail_if(buf.buftype != K5BUF_ERROR, "error"); 165 check_buf(&buf, "error"); 166 k5_buf_add(&buf, "test"); 167 check_buf(&buf, "error"); 168 k5_buf_add_len(&buf, "test", 4); 169 check_buf(&buf, "error"); 170 k5_buf_truncate(&buf, 3); 171 check_buf(&buf, "error"); 172 fail_if(buf.buftype != K5BUF_ERROR, "error"); 173 } 174 175 static void 176 test_truncate() 177 { 178 struct k5buf buf; 179 180 k5_buf_init_dynamic(&buf); 181 k5_buf_add(&buf, "abcde"); 182 k5_buf_add(&buf, "fghij"); 183 k5_buf_truncate(&buf, 7); 184 check_buf(&buf, "truncate"); 185 fail_if(buf.data == NULL || buf.len != 7, "truncate"); 186 fail_if(memcmp(buf.data, "abcdefg", 7) != 0, "truncate"); 187 k5_buf_free(&buf); 188 } 189 190 static void 191 test_binary() 192 { 193 struct k5buf buf; 194 char data[] = { 'a', 0, 'b' }, *s; 195 196 k5_buf_init_dynamic(&buf); 197 k5_buf_add_len(&buf, data, 3); 198 k5_buf_add_len(&buf, data, 3); 199 check_buf(&buf, "binary"); 200 fail_if(buf.data == NULL || buf.len != 6, "binary"); 201 s = buf.data; 202 fail_if(s[0] != 'a' || s[1] != 0 || s[2] != 'b', "binary"); 203 fail_if(s[3] != 'a' || s[4] != 0 || s[5] != 'b', "binary"); 204 k5_buf_free(&buf); 205 } 206 207 static void 208 test_fmt() 209 { 210 struct k5buf buf; 211 char storage[10], data[1024]; 212 size_t i; 213 214 for (i = 0; i < sizeof(data) - 1; i++) 215 data[i] = 'a'; 216 data[i] = '\0'; 217 218 /* Format some text into a non-empty fixed buffer. */ 219 k5_buf_init_fixed(&buf, storage, sizeof(storage)); 220 k5_buf_add(&buf, "foo"); 221 k5_buf_add_fmt(&buf, " %d ", 3); 222 check_buf(&buf, "fmt 1"); 223 fail_if(buf.data == NULL || buf.len != 6, "fmt 1"); 224 fail_if(memcmp(buf.data, "foo 3 ", 6) != 0, "fmt 1"); 225 226 /* Overflow the same buffer with formatted text. */ 227 k5_buf_add_fmt(&buf, "%d%d%d%d", 1, 2, 3, 4); 228 check_buf(&buf, "fmt 2"); 229 fail_if(buf.buftype != K5BUF_ERROR, "fmt 2"); 230 231 /* Format some text into a non-empty dynamic buffer. */ 232 k5_buf_init_dynamic(&buf); 233 k5_buf_add(&buf, "foo"); 234 k5_buf_add_fmt(&buf, " %d ", 3); 235 check_buf(&buf, "fmt 3"); 236 fail_if(buf.data == NULL || buf.len != 6, "fmt 3"); 237 fail_if(memcmp(buf.data, "foo 3 ", 6) != 0, "fmt 3"); 238 239 /* Format more text into the same buffer, causing a big resize. */ 240 k5_buf_add_fmt(&buf, "%s", data); 241 check_buf(&buf, "fmt 4"); 242 fail_if(buf.space != 2048, "fmt 4"); 243 fail_if(buf.data == NULL || buf.len != 1029, "fmt 4"); 244 fail_if(memcmp((char *)buf.data + 6, data, 1023) != 0, "fmt 4"); 245 k5_buf_free(&buf); 246 } 247 248 int 249 main() 250 { 251 test_basic(); 252 test_realloc(); 253 test_overflow(); 254 test_error(); 255 test_truncate(); 256 test_binary(); 257 test_fmt(); 258 return 0; 259 } 260