| #include <errno.h> |
| #include <fcntl.h> |
| #include <inttypes.h> |
| #include <libgen.h> |
| #include <limits.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include "honggfuzz.h" |
| #include "libhfcommon/common.h" |
| #include "libhfcommon/files.h" |
| #include "libhfcommon/log.h" |
| #include "libhfcommon/util.h" |
| |
| #define ARGS_MAX 4096 |
| |
| static bool isCXX = false; |
| static bool isGCC = false; |
| static bool usePCGuard = true; |
| static bool hasCmdLineFSanitizeFuzzer = false; |
| |
| /* Embed libhf/.a inside this binary */ |
| __asm__("\n" |
| #if !defined(_HF_ARCH_DARWIN) && !defined(__APPLE__) |
| " .section .rodata\n" |
| #endif /* _HF_ARCH_DARWIN */ |
| " .global lhfuzz_start\n" |
| " .global lhfuzz_end\n" |
| "lhfuzz_start:\n" |
| " .incbin \"libhfuzz/libhfuzz.a\"\n" |
| "lhfuzz_end:\n" |
| "\n" |
| " .global lhfnetdriver_start\n" |
| " .global lhfnetdriver_end\n" |
| "lhfnetdriver_start:\n" |
| " .incbin \"libhfnetdriver/libhfnetdriver.a\"\n" |
| "lhfnetdriver_end:\n" |
| "\n" |
| " .global lhfcommon_start\n" |
| " .global lhfcommon_end\n" |
| "lhfcommon_start:\n" |
| " .incbin \"libhfcommon/libhfcommon.a\"\n" |
| "lhfcommon_end:\n" |
| "\n"); |
| |
| static const char* _basename(const char* path) { |
| static __thread char fname[PATH_MAX]; |
| /* basename() can modify the argument (sic!) */ |
| snprintf(fname, sizeof(fname), "%s", path); |
| return basename(fname); |
| } |
| |
| static bool useASAN() { |
| if (getenv("HFUZZ_CC_ASAN")) { |
| return true; |
| } |
| return false; |
| } |
| |
| static bool useMSAN() { |
| if (getenv("HFUZZ_CC_MSAN")) { |
| return true; |
| } |
| return false; |
| } |
| |
| static bool useUBSAN() { |
| if (getenv("HFUZZ_CC_UBSAN")) { |
| return true; |
| } |
| return false; |
| } |
| |
| static bool useM32() { |
| if (getenv("HFUZZ_FORCE_M32")) { |
| return true; |
| } |
| return false; |
| } |
| |
| static bool useBelowGCC8() { |
| if (getenv("HFUZZ_CC_USE_GCC_BELOW_8")) { |
| return true; |
| } |
| return false; |
| } |
| |
| static bool isVersionMode(int argc, char** argv) { |
| for (int i = 1; i < argc; i++) { |
| if (strcmp(argv[i], "--version") == 0) { |
| return true; |
| } |
| if (strcmp(argv[i], "--target-help") == 0) { |
| return true; |
| } |
| if (strcmp(argv[i], "--help") == 0) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| static bool isLDMode(int argc, char** argv) { |
| for (int i = 1; i < argc; i++) { |
| if (strcmp(argv[i], "--version") == 0) { |
| return false; |
| } |
| if (strcmp(argv[i], "--target-help") == 0) { |
| return false; |
| } |
| if (strcmp(argv[i], "-c") == 0) { |
| return false; |
| } |
| if (strcmp(argv[i], "-E") == 0) { |
| return false; |
| } |
| if (strcmp(argv[i], "-S") == 0) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| static bool isExecutableBuild(int argc, char** argv) { |
| bool shared_flag = false; |
| char* output_filename = NULL; |
| |
| for (int i = 0; i < argc; i++) { |
| // Check for Linux shared or macOS dynamic library flags. |
| if (strcmp(argv[i], "-shared") == 0 || strcmp(argv[i], "--shared") == 0 || |
| strcmp(argv[i], "-dynamiclib") == 0) { |
| shared_flag = true; |
| } else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) { |
| output_filename = argv[i + 1]; |
| } |
| } |
| |
| if (shared_flag) { |
| return false; |
| } |
| |
| if (output_filename != NULL) { |
| const char* ext = strrchr(output_filename, '.'); |
| if (ext != NULL && (strcmp(ext, ".so") == 0 || strcmp(ext, ".dylib") == 0)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| static bool hasFSanitizeFuzzer(int argc, char** argv) { |
| for (int i = 1; i < argc; i++) { |
| if (util_strStartsWith(argv[i], "-fsanitize=") && strstr(argv[i], "fuzzer")) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| static int hf_execvp(const char* file, char** argv) { |
| argv[0] = (char*)file; |
| return execvp(file, argv); |
| } |
| |
| static int execCC(int argc, char** argv) { |
| if (useASAN()) { |
| argv[argc++] = "-fsanitize=address"; |
| } |
| if (useMSAN()) { |
| argv[argc++] = "-fsanitize=memory"; |
| } |
| if (useUBSAN()) { |
| argv[argc++] = "-fsanitize=undefined"; |
| argv[argc++] = "-fno-sanitize-recover=undefined"; |
| } |
| argv[argc] = NULL; |
| |
| if (isCXX) { |
| const char* cxx_path = getenv("HFUZZ_CXX_PATH"); |
| if (cxx_path != NULL) { |
| hf_execvp(cxx_path, argv); |
| PLOG_E("execvp('%s')", cxx_path); |
| return EXIT_FAILURE; |
| } |
| } else { |
| const char* cc_path = getenv("HFUZZ_CC_PATH"); |
| if (cc_path != NULL) { |
| hf_execvp(cc_path, argv); |
| PLOG_E("execvp('%s')", cc_path); |
| return EXIT_FAILURE; |
| } |
| } |
| |
| if (isGCC) { |
| if (isCXX) { |
| hf_execvp("g++", argv); |
| hf_execvp("gcc", argv); |
| } else { |
| hf_execvp("gcc", argv); |
| } |
| } else { |
| if (isCXX) { |
| /* Try the default one, then the newest ones (hopefully) in order */ |
| hf_execvp("clang++", argv); |
| hf_execvp("clang++-22.0", argv); |
| hf_execvp("clang++-22", argv); |
| hf_execvp("clang++-21.0", argv); |
| hf_execvp("clang++-21", argv); |
| hf_execvp("clang++-20.0", argv); |
| hf_execvp("clang++-20", argv); |
| hf_execvp("clang++-19.0", argv); |
| hf_execvp("clang++-19", argv); |
| hf_execvp("clang++-18.0", argv); |
| hf_execvp("clang++-18", argv); |
| hf_execvp("clang++-17.0", argv); |
| hf_execvp("clang++-17", argv); |
| hf_execvp("clang++-16.0", argv); |
| hf_execvp("clang++-16", argv); |
| hf_execvp("clang++-15.0", argv); |
| hf_execvp("clang++-15", argv); |
| hf_execvp("clang++-14.0", argv); |
| hf_execvp("clang++-14", argv); |
| hf_execvp("clang++-13.0", argv); |
| hf_execvp("clang++-13", argv); |
| hf_execvp("clang++-12.0", argv); |
| hf_execvp("clang++-12", argv); |
| hf_execvp("clang++12", argv); |
| hf_execvp("clang++-11.0", argv); |
| hf_execvp("clang++-11", argv); |
| hf_execvp("clang++11", argv); |
| hf_execvp("clang++-10.0", argv); |
| hf_execvp("clang++-10", argv); |
| hf_execvp("clang++10", argv); |
| hf_execvp("clang++-9.0", argv); |
| hf_execvp("clang++-9", argv); |
| hf_execvp("clang++9", argv); |
| hf_execvp("clang++-8.0", argv); |
| hf_execvp("clang++-8", argv); |
| hf_execvp("clang++8", argv); |
| hf_execvp("clang++-7.0", argv); |
| hf_execvp("clang++-7", argv); |
| hf_execvp("clang++7", argv); |
| hf_execvp("clang", argv); |
| hf_execvp("clang++", argv); |
| } else { |
| /* Try the default one, then the newest ones (hopefully) in order */ |
| hf_execvp("clang", argv); |
| hf_execvp("clang-22.0", argv); |
| hf_execvp("clang-22", argv); |
| hf_execvp("clang-21.0", argv); |
| hf_execvp("clang-21", argv); |
| hf_execvp("clang-20.0", argv); |
| hf_execvp("clang-20", argv); |
| hf_execvp("clang-19.0", argv); |
| hf_execvp("clang-19", argv); |
| hf_execvp("clang-18.0", argv); |
| hf_execvp("clang-18", argv); |
| hf_execvp("clang-17.0", argv); |
| hf_execvp("clang-17", argv); |
| hf_execvp("clang-16.0", argv); |
| hf_execvp("clang-16", argv); |
| hf_execvp("clang-15.0", argv); |
| hf_execvp("clang-15", argv); |
| hf_execvp("clang-14.0", argv); |
| hf_execvp("clang-14", argv); |
| hf_execvp("clang-13.0", argv); |
| hf_execvp("clang-13", argv); |
| hf_execvp("clang-12.0", argv); |
| hf_execvp("clang-12", argv); |
| hf_execvp("clang12", argv); |
| hf_execvp("clang-11.0", argv); |
| hf_execvp("clang-11", argv); |
| hf_execvp("clang11", argv); |
| hf_execvp("clang-10.0", argv); |
| hf_execvp("clang-10", argv); |
| hf_execvp("clang10", argv); |
| hf_execvp("clang-9.0", argv); |
| hf_execvp("clang-9", argv); |
| hf_execvp("clang9", argv); |
| hf_execvp("clang-8.0", argv); |
| hf_execvp("clang-8", argv); |
| hf_execvp("clang8", argv); |
| hf_execvp("clang-7.0", argv); |
| hf_execvp("clang-7", argv); |
| hf_execvp("clang7", argv); |
| hf_execvp("clang", argv); |
| } |
| } |
| |
| PLOG_F("execvp('%s')", argv[0]); |
| return EXIT_FAILURE; |
| } |
| |
| /* It'll point back to the libhfuzz's source tree */ |
| char* getIncPaths(void) { |
| #if !defined(_HFUZZ_INC_PATH) |
| #error \ |
| "You need to define _HFUZZ_INC_PATH to a directory with the directory called 'includes', containing honggfuzz's lib* includes. Typically it'd be the build/sources dir" |
| #endif |
| |
| static char path[PATH_MAX]; |
| snprintf(path, sizeof(path), "-I%s/includes/", HF_XSTR(_HFUZZ_INC_PATH)); |
| return path; |
| } |
| |
| static bool getLibPath( |
| const char* name, const char* env, const uint8_t* start, const uint8_t* end, char* path) { |
| const char* libEnvLoc = getenv(env); |
| if (libEnvLoc) { |
| snprintf(path, PATH_MAX, "%s", libEnvLoc); |
| return true; |
| } |
| |
| ptrdiff_t len = (uintptr_t)end - (uintptr_t)start; |
| uint64_t crc64 = util_CRC64(start, len); |
| snprintf(path, PATH_MAX, "/tmp/%s.%d.%" PRIx64 ".a", name, geteuid(), crc64); |
| |
| /* Does the library exist, belongs to the user, and is of expected size? */ |
| struct stat st; |
| if (stat(path, &st) != -1 && st.st_size == len && st.st_uid == geteuid()) { |
| return true; |
| } |
| |
| /* If not, create it with atomic rename() */ |
| char template[] = "/tmp/lib.honggfuzz.a.XXXXXX"; |
| int fd = TEMP_FAILURE_RETRY(mkostemp(template, O_CLOEXEC)); |
| if (fd == -1) { |
| PLOG_E("mkostemp('%s')", template); |
| return false; |
| } |
| defer { |
| close(fd); |
| }; |
| |
| if (!files_writeToFd(fd, start, len)) { |
| PLOG_E("Couldn't write to '%s'", template); |
| unlink(template); |
| return false; |
| } |
| |
| if (TEMP_FAILURE_RETRY(rename(template, path)) == -1) { |
| PLOG_E("Couldn't rename('%s', '%s')", template, path); |
| unlink(template); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static char* getLibHFuzzPath() { |
| extern uint8_t lhfuzz_start __asm__("lhfuzz_start"); |
| extern uint8_t lhfuzz_end __asm__("lhfuzz_end"); |
| |
| static char path[PATH_MAX] = {}; |
| if (path[0]) { |
| return path; |
| } |
| if (!getLibPath("libhfuzz", "HFUZZ_LHFUZZ_PATH", &lhfuzz_start, &lhfuzz_end, path)) { |
| LOG_F("Couldn't create the temporary libhfuzz.a"); |
| } |
| return path; |
| } |
| |
| static char* getLibHFNetDriverPath() { |
| extern uint8_t lhfnetdriver_start __asm__("lhfnetdriver_start"); |
| extern uint8_t lhfnetdriver_end __asm__("lhfnetdriver_end"); |
| |
| static char path[PATH_MAX] = {}; |
| if (path[0]) { |
| return path; |
| } |
| if (!getLibPath("libhfnetdriver", "HFUZZ_LHFNETDRIVER_PATH", &lhfnetdriver_start, |
| &lhfnetdriver_end, path)) { |
| LOG_F("Couldn't create the temporary libhfnetdriver.a"); |
| } |
| return path; |
| } |
| |
| static char* getLibHFCommonPath() { |
| extern uint8_t lhfcommon_start __asm__("lhfcommon_start"); |
| extern uint8_t lhfcommon_end __asm__("lhfcommon_end"); |
| |
| static char path[PATH_MAX] = {}; |
| if (path[0]) { |
| return path; |
| } |
| if (!getLibPath( |
| "libhfcommon", "HFUZZ_LHFCOMMON_PATH", &lhfcommon_start, &lhfcommon_end, path)) { |
| LOG_F("Couldn't create the temporary libhcommon.a"); |
| } |
| return path; |
| } |
| |
| static void commonPreOpts(int* j, char** args) { |
| args[(*j)++] = getIncPaths(); |
| |
| if (!isGCC) { |
| args[(*j)++] = "-Wno-unused-command-line-argument"; |
| } |
| |
| /* |
| * Make the execution flow more explicit, allowing for more code blocks |
| * (and better code coverage estimates) |
| */ |
| if (isGCC) { |
| args[(*j)++] = "-finline-limit=1000"; |
| } else { |
| args[(*j)++] = "-mllvm"; |
| args[(*j)++] = "-inline-threshold=1000"; |
| } |
| |
| args[(*j)++] = "-fno-builtin"; |
| args[(*j)++] = "-fno-omit-frame-pointer"; |
| args[(*j)++] = "-D__NO_STRING_INLINES"; |
| |
| /* Make it possible to use the libhfnetdriver */ |
| args[(*j)++] = "-DHFND_FUZZING_ENTRY_FUNCTION_CXX(x,y)=" |
| "extern const char* LIBHFNETDRIVER_module_netdriver;" |
| "const char** LIBHFNETDRIVER_tmp1 = &LIBHFNETDRIVER_module_netdriver;" |
| "extern \"C\" int HonggfuzzNetDriver_main(x,y);" |
| "int HonggfuzzNetDriver_main(x,y)"; |
| args[(*j)++] = "-DHFND_FUZZING_ENTRY_FUNCTION(x,y)=" |
| "extern const char* LIBHFNETDRIVER_module_netdriver;" |
| "const char** LIBHFNETDRIVER_tmp1 = &LIBHFNETDRIVER_module_netdriver;" |
| "int HonggfuzzNetDriver_main(x,y);" |
| "int HonggfuzzNetDriver_main(x,y)"; |
| |
| if (useM32()) { |
| args[(*j)++] = "-m32"; |
| } |
| } |
| |
| static void commonPostOpts(int* j, char** args) { |
| if (isGCC) { |
| if (useBelowGCC8()) { |
| /* trace-pc is the best that gcc-6/7 currently offers */ |
| args[(*j)++] = "-fsanitize-coverage=trace-pc"; |
| } else { |
| /* gcc-8+ offers trace-cmp as well, but it's not that widely used yet */ |
| args[(*j)++] = "-fsanitize-coverage=trace-pc,trace-cmp"; |
| } |
| } else { |
| if (usePCGuard) { |
| if (hasCmdLineFSanitizeFuzzer) { |
| args[(*j)++] = "-fno-sanitize=fuzzer"; |
| args[(*j)++] = "-fno-sanitize=fuzzer-no-link"; |
| } |
| args[(*j)++] = "-fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div,indirect-calls"; |
| } else { |
| args[(*j)++] = "-fno-sanitize-coverage=trace-pc-guard"; |
| args[(*j)++] = "-fno-sanitize=fuzzer"; |
| args[(*j)++] = "-fsanitize=fuzzer-no-link"; |
| args[(*j)++] = "-fsanitize-coverage=trace-cmp,trace-div,indirect-calls"; |
| } |
| } |
| } |
| |
| static int ccMode(int argc, char** argv) { |
| char* args[ARGS_MAX]; |
| |
| int j = 0; |
| if (isCXX) { |
| args[j++] = "c++"; |
| } else { |
| args[j++] = "cc"; |
| } |
| |
| commonPreOpts(&j, args); |
| |
| for (int i = 1; i < argc; i++) { |
| args[j++] = argv[i]; |
| } |
| |
| commonPostOpts(&j, args); |
| |
| return execCC(j, args); |
| } |
| |
| static int ldMode(int argc, char** argv) { |
| char* args[ARGS_MAX]; |
| |
| int j = 0; |
| if (isCXX) { |
| args[j++] = "c++"; |
| } else { |
| args[j++] = "cc"; |
| } |
| |
| commonPreOpts(&j, args); |
| |
| /* MacOS X linker doesn't like those */ |
| #ifndef _HF_ARCH_DARWIN |
| /* Intercept common *cmp functions */ |
| args[j++] = "-Wl,--wrap=strcmp"; |
| args[j++] = "-Wl,--wrap=strcasecmp"; |
| args[j++] = "-Wl,--wrap=stricmp"; |
| args[j++] = "-Wl,--wrap=strncmp"; |
| args[j++] = "-Wl,--wrap=strncasecmp"; |
| args[j++] = "-Wl,--wrap=strnicmp"; |
| args[j++] = "-Wl,--wrap=strstr"; |
| args[j++] = "-Wl,--wrap=strcasestr"; |
| args[j++] = "-Wl,--wrap=memcmp"; |
| args[j++] = "-Wl,--wrap=bcmp"; |
| args[j++] = "-Wl,--wrap=memmem"; |
| args[j++] = "-Wl,--wrap=strcpy"; |
| args[j++] = "-Wl,--wrap=strlcpy"; |
| /* Apache httpd */ |
| args[j++] = "-Wl,--wrap=ap_cstr_casecmp"; |
| args[j++] = "-Wl,--wrap=ap_cstr_casecmpn"; |
| args[j++] = "-Wl,--wrap=ap_strcasestr"; |
| args[j++] = "-Wl,--wrap=apr_cstr_casecmp"; |
| args[j++] = "-Wl,--wrap=apr_cstr_casecmpn"; |
| /* *SSL */ |
| args[j++] = "-Wl,--wrap=CRYPTO_memcmp"; |
| args[j++] = "-Wl,--wrap=OPENSSL_memcmp"; |
| args[j++] = "-Wl,--wrap=OPENSSL_strcasecmp"; |
| args[j++] = "-Wl,--wrap=OPENSSL_strncasecmp"; |
| args[j++] = "-Wl,--wrap=memcmpct"; |
| /* libXML2 */ |
| args[j++] = "-Wl,--wrap=xmlStrncmp"; |
| args[j++] = "-Wl,--wrap=xmlStrcmp"; |
| args[j++] = "-Wl,--wrap=xmlStrEqual"; |
| args[j++] = "-Wl,--wrap=xmlStrcasecmp"; |
| args[j++] = "-Wl,--wrap=xmlStrncasecmp"; |
| args[j++] = "-Wl,--wrap=xmlStrstr"; |
| args[j++] = "-Wl,--wrap=xmlStrcasestr"; |
| /* Samba */ |
| args[j++] = "-Wl,--wrap=memcmp_const_time"; |
| args[j++] = "-Wl,--wrap=strcsequal"; |
| /* LittleCMS */ |
| args[j++] = "-Wl,--wrap=cmsstrcasecmp"; |
| /* GLib */ |
| args[j++] = "-Wl,--wrap=g_strcmp0"; |
| args[j++] = "-Wl,--wrap=g_strcasecmp"; |
| args[j++] = "-Wl,--wrap=g_strncasecmp"; |
| args[j++] = "-Wl,--wrap=g_strstr_len"; |
| args[j++] = "-Wl,--wrap=g_ascii_strcasecmp"; |
| args[j++] = "-Wl,--wrap=g_ascii_strncasecmp"; |
| args[j++] = "-Wl,--wrap=g_str_has_prefix"; |
| args[j++] = "-Wl,--wrap=g_str_has_suffix"; |
| /* CUrl */ |
| args[j++] = "-Wl,--wrap=Curl_strcasecompare"; |
| args[j++] = "-Wl,--wrap=curl_strequal"; |
| args[j++] = "-Wl,--wrap=Curl_safe_strcasecompare"; |
| args[j++] = "-Wl,--wrap=Curl_strncasecompare"; |
| args[j++] = "-Wl,--wrap=curl_strnequal"; |
| /* SQLite3 */ |
| args[j++] = "-Wl,--wrap=sqlite3_stricmp"; |
| args[j++] = "-Wl,--wrap=sqlite3_strnicmp"; |
| args[j++] = "-Wl,--wrap=sqlite3StrICmp"; |
| #endif /* _HF_ARCH_DARWIN */ |
| |
| /* Pull modules defining the following symbols (if they exist) */ |
| #ifdef _HF_ARCH_DARWIN |
| args[j++] = "-Wl,-U,_HonggfuzzNetDriver_main"; |
| args[j++] = "-Wl,-U,_LIBHFUZZ_module_instrument"; |
| args[j++] = "-Wl,-U,_LIBHFUZZ_module_memorycmp"; |
| #else /* _HF_ARCH_DARWIN */ |
| args[j++] = "-Wl,-u,HonggfuzzNetDriver_main"; |
| args[j++] = "-Wl,-u,LIBHFUZZ_module_instrument"; |
| args[j++] = "-Wl,-u,LIBHFUZZ_module_memorycmp"; |
| #endif /* _HF_ARCH_DARWIN */ |
| |
| for (int i = 1; i < argc; i++) { |
| args[j++] = argv[i]; |
| } |
| |
| /* |
| * Disable enforcement of the programming language, in case it had been enabled explicitly, |
| * e.g. via -xc |
| */ |
| args[j++] = "-xnone"; |
| |
| /* Reference standard honggfuzz libraries first (libhfuzz, libhfcommon and libhfnetdriver) */ |
| args[j++] = getLibHFNetDriverPath(); |
| |
| /* Ensure to link libhfuzz to the fuzz test executable*/ |
| if (isExecutableBuild(argc, argv)) { |
| #if defined(_HF_ARCH_DARWIN) |
| args[j++] = "-Wl,-force_load"; |
| #else |
| args[j++] = "-Wl,--whole-archive"; |
| #endif |
| } |
| |
| args[j++] = getLibHFuzzPath(); |
| |
| #if !defined(_HF_ARCH_DARWIN) |
| if (isExecutableBuild(argc, argv)) { |
| args[j++] = "-Wl,--no-whole-archive"; |
| } |
| #endif /* !defined(_HF_ARCH_DARWIN) */ |
| |
| args[j++] = getLibHFCommonPath(); |
| |
| /* Needed by libhfcommon */ |
| args[j++] = "-pthread"; |
| #if !defined(__NetBSD__) |
| args[j++] = "-ldl"; |
| #endif /* !defined(__NetBSD__) */ |
| #if !defined(_HF_ARCH_DARWIN) && !defined(__OpenBSD__) |
| args[j++] = "-lrt"; |
| #endif /* !defined(_HF_ARCH_DARWIN) && !defined(__OpenBSD__) */ |
| #if defined(__ANDROID__) |
| args[j++] = "-latomic"; |
| #endif |
| |
| commonPostOpts(&j, args); |
| |
| return execCC(j, args); |
| } |
| |
| static bool baseNameContains(const char* path, const char* str) { |
| if (strstr(_basename(path), str)) { |
| return true; |
| } |
| return false; |
| } |
| |
| int main(int argc, char** argv) { |
| if (baseNameContains(argv[0], "++")) { |
| isCXX = true; |
| } |
| if (baseNameContains(argv[0], "-gcc")) { |
| isGCC = true; |
| } |
| if (baseNameContains(argv[0], "-g++")) { |
| isGCC = true; |
| } |
| if (baseNameContains(argv[0], "-pcguard-")) { |
| usePCGuard = true; |
| } |
| if (baseNameContains(argv[0], "-8bitcnt-")) { |
| usePCGuard = false; |
| } |
| hasCmdLineFSanitizeFuzzer = hasFSanitizeFuzzer(argc, argv); |
| |
| if (argc <= 1) { |
| return execCC(argc, argv); |
| } |
| if (isVersionMode(argc, argv)) { |
| return execCC(argc, argv); |
| } |
| |
| if (argc > (ARGS_MAX - 128)) { |
| LOG_F("'%s': Too many positional arguments: %d", argv[0], argc); |
| return EXIT_FAILURE; |
| } |
| |
| if (isLDMode(argc, argv)) { |
| return ldMode(argc, argv); |
| } |
| return ccMode(argc, argv); |
| } |