1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "testutil.h" 18 19#include <assert.h> 20#include <stdlib.h> 21#include <stdio.h> 22#include <string.h> 23 24#if APR_HAVE_LIMITS_H 25#include <limits.h> 26#endif 27 28#include "apr_general.h" 29#include "apr_strings.h" 30#include "apr_errno.h" 31 32/* I haven't bothered to check for APR_ENOTIMPL here, AFAIK, all string 33 * functions exist on all platforms. 34 */ 35 36static void test_strtok(abts_case *tc, void *data) 37{ 38 struct { 39 char *input; 40 char *sep; 41 } 42 cases[] = { 43 { 44 "", 45 "Z" 46 }, 47 { 48 " asdf jkl; 77889909 \r\n\1\2\3Z", 49 " \r\n\3\2\1" 50 }, 51 { 52 NULL, /* but who cares if apr_strtok() segfaults? */ 53 " \t" 54 }, 55#if 0 /* don't do this... you deserve to segfault */ 56 { 57 "a b c ", 58 NULL 59 }, 60#endif 61 { 62 " a b c ", 63 "" 64 }, 65 { 66 "a b c ", 67 " " 68 } 69 }; 70 int curtc; 71 72 for (curtc = 0; curtc < sizeof cases / sizeof cases[0]; curtc++) { 73 char *retval1, *retval2; 74 char *str1, *str2; 75 char *state; 76 77 str1 = apr_pstrdup(p, cases[curtc].input); 78 str2 = apr_pstrdup(p, cases[curtc].input); 79 80 do { 81 retval1 = apr_strtok(str1, cases[curtc].sep, &state); 82 retval2 = strtok(str2, cases[curtc].sep); 83 84 if (!retval1) { 85 ABTS_TRUE(tc, retval2 == NULL); 86 } 87 else { 88 ABTS_TRUE(tc, retval2 != NULL); 89 ABTS_STR_EQUAL(tc, retval2, retval1); 90 } 91 92 str1 = str2 = NULL; /* make sure we pass NULL on subsequent calls */ 93 } while (retval1); 94 } 95} 96 97static void snprintf_noNULL(abts_case *tc, void *data) 98{ 99 char buff[100]; 100 char *testing = apr_palloc(p, 10); 101 102 testing[0] = 't'; 103 testing[1] = 'e'; 104 testing[2] = 's'; 105 testing[3] = 't'; 106 testing[4] = 'i'; 107 testing[5] = 'n'; 108 testing[6] = 'g'; 109 110 /* If this test fails, we are going to seg fault. */ 111 apr_snprintf(buff, sizeof(buff), "%.*s", 7, testing); 112 ABTS_STR_NEQUAL(tc, buff, testing, 7); 113} 114 115static void snprintf_0NULL(abts_case *tc, void *data) 116{ 117 int rv; 118 119 rv = apr_snprintf(NULL, 0, "%sBAR", "FOO"); 120 ABTS_INT_EQUAL(tc, 6, rv); 121} 122 123static void snprintf_0nonNULL(abts_case *tc, void *data) 124{ 125 int rv; 126 char *buff = "testing"; 127 128 rv = apr_snprintf(buff, 0, "%sBAR", "FOO"); 129 ABTS_INT_EQUAL(tc, 6, rv); 130 ABTS_ASSERT(tc, "buff unmangled", strcmp(buff, "FOOBAR") != 0); 131} 132 133static void snprintf_underflow(abts_case *tc, void *data) 134{ 135 char buf[20]; 136 int rv; 137 138 rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.0001); 139 ABTS_INT_EQUAL(tc, 4, rv); 140 ABTS_STR_EQUAL(tc, "0.00", buf); 141 142 rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.001); 143 ABTS_INT_EQUAL(tc, 4, rv); 144 ABTS_STR_EQUAL(tc, "0.00", buf); 145 146 rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.01); 147 ABTS_INT_EQUAL(tc, 4, rv); 148 ABTS_STR_EQUAL(tc, "0.01", buf); 149} 150 151static void string_error(abts_case *tc, void *data) 152{ 153 char buf[128], *rv; 154 apr_status_t n; 155 156 buf[0] = '\0'; 157 rv = apr_strerror(APR_ENOENT, buf, sizeof buf); 158 ABTS_PTR_EQUAL(tc, buf, rv); 159 ABTS_TRUE(tc, strlen(buf) > 0); 160 161 rv = apr_strerror(APR_TIMEUP, buf, sizeof buf); 162 ABTS_PTR_EQUAL(tc, buf, rv); 163 ABTS_STR_EQUAL(tc, "The timeout specified has expired", buf); 164 165 /* throw some randomish numbers at it to check for robustness */ 166 for (n = 1; n < 1000000; n *= 2) { 167 apr_strerror(n, buf, sizeof buf); 168 } 169} 170 171#define SIZE 180000 172static void string_long(abts_case *tc, void *data) 173{ 174 char s[SIZE + 1]; 175 176 memset(s, 'A', SIZE); 177 s[SIZE] = '\0'; 178 179 apr_psprintf(p, "%s", s); 180} 181 182/* ### FIXME: apr.h/apr_strings.h should provide these! */ 183#define MY_LLONG_MAX (APR_INT64_C(9223372036854775807)) 184#define MY_LLONG_MIN (-MY_LLONG_MAX - APR_INT64_C(1)) 185 186static void string_strtoi64(abts_case *tc, void *data) 187{ 188 static const struct { 189 int errnum, base; 190 const char *in, *end; 191 apr_int64_t result; 192 } ts[] = { 193 194 /* base 10 tests */ 195 { 0, 10, "123545", NULL, APR_INT64_C(123545) }, 196 { 0, 10, " 123545", NULL, APR_INT64_C(123545) }, 197 { 0, 10, " +123545", NULL, APR_INT64_C(123545) }, 198 { 0, 10, "-123545", NULL, APR_INT64_C(-123545) }, 199 { 0, 10, " 00000123545", NULL, APR_INT64_C(123545) }, 200 { 0, 10, "123545ZZZ", "ZZZ", APR_INT64_C(123545) }, 201 { 0, 10, " 123545 ", " ", APR_INT64_C(123545) }, 202 203 /* base 16 tests */ 204 { 0, 16, "1E299", NULL, APR_INT64_C(123545) }, 205 { 0, 16, "1e299", NULL, APR_INT64_C(123545) }, 206 { 0, 16, "0x1e299", NULL, APR_INT64_C(123545) }, 207 { 0, 16, "0X1E299", NULL, APR_INT64_C(123545) }, 208 { 0, 16, "+1e299", NULL, APR_INT64_C(123545) }, 209 { 0, 16, "-1e299", NULL, APR_INT64_C(-123545) }, 210 { 0, 16, " -1e299", NULL, APR_INT64_C(-123545) }, 211 212 /* automatic base detection tests */ 213 { 0, 0, "123545", NULL, APR_INT64_C(123545) }, 214 { 0, 0, "0x1e299", NULL, APR_INT64_C(123545) }, 215 { 0, 0, " 0x1e299", NULL, APR_INT64_C(123545) }, 216 { 0, 0, "+0x1e299", NULL, APR_INT64_C(123545) }, 217 { 0, 0, "-0x1e299", NULL, APR_INT64_C(-123545) }, 218 219 /* large number tests */ 220 { 0, 10, "8589934605", NULL, APR_INT64_C(8589934605) }, 221 { 0, 10, "-8589934605", NULL, APR_INT64_C(-8589934605) }, 222 { 0, 16, "0x20000000D", NULL, APR_INT64_C(8589934605) }, 223 { 0, 16, "-0x20000000D", NULL, APR_INT64_C(-8589934605) }, 224 { 0, 16, " 0x20000000D", NULL, APR_INT64_C(8589934605) }, 225 { 0, 16, " 0x20000000D", NULL, APR_INT64_C(8589934605) }, 226 227 /* error cases */ 228 { ERANGE, 10, "999999999999999999999999999999999", "", MY_LLONG_MAX }, 229 { ERANGE, 10, "-999999999999999999999999999999999", "", MY_LLONG_MIN }, 230 231#if 0 232 /* C99 doesn't require EINVAL for an invalid range. */ 233 { EINVAL, 99, "", (void *)-1 /* don't care */, 0 }, 234#endif 235 236 /* some strtoll implementations give EINVAL when no conversion 237 * is performed. */ 238 { -1 /* don't care */, 10, "zzz", "zzz", APR_INT64_C(0) }, 239 { -1 /* don't care */, 10, "", NULL, APR_INT64_C(0) } 240 241 }; 242 int n; 243 244 for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) { 245 char *end = "end ptr not changed"; 246 apr_int64_t result; 247 int errnum; 248 249 errno = 0; 250 result = apr_strtoi64(ts[n].in, &end, ts[n].base); 251 errnum = errno; 252 253 ABTS_ASSERT(tc, 254 apr_psprintf(p, "for '%s': result was %" APR_INT64_T_FMT 255 " not %" APR_INT64_T_FMT, ts[n].in, 256 result, ts[n].result), 257 result == ts[n].result); 258 259 if (ts[n].errnum != -1) { 260 ABTS_ASSERT(tc, 261 apr_psprintf(p, "for '%s': errno was %d not %d", ts[n].in, 262 errnum, ts[n].errnum), 263 ts[n].errnum == errnum); 264 } 265 266 if (ts[n].end == NULL) { 267 /* end must point to NUL terminator of .in */ 268 ABTS_PTR_EQUAL(tc, ts[n].in + strlen(ts[n].in), end); 269 } else if (ts[n].end != (void *)-1) { 270 ABTS_ASSERT(tc, 271 apr_psprintf(p, "for '%s', end was '%s' not '%s'", 272 ts[n].in, end, ts[n].end), 273 strcmp(ts[n].end, end) == 0); 274 } 275 } 276} 277 278static void string_strtoff(abts_case *tc, void *data) 279{ 280 apr_off_t off; 281 282 ABTS_ASSERT(tc, "strtoff fails on out-of-range integer", 283 apr_strtoff(&off, "999999999999999999999999999999", 284 NULL, 10) != APR_SUCCESS); 285 286 ABTS_ASSERT(tc, "strtoff failed for 1234", 287 apr_strtoff(&off, "1234", NULL, 10) == APR_SUCCESS); 288 289 ABTS_ASSERT(tc, "strtoff failed to parse 1234", off == 1234); 290} 291 292/* random-ish checks for strfsize buffer overflows */ 293static void overflow_strfsize(abts_case *tc, void *data) 294{ 295 apr_off_t off; 296 char buf[7]; 297 298 buf[5] = '$'; 299 buf[6] = '@'; 300 301 for (off = -9999; off < 20000; off++) { 302 apr_strfsize(off, buf); 303 } 304 for (; off < 9999999; off += 9) { 305 apr_strfsize(off, buf); 306 } 307 for (; off < 999999999; off += 999) { 308 apr_strfsize(off, buf); 309 } 310 for (off = 1; off < LONG_MAX && off > 0; off *= 2) { 311 apr_strfsize(off, buf); 312 apr_strfsize(off + 1, buf); 313 apr_strfsize(off - 1, buf); 314 } 315 316 ABTS_ASSERT(tc, "strfsize overflowed", buf[5] == '$'); 317 ABTS_ASSERT(tc, "strfsize overflowed", buf[6] == '@'); 318} 319 320static void string_strfsize(abts_case *tc, void *data) 321{ 322 static const struct { 323 apr_off_t size; 324 const char *buf; 325 } ts[] = { 326 { -1, " - " }, 327 { 0, " 0 " }, 328 { 666, "666 " }, 329 { 1024, "1.0K" }, 330 { 1536, "1.5K" }, 331 { 2048, "2.0K" }, 332 { 1293874, "1.2M" }, 333 { 9999999, "9.5M" }, 334 { 103809024, " 99M" }, 335 { 1047527424, "1.0G" } /* "999M" would be more correct */ 336 }; 337 apr_size_t n; 338 339 for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) { 340 char buf[6], *ret; 341 342 buf[5] = '%'; 343 344 ret = apr_strfsize(ts[n].size, buf); 345 ABTS_ASSERT(tc, "strfsize returned wrong buffer", ret == buf); 346 ABTS_ASSERT(tc, "strfsize overflowed", buf[5] == '%'); 347 348 ABTS_STR_EQUAL(tc, ts[n].buf, ret); 349 } 350} 351 352static void string_cpystrn(abts_case *tc, void *data) 353{ 354 char buf[6], *ret; 355 356 buf[5] = 'Z'; 357 358 ret = apr_cpystrn(buf, "123456", 5); 359 360 ABTS_STR_EQUAL(tc, "1234", buf); 361 ABTS_PTR_EQUAL(tc, buf + 4, ret); 362 ABTS_TRUE(tc, *ret == '\0'); 363 ABTS_TRUE(tc, ret[1] == 'Z'); 364} 365 366static void snprintf_overflow(abts_case *tc, void *data) 367{ 368 char buf[4]; 369 int rv; 370 371 buf[2] = '4'; 372 buf[3] = '2'; 373 374 rv = apr_snprintf(buf, 2, "%s", "a"); 375 ABTS_INT_EQUAL(tc, 1, rv); 376 377 rv = apr_snprintf(buf, 2, "%s", "abcd"); 378 ABTS_INT_EQUAL(tc, 1, rv); 379 380 ABTS_STR_EQUAL(tc, "a", buf); 381 382 /* Check the buffer really hasn't been overflowed. */ 383 ABTS_TRUE(tc, buf[2] == '4' && buf[3] == '2'); 384} 385 386abts_suite *teststr(abts_suite *suite) 387{ 388 suite = ADD_SUITE(suite) 389 390 abts_run_test(suite, snprintf_0NULL, NULL); 391 abts_run_test(suite, snprintf_0nonNULL, NULL); 392 abts_run_test(suite, snprintf_noNULL, NULL); 393 abts_run_test(suite, snprintf_underflow, NULL); 394 abts_run_test(suite, test_strtok, NULL); 395 abts_run_test(suite, string_error, NULL); 396 abts_run_test(suite, string_long, NULL); 397 abts_run_test(suite, string_strtoi64, NULL); 398 abts_run_test(suite, string_strtoff, NULL); 399 abts_run_test(suite, overflow_strfsize, NULL); 400 abts_run_test(suite, string_strfsize, NULL); 401 abts_run_test(suite, string_cpystrn, NULL); 402 abts_run_test(suite, snprintf_overflow, NULL); 403 404 return suite; 405} 406 407