signal-logging.c revision 1b5d61b8
1/**
2 * Copyright © 2012 Canonical, Ltd.
3 *
4 *  Permission is hereby granted, free of charge, to any person obtaining a
5 *  copy of this software and associated documentation files (the "Software"),
6 *  to deal in the Software without restriction, including without limitation
7 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 *  and/or sell copies of the Software, and to permit persons to whom the
9 *  Software is furnished to do so, subject to the following conditions:
10 *
11 *  The above copyright notice and this permission notice (including the next
12 *  paragraph) shall be included in all copies or substantial portions of the
13 *  Software.
14 *
15 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 *  DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_DIX_CONFIG_H
25#include <dix-config.h>
26#endif
27
28#include <stdint.h>
29#include <unistd.h>
30#include "assert.h"
31#include "misc.h"
32
33#include "tests-common.h"
34
35struct number_format_test {
36    uint64_t number;
37    char string[21];
38    char hex_string[17];
39};
40
41struct signed_number_format_test {
42    int64_t number;
43    char string[21];
44};
45
46struct float_number_format_test {
47    double number;
48    char string[21];
49};
50
51static Bool
52check_signed_number_format_test(long int number)
53{
54    char string[21];
55    char expected[21];
56
57    sprintf(expected, "%ld", number);
58    FormatInt64(number, string);
59    if(strncmp(string, expected, 21) != 0) {
60        fprintf(stderr, "Failed to convert %jd to decimal string (expected %s but got %s)\n",
61                (intmax_t) number, expected, string);
62        return FALSE;
63    }
64
65    return TRUE;
66}
67
68static Bool
69check_float_format_test(double number)
70{
71    char string[21];
72    char expected[21];
73
74    /* we currently always print float as .2f */
75    sprintf(expected, "%.2f", number);
76
77    FormatDouble(number, string);
78    if(strncmp(string, expected, 21) != 0) {
79        fprintf(stderr, "Failed to convert %f to string (%s vs %s)\n",
80                number, expected, string);
81        return FALSE;
82    }
83
84    return TRUE;
85}
86
87static Bool
88check_number_format_test(long unsigned int number)
89{
90    char string[21];
91    char expected[21];
92
93    sprintf(expected, "%lu", number);
94
95    FormatUInt64(number, string);
96    if(strncmp(string, expected, 21) != 0) {
97        fprintf(stderr, "Failed to convert %ju to decimal string (%s vs %s)\n",
98                (intmax_t) number, expected, string);
99        return FALSE;
100    }
101
102    sprintf(expected, "%lx", number);
103    FormatUInt64Hex(number, string);
104    if(strncmp(string, expected, 17) != 0) {
105        fprintf(stderr, "Failed to convert %ju to hexadecimal string (%s vs %s)\n",
106                (intmax_t) number, expected, string);
107        return FALSE;
108    }
109
110    return TRUE;
111}
112
113/* FIXME: max range stuff */
114double float_tests[] = { 0, 5, 0.1, 0.01, 5.2342, 10.2301,
115                         -1, -2.00, -0.6023, -1203.30
116                        };
117
118#pragma GCC diagnostic push
119#pragma GCC diagnostic ignored "-Woverflow"
120
121static void
122number_formatting(void)
123{
124    int i;
125    long unsigned int unsigned_tests[] = { 0,/* Zero */
126                                           5, /* Single digit number */
127                                           12, /* Two digit decimal number */
128                                           37, /* Two digit hex number */
129                                           0xC90B2, /* Large < 32 bit number */
130                                           0x15D027BF211B37A, /* Large > 32 bit number */
131                                           0xFFFFFFFFFFFFFFFF, /* Maximum 64-bit number */
132    };
133
134    long int signed_tests[] = { 0,/* Zero */
135                                5, /* Single digit number */
136                                12, /* Two digit decimal number */
137                                37, /* Two digit hex number */
138                                0xC90B2, /* Large < 32 bit number */
139                                0x15D027BF211B37A, /* Large > 32 bit number */
140                                0x7FFFFFFFFFFFFFFF, /* Maximum 64-bit signed number */
141                                -1, /* Single digit number */
142                                -12, /* Two digit decimal number */
143                                -0xC90B2, /* Large < 32 bit number */
144                                -0x15D027BF211B37A, /* Large > 32 bit number */
145                                -0x7FFFFFFFFFFFFFFF, /* Maximum 64-bit signed number */
146    } ;
147
148    for (i = 0; i < ARRAY_SIZE(unsigned_tests); i++)
149        assert(check_number_format_test(unsigned_tests[i]));
150
151    for (i = 0; i < ARRAY_SIZE(signed_tests); i++)
152        assert(check_signed_number_format_test(signed_tests[i]));
153
154    for (i = 0; i < ARRAY_SIZE(float_tests); i++)
155        assert(check_float_format_test(float_tests[i]));
156}
157#pragma GCC diagnostic pop
158
159#pragma GCC diagnostic push
160#pragma GCC diagnostic ignored "-Wformat-security"
161#pragma GCC diagnostic ignored "-Wformat"
162#pragma GCC diagnostic ignored "-Wformat-extra-args"
163static void logging_format(void)
164{
165    const char *log_file_path = "/tmp/Xorg-logging-test.log";
166    const char *str = "%s %d %u %% %p %i";
167    char buf[1024];
168    int i;
169    unsigned int ui;
170    long li;
171    unsigned long lui;
172    FILE *f;
173    char read_buf[2048];
174    char *logmsg;
175    uintptr_t ptr;
176
177    /* set up buf to contain ".....end" */
178    memset(buf, '.', sizeof(buf));
179    strcpy(&buf[sizeof(buf) - 4], "end");
180
181    LogInit(log_file_path, NULL);
182    assert((f = fopen(log_file_path, "r")));
183
184#define read_log_msg(msg) do {                                  \
185        msg = fgets(read_buf, sizeof(read_buf), f);             \
186        assert(msg != NULL);                                   \
187        msg = strchr(read_buf, ']');                            \
188        assert(msg != NULL);                                    \
189        assert(strlen(msg) > 2);                                \
190        msg = msg + 2; /* advance past [time.stamp] */          \
191    } while (0)
192
193    /* boring test message */
194    LogMessageVerbSigSafe(X_ERROR, -1, "test message\n");
195    read_log_msg(logmsg);
196    assert(strcmp(logmsg, "(EE) test message\n") == 0);
197
198    /* long buf is truncated to "....en\n" */
199    LogMessageVerbSigSafe(X_ERROR, -1, buf);
200    read_log_msg(logmsg);
201    assert(strcmp(&logmsg[strlen(logmsg) - 3], "en\n") == 0);
202
203    /* same thing, this time as string substitution */
204    LogMessageVerbSigSafe(X_ERROR, -1, "%s", buf);
205    read_log_msg(logmsg);
206    assert(strcmp(&logmsg[strlen(logmsg) - 3], "en\n") == 0);
207
208    /* strings containing placeholders should just work */
209    LogMessageVerbSigSafe(X_ERROR, -1, "%s\n", str);
210    read_log_msg(logmsg);
211    assert(strcmp(logmsg, "(EE) %s %d %u %% %p %i\n") == 0);
212
213    /* literal % */
214    LogMessageVerbSigSafe(X_ERROR, -1, "test %%\n");
215    read_log_msg(logmsg);
216    assert(strcmp(logmsg, "(EE) test %\n") == 0);
217
218    /* character */
219    LogMessageVerbSigSafe(X_ERROR, -1, "test %c\n", 'a');
220    read_log_msg(logmsg);
221    assert(strcmp(logmsg, "(EE) test a\n") == 0);
222
223    /* something unsupported % */
224    LogMessageVerbSigSafe(X_ERROR, -1, "test %Q\n");
225    read_log_msg(logmsg);
226    assert(strstr(logmsg, "BUG") != NULL);
227    LogMessageVerbSigSafe(X_ERROR, -1, "\n");
228    fseek(f, 0, SEEK_END);
229
230    /* string substitution */
231    LogMessageVerbSigSafe(X_ERROR, -1, "%s\n", "substituted string");
232    read_log_msg(logmsg);
233    assert(strcmp(logmsg, "(EE) substituted string\n") == 0);
234
235    /* Invalid format */
236    LogMessageVerbSigSafe(X_ERROR, -1, "%4", 4);
237    read_log_msg(logmsg);
238    assert(strcmp(logmsg, "(EE) ") == 0);
239    LogMessageVerbSigSafe(X_ERROR, -1, "\n");
240    fseek(f, 0, SEEK_END);
241
242    /* %hld is bogus */
243    LogMessageVerbSigSafe(X_ERROR, -1, "%hld\n", 4);
244    read_log_msg(logmsg);
245    assert(strstr(logmsg, "BUG") != NULL);
246    LogMessageVerbSigSafe(X_ERROR, -1, "\n");
247    fseek(f, 0, SEEK_END);
248
249    /* number substitution */
250    ui = 0;
251    do {
252        char expected[30];
253        sprintf(expected, "(EE) %u\n", ui);
254        LogMessageVerbSigSafe(X_ERROR, -1, "%u\n", ui);
255        read_log_msg(logmsg);
256        assert(strcmp(logmsg, expected) == 0);
257
258        sprintf(expected, "(EE) %x\n", ui);
259        LogMessageVerbSigSafe(X_ERROR, -1, "%x\n", ui);
260        read_log_msg(logmsg);
261        assert(strcmp(logmsg, expected) == 0);
262
263        if (ui == 0)
264            ui = 1;
265        else
266            ui <<= 1;
267    } while(ui);
268
269    lui = 0;
270    do {
271        char expected[30];
272        sprintf(expected, "(EE) %lu\n", lui);
273        LogMessageVerbSigSafe(X_ERROR, -1, "%lu\n", lui);
274        read_log_msg(logmsg);
275
276        sprintf(expected, "(EE) %lld\n", (unsigned long long)ui);
277        LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (unsigned long long)ui);
278        read_log_msg(logmsg);
279        assert(strcmp(logmsg, expected) == 0);
280
281        sprintf(expected, "(EE) %lx\n", lui);
282        printf("%s\n", expected);
283        LogMessageVerbSigSafe(X_ERROR, -1, "%lx\n", lui);
284        read_log_msg(logmsg);
285        assert(strcmp(logmsg, expected) == 0);
286
287        sprintf(expected, "(EE) %llx\n", (unsigned long long)ui);
288        LogMessageVerbSigSafe(X_ERROR, -1, "%llx\n", (unsigned long long)ui);
289        read_log_msg(logmsg);
290        assert(strcmp(logmsg, expected) == 0);
291
292        if (lui == 0)
293            lui = 1;
294        else
295            lui <<= 1;
296    } while(lui);
297
298    /* signed number substitution */
299    i = 0;
300    do {
301        char expected[30];
302        sprintf(expected, "(EE) %d\n", i);
303        LogMessageVerbSigSafe(X_ERROR, -1, "%d\n", i);
304        read_log_msg(logmsg);
305        assert(strcmp(logmsg, expected) == 0);
306
307        sprintf(expected, "(EE) %d\n", i | INT_MIN);
308        LogMessageVerbSigSafe(X_ERROR, -1, "%d\n", i | INT_MIN);
309        read_log_msg(logmsg);
310        assert(strcmp(logmsg, expected) == 0);
311
312        if (i == 0)
313            i = 1;
314        else
315            i <<= 1;
316    } while(i > INT_MIN);
317
318    li = 0;
319    do {
320        char expected[30];
321        sprintf(expected, "(EE) %ld\n", li);
322        LogMessageVerbSigSafe(X_ERROR, -1, "%ld\n", li);
323        read_log_msg(logmsg);
324        assert(strcmp(logmsg, expected) == 0);
325
326        sprintf(expected, "(EE) %ld\n", li | LONG_MIN);
327        LogMessageVerbSigSafe(X_ERROR, -1, "%ld\n", li | LONG_MIN);
328        read_log_msg(logmsg);
329        assert(strcmp(logmsg, expected) == 0);
330
331        sprintf(expected, "(EE) %lld\n", (long long)li);
332        LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (long long)li);
333        read_log_msg(logmsg);
334        assert(strcmp(logmsg, expected) == 0);
335
336        sprintf(expected, "(EE) %lld\n", (long long)(li | LONG_MIN));
337        LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (long long)(li | LONG_MIN));
338        read_log_msg(logmsg);
339        assert(strcmp(logmsg, expected) == 0);
340
341        if (li == 0)
342            li = 1;
343        else
344            li <<= 1;
345    } while(li > LONG_MIN);
346
347
348    /* pointer substitution */
349    /* we print a null-pointer differently to printf */
350    LogMessageVerbSigSafe(X_ERROR, -1, "%p\n", NULL);
351    read_log_msg(logmsg);
352    assert(strcmp(logmsg, "(EE) 0x0\n") == 0);
353
354    ptr = 1;
355    do {
356        char expected[30];
357#ifdef __sun /* Solaris doesn't autoadd "0x" to %p format */
358        sprintf(expected, "(EE) 0x%p\n", (void*)ptr);
359#else
360        sprintf(expected, "(EE) %p\n", (void*)ptr);
361#endif
362        LogMessageVerbSigSafe(X_ERROR, -1, "%p\n", (void*)ptr);
363        read_log_msg(logmsg);
364        assert(strcmp(logmsg, expected) == 0);
365        ptr <<= 1;
366    } while(ptr);
367
368
369    for (i = 0; i < ARRAY_SIZE(float_tests); i++) {
370        double d = float_tests[i];
371        char expected[30];
372        sprintf(expected, "(EE) %.2f\n", d);
373        LogMessageVerbSigSafe(X_ERROR, -1, "%f\n", d);
374        read_log_msg(logmsg);
375        assert(strcmp(logmsg, expected) == 0);
376
377        /* test for length modifiers, we just ignore them atm */
378        LogMessageVerbSigSafe(X_ERROR, -1, "%.3f\n", d);
379        read_log_msg(logmsg);
380        assert(strcmp(logmsg, expected) == 0);
381
382        LogMessageVerbSigSafe(X_ERROR, -1, "%3f\n", d);
383        read_log_msg(logmsg);
384        assert(strcmp(logmsg, expected) == 0);
385
386        LogMessageVerbSigSafe(X_ERROR, -1, "%.0f\n", d);
387        read_log_msg(logmsg);
388        assert(strcmp(logmsg, expected) == 0);
389    }
390
391
392    LogClose(EXIT_NO_ERROR);
393    unlink(log_file_path);
394
395#undef read_log_msg
396}
397#pragma GCC diagnostic pop /* "-Wformat-security" */
398
399int
400signal_logging_test(void)
401{
402    number_formatting();
403    logging_format();
404
405    return 0;
406}
407