##// END OF EJS Templates
fuzz: use a more standard approach to allow local builds of fuzzers...
fuzz: use a more standard approach to allow local builds of fuzzers This is taken from the (improved since we started fuzzing) guide on ideal integrations. Rather than have our own wonky targets for building outside the fuzzer universe, we have a driver program we carry along and use when we're not using LibFuzzer. This will let us jettison a fair amount of goo. contrib/fuzz/standalone_fuzz_target_runner.cc is https://github.com/google/oss-fuzz/ file projects/example/my-api-repo/standalone from git revision c4579d9358a73ea5dbcc99cb985de1f2bf76dcf7, reformatted with out clang-format settings and a no-check-code comment added. It allows running a single test input through a fuzzer, rather than performing ongoing fuzzing as libfuzzer would. contrib/fuzz/FuzzedDataProvider.h is https://github.com/llvm/llvm-project/ file /compiler-rt/include/fuzzer/FuzzedDataProvider.h from git revision a44ef027ebca1598892ea9b104d6189aeb3bc2f0, reformatted with our clang-format settings and a no-check-code comment added. We can discard this if we instead want to add an hghave check for a new enough llvm that includes FuzzedDataProvder.h in the fuzzer headers. Differential Revision: https://phab.mercurial-scm.org/D7564

File last commit:

r41367:763b45bc default
r44265:5a9e2ae9 default
Show More
util.c
222 lines | 4.3 KiB | text/x-c | CLexer
/*
* Utility functions
*
* Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2 or any later version.
*/
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "util.h"
static int colorenabled = 0;
static inline void fsetcolor(FILE *fp, const char *code)
{
if (!colorenabled) {
return;
}
fprintf(fp, "\033[%sm", code);
}
static void vabortmsgerrno(int no, const char *fmt, va_list args)
{
fsetcolor(stderr, "1;31");
fputs("chg: abort: ", stderr);
vfprintf(stderr, fmt, args);
if (no != 0) {
fprintf(stderr, " (errno = %d, %s)", no, strerror(no));
}
fsetcolor(stderr, "");
fputc('\n', stderr);
exit(255);
}
void abortmsg(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vabortmsgerrno(0, fmt, args);
va_end(args);
}
void abortmsgerrno(const char *fmt, ...)
{
int no = errno;
va_list args;
va_start(args, fmt);
vabortmsgerrno(no, fmt, args);
va_end(args);
}
static int debugmsgenabled = 0;
static double debugstart = 0;
static double now()
{
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_usec / 1e6 + t.tv_sec;
}
void enablecolor(void)
{
colorenabled = 1;
}
void enabledebugmsg(void)
{
debugmsgenabled = 1;
debugstart = now();
}
void debugmsg(const char *fmt, ...)
{
if (!debugmsgenabled) {
return;
}
va_list args;
va_start(args, fmt);
fsetcolor(stderr, "1;30");
fprintf(stderr, "chg: debug: %4.6f ", now() - debugstart);
vfprintf(stderr, fmt, args);
fsetcolor(stderr, "");
fputc('\n', stderr);
va_end(args);
}
void fchdirx(int dirfd)
{
int r = fchdir(dirfd);
if (r == -1) {
abortmsgerrno("failed to fchdir");
}
}
void fsetcloexec(int fd)
{
int flags = fcntl(fd, F_GETFD);
if (flags < 0) {
abortmsgerrno("cannot get flags of fd %d", fd);
}
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
abortmsgerrno("cannot set flags of fd %d", fd);
}
}
void *mallocx(size_t size)
{
void *result = malloc(size);
if (!result) {
abortmsg("failed to malloc");
}
return result;
}
void *reallocx(void *ptr, size_t size)
{
void *result = realloc(ptr, size);
if (!result) {
abortmsg("failed to realloc");
}
return result;
}
/*
* Execute a shell command in mostly the same manner as system(), with the
* give environment variables, after chdir to the given cwd. Returns a status
* code compatible with the Python subprocess module.
*/
int runshellcmd(const char *cmd, const char *envp[], const char *cwd)
{
enum { F_SIGINT = 1, F_SIGQUIT = 2, F_SIGMASK = 4, F_WAITPID = 8 };
unsigned int doneflags = 0;
int status = 0;
struct sigaction newsa, oldsaint, oldsaquit;
sigset_t oldmask;
/* block or mask signals just as system() does */
memset(&newsa, 0, sizeof(newsa));
newsa.sa_handler = SIG_IGN;
newsa.sa_flags = 0;
if (sigemptyset(&newsa.sa_mask) < 0) {
goto done;
}
if (sigaction(SIGINT, &newsa, &oldsaint) < 0) {
goto done;
}
doneflags |= F_SIGINT;
if (sigaction(SIGQUIT, &newsa, &oldsaquit) < 0) {
goto done;
}
doneflags |= F_SIGQUIT;
if (sigaddset(&newsa.sa_mask, SIGCHLD) < 0) {
goto done;
}
if (sigprocmask(SIG_BLOCK, &newsa.sa_mask, &oldmask) < 0) {
goto done;
}
doneflags |= F_SIGMASK;
pid_t pid = fork();
if (pid < 0) {
goto done;
}
if (pid == 0) {
sigaction(SIGINT, &oldsaint, NULL);
sigaction(SIGQUIT, &oldsaquit, NULL);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
if (cwd && chdir(cwd) < 0) {
_exit(127);
}
const char *argv[] = {"sh", "-c", cmd, NULL};
if (envp) {
execve("/bin/sh", (char **)argv, (char **)envp);
} else {
execv("/bin/sh", (char **)argv);
}
_exit(127);
} else {
if (waitpid(pid, &status, 0) < 0) {
goto done;
}
doneflags |= F_WAITPID;
}
done:
if (doneflags & F_SIGINT) {
sigaction(SIGINT, &oldsaint, NULL);
}
if (doneflags & F_SIGQUIT) {
sigaction(SIGQUIT, &oldsaquit, NULL);
}
if (doneflags & F_SIGMASK) {
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
/* no way to report other errors, use 127 (= shell termination) */
if (!(doneflags & F_WAITPID)) {
return 127;
}
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
if (WIFSIGNALED(status)) {
return -WTERMSIG(status);
}
return 127;
}