Coverage Report

Created: 2019-07-03 22:50

/home/liu/buildslave/linux-x64-runtests/build/test/case_main.h
Line
Count
Source (jump to first uncovered line)
1
#if !defined(_GUARD_case_main_h_) && !defined(CASE_DISABLE_MAIN)
2
#define _GUARD_case_main_h_
3
4
#include <string.h>
5
#include <assert.h>
6
7
static int case_print_hi(char* str, const char* const hi)
8
0
{
9
0
  if (!hi)
10
0
    return printf("%s", str);
11
0
  const size_t hilen = strlen(hi);
12
0
  char* savestr = strstr(str, hi);
13
0
  int nchr = 0;
14
0
  while (savestr)
15
0
  {
16
0
    for (;str < savestr; ++str, ++nchr)
17
0
      putchar(str[0]);
18
0
    nchr += printf("\033[7m%s\033[0m", hi); // decorate with underline.
19
0
    str += hilen;
20
0
    savestr = strstr(str, hi);
21
0
  }
22
0
  nchr += printf("%s", str);
23
0
  return nchr;
24
0
}
25
26
static void case_run(case_t* test_case, const char* const match_test, int i, int total, int* pass, int* skip, int* fail)
27
308
{
28
308
  // Change the current directory.
29
308
  if (test_case->dir && test_case->dir[0] != 0 && strcmp(test_case->dir, ".") != 0)
30
308
    chdir(test_case->dir);
31
308
  int clr = 0;
32
308
  if (isatty(fileno(stdout)))
33
0
  {
34
0
    clr += printf("\033[0;34m[%d/%d]\033[0;0m \033[1;33m[RUN]\033[0;0m ", i + 1, total);
35
0
    clr += case_print_hi(test_case->name, match_test);
36
0
    clr += printf(" ...");
37
0
  } else
38
308
    clr += printf("[%d/%d] [RUN] %s ...", i + 1, total, test_case->name);
39
308
  fflush(stdout);
40
308
  int result = 0;
41
308
  test_case->func(test_case->name, &result);
42
308
  if (result == 0)
43
308
  {
44
308
    (*pass)++;
45
20.1k
    for (; clr > 0; 
--clr19.8k
)
46
19.8k
      printf("\b");
47
308
    if (isatty(fileno(stdout)))
48
0
    {
49
0
      printf("\r\033[0;34m[%d/%d]\033[0;0m \033[1;32m[PASS]\033[0;0m ", i + 1, total);
50
0
      case_print_hi(test_case->name, match_test);
51
0
      printf("    \n");
52
0
    } else
53
308
      printf("\r[%d/%d] [PASS] %s    \n", i + 1, total, test_case->name);
54
308
  } else 
if (0
result == -20
) {
55
0
    (*skip)++;
56
0
    if (isatty(fileno(stdout)))
57
0
    {
58
0
      printf("\n\033[0;34m[%d/%d]\033[0;0m \033[1;32m[SKIP]\033[0;0m ", i + 1, total);
59
0
      case_print_hi(test_case->name, match_test);
60
0
      printf("\n");
61
0
    } else
62
0
      printf("\n[%d/%d] [SKIP] %s\n", i + 1, total, test_case->name);
63
0
  } else {
64
0
    (*fail)++;
65
0
    if (isatty(fileno(stdout)))
66
0
    {
67
0
      printf("\n\033[0;34m[%d/%d]\033[0;0m \033[1;31m[FAIL]\033[0;0m ", i + 1, total);
68
0
      case_print_hi(test_case->name, match_test);
69
0
      printf("\n");
70
0
    } else
71
0
      printf("\n[%d/%d] [FAIL] %s\n", i + 1, total, test_case->name);
72
0
  }
73
308
}
74
75
static void case_conclude(int pass, int skip, int fail)
76
1
{
77
1
  if (isatty(fileno(stdout)))
78
0
  {
79
0
    if (skip > 0)
80
0
    {
81
0
      if (fail == 0)
82
0
        printf("\033[0;32mall test case(s) passed, %d test case(s) skipped, congratulations!\033[0;0m\n", skip);
83
0
      else
84
0
        printf("\033[0;31m%d of %d test case(s) passed, %d test case(s) skipped\033[0;0m\n", pass, fail + pass, skip);
85
0
    } else {
86
0
      if (fail == 0)
87
0
        printf("\033[0;32mall test case(s) passed, congratulations!\033[0;0m\n");
88
0
      else
89
0
        printf("\033[0;31m%d of %d test case(s) passed\033[0;0m\n", pass, fail + pass);
90
0
    }
91
1
  } else {
92
1
    if (skip > 0)
93
0
    {
94
0
      if (fail == 0)
95
0
        printf("all test case(s) passed, %d test case(s) skipped, congratulations!\n", skip);
96
0
      else
97
0
        printf("%d of %d test case(s) passed, %d test case(s) skipped\n", pass, fail + pass, skip);
98
1
    } else {
99
1
      if (fail == 0)
100
1
        printf("all test case(s) passed, congratulations!\n");
101
0
      else
102
0
        printf("%d of %d test case(s) passed\n", pass, fail + pass);
103
1
    }
104
1
  }
105
1
}
106
107
#ifdef __ELF__
108
// in ELF object format, we can simply query custom section rather than scan through the whole binary memory
109
// to find function pointer. We do this whenever possible because in this way, we don't have access error
110
// when hooking up with memory checkers such as address sanitizer or valgrind
111
112
static case_t __test_case_ctx_assessment__ __attribute__((used, section("case_data_assessment"), aligned(8))) = {0};
113
114
extern case_t __start_case_data[];
115
extern case_t __stop_case_data[];
116
117
extern case_t __start_case_data_assessment[];
118
extern case_t __stop_case_data_assessment[];
119
120
int main(int argc, char** argv)
121
1
{
122
1
  int case_size = (intptr_t)__stop_case_data_assessment - (intptr_t)__start_case_data_assessment;
123
1
  int test_size = (intptr_t)__stop_case_data - (intptr_t)__start_case_data;
124
1
  char buf[1024];
125
1
  char* cur_dir = getcwd(buf, 1024);
126
1
  static uint64_t the_sig = 0x883253372849284B;
127
1
  int scan_mode = (test_size % case_size != 0);
128
1
  const char* match_test = (argc == 2) ? 
argv[1]0
: 0;
129
1
  int i, total = 0;
130
1
  if (!scan_mode)
131
1
    total = test_size / case_size;
132
309
  for (i = 0; i < total; 
i++308
)
133
308
  {
134
308
    case_t* test_case = (case_t*)((unsigned char*)__start_case_data + i * case_size);
135
308
    // If it doesn't match well, fallback to scan mode.
136
308
    if (test_case->sig_head != the_sig || test_case->sig_tail != the_sig + 2)
137
0
    {
138
0
      scan_mode = 1;
139
0
      break;
140
0
    }
141
308
  }
142
1
  int len, pass = 0, skip = 0, fail = 0;
143
1
  // In scan mode, we will scan the whole section for a matching test case.
144
1
  if (scan_mode)
145
0
  {
146
0
    total = 0;
147
0
    len = (intptr_t)__stop_case_data - (intptr_t)__start_case_data - sizeof(case_t) + 1;
148
0
    for (i = 0; i < len; i++)
149
0
    {
150
0
      case_t* test_case = (case_t*)((unsigned char*)__start_case_data + i);
151
0
      if (test_case->sig_head == the_sig && test_case->sig_tail == the_sig + 2 &&
152
0
        (!match_test || strstr(test_case->name, match_test)))
153
0
        total++;
154
0
    }
155
0
  }
156
1
  if (__test_case_setup)
157
1
    __test_case_setup();
158
1
  if (scan_mode)
159
0
  {
160
0
    int j = 0;
161
0
    for (i = 0; i < len; i++)
162
0
    {
163
0
      case_t* test_case = (case_t*)((unsigned char*)__start_case_data + i);
164
0
      if (test_case->sig_head == the_sig && test_case->sig_tail == the_sig + 2 &&
165
0
        (!match_test || strstr(test_case->name, match_test)))
166
0
      {
167
0
        case_run(test_case, match_test, j++, total, &pass, &skip, &fail);
168
0
        chdir(cur_dir);
169
0
      }
170
0
    }
171
1
  } else {
172
1
    int matched_total = match_test ? 
00
: total;
173
1
    if (match_test)
174
0
      for (i = 0; i < total; i++)
175
0
      {
176
0
        case_t* test_case = (case_t*)((unsigned char*)__start_case_data + i * case_size);
177
0
        if (strstr(test_case->name, match_test))
178
0
          matched_total++;
179
0
      }
180
1
    int j = 0;
181
1
    // Simple case, I don't need to scan the data section.
182
309
    for (i = 0; i < total; 
i++308
)
183
308
    {
184
308
      case_t* test_case = (case_t*)((unsigned char*)__start_case_data + i * case_size);
185
308
      if (!match_test || 
strstr(test_case->name, match_test)0
)
186
308
        case_run(test_case, match_test, j++, matched_total, &pass, &skip, &fail);
187
308
      chdir(cur_dir);
188
308
    }
189
1
  }
190
1
  if (__test_case_teardown)
191
0
    __test_case_teardown();
192
1
  case_conclude(pass, skip, fail);
193
1
  return fail;
194
1
}
195
196
#else
197
198
#include <stdio.h>
199
#include <unistd.h>
200
#include <stdlib.h>
201
#include <fcntl.h>
202
#include <ctype.h>
203
#include <signal.h>
204
#include <setjmp.h>
205
206
/* the following functions come from Hans Boehm's conservative gc with slightly
207
 * modifications, here is the licence:
208
 * Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers
209
 * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
210
 * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
211
 * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
212
213
 * The file linux_threads.c is also
214
 * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
215
216
 * The files Makefile.am, and configure.in are
217
 * Copyright (c) 2001 by Red Hat Inc. All rights reserved.
218
219
 * Several files supporting GNU-style builds are copyrighted by the Free
220
 * Software Foundation, and carry a different license from that given
221
 * below.
222
223
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
224
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
225
226
 * Permission is hereby granted to use or copy this program
227
 * for any purpose,  provided the above notices are retained on all copies.
228
 * Permission to modify the code and to distribute modified code is granted,
229
 * provided the above notices are retained, and a notice that the code was
230
 * modified is included with the above copyright notice.
231
232
 * A few of the files needed to use the GNU-style build procedure come with
233
 * slightly different licenses, though they are all similar in spirit.  A few
234
 * are GPL'ed, but with an exception that should cover all uses in the
235
 * collector. */
236
237
/* Repeatedly perform a read call until the buffer is filled or */
238
/* we encounter EOF.            */
239
static ssize_t case_repeat_read(int fd, char *buf, size_t count)
240
{
241
    ssize_t num_read = 0;
242
    ssize_t result;
243
    
244
    while (num_read < count)
245
  {
246
    result = read(fd, buf + num_read, count - num_read);
247
    if (result < 0)
248
      return result;
249
    if (result == 0)
250
      break;
251
    num_read += result;
252
    }
253
    return num_read;
254
}
255
256
/* Determine the length of a file by incrementally reading it into a buffer */
257
/* This would be silly to use on a file supporting lseek, but Linux */
258
/* /proc files usually do not.  */
259
static size_t case_get_file_len(int f)
260
{
261
    size_t total = 0;
262
    ssize_t result;
263
    char buf[500];
264
265
    do {
266
    result = read(f, buf, 500);
267
    if (result == -1)
268
      return 0;
269
    total += result;
270
    } while (result > 0);
271
    return total;
272
}
273
274
static size_t case_get_maps_len(void)
275
{
276
    int f = open("/proc/self/maps", O_RDONLY);
277
    size_t result = case_get_file_len(f);
278
    close(f);
279
    return result;
280
}
281
282
/*
283
 * Copy the contents of /proc/self/maps to a buffer in our address space.
284
 * Return the address of the buffer, or zero on failure.
285
 * This code could be simplified if we could determine its size
286
 * ahead of time.
287
 */
288
static char* case_get_maps()
289
{
290
    int f;
291
    int result;
292
    static char init_buf[1];
293
    static char *maps_buf = init_buf;
294
    static size_t maps_buf_sz = 1;
295
    size_t maps_size, old_maps_size = 0;
296
297
    /* Note that in the presence of threads, the maps file can  */
298
    /* essentially shrink asynchronously and unexpectedly as  */
299
    /* threads that we already think of as dead release their */
300
    /* stacks.  And there is no easy way to read the entire */
301
    /* file atomically.  This is arguably a misfeature of the */
302
    /* /proc/.../maps interface.        */
303
304
    /* Since we dont believe the file can grow      */
305
    /* asynchronously, it should suffice to first determine */
306
    /* the size (using lseek or read), and then to reread the */
307
    /* file.  If the size is inconsistent we have to retry. */
308
    /* This only matters with threads enabled, and if we use  */
309
    /* this to locate roots (not the default).      */
310
311
    /* Determine the initial size of /proc/self/maps.   */
312
    /* Note that lseek doesn't work, at least as of 2.6.15. */
313
  maps_size = case_get_maps_len();
314
  if (0 == maps_size)
315
    return 0;
316
317
    /* Read /proc/self/maps, growing maps_buf as necessary. */
318
    /* Note that we may not allocate conventionally, and  */
319
    /* thus can't use stdio.          */
320
  do {
321
      while (maps_size >= maps_buf_sz)
322
    {
323
      /* Grow only by powers of 2, since we leak "too small" buffers. */
324
      while (maps_size >= maps_buf_sz)
325
        maps_buf_sz *= 2;
326
      maps_buf = malloc(maps_buf_sz);
327
      /* Recompute initial length, since we allocated.  */
328
      /* This can only happen a few times per program   */
329
      /* execution.           */
330
      maps_size = case_get_maps_len();
331
      if (0 == maps_size)
332
        return 0;
333
      }
334
      f = open("/proc/self/maps", O_RDONLY);
335
      if (-1 == f)
336
      return 0;
337
    old_maps_size = maps_size;
338
      maps_size = 0;
339
      do {
340
      result = case_repeat_read(f, maps_buf, maps_buf_sz - 1);
341
      if (result <= 0)
342
        return 0;
343
      maps_size += result;
344
      } while (result == maps_buf_sz - 1);
345
      close(f);
346
  } while (maps_size >= maps_buf_sz || maps_size < old_maps_size);
347
  /* In the single-threaded case, the second clause is false. */
348
    maps_buf[maps_size] = '\0';
349
  
350
    /* Apply fn to result. */
351
  return maps_buf;
352
}
353
354
//
355
//  GC_parse_map_entry parses an entry from /proc/self/maps so we can
356
//  locate all writable data segments that belong to shared libraries.
357
//  The format of one of these entries and the fields we care about
358
//  is as follows:
359
//  XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537     name of mapping...\n
360
//  ^^^^^^^^ ^^^^^^^^ ^^^^          ^^
361
//  start    end      prot          maj_dev
362
//
363
//  Note that since about august 2003 kernels, the columns no longer have
364
//  fixed offsets on 64-bit kernels.  Hence we no longer rely on fixed offsets
365
//  anywhere, which is safer anyway.
366
//
367
368
/*
369
 * Assign various fields of the first line in buf_ptr to *start, *end,
370
 * *prot, *maj_dev and *mapping_name.  Mapping_name may be NULL.
371
 * *prot and *mapping_name are assigned pointers into the original
372
 * buffer.
373
 */
374
static char* case_parse_map_entry(char* buf_ptr, void** start, void** end, char** prot, unsigned int* maj_dev, char** mapping_name)
375
{
376
    char *start_start, *end_start, *maj_dev_start;
377
    char *p;
378
    char *endp;
379
380
    if (buf_ptr == NULL || *buf_ptr == '\0')
381
        return NULL;
382
383
    p = buf_ptr;
384
    while (isspace(*p))
385
    ++p;
386
    start_start = p;
387
    *start = (void*)strtoul(start_start, &endp, 16);
388
  p = endp;
389
390
    ++p;
391
    end_start = p;
392
    *end = (void*)strtoul(end_start, &endp, 16);
393
  p = endp;
394
395
    while (isspace(*p))
396
    ++p;
397
    *prot = p;
398
    /* Skip past protection field to offset field */
399
  while (!isspace(*p))
400
    ++p;
401
  while (isspace(*p))
402
    ++p;
403
    /* Skip past offset field, which we ignore */
404
  while (!isspace(*p))
405
    ++p;
406
  while (isspace(*p))
407
    ++p;
408
    maj_dev_start = p;
409
    *maj_dev = strtoul(maj_dev_start, NULL, 16);
410
411
    if (mapping_name == 0)
412
  {
413
      while (*p && *p++ != '\n');
414
    } else {
415
      while (*p && *p != '\n' && *p != '/' && *p != '[')
416
      p++;
417
      *mapping_name = p;
418
      while (*p && *p++ != '\n');
419
    }
420
421
    return p;
422
}
423
424
#define MIN_PAGE_SIZE (256)
425
426
static jmp_buf case_jmp_buf;
427
428
static void case_fault_handler(int sig)
429
{
430
  longjmp(case_jmp_buf, 1);
431
}
432
433
static struct sigaction old_segv_act;
434
static struct sigaction old_bus_act;
435
436
static void case_setup_temporary_fault_handler(void)
437
{
438
  struct sigaction act;
439
  act.sa_handler = case_fault_handler;
440
  act.sa_flags = SA_RESTART;
441
  (void)sigemptyset(&act.sa_mask);
442
  (void)sigaction(SIGSEGV, &act, &old_segv_act);
443
  (void)sigaction(SIGBUS, &act, &old_bus_act);
444
}
445
446
static void case_reset_fault_handler(void)
447
{
448
  (void)sigaction(SIGSEGV, &old_segv_act, 0);
449
  (void)sigaction(SIGBUS, &old_bus_act, 0);
450
}
451
452
static void case_find_limit(char* p, void** start, void** end)
453
{
454
  static volatile char* result;
455
  static volatile char sink;
456
  case_setup_temporary_fault_handler();
457
  if (setjmp(case_jmp_buf) == 0)
458
  {
459
    result = (char*)((uint64_t)p & (uint64_t)~(MIN_PAGE_SIZE - 1));
460
    for (;;)
461
    {
462
      result -= MIN_PAGE_SIZE;
463
      sink = *result;
464
    }
465
  }
466
  *start = (void*)(result + MIN_PAGE_SIZE);
467
  if (setjmp(case_jmp_buf) == 0)
468
  {
469
    result = (char*)((uint64_t)p & (uint64_t)~(MIN_PAGE_SIZE - 1));
470
    for (;;)
471
    {
472
      result += MIN_PAGE_SIZE;
473
      sink = *result;
474
    }
475
  }
476
  *end = (void*)result;
477
  case_reset_fault_handler();
478
}
479
480
static char _test_end[8];
481
482
int main(int argc, char** argv)
483
{
484
  const char* match_test = (argc == 2) ? argv[1] : 0;
485
  char* buf = case_get_maps();
486
  void* start;
487
  void* end;
488
  char* prot[4];
489
  unsigned int maj_dev;
490
  static uint64_t the_sig = 0x883253372849284B;
491
  if (buf == 0)
492
  {
493
    case_find_limit(_test_end, &start, &end);
494
  } else {
495
    do {
496
      buf = case_parse_map_entry(buf, &start, &end, (char**)&prot, &maj_dev, 0);
497
      if (buf == NULL)
498
        break;
499
    } while ((intptr_t)start >= (intptr_t)&_test_end || (intptr_t)&_test_end >= (intptr_t)end);
500
  }
501
  char* start_pointer = (char*)start;
502
  int total = 0;
503
  int len = (intptr_t)end - (intptr_t)start - sizeof(case_t) + 1;
504
  int i;
505
  for (i = 0; i < len; i++)
506
  {
507
    case_t* test_case = (case_t*)(start_pointer + i);
508
    if (test_case->sig_head == the_sig && test_case->sig_tail == the_sig + 2 &&
509
      (!match_test || strstr(test_case->name, match_test)))
510
      total++;
511
  }
512
  char dir_buf[1024];
513
  char* cur_dir = getcwd(dir_buf, 1024);
514
  if (__test_case_setup)
515
    __test_case_setup();
516
  int j = 0, pass = 0, skip = 0, fail = 0;
517
  for (i = 0; i < len; i++)
518
  {
519
    case_t* test_case = (case_t*)(start_pointer + i);
520
    if (test_case->sig_head == the_sig && test_case->sig_tail == the_sig + 2 &&
521
      (!match_test || strstr(test_case->name, match_test)))
522
    {
523
      case_run(test_case, match_test, j++, total, &pass, &skip, &fail);
524
      chdir(cur_dir);
525
    }
526
  }
527
  if (__test_case_teardown)
528
    __test_case_teardown();
529
  case_conclude(pass, skip, fail);
530
  return fail;
531
}
532
533
#endif
534
#endif