📄 coredumper_unittest.c
字号:
} /* No more patterns. We have a successful match. */ if (!c) goto found; templ[l] = c; templ += l + 1; } } found: /* Print matched pattern. Enter arg into command stream. Then loop. */ printf("Found: %s", *ptr); if (arg && *out_ptr == '@') { /* We only want to match the very last word; drop leading tokens. */ int rc; char *last = strrchr(arg, ' '); if (last != NULL) arg = last + 1; /* Enter matched data into the command stream. */ rc = fputs(arg, input); assert(rc > 0); printf(" (arg = \"%s\")", arg); arg = 0; out_ptr++; } puts(""); } assert(*dummy == cmp); printf("Magic marker matches %d\n", *dummy); }}/* We can test both the WriteCoreDump() and the GetCoreDump() functions * with the same test cases. We just need to wrap the GetCoreDump() * family of functions with some code that emulates the WriteCoreDump() * functions. */static int MyWriteCompressedCoreDump(const char *file_name, size_t max_length, const struct CoredumperCompressor compressors[], struct CoredumperCompressor **selected_compressor){ int rc = 0; int coreFd; struct CoredumperCompressor *comp; if (!max_length) return 0; coreFd = GetCompressedCoreDump(compressors, &comp); if (selected_compressor != NULL) *selected_compressor = comp; if (coreFd >= 0) { int writeFd; const char *suffix = ""; if (comp != NULL && comp->compressor != NULL && comp->suffix != NULL) suffix = comp->suffix; /* scope */ { char extended_file_name[strlen(file_name) + strlen(suffix) + 1]; strcat(strcpy(extended_file_name, file_name), suffix); writeFd = open(extended_file_name, O_WRONLY|O_CREAT|O_TRUNC, 0600); } if (writeFd >= 0) { char buffer[16384]; ssize_t len; while (max_length > 0 && ((len = read(coreFd, buffer, sizeof(buffer) < max_length ? sizeof(buffer) : max_length)) > 0 || (len < 0 && errno == EINTR))) { char *ptr = buffer; while (len > 0) { int i; i = write(writeFd, ptr, len); if (i <= 0) { rc = -1; break; } ptr += i; len -= i; max_length -= i; } } close(writeFd); } else { rc = -1; } close(coreFd); } else { rc = -1; } return rc;}static int MyWriteCoreDump(const char *file_name) { return MyWriteCompressedCoreDump(file_name, SIZE_MAX, NULL, NULL);}static int MyWriteCoreDumpLimited(const char *file_name, size_t max_length) { return MyWriteCompressedCoreDump(file_name, max_length, NULL, NULL);}/* Do not declare this function static, so that the compiler does not get * tempted to inline it. We want to be able to see some stack traces. */void TestCoreDump() { static struct CoredumperCompressor my_compressor[] = { { "/NOSUCHDIR/NOSUCHFILE", 0, 0 }, { 0, 0, 0 }, /* Will be overwritten by test */ { 0, 0, 0 } }; int loop, in[2], out[2], dummy, cmp, rc; pid_t pid; FILE *input, *output; pthread_t thread; struct stat statBuf; struct CoredumperCompressor *compressor; /* Make stdout unbuffered. We absolutely want to see all output, even * if the application aborted with an assertion failure. */ setvbuf(stdout, NULL, _IONBF, 0); /* It is rather tricky to properly call fork() from within a multi-threaded * application. To simplify this problem, we fork and exec /bin/bash before * creating the first thread. */ puts("Forking /bin/bash process"); rc = pipe(in); assert(!rc); rc = pipe(out); assert(!rc); if ((pid = fork()) == 0) { int i, openmax; dup2(in[0], 0); dup2(out[1], 1); dup2(out[1], 2); openmax = sysconf(_SC_OPEN_MAX); for (i = 3; i < openmax; i++) close(i); fcntl(0, F_SETFD, 0); fcntl(1, F_SETFD, 0); fcntl(2, F_SETFD, 0); execl("/bin/bash", "bash", "-ex", NULL); _exit(1); } assert(pid >= 0); assert(!close(in[0])); assert(!close(out[1])); input = fdopen(in[1], "w"); output = fdopen(out[0], "r"); setvbuf(input, NULL, _IONBF, 0); setvbuf(output, NULL, _IONBF, 0); /* Create a random value in one of our auto variables; we will later look * for this value by inspecting the core file with gdb. */ srand(time(0)); dummy = random(); cmp = ~dummy; /* Start some threads that should show up in our core dump; this is * complicated by the fact that we do not want our threads to perform any * system calls. So, they are busy looping and checking a volatile * state variable, instead. */ puts("Starting threads"); pthread_create(&thread, 0, Busy, (void *)&state1); pthread_create(&thread, 0, Busy, (void *)&state2); while (state1 != RUNNING || state2 != RUNNING) { usleep(100*1000); } for (loop = 0; loop < 2; loop++) { /* Prepare to create a core dump for the current process */ puts("Writing core file to \"core-test\""); unlink("core-test"); /* Check whether limits work correctly */ rc = (loop?MyWriteCoreDumpLimited:WriteCoreDumpLimited)("core-test", 0); assert(!rc); assert(stat("core-test", &statBuf) < 0); rc = (loop?MyWriteCoreDumpLimited:WriteCoreDumpLimited)("core-test", 256); assert(!rc); assert(!stat("core-test", &statBuf)); assert(statBuf.st_size == 256); assert(!unlink("core-test")); /* Check wether compression works */ puts("Checking compressed core files"); rc = (loop?MyWriteCompressedCoreDump:WriteCompressedCoreDump) ("core-test", SIZE_MAX, COREDUMPER_GZIP_COMPRESSED, &compressor); assert(!rc); assert(compressor); assert(strstr(compressor->compressor, "gzip")); assert(!strcmp(compressor->suffix, ".gz")); CheckWithReadElf(input, output, "core-test", compressor->suffix, compressor->compressor, "-d"); assert(!unlink("core-test.gz")); /* Check wether fallback to uncompressed core files works */ puts("Checking fallback to uncompressed core files"); my_compressor[1].compressor = NULL; /* Disable uncompressed files */ rc = (loop?MyWriteCompressedCoreDump:WriteCompressedCoreDump) ("core-test", SIZE_MAX, my_compressor, &compressor); assert(rc); assert(!compressor->compressor); my_compressor[1].compressor = ""; /* Enable uncompressed files */ rc = (loop?MyWriteCompressedCoreDump:WriteCompressedCoreDump) ("core-test", SIZE_MAX, my_compressor, &compressor); assert(!rc); assert(compressor->compressor); assert(!*compressor->compressor); CheckWithReadElf(input, output, "core-test", "", "cat", ""); assert(!unlink("core-test")); /* Create a full-size core file */ puts("Checking uncompressed core files"); rc = (loop?MyWriteCoreDump:WriteCoreDump)("core-test"); assert(!rc); CheckWithReadElf(input, output, "core-test", "", "cat", ""); CheckWithGDB(input, output, "core-test", &dummy, cmp); /* Get rid of our temporary test file */ unlink("core-test"); } /* Stop our threads */ puts("Stopping threads"); state1 = DEAD; state2 = DEAD; /* Kill bash process */ kill(SIGTERM, pid); fclose(input); fclose(output); return;}int main(int argc, char *argv[]) { static int bloat[1024*1024]; int i; /* This unittest parses the output from "readelf" and "gdb" in order to * verify that the core files look correct. And unfortunately, some of * the messages for these programs have been localized, so the unittest * cannot always find the text that it is looking for. * Let's just force everything back to English: */ putenv(strdup("LANGUAGE=C")); putenv(strdup("LC_ALL=C")); /* Make our RSS a little bigger, so that we can test codepaths that do not * trigger for very small core files. Also, make sure that this data is * not easily compressible nor in a read-only memory segment. */ for (i = 0; i < sizeof(bloat)/sizeof(int); i++) { bloat[i] = rand(); } TestCoreDump(); puts("PASS"); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -