signal-logging.c revision 35c4bbdf
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
33struct number_format_test {
34    uint64_t number;
35    char string[21];
36    char hex_string[17];
37};
38
39struct signed_number_format_test {
40    int64_t number;
41    char string[21];
42};
43
44struct float_number_format_test {
45    double number;
46    char string[21];
47};
48
49static Bool
50check_signed_number_format_test(long int number)
51{
52    char string[21];
53    char expected[21];
54
55    sprintf(expected, "%ld", number);
56    FormatInt64(number, string);
57    if(strncmp(string, expected, 21) != 0) {
58        fprintf(stderr, "Failed to convert %jd to decimal string (expected %s but got %s)\n",
59                (intmax_t) number, expected, string);
60        return FALSE;
61    }
62
63    return TRUE;
64}
65
66static Bool
67check_float_format_test(double number)
68{
69    char string[21];
70    char expected[21];
71
72    /* we currently always print float as .2f */
73    sprintf(expected, "%.2f", number);
74
75    FormatDouble(number, string);
76    if(strncmp(string, expected, 21) != 0) {
77        fprintf(stderr, "Failed to convert %f to string (%s vs %s)\n",
78                number, expected, string);
79        return FALSE;
80    }
81
82    return TRUE;
83}
84
85static Bool
86check_number_format_test(long unsigned int number)
87{
88    char string[21];
89    char expected[21];
90
91    sprintf(expected, "%lu", number);
92
93    FormatUInt64(number, string);
94    if(strncmp(string, expected, 21) != 0) {
95        fprintf(stderr, "Failed to convert %ju to decimal string (%s vs %s)\n",
96                (intmax_t) number, expected, string);
97        return FALSE;
98    }
99
100    sprintf(expected, "%lx", number);
101    FormatUInt64Hex(number, string);
102    if(strncmp(string, expected, 17) != 0) {
103        fprintf(stderr, "Failed to convert %ju to hexadecimal string (%s vs %s)\n",
104                (intmax_t) number, expected, string);
105        return FALSE;
106    }
107
108    return TRUE;
109}
110
111/* FIXME: max range stuff */
112double float_tests[] = { 0, 5, 0.1, 0.01, 5.2342, 10.2301,
113                         -1, -2.00, -0.6023, -1203.30
114                        };
115
116#pragma GCC diagnostic push
117#pragma GCC diagnostic ignored "-Woverflow"
118
119static void
120number_formatting(void)
121{
122    int i;
123    long unsigned int unsigned_tests[] = { 0,/* Zero */
124                                           5, /* Single digit number */
125                                           12, /* Two digit decimal number */
126                                           37, /* Two digit hex number */
127                                           0xC90B2, /* Large < 32 bit number */
128                                           0x15D027BF211B37A, /* Large > 32 bit number */
129                                           0xFFFFFFFFFFFFFFFF, /* Maximum 64-bit number */
130    };
131
132    long int signed_tests[] = { 0,/* Zero */
133                                5, /* Single digit number */
134                                12, /* Two digit decimal number */
135                                37, /* Two digit hex number */
136                                0xC90B2, /* Large < 32 bit number */
137                                0x15D027BF211B37A, /* Large > 32 bit number */
138                                0x7FFFFFFFFFFFFFFF, /* Maximum 64-bit signed number */
139                                -1, /* Single digit number */
140                                -12, /* Two digit decimal number */
141                                -0xC90B2, /* Large < 32 bit number */
142                                -0x15D027BF211B37A, /* Large > 32 bit number */
143                                -0x7FFFFFFFFFFFFFFF, /* Maximum 64-bit signed number */
144    } ;
145
146    for (i = 0; i < sizeof(unsigned_tests) / sizeof(unsigned_tests[0]); i++)
147        assert(check_number_format_test(unsigned_tests[i]));
148
149    for (i = 0; i < sizeof(unsigned_tests) / sizeof(signed_tests[0]); i++)
150        assert(check_signed_number_format_test(signed_tests[i]));
151
152    for (i = 0; i < sizeof(float_tests) / sizeof(float_tests[0]); i++)
153        assert(check_float_format_test(float_tests[i]));
154}
155#pragma GCC diagnostic pop
156
157#pragma GCC diagnostic push
158#pragma GCC diagnostic ignored "-Wformat-security"
159#pragma GCC diagnostic ignored "-Wformat"
160#pragma GCC diagnostic ignored "-Wformat-extra-args"
161static void logging_format(void)
162{
163    const char *log_file_path = "/tmp/Xorg-logging-test.log";
164    const char *str = "%s %d %u %% %p %i";
165    char buf[1024];
166    int i;
167    unsigned int ui;
168    long li;
169    unsigned long lui;
170    FILE *f;
171    char read_buf[2048];
172    char *logmsg;
173    uintptr_t ptr;
174
175    /* set up buf to contain ".....end" */
176    memset(buf, '.', sizeof(buf));
177    strcpy(&buf[sizeof(buf) - 4], "end");
178
179    LogInit(log_file_path, NULL);
180    assert(f = fopen(log_file_path, "r"));
181
182#define read_log_msg(msg) do {                                  \
183        msg = fgets(read_buf, sizeof(read_buf), f);             \
184        assert(msg != NULL);                                   \
185        msg = strchr(read_buf, ']');                            \
186        assert(msg != NULL);                                    \
187        assert(strlen(msg) > 2);                                \
188        msg = msg + 2; /* advance past [time.stamp] */          \
189    } while (0)
190
191    /* boring test message */
192    LogMessageVerbSigSafe(X_ERROR, -1, "test message\n");
193    read_log_msg(logmsg);
194    assert(strcmp(logmsg, "(EE) test message\n") == 0);
195
196    /* long buf is truncated to "....en\n" */
197    LogMessageVerbSigSafe(X_ERROR, -1, buf);
198    read_log_msg(logmsg);
199    assert(strcmp(&logmsg[strlen(logmsg) - 3], "en\n") == 0);
200
201    /* same thing, this time as string substitution */
202    LogMessageVerbSigSafe(X_ERROR, -1, "%s", buf);
203    read_log_msg(logmsg);
204    assert(strcmp(&logmsg[strlen(logmsg) - 3], "en\n") == 0);
205
206    /* strings containing placeholders should just work */
207    LogMessageVerbSigSafe(X_ERROR, -1, "%s\n", str);
208    read_log_msg(logmsg);
209    assert(strcmp(logmsg, "(EE) %s %d %u %% %p %i\n") == 0);
210
211    /* literal % */
212    LogMessageVerbSigSafe(X_ERROR, -1, "test %%\n");
213    read_log_msg(logmsg);
214    assert(strcmp(logmsg, "(EE) test %\n") == 0);
215
216    /* character */
217    LogMessageVerbSigSafe(X_ERROR, -1, "test %c\n", 'a');
218    read_log_msg(logmsg);
219    assert(strcmp(logmsg, "(EE) test a\n") == 0);
220
221    /* something unsupported % */
222    LogMessageVerbSigSafe(X_ERROR, -1, "test %Q\n");
223    read_log_msg(logmsg);
224    assert(strstr(logmsg, "BUG") != NULL);
225    LogMessageVerbSigSafe(X_ERROR, -1, "\n");
226    fseek(f, 0, SEEK_END);
227
228    /* string substitution */
229    LogMessageVerbSigSafe(X_ERROR, -1, "%s\n", "substituted string");
230    read_log_msg(logmsg);
231    assert(strcmp(logmsg, "(EE) substituted string\n") == 0);
232
233    /* Invalid format */
234    LogMessageVerbSigSafe(X_ERROR, -1, "%4", 4);
235    read_log_msg(logmsg);
236    assert(strcmp(logmsg, "(EE) ") == 0);
237    LogMessageVerbSigSafe(X_ERROR, -1, "\n");
238    fseek(f, 0, SEEK_END);
239
240    /* %hld is bogus */
241    LogMessageVerbSigSafe(X_ERROR, -1, "%hld\n", 4);
242    read_log_msg(logmsg);
243    assert(strstr(logmsg, "BUG") != NULL);
244    LogMessageVerbSigSafe(X_ERROR, -1, "\n");
245    fseek(f, 0, SEEK_END);
246
247    /* number substitution */
248    ui = 0;
249    do {
250        char expected[30];
251        sprintf(expected, "(EE) %u\n", ui);
252        LogMessageVerbSigSafe(X_ERROR, -1, "%u\n", ui);
253        read_log_msg(logmsg);
254        assert(strcmp(logmsg, expected) == 0);
255
256        sprintf(expected, "(EE) %x\n", ui);
257        LogMessageVerbSigSafe(X_ERROR, -1, "%x\n", ui);
258        read_log_msg(logmsg);
259        assert(strcmp(logmsg, expected) == 0);
260
261        if (ui == 0)
262            ui = 1;
263        else
264            ui <<= 1;
265    } while(ui);
266
267    lui = 0;
268    do {
269        char expected[30];
270        sprintf(expected, "(EE) %lu\n", lui);
271        LogMessageVerbSigSafe(X_ERROR, -1, "%lu\n", lui);
272        read_log_msg(logmsg);
273
274        sprintf(expected, "(EE) %lld\n", (unsigned long long)ui);
275        LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (unsigned long long)ui);
276        read_log_msg(logmsg);
277        assert(strcmp(logmsg, expected) == 0);
278
279        sprintf(expected, "(EE) %lx\n", lui);
280        printf("%s\n", expected);
281        LogMessageVerbSigSafe(X_ERROR, -1, "%lx\n", lui);
282        read_log_msg(logmsg);
283        assert(strcmp(logmsg, expected) == 0);
284
285        sprintf(expected, "(EE) %llx\n", (unsigned long long)ui);
286        LogMessageVerbSigSafe(X_ERROR, -1, "%llx\n", (unsigned long long)ui);
287        read_log_msg(logmsg);
288        assert(strcmp(logmsg, expected) == 0);
289
290        if (lui == 0)
291            lui = 1;
292        else
293            lui <<= 1;
294    } while(lui);
295
296    /* signed number substitution */
297    i = 0;
298    do {
299        char expected[30];
300        sprintf(expected, "(EE) %d\n", i);
301        LogMessageVerbSigSafe(X_ERROR, -1, "%d\n", i);
302        read_log_msg(logmsg);
303        assert(strcmp(logmsg, expected) == 0);
304
305        sprintf(expected, "(EE) %d\n", i | INT_MIN);
306        LogMessageVerbSigSafe(X_ERROR, -1, "%d\n", i | INT_MIN);
307        read_log_msg(logmsg);
308        assert(strcmp(logmsg, expected) == 0);
309
310        if (i == 0)
311            i = 1;
312        else
313            i <<= 1;
314    } while(i > INT_MIN);
315
316    li = 0;
317    do {
318        char expected[30];
319        sprintf(expected, "(EE) %ld\n", li);
320        LogMessageVerbSigSafe(X_ERROR, -1, "%ld\n", li);
321        read_log_msg(logmsg);
322        assert(strcmp(logmsg, expected) == 0);
323
324        sprintf(expected, "(EE) %ld\n", li | LONG_MIN);
325        LogMessageVerbSigSafe(X_ERROR, -1, "%ld\n", li | LONG_MIN);
326        read_log_msg(logmsg);
327        assert(strcmp(logmsg, expected) == 0);
328
329        sprintf(expected, "(EE) %lld\n", (long long)li);
330        LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (long long)li);
331        read_log_msg(logmsg);
332        assert(strcmp(logmsg, expected) == 0);
333
334        sprintf(expected, "(EE) %lld\n", (long long)(li | LONG_MIN));
335        LogMessageVerbSigSafe(X_ERROR, -1, "%lld\n", (long long)(li | LONG_MIN));
336        read_log_msg(logmsg);
337        assert(strcmp(logmsg, expected) == 0);
338
339        if (li == 0)
340            li = 1;
341        else
342            li <<= 1;
343    } while(li > LONG_MIN);
344
345
346    /* pointer substitution */
347    /* we print a null-pointer differently to printf */
348    LogMessageVerbSigSafe(X_ERROR, -1, "%p\n", NULL);
349    read_log_msg(logmsg);
350    assert(strcmp(logmsg, "(EE) 0x0\n") == 0);
351
352    ptr = 1;
353    do {
354        char expected[30];
355#ifdef __sun /* Solaris doesn't autoadd "0x" to %p format */
356        sprintf(expected, "(EE) 0x%p\n", (void*)ptr);
357#else
358        sprintf(expected, "(EE) %p\n", (void*)ptr);
359#endif
360        LogMessageVerbSigSafe(X_ERROR, -1, "%p\n", (void*)ptr);
361        read_log_msg(logmsg);
362        assert(strcmp(logmsg, expected) == 0);
363        ptr <<= 1;
364    } while(ptr);
365
366
367    for (i = 0; i < sizeof(float_tests)/sizeof(float_tests[0]); i++) {
368        double d = float_tests[i];
369        char expected[30];
370        sprintf(expected, "(EE) %.2f\n", d);
371        LogMessageVerbSigSafe(X_ERROR, -1, "%f\n", d);
372        read_log_msg(logmsg);
373        assert(strcmp(logmsg, expected) == 0);
374
375        /* test for length modifiers, we just ignore them atm */
376        LogMessageVerbSigSafe(X_ERROR, -1, "%.3f\n", d);
377        read_log_msg(logmsg);
378        assert(strcmp(logmsg, expected) == 0);
379
380        LogMessageVerbSigSafe(X_ERROR, -1, "%3f\n", d);
381        read_log_msg(logmsg);
382        assert(strcmp(logmsg, expected) == 0);
383
384        LogMessageVerbSigSafe(X_ERROR, -1, "%.0f\n", d);
385        read_log_msg(logmsg);
386        assert(strcmp(logmsg, expected) == 0);
387    }
388
389
390    LogClose(EXIT_NO_ERROR);
391    unlink(log_file_path);
392
393#undef read_log_msg
394}
395#pragma GCC diagnostic pop /* "-Wformat-security" */
396
397int
398main(int argc, char **argv)
399{
400    number_formatting();
401    logging_format();
402
403    return 0;
404}
405