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