Create install targets for scan-build-py.

A new revision identical to https://reviews.llvm.org/D101139
The parent revision of aforementioned revision seems to cause pre-merge checks to fail opaquely. Seeing if creating a new revision will work.

Reviewed By: phosek

Differential Revision: https://reviews.llvm.org/D104138
This commit is contained in:
Daniel Hwang 2021-06-21 13:01:42 -07:00 committed by Marco Vanotti
parent e2c2124a4b
commit d9cf8291e7
31 changed files with 1327 additions and 655 deletions

View File

@ -291,6 +291,7 @@ set(LLVM_TOOLCHAIN_TOOLS
llvm-symbolizer
llvm-xray
sancov
scan-build-py
CACHE STRING "")
set(LLVM_DISTRIBUTION_COMPONENTS

View File

@ -32,6 +32,7 @@ if(CLANG_ENABLE_STATIC_ANALYZER)
add_clang_subdirectory(clang-check)
add_clang_subdirectory(clang-extdef-mapping)
add_clang_subdirectory(scan-build)
add_clang_subdirectory(scan-build-py)
add_clang_subdirectory(scan-view)
endif()

View File

@ -0,0 +1,132 @@
set (BinFiles
"analyze-build"
"intercept-build"
"scan-build")
set (LibExecs
"analyze-c++"
"analyze-cc"
"intercept-c++"
"intercept-cc")
set (LibScanbuild
"__init__.py"
"analyze.py"
"arguments.py"
"clang.py"
"compilation.py"
"intercept.py"
"report.py"
"shell.py")
set (LibScanbuildResources
"scanview.css"
"selectable.js"
"sorttable.js")
# libear is compiled dynamically in build_libear using the specified cc
# compiler.
set (LibEar
"__init__.py"
"config.h.in"
"ear.c")
foreach(BinFile ${BinFiles})
if ("${BinFile}" STREQUAL "scan-build")
# Need to rename scan-build to scan-build-py to prevent overwriting
# scan-build Perl implementation.
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/scan-build-py
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/bin
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/bin/scan-build
${CMAKE_BINARY_DIR}/bin/scan-build-py
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/scan-build)
install (PROGRAMS "bin/scan-build"
DESTINATION bin
RENAME scan-build-py
COMPONENT scan-build-py)
list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/scan-build-py)
else()
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${BinFile}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/bin
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile}
${CMAKE_BINARY_DIR}/bin/
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile})
install(PROGRAMS bin/${BinFile}
DESTINATION bin
COMPONENT scan-build-py)
list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile})
endif()
endforeach()
foreach(lib ${LibExecs})
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/libexec/${lib}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/libexec
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/libexec/${lib}
${CMAKE_BINARY_DIR}/libexec/
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${lib})
list(APPEND Depends ${CMAKE_BINARY_DIR}/libexec/${lib})
install(PROGRAMS libexec/${lib}
DESTINATION libexec
COMPONENT scan-build-py)
endforeach()
foreach(lib ${LibScanbuild})
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libscanbuild/${lib}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/lib
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/lib/libscanbuild
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/${lib}
${CMAKE_BINARY_DIR}/lib/libscanbuild/
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/${lib})
list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libscanbuild/${lib})
install(PROGRAMS lib/libscanbuild/${lib}
DESTINATION lib/libscanbuild
COMPONENT scan-build-py)
endforeach()
foreach(resource ${LibScanbuildResources})
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources/${resource}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/lib
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/lib/libscanbuild
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/lib/libscanbuild/resources
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/resources/${resource}
${CMAKE_BINARY_DIR}/lib/libscanbuild/resources
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/resources/${resource})
list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources/${resource})
install(PROGRAMS lib/libscanbuild/resources/${resource}
DESTINATION lib/libscanbuild/resources
COMPONENT scan-build-py)
endforeach()
foreach(lib ${LibEar})
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libear/${lib}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/lib
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/lib/libear
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/lib/libear/${lib}
${CMAKE_BINARY_DIR}/lib/libear/
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libear/${lib})
list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libear/${lib})
install(PROGRAMS lib/libear/${lib}
DESTINATION lib/libear
COMPONENT scan-build-py)
endforeach()
add_custom_target(scan-build-py ALL DEPENDS ${Depends})
add_llvm_install_targets("install-scan-build-py"
DEPENDS scan-build-py
COMPONENT scan-build-py)

View File

@ -8,7 +8,7 @@ import multiprocessing
import sys
import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
from libscanbuild.analyze import analyze_build

View File

@ -8,7 +8,7 @@ import multiprocessing
import sys
import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
from libscanbuild.intercept import intercept_build

View File

@ -8,7 +8,7 @@ import multiprocessing
import sys
import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
from libscanbuild.analyze import scan_build

View File

@ -0,0 +1,601 @@
/* -*- coding: utf-8 -*-
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/**
* This file implements a shared library. This library can be pre-loaded by
* the dynamic linker of the Operating System (OS). It implements a few function
* related to process creation. By pre-load this library the executed process
* uses these functions instead of those from the standard library.
*
* The idea here is to inject a logic before call the real methods. The logic is
* to dump the call into a file. To call the real method this library is doing
* the job of the dynamic linker.
*
* The only input for the log writing is about the destination directory.
* This is passed as environment variable.
*/
// NOLINTNEXTLINE
#include "config.h"
#include <dlfcn.h>
#include <pthread.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
#include <spawn.h>
#endif
#if defined HAVE_NSGETENVIRON
#include <crt_externs.h>
#else
extern char **environ;
#endif
#define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
#ifdef APPLE
#define ENV_FLAT "DYLD_FORCE_FLAT_NAMESPACE"
#define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
#define ENV_SIZE 3
#else
#define ENV_PRELOAD "LD_PRELOAD"
#define ENV_SIZE 2
#endif
#define DLSYM(TYPE_, VAR_, SYMBOL_) \
union { \
void *from; \
TYPE_ to; \
} cast; \
if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) { \
perror("bear: dlsym"); \
exit(EXIT_FAILURE); \
} \
TYPE_ const VAR_ = cast.to;
typedef char const *bear_env_t[ENV_SIZE];
static int bear_capture_env_t(bear_env_t *env);
static int bear_reset_env_t(bear_env_t *env);
static void bear_release_env_t(bear_env_t *env);
static char const **bear_update_environment(char *const envp[],
bear_env_t *env);
static char const **bear_update_environ(char const **in, char const *key,
char const *value);
static char **bear_get_environment();
static void bear_report_call(char const *fun, char const *const argv[]);
static char const **bear_strings_build(char const *arg, va_list *ap);
static char const **bear_strings_copy(char const **const in);
static char const **bear_strings_append(char const **in, char const *e);
static size_t bear_strings_length(char const *const *in);
static void bear_strings_release(char const **);
static bear_env_t env_names = {ENV_OUTPUT, ENV_PRELOAD
#ifdef ENV_FLAT
,
ENV_FLAT
#endif
};
static bear_env_t initial_env = {0, 0
#ifdef ENV_FLAT
,
0
#endif
};
static int initialized = 0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static void on_load(void) __attribute__((constructor));
static void on_unload(void) __attribute__((destructor));
#ifdef HAVE_EXECVE
static int call_execve(const char *path, char *const argv[],
char *const envp[]);
#endif
#ifdef HAVE_EXECVP
static int call_execvp(const char *file, char *const argv[]);
#endif
#ifdef HAVE_EXECVPE
static int call_execvpe(const char *file, char *const argv[],
char *const envp[]);
#endif
#ifdef HAVE_EXECVP2
static int call_execvP(const char *file, const char *search_path,
char *const argv[]);
#endif
#ifdef HAVE_EXECT
static int call_exect(const char *path, char *const argv[], char *const envp[]);
#endif
#ifdef HAVE_POSIX_SPAWN
static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict],
char *const envp[restrict]);
#endif
#ifdef HAVE_POSIX_SPAWNP
static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict],
char *const envp[restrict]);
#endif
/* Initialization method to Captures the relevant environment variables.
*/
static void on_load(void) {
pthread_mutex_lock(&mutex);
if (!initialized)
initialized = bear_capture_env_t(&initial_env);
pthread_mutex_unlock(&mutex);
}
static void on_unload(void) {
pthread_mutex_lock(&mutex);
bear_release_env_t(&initial_env);
initialized = 0;
pthread_mutex_unlock(&mutex);
}
/* These are the methods we are try to hijack.
*/
#ifdef HAVE_EXECVE
int execve(const char *path, char *const argv[], char *const envp[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_execve(path, argv, envp);
}
#endif
#ifdef HAVE_EXECV
#ifndef HAVE_EXECVE
#error can not implement execv without execve
#endif
int execv(const char *path, char *const argv[]) {
bear_report_call(__func__, (char const *const *)argv);
char *const *envp = bear_get_environment();
return call_execve(path, argv, envp);
}
#endif
#ifdef HAVE_EXECVPE
int execvpe(const char *file, char *const argv[], char *const envp[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_execvpe(file, argv, envp);
}
#endif
#ifdef HAVE_EXECVP
int execvp(const char *file, char *const argv[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_execvp(file, argv);
}
#endif
#ifdef HAVE_EXECVP2
int execvP(const char *file, const char *search_path, char *const argv[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_execvP(file, search_path, argv);
}
#endif
#ifdef HAVE_EXECT
int exect(const char *path, char *const argv[], char *const envp[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_exect(path, argv, envp);
}
#endif
#ifdef HAVE_EXECL
#ifndef HAVE_EXECVE
#error can not implement execl without execve
#endif
int execl(const char *path, const char *arg, ...) {
va_list args;
va_start(args, arg);
char const **argv = bear_strings_build(arg, &args);
va_end(args);
bear_report_call(__func__, (char const *const *)argv);
char *const *envp = bear_get_environment();
int const result = call_execve(path, (char *const *)argv, envp);
bear_strings_release(argv);
return result;
}
#endif
#ifdef HAVE_EXECLP
#ifndef HAVE_EXECVP
#error can not implement execlp without execvp
#endif
int execlp(const char *file, const char *arg, ...) {
va_list args;
va_start(args, arg);
char const **argv = bear_strings_build(arg, &args);
va_end(args);
bear_report_call(__func__, (char const *const *)argv);
int const result = call_execvp(file, (char *const *)argv);
bear_strings_release(argv);
return result;
}
#endif
#ifdef HAVE_EXECLE
#ifndef HAVE_EXECVE
#error can not implement execle without execve
#endif
// int execle(const char *path, const char *arg, ..., char * const envp[]);
int execle(const char *path, const char *arg, ...) {
va_list args;
va_start(args, arg);
char const **argv = bear_strings_build(arg, &args);
char const **envp = va_arg(args, char const **);
va_end(args);
bear_report_call(__func__, (char const *const *)argv);
int const result =
call_execve(path, (char *const *)argv, (char *const *)envp);
bear_strings_release(argv);
return result;
}
#endif
#ifdef HAVE_POSIX_SPAWN
int posix_spawn(pid_t *restrict pid, const char *restrict path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict], char *const envp[restrict]) {
bear_report_call(__func__, (char const *const *)argv);
return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
}
#endif
#ifdef HAVE_POSIX_SPAWNP
int posix_spawnp(pid_t *restrict pid, const char *restrict file,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict], char *const envp[restrict]) {
bear_report_call(__func__, (char const *const *)argv);
return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
}
#endif
/* These are the methods which forward the call to the standard implementation.
*/
#ifdef HAVE_EXECVE
static int call_execve(const char *path, char *const argv[],
char *const envp[]) {
typedef int (*func)(const char *, char *const *, char *const *);
DLSYM(func, fp, "execve");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result = (*fp)(path, argv, (char *const *)menvp);
bear_strings_release(menvp);
return result;
}
#endif
#ifdef HAVE_EXECVPE
static int call_execvpe(const char *file, char *const argv[],
char *const envp[]) {
typedef int (*func)(const char *, char *const *, char *const *);
DLSYM(func, fp, "execvpe");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result = (*fp)(file, argv, (char *const *)menvp);
bear_strings_release(menvp);
return result;
}
#endif
#ifdef HAVE_EXECVP
static int call_execvp(const char *file, char *const argv[]) {
typedef int (*func)(const char *file, char *const argv[]);
DLSYM(func, fp, "execvp");
bear_env_t current_env;
bear_capture_env_t(&current_env);
bear_reset_env_t(&initial_env);
int const result = (*fp)(file, argv);
bear_reset_env_t(&current_env);
bear_release_env_t(&current_env);
return result;
}
#endif
#ifdef HAVE_EXECVP2
static int call_execvP(const char *file, const char *search_path,
char *const argv[]) {
typedef int (*func)(const char *, const char *, char *const *);
DLSYM(func, fp, "execvP");
bear_env_t current_env;
bear_capture_env_t(&current_env);
bear_reset_env_t(&initial_env);
int const result = (*fp)(file, search_path, argv);
bear_reset_env_t(&current_env);
bear_release_env_t(&current_env);
return result;
}
#endif
#ifdef HAVE_EXECT
static int call_exect(const char *path, char *const argv[],
char *const envp[]) {
typedef int (*func)(const char *, char *const *, char *const *);
DLSYM(func, fp, "exect");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result = (*fp)(path, argv, (char *const *)menvp);
bear_strings_release(menvp);
return result;
}
#endif
#ifdef HAVE_POSIX_SPAWN
static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict],
char *const envp[restrict]) {
typedef int (*func)(pid_t *restrict, const char *restrict,
const posix_spawn_file_actions_t *,
const posix_spawnattr_t *restrict, char *const *restrict,
char *const *restrict);
DLSYM(func, fp, "posix_spawn");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result =
(*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
bear_strings_release(menvp);
return result;
}
#endif
#ifdef HAVE_POSIX_SPAWNP
static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict],
char *const envp[restrict]) {
typedef int (*func)(pid_t *restrict, const char *restrict,
const posix_spawn_file_actions_t *,
const posix_spawnattr_t *restrict, char *const *restrict,
char *const *restrict);
DLSYM(func, fp, "posix_spawnp");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result =
(*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
bear_strings_release(menvp);
return result;
}
#endif
/* this method is to write log about the process creation. */
static void bear_report_call(char const *fun, char const *const argv[]) {
static int const GS = 0x1d;
static int const RS = 0x1e;
static int const US = 0x1f;
if (!initialized)
return;
pthread_mutex_lock(&mutex);
const char *cwd = getcwd(NULL, 0);
if (0 == cwd) {
perror("bear: getcwd");
exit(EXIT_FAILURE);
}
char const *const out_dir = initial_env[0];
size_t const path_max_length = strlen(out_dir) + 32;
char filename[path_max_length];
if (-1 ==
snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
perror("bear: snprintf");
exit(EXIT_FAILURE);
}
FILE *fd = fopen(filename, "a+");
if (0 == fd) {
perror("bear: fopen");
exit(EXIT_FAILURE);
}
fprintf(fd, "%d%c", getpid(), RS);
fprintf(fd, "%d%c", getppid(), RS);
fprintf(fd, "%s%c", fun, RS);
fprintf(fd, "%s%c", cwd, RS);
size_t const argc = bear_strings_length(argv);
for (size_t it = 0; it < argc; ++it) {
fprintf(fd, "%s%c", argv[it], US);
}
fprintf(fd, "%c", GS);
if (fclose(fd)) {
perror("bear: fclose");
exit(EXIT_FAILURE);
}
free((void *)cwd);
pthread_mutex_unlock(&mutex);
}
/* update environment assure that chilren processes will copy the desired
* behaviour */
static int bear_capture_env_t(bear_env_t *env) {
int status = 1;
for (size_t it = 0; it < ENV_SIZE; ++it) {
char const *const env_value = getenv(env_names[it]);
char const *const env_copy = (env_value) ? strdup(env_value) : env_value;
(*env)[it] = env_copy;
status &= (env_copy) ? 1 : 0;
}
return status;
}
static int bear_reset_env_t(bear_env_t *env) {
int status = 1;
for (size_t it = 0; it < ENV_SIZE; ++it) {
if ((*env)[it]) {
setenv(env_names[it], (*env)[it], 1);
} else {
unsetenv(env_names[it]);
}
}
return status;
}
static void bear_release_env_t(bear_env_t *env) {
for (size_t it = 0; it < ENV_SIZE; ++it) {
free((void *)(*env)[it]);
(*env)[it] = 0;
}
}
static char const **bear_update_environment(char *const envp[],
bear_env_t *env) {
char const **result = bear_strings_copy((char const **)envp);
for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
result = bear_update_environ(result, env_names[it], (*env)[it]);
return result;
}
static char const **bear_update_environ(char const *envs[], char const *key,
char const *const value) {
// find the key if it's there
size_t const key_length = strlen(key);
char const **it = envs;
for (; (it) && (*it); ++it) {
if ((0 == strncmp(*it, key, key_length)) && (strlen(*it) > key_length) &&
('=' == (*it)[key_length]))
break;
}
// allocate a environment entry
size_t const value_length = strlen(value);
size_t const env_length = key_length + value_length + 2;
char *env = malloc(env_length);
if (0 == env) {
perror("bear: malloc [in env_update]");
exit(EXIT_FAILURE);
}
if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
perror("bear: snprintf");
exit(EXIT_FAILURE);
}
// replace or append the environment entry
if (it && *it) {
free((void *)*it);
*it = env;
return envs;
}
return bear_strings_append(envs, env);
}
static char **bear_get_environment() {
#if defined HAVE_NSGETENVIRON
return *_NSGetEnviron();
#else
return environ;
#endif
}
/* util methods to deal with string arrays. environment and process arguments
* are both represented as string arrays. */
static char const **bear_strings_build(char const *const arg, va_list *args) {
char const **result = 0;
size_t size = 0;
for (char const *it = arg; it; it = va_arg(*args, char const *)) {
result = realloc(result, (size + 1) * sizeof(char const *));
if (0 == result) {
perror("bear: realloc");
exit(EXIT_FAILURE);
}
char const *copy = strdup(it);
if (0 == copy) {
perror("bear: strdup");
exit(EXIT_FAILURE);
}
result[size++] = copy;
}
result = realloc(result, (size + 1) * sizeof(char const *));
if (0 == result) {
perror("bear: realloc");
exit(EXIT_FAILURE);
}
result[size++] = 0;
return result;
}
static char const **bear_strings_copy(char const **const in) {
size_t const size = bear_strings_length(in);
char const **const result = malloc((size + 1) * sizeof(char const *));
if (0 == result) {
perror("bear: malloc");
exit(EXIT_FAILURE);
}
char const **out_it = result;
for (char const *const *in_it = in; (in_it) && (*in_it); ++in_it, ++out_it) {
*out_it = strdup(*in_it);
if (0 == *out_it) {
perror("bear: strdup");
exit(EXIT_FAILURE);
}
}
*out_it = 0;
return result;
}
static char const **bear_strings_append(char const **const in,
char const *const e) {
size_t size = bear_strings_length(in);
char const **result = realloc(in, (size + 2) * sizeof(char const *));
if (0 == result) {
perror("bear: realloc");
exit(EXIT_FAILURE);
}
result[size++] = e;
result[size++] = 0;
return result;
}
static size_t bear_strings_length(char const *const *const in) {
size_t result = 0;
for (char const *const *it = in; (it) && (*it); ++it)
++result;
return result;
}
static void bear_strings_release(char const **in) {
for (char const *const *it = in; (it) && (*it); ++it) {
free((void *)*it);
}
free((void *)in);
}

View File

@ -379,7 +379,8 @@ def merge_sarif_files(output_dir, sort_files=False):
def parse_bug_plist(filename):
""" Returns the generator of bugs from a single .plist file. """
content = plistlib.readPlist(filename)
with open(filename, 'rb') as fp:
content = plistlib.load(fp)
files = content.get('files')
for bug in content.get('diagnostics', []):
if len(files) <= int(bug['location']['file']):

View File

@ -1,7 +1,6 @@
function SetDisplay(RowClass, DisplayVal)
{
function SetDisplay(RowClass, DisplayVal) {
var Rows = document.getElementsByTagName("tr");
for ( var i = 0 ; i < Rows.length; ++i ) {
for (var i = 0; i < Rows.length; ++i) {
if (Rows[i].className == RowClass) {
Rows[i].style.display = DisplayVal;
}
@ -10,9 +9,9 @@ function SetDisplay(RowClass, DisplayVal)
function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
var Inputs = document.getElementsByTagName("input");
for ( var i = 0 ; i < Inputs.length; ++i ) {
for (var i = 0; i < Inputs.length; ++i) {
if (Inputs[i].type == "checkbox") {
if(Inputs[i] != SummaryCheckButton) {
if (Inputs[i] != SummaryCheckButton) {
Inputs[i].checked = SummaryCheckButton.checked;
Inputs[i].onclick();
}
@ -20,7 +19,7 @@ function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
}
}
function returnObjById( id ) {
function returnObjById(id) {
if (document.getElementById)
var returnVar = document.getElementById(id);
else if (document.all)
@ -38,8 +37,7 @@ function ToggleDisplay(CheckButton, ClassName) {
if (--NumUnchecked == 0) {
returnObjById("AllBugsCheck").checked = true;
}
}
else {
} else {
SetDisplay(ClassName, "none");
NumUnchecked++;
returnObjById("AllBugsCheck").checked = false;

View File

@ -0,0 +1,535 @@
/*
SortTable
version 2
7th April 2007
Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
Instructions:
Download this file
Add <script src="sorttable.js"></script> to your HTML
Add class="sortable" to any table you'd like to make sortable
Click on the headers to sort
Thanks to many, many people for contributions and suggestions.
Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
This basically means: do what you want with it.
*/
var stIsIE = /*@cc_on!@*/ false;
sorttable = {
init : function() {
// quit if this function has already been called
if (arguments.callee.done)
return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// kill the timer
if (_timer)
clearInterval(_timer);
if (!document.createElement || !document.getElementsByTagName)
return;
sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
forEach(document.getElementsByTagName('table'), function(table) {
if (table.className.search(/\bsortable\b/) != -1) {
sorttable.makeSortable(table);
}
});
},
makeSortable : function(table) {
if (table.getElementsByTagName('thead').length == 0) {
// table doesn't have a tHead. Since it should have, create one and
// put the first table row in it.
the = document.createElement('thead');
the.appendChild(table.rows[0]);
table.insertBefore(the, table.firstChild);
}
// Safari doesn't support table.tHead, sigh
if (table.tHead == null)
table.tHead = table.getElementsByTagName('thead')[0];
if (table.tHead.rows.length != 1)
return; // can't cope with two header rows
// Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
// "total" rows, for example). This is B&R, since what you're supposed
// to do is put them in a tfoot. So, if there are sortbottom rows,
// for backward compatibility, move them to tfoot (creating it if needed).
sortbottomrows = [];
for (var i = 0; i < table.rows.length; i++) {
if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
sortbottomrows[sortbottomrows.length] = table.rows[i];
}
}
if (sortbottomrows) {
if (table.tFoot == null) {
// table doesn't have a tfoot. Create one.
tfo = document.createElement('tfoot');
table.appendChild(tfo);
}
for (var i = 0; i < sortbottomrows.length; i++) {
tfo.appendChild(sortbottomrows[i]);
}
delete sortbottomrows;
}
// work through each column and calculate its type
headrow = table.tHead.rows[0].cells;
for (var i = 0; i < headrow.length; i++) {
// manually override the type with a sorttable_type attribute
if (!headrow[i].className.match(
/\bsorttable_nosort\b/)) { // skip this col
mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
if (mtch) {
override = mtch[1];
}
if (mtch && typeof sorttable["sort_" + override] == 'function') {
headrow[i].sorttable_sortfunction = sorttable["sort_" + override];
} else {
headrow[i].sorttable_sortfunction = sorttable.guessType(table, i);
}
// make it clickable to sort
headrow[i].sorttable_columnindex = i;
headrow[i].sorttable_tbody = table.tBodies[0];
dean_addEvent(headrow[i], "click", function(e) {
if (this.className.search(/\bsorttable_sorted\b/) != -1) {
// if we're already sorted by this column, just
// reverse the table, which is quicker
sorttable.reverse(this.sorttable_tbody);
this.className = this.className.replace('sorttable_sorted',
'sorttable_sorted_reverse');
this.removeChild(document.getElementById('sorttable_sortfwdind'));
sortrevind = document.createElement('span');
sortrevind.id = "sorttable_sortrevind";
sortrevind.innerHTML = stIsIE
? '&nbsp<font face="webdings">5</font>'
: '&nbsp;&#x25B4;';
this.appendChild(sortrevind);
return;
}
if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
// if we're already sorted by this column in reverse, just
// re-reverse the table, which is quicker
sorttable.reverse(this.sorttable_tbody);
this.className = this.className.replace('sorttable_sorted_reverse',
'sorttable_sorted');
this.removeChild(document.getElementById('sorttable_sortrevind'));
sortfwdind = document.createElement('span');
sortfwdind.id = "sorttable_sortfwdind";
sortfwdind.innerHTML = stIsIE
? '&nbsp<font face="webdings">6</font>'
: '&nbsp;&#x25BE;';
this.appendChild(sortfwdind);
return;
}
// remove sorttable_sorted classes
theadrow = this.parentNode;
forEach(theadrow.childNodes, function(cell) {
if (cell.nodeType == 1) { // an element
cell.className =
cell.className.replace('sorttable_sorted_reverse', '');
cell.className = cell.className.replace('sorttable_sorted', '');
}
});
sortfwdind = document.getElementById('sorttable_sortfwdind');
if (sortfwdind) {
sortfwdind.parentNode.removeChild(sortfwdind);
}
sortrevind = document.getElementById('sorttable_sortrevind');
if (sortrevind) {
sortrevind.parentNode.removeChild(sortrevind);
}
this.className += ' sorttable_sorted';
sortfwdind = document.createElement('span');
sortfwdind.id = "sorttable_sortfwdind";
sortfwdind.innerHTML =
stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
this.appendChild(sortfwdind);
// build an array to sort. This is a Schwartzian transform thing,
// i.e., we "decorate" each row with the actual sort key,
// sort based on the sort keys, and then put the rows back in order
// which is a lot faster because you only do getInnerText once per row
row_array = [];
col = this.sorttable_columnindex;
rows = this.sorttable_tbody.rows;
for (var j = 0; j < rows.length; j++) {
row_array[row_array.length] =
[ sorttable.getInnerText(rows[j].cells[col]), rows[j] ];
}
/* If you want a stable sort, uncomment the following line */
sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
/* and comment out this one */
// row_array.sort(this.sorttable_sortfunction);
tb = this.sorttable_tbody;
for (var j = 0; j < row_array.length; j++) {
tb.appendChild(row_array[j][1]);
}
delete row_array;
});
}
}
},
guessType : function(table, column) {
// guess the type of a column based on its first non-blank row
sortfn = sorttable.sort_alpha;
for (var i = 0; i < table.tBodies[0].rows.length; i++) {
text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
if (text != '') {
if (text.match(/^-?[」$、]?[\d,.]+%?$/)) {
return sorttable.sort_numeric;
}
// check for a date: dd/mm/yyyy or dd/mm/yy
// can have / or . or - as separator
// can be mm/dd as well
possdate = text.match(sorttable.DATE_RE)
if (possdate) {
// looks like a date
first = parseInt(possdate[1]);
second = parseInt(possdate[2]);
if (first > 12) {
// definitely dd/mm
return sorttable.sort_ddmm;
} else if (second > 12) {
return sorttable.sort_mmdd;
} else {
// looks like a date, but we can't tell which, so assume
// that it's dd/mm (English imperialism!) and keep looking
sortfn = sorttable.sort_ddmm;
}
}
}
}
return sortfn;
},
getInnerText : function(node) {
// gets the text we want to use for sorting for a cell.
// strips leading and trailing whitespace.
// this is *not* a generic getInnerText function; it's special to sorttable.
// for example, you can override the cell text with a customkey attribute.
// it also gets .value for <input> fields.
hasInputs = (typeof node.getElementsByTagName == 'function') &&
node.getElementsByTagName('input').length;
if (node.getAttribute("sorttable_customkey") != null) {
return node.getAttribute("sorttable_customkey");
} else if (typeof node.textContent != 'undefined' && !hasInputs) {
return node.textContent.replace(/^\s+|\s+$/g, '');
} else if (typeof node.innerText != 'undefined' && !hasInputs) {
return node.innerText.replace(/^\s+|\s+$/g, '');
} else if (typeof node.text != 'undefined' && !hasInputs) {
return node.text.replace(/^\s+|\s+$/g, '');
} else {
switch (node.nodeType) {
case 3:
if (node.nodeName.toLowerCase() == 'input') {
return node.value.replace(/^\s+|\s+$/g, '');
}
case 4:
return node.nodeValue.replace(/^\s+|\s+$/g, '');
break;
case 1:
case 11:
var innerText = '';
for (var i = 0; i < node.childNodes.length; i++) {
innerText += sorttable.getInnerText(node.childNodes[i]);
}
return innerText.replace(/^\s+|\s+$/g, '');
break;
default:
return '';
}
}
},
reverse : function(tbody) {
// reverse the rows in a tbody
newrows = [];
for (var i = 0; i < tbody.rows.length; i++) {
newrows[newrows.length] = tbody.rows[i];
}
for (var i = newrows.length - 1; i >= 0; i--) {
tbody.appendChild(newrows[i]);
}
delete newrows;
},
/* sort functions
each sort function takes two parameters, a and b
you are comparing a[0] and b[0] */
sort_numeric : function(a, b) {
aa = parseFloat(a[0].replace(/[^0-9.-]/g, ''));
if (isNaN(aa))
aa = 0;
bb = parseFloat(b[0].replace(/[^0-9.-]/g, ''));
if (isNaN(bb))
bb = 0;
return aa - bb;
},
sort_alpha : function(a, b) {
if (a[0] == b[0])
return 0;
if (a[0] < b[0])
return -1;
return 1;
},
sort_ddmm : function(a, b) {
mtch = a[0].match(sorttable.DATE_RE);
y = mtch[3];
m = mtch[2];
d = mtch[1];
if (m.length == 1)
m = '0' + m;
if (d.length == 1)
d = '0' + d;
dt1 = y + m + d;
mtch = b[0].match(sorttable.DATE_RE);
y = mtch[3];
m = mtch[2];
d = mtch[1];
if (m.length == 1)
m = '0' + m;
if (d.length == 1)
d = '0' + d;
dt2 = y + m + d;
if (dt1 == dt2)
return 0;
if (dt1 < dt2)
return -1;
return 1;
},
sort_mmdd : function(a, b) {
mtch = a[0].match(sorttable.DATE_RE);
y = mtch[3];
d = mtch[2];
m = mtch[1];
if (m.length == 1)
m = '0' + m;
if (d.length == 1)
d = '0' + d;
dt1 = y + m + d;
mtch = b[0].match(sorttable.DATE_RE);
y = mtch[3];
d = mtch[2];
m = mtch[1];
if (m.length == 1)
m = '0' + m;
if (d.length == 1)
d = '0' + d;
dt2 = y + m + d;
if (dt1 == dt2)
return 0;
if (dt1 < dt2)
return -1;
return 1;
},
shaker_sort : function(list, comp_func) {
// A stable sort function to allow multi-level sorting of data
// see: http://en.wikipedia.org/wiki/Cocktail_sort
// thanks to Joseph Nahmias
var b = 0;
var t = list.length - 1;
var swap = true;
while (swap) {
swap = false;
for (var i = b; i < t; ++i) {
if (comp_func(list[i], list[i + 1]) > 0) {
var q = list[i];
list[i] = list[i + 1];
list[i + 1] = q;
swap = true;
}
} // for
t--;
if (!swap)
break;
for (var i = t; i > b; --i) {
if (comp_func(list[i], list[i - 1]) < 0) {
var q = list[i];
list[i] = list[i - 1];
list[i - 1] = q;
swap = true;
}
} // for
b++;
} // while(swap)
}
}
/* ******************************************************************
Supporting functions: bundled here to avoid depending on a library
****************************************************************** */
// Dean Edwards/Matthias Miller/John Resig
/* for Mozilla/Opera9 */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", sorttable.init, false);
}
/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer
src=javascript:void(0)><\/script>"); var script =
document.getElementById("__ie_onload"); script.onreadystatechange = function() {
if (this.readyState == "complete") {
sorttable.init(); // call the onload handler
}
};
/*@end @*/
/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
sorttable.init(); // call the onload handler
}
}, 10);
}
/* for other browsers */
window.onload = sorttable.init;
// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/
function dean_addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
// assign each event handler a unique ID
if (!handler.$$guid)
handler.$$guid = dean_addEvent.guid++;
// create a hash table of event types for the element
if (!element.events)
element.events = {};
// create a hash table of event handlers for each element/event pair
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// store the existing event handler (if there is one)
if (element["on" + type]) {
handlers[0] = element["on" + type];
}
}
// store the event handler in the hash table
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work
element["on" + type] = handleEvent;
}
};
// a counter used to create unique IDs
dean_addEvent.guid = 1;
function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
};
function handleEvent(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event =
event ||
fixEvent(
((this.ownerDocument || this.document || this).parentWindow || window)
.event);
// get a reference to the hash table of event handlers
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};
function fixEvent(event) {
// add W3C standard event methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() { this.returnValue = false; };
fixEvent.stopPropagation = function() { this.cancelBubble = true; }
// Dean's forEach: http://dean.edwards.name/base/forEach.js
/*
forEach, version 1.0
Copyright 2006, Dean Edwards
License: http://www.opensource.org/licenses/mit-license.php
*/
// array-like enumeration
if (!Array.forEach) { // mozilla already supports this
Array.forEach = function(array, block, context) {
for (var i = 0; i < array.length; i++) {
block.call(context, array[i], i, array);
}
};
}
// generic enumeration
Function.prototype.forEach = function(object, block, context) {
for (var key in object) {
if (typeof this.prototype[key] == "undefined") {
block.call(context, object[key], key, object);
}
}
};
// character enumeration
String.forEach = function(string, block, context) {
Array.forEach(
string.split(""),
function(chr, index) { block.call(context, chr, index, string); });
};
// globally resolve forEach enumeration
var forEach = function(object, block, context) {
if (object) {
var resolve = Object; // default
if (object instanceof Function) {
// functions have a "length" property
resolve = Function;
} else if (object.forEach instanceof Function) {
// the object implements a custom forEach method so use that
object.forEach(block, context);
return;
} else if (typeof object == "string") {
// the object is a string
resolve = String;
} else if (typeof object.length == "number") {
// the object is array-like
resolve = Array;
}
resolve.forEach(object, block, context);
}
};

View File

@ -1,604 +0,0 @@
/* -*- coding: utf-8 -*-
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/**
* This file implements a shared library. This library can be pre-loaded by
* the dynamic linker of the Operating System (OS). It implements a few function
* related to process creation. By pre-load this library the executed process
* uses these functions instead of those from the standard library.
*
* The idea here is to inject a logic before call the real methods. The logic is
* to dump the call into a file. To call the real method this library is doing
* the job of the dynamic linker.
*
* The only input for the log writing is about the destination directory.
* This is passed as environment variable.
*/
#include "config.h"
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <pthread.h>
#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
#include <spawn.h>
#endif
#if defined HAVE_NSGETENVIRON
# include <crt_externs.h>
#else
extern char **environ;
#endif
#define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
#ifdef APPLE
# define ENV_FLAT "DYLD_FORCE_FLAT_NAMESPACE"
# define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
# define ENV_SIZE 3
#else
# define ENV_PRELOAD "LD_PRELOAD"
# define ENV_SIZE 2
#endif
#define DLSYM(TYPE_, VAR_, SYMBOL_) \
union { \
void *from; \
TYPE_ to; \
} cast; \
if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) { \
perror("bear: dlsym"); \
exit(EXIT_FAILURE); \
} \
TYPE_ const VAR_ = cast.to;
typedef char const * bear_env_t[ENV_SIZE];
static int bear_capture_env_t(bear_env_t *env);
static int bear_reset_env_t(bear_env_t *env);
static void bear_release_env_t(bear_env_t *env);
static char const **bear_update_environment(char *const envp[], bear_env_t *env);
static char const **bear_update_environ(char const **in, char const *key, char const *value);
static char **bear_get_environment();
static void bear_report_call(char const *fun, char const *const argv[]);
static char const **bear_strings_build(char const *arg, va_list *ap);
static char const **bear_strings_copy(char const **const in);
static char const **bear_strings_append(char const **in, char const *e);
static size_t bear_strings_length(char const *const *in);
static void bear_strings_release(char const **);
static bear_env_t env_names =
{ ENV_OUTPUT
, ENV_PRELOAD
#ifdef ENV_FLAT
, ENV_FLAT
#endif
};
static bear_env_t initial_env =
{ 0
, 0
#ifdef ENV_FLAT
, 0
#endif
};
static int initialized = 0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static void on_load(void) __attribute__((constructor));
static void on_unload(void) __attribute__((destructor));
#ifdef HAVE_EXECVE
static int call_execve(const char *path, char *const argv[],
char *const envp[]);
#endif
#ifdef HAVE_EXECVP
static int call_execvp(const char *file, char *const argv[]);
#endif
#ifdef HAVE_EXECVPE
static int call_execvpe(const char *file, char *const argv[],
char *const envp[]);
#endif
#ifdef HAVE_EXECVP2
static int call_execvP(const char *file, const char *search_path,
char *const argv[]);
#endif
#ifdef HAVE_EXECT
static int call_exect(const char *path, char *const argv[],
char *const envp[]);
#endif
#ifdef HAVE_POSIX_SPAWN
static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict],
char *const envp[restrict]);
#endif
#ifdef HAVE_POSIX_SPAWNP
static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict],
char *const envp[restrict]);
#endif
/* Initialization method to Captures the relevant environment variables.
*/
static void on_load(void) {
pthread_mutex_lock(&mutex);
if (!initialized)
initialized = bear_capture_env_t(&initial_env);
pthread_mutex_unlock(&mutex);
}
static void on_unload(void) {
pthread_mutex_lock(&mutex);
bear_release_env_t(&initial_env);
initialized = 0;
pthread_mutex_unlock(&mutex);
}
/* These are the methods we are try to hijack.
*/
#ifdef HAVE_EXECVE
int execve(const char *path, char *const argv[], char *const envp[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_execve(path, argv, envp);
}
#endif
#ifdef HAVE_EXECV
#ifndef HAVE_EXECVE
#error can not implement execv without execve
#endif
int execv(const char *path, char *const argv[]) {
bear_report_call(__func__, (char const *const *)argv);
char * const * envp = bear_get_environment();
return call_execve(path, argv, envp);
}
#endif
#ifdef HAVE_EXECVPE
int execvpe(const char *file, char *const argv[], char *const envp[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_execvpe(file, argv, envp);
}
#endif
#ifdef HAVE_EXECVP
int execvp(const char *file, char *const argv[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_execvp(file, argv);
}
#endif
#ifdef HAVE_EXECVP2
int execvP(const char *file, const char *search_path, char *const argv[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_execvP(file, search_path, argv);
}
#endif
#ifdef HAVE_EXECT
int exect(const char *path, char *const argv[], char *const envp[]) {
bear_report_call(__func__, (char const *const *)argv);
return call_exect(path, argv, envp);
}
#endif
#ifdef HAVE_EXECL
# ifndef HAVE_EXECVE
# error can not implement execl without execve
# endif
int execl(const char *path, const char *arg, ...) {
va_list args;
va_start(args, arg);
char const **argv = bear_strings_build(arg, &args);
va_end(args);
bear_report_call(__func__, (char const *const *)argv);
char * const * envp = bear_get_environment();
int const result = call_execve(path, (char *const *)argv, envp);
bear_strings_release(argv);
return result;
}
#endif
#ifdef HAVE_EXECLP
# ifndef HAVE_EXECVP
# error can not implement execlp without execvp
# endif
int execlp(const char *file, const char *arg, ...) {
va_list args;
va_start(args, arg);
char const **argv = bear_strings_build(arg, &args);
va_end(args);
bear_report_call(__func__, (char const *const *)argv);
int const result = call_execvp(file, (char *const *)argv);
bear_strings_release(argv);
return result;
}
#endif
#ifdef HAVE_EXECLE
# ifndef HAVE_EXECVE
# error can not implement execle without execve
# endif
// int execle(const char *path, const char *arg, ..., char * const envp[]);
int execle(const char *path, const char *arg, ...) {
va_list args;
va_start(args, arg);
char const **argv = bear_strings_build(arg, &args);
char const **envp = va_arg(args, char const **);
va_end(args);
bear_report_call(__func__, (char const *const *)argv);
int const result =
call_execve(path, (char *const *)argv, (char *const *)envp);
bear_strings_release(argv);
return result;
}
#endif
#ifdef HAVE_POSIX_SPAWN
int posix_spawn(pid_t *restrict pid, const char *restrict path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict], char *const envp[restrict]) {
bear_report_call(__func__, (char const *const *)argv);
return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
}
#endif
#ifdef HAVE_POSIX_SPAWNP
int posix_spawnp(pid_t *restrict pid, const char *restrict file,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict], char *const envp[restrict]) {
bear_report_call(__func__, (char const *const *)argv);
return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
}
#endif
/* These are the methods which forward the call to the standard implementation.
*/
#ifdef HAVE_EXECVE
static int call_execve(const char *path, char *const argv[],
char *const envp[]) {
typedef int (*func)(const char *, char *const *, char *const *);
DLSYM(func, fp, "execve");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result = (*fp)(path, argv, (char *const *)menvp);
bear_strings_release(menvp);
return result;
}
#endif
#ifdef HAVE_EXECVPE
static int call_execvpe(const char *file, char *const argv[],
char *const envp[]) {
typedef int (*func)(const char *, char *const *, char *const *);
DLSYM(func, fp, "execvpe");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result = (*fp)(file, argv, (char *const *)menvp);
bear_strings_release(menvp);
return result;
}
#endif
#ifdef HAVE_EXECVP
static int call_execvp(const char *file, char *const argv[]) {
typedef int (*func)(const char *file, char *const argv[]);
DLSYM(func, fp, "execvp");
bear_env_t current_env;
bear_capture_env_t(&current_env);
bear_reset_env_t(&initial_env);
int const result = (*fp)(file, argv);
bear_reset_env_t(&current_env);
bear_release_env_t(&current_env);
return result;
}
#endif
#ifdef HAVE_EXECVP2
static int call_execvP(const char *file, const char *search_path,
char *const argv[]) {
typedef int (*func)(const char *, const char *, char *const *);
DLSYM(func, fp, "execvP");
bear_env_t current_env;
bear_capture_env_t(&current_env);
bear_reset_env_t(&initial_env);
int const result = (*fp)(file, search_path, argv);
bear_reset_env_t(&current_env);
bear_release_env_t(&current_env);
return result;
}
#endif
#ifdef HAVE_EXECT
static int call_exect(const char *path, char *const argv[],
char *const envp[]) {
typedef int (*func)(const char *, char *const *, char *const *);
DLSYM(func, fp, "exect");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result = (*fp)(path, argv, (char *const *)menvp);
bear_strings_release(menvp);
return result;
}
#endif
#ifdef HAVE_POSIX_SPAWN
static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict],
char *const envp[restrict]) {
typedef int (*func)(pid_t *restrict, const char *restrict,
const posix_spawn_file_actions_t *,
const posix_spawnattr_t *restrict,
char *const *restrict, char *const *restrict);
DLSYM(func, fp, "posix_spawn");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result =
(*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
bear_strings_release(menvp);
return result;
}
#endif
#ifdef HAVE_POSIX_SPAWNP
static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp,
char *const argv[restrict],
char *const envp[restrict]) {
typedef int (*func)(pid_t *restrict, const char *restrict,
const posix_spawn_file_actions_t *,
const posix_spawnattr_t *restrict,
char *const *restrict, char *const *restrict);
DLSYM(func, fp, "posix_spawnp");
char const **const menvp = bear_update_environment(envp, &initial_env);
int const result =
(*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
bear_strings_release(menvp);
return result;
}
#endif
/* this method is to write log about the process creation. */
static void bear_report_call(char const *fun, char const *const argv[]) {
static int const GS = 0x1d;
static int const RS = 0x1e;
static int const US = 0x1f;
if (!initialized)
return;
pthread_mutex_lock(&mutex);
const char *cwd = getcwd(NULL, 0);
if (0 == cwd) {
perror("bear: getcwd");
exit(EXIT_FAILURE);
}
char const * const out_dir = initial_env[0];
size_t const path_max_length = strlen(out_dir) + 32;
char filename[path_max_length];
if (-1 == snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
perror("bear: snprintf");
exit(EXIT_FAILURE);
}
FILE * fd = fopen(filename, "a+");
if (0 == fd) {
perror("bear: fopen");
exit(EXIT_FAILURE);
}
fprintf(fd, "%d%c", getpid(), RS);
fprintf(fd, "%d%c", getppid(), RS);
fprintf(fd, "%s%c", fun, RS);
fprintf(fd, "%s%c", cwd, RS);
size_t const argc = bear_strings_length(argv);
for (size_t it = 0; it < argc; ++it) {
fprintf(fd, "%s%c", argv[it], US);
}
fprintf(fd, "%c", GS);
if (fclose(fd)) {
perror("bear: fclose");
exit(EXIT_FAILURE);
}
free((void *)cwd);
pthread_mutex_unlock(&mutex);
}
/* update environment assure that chilren processes will copy the desired
* behaviour */
static int bear_capture_env_t(bear_env_t *env) {
int status = 1;
for (size_t it = 0; it < ENV_SIZE; ++it) {
char const * const env_value = getenv(env_names[it]);
char const * const env_copy = (env_value) ? strdup(env_value) : env_value;
(*env)[it] = env_copy;
status &= (env_copy) ? 1 : 0;
}
return status;
}
static int bear_reset_env_t(bear_env_t *env) {
int status = 1;
for (size_t it = 0; it < ENV_SIZE; ++it) {
if ((*env)[it]) {
setenv(env_names[it], (*env)[it], 1);
} else {
unsetenv(env_names[it]);
}
}
return status;
}
static void bear_release_env_t(bear_env_t *env) {
for (size_t it = 0; it < ENV_SIZE; ++it) {
free((void *)(*env)[it]);
(*env)[it] = 0;
}
}
static char const **bear_update_environment(char *const envp[], bear_env_t *env) {
char const **result = bear_strings_copy((char const **)envp);
for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
result = bear_update_environ(result, env_names[it], (*env)[it]);
return result;
}
static char const **bear_update_environ(char const *envs[], char const *key, char const * const value) {
// find the key if it's there
size_t const key_length = strlen(key);
char const **it = envs;
for (; (it) && (*it); ++it) {
if ((0 == strncmp(*it, key, key_length)) &&
(strlen(*it) > key_length) && ('=' == (*it)[key_length]))
break;
}
// allocate a environment entry
size_t const value_length = strlen(value);
size_t const env_length = key_length + value_length + 2;
char *env = malloc(env_length);
if (0 == env) {
perror("bear: malloc [in env_update]");
exit(EXIT_FAILURE);
}
if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
perror("bear: snprintf");
exit(EXIT_FAILURE);
}
// replace or append the environment entry
if (it && *it) {
free((void *)*it);
*it = env;
return envs;
}
return bear_strings_append(envs, env);
}
static char **bear_get_environment() {
#if defined HAVE_NSGETENVIRON
return *_NSGetEnviron();
#else
return environ;
#endif
}
/* util methods to deal with string arrays. environment and process arguments
* are both represented as string arrays. */
static char const **bear_strings_build(char const *const arg, va_list *args) {
char const **result = 0;
size_t size = 0;
for (char const *it = arg; it; it = va_arg(*args, char const *)) {
result = realloc(result, (size + 1) * sizeof(char const *));
if (0 == result) {
perror("bear: realloc");
exit(EXIT_FAILURE);
}
char const *copy = strdup(it);
if (0 == copy) {
perror("bear: strdup");
exit(EXIT_FAILURE);
}
result[size++] = copy;
}
result = realloc(result, (size + 1) * sizeof(char const *));
if (0 == result) {
perror("bear: realloc");
exit(EXIT_FAILURE);
}
result[size++] = 0;
return result;
}
static char const **bear_strings_copy(char const **const in) {
size_t const size = bear_strings_length(in);
char const **const result = malloc((size + 1) * sizeof(char const *));
if (0 == result) {
perror("bear: malloc");
exit(EXIT_FAILURE);
}
char const **out_it = result;
for (char const *const *in_it = in; (in_it) && (*in_it);
++in_it, ++out_it) {
*out_it = strdup(*in_it);
if (0 == *out_it) {
perror("bear: strdup");
exit(EXIT_FAILURE);
}
}
*out_it = 0;
return result;
}
static char const **bear_strings_append(char const **const in,
char const *const e) {
size_t size = bear_strings_length(in);
char const **result = realloc(in, (size + 2) * sizeof(char const *));
if (0 == result) {
perror("bear: realloc");
exit(EXIT_FAILURE);
}
result[size++] = e;
result[size++] = 0;
return result;
}
static size_t bear_strings_length(char const *const *const in) {
size_t result = 0;
for (char const *const *it = in; (it) && (*it); ++it)
++result;
return result;
}
static void bear_strings_release(char const **in) {
for (char const *const *it = in; (it) && (*it); ++it) {
free((void *)*it);
}
free((void *)in);
}

View File

@ -7,7 +7,8 @@
import sys
import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
from libscanbuild.analyze import analyze_compiler_wrapper
sys.exit(analyze_compiler_wrapper())

View File

@ -7,7 +7,7 @@
import sys
import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
from libscanbuild.analyze import analyze_compiler_wrapper
sys.exit(analyze_compiler_wrapper())

View File

@ -7,7 +7,7 @@
import sys
import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
from libscanbuild.intercept import intercept_compiler_wrapper
sys.exit(intercept_compiler_wrapper())

View File

@ -7,7 +7,7 @@
import sys
import os.path
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))
sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
from libscanbuild.intercept import intercept_compiler_wrapper
sys.exit(intercept_compiler_wrapper())

View File

@ -3,6 +3,12 @@
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
import os
import sys
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
import unittest
import tests.unit

View File

@ -22,7 +22,7 @@ def load_tests(loader, suite, pattern):
def make_args(target):
this_dir, _ = os.path.split(__file__)
path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
path = os.path.abspath(os.path.join(this_dir, '..', 'src'))
return ['make', 'SRCDIR={}'.format(path), 'OBJDIR={}'.format(target), '-f',
os.path.join(path, 'build', 'Makefile')]

View File

@ -43,7 +43,7 @@ class ExecAnatomyTest(unittest.TestCase):
def test_all_exec_calls(self):
this_dir, _ = os.path.split(__file__)
source_dir = os.path.normpath(os.path.join(this_dir, '..', 'exec'))
source_dir = os.path.abspath(os.path.join(this_dir, '..', 'exec'))
with libear.TemporaryDirectory() as tmp_dir:
expected, result = run(source_dir, tmp_dir)
self.assertEqualJson(expected, result)

View File

@ -15,7 +15,7 @@ import glob
def prepare_cdb(name, target_dir):
target_file = 'build_{0}.json'.format(name)
this_dir, _ = os.path.split(__file__)
path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
path = os.path.abspath(os.path.join(this_dir, '..', 'src'))
source_dir = os.path.join(path, 'compilation_database')
source_file = os.path.join(source_dir, target_file + '.in')
target_file = os.path.join(target_dir, 'compile_commands.json')

View File

@ -17,7 +17,7 @@ class OutputDirectoryTest(unittest.TestCase):
@staticmethod
def run_analyzer(outdir, args, cmd):
return check_call_and_report(
['scan-build', '--intercept-first', '-o', outdir] + args,
['scan-build-py', '--intercept-first', '-o', outdir] + args,
cmd)
def test_regular_keeps_report_dir(self):
@ -49,7 +49,7 @@ class RunAnalyzerTest(unittest.TestCase):
with libear.TemporaryDirectory() as tmpdir:
make = make_args(tmpdir) + ['build_regular']
outdir = check_call_and_report(
['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
make)
self.assertTrue(os.path.isdir(outdir))
@ -59,7 +59,7 @@ class RunAnalyzerTest(unittest.TestCase):
with libear.TemporaryDirectory() as tmpdir:
make = make_args(tmpdir) + ['build_regular']
outdir = check_call_and_report(
['scan-build', '--plist', '-o', tmpdir, '--intercept-first',
['scan-build-py', '--plist', '-o', tmpdir, '--intercept-first',
'--override-compiler'],
make)
@ -70,7 +70,7 @@ class RunAnalyzerTest(unittest.TestCase):
with libear.TemporaryDirectory() as tmpdir:
make = make_args(tmpdir) + ['build_regular']
outdir = check_call_and_report(
['scan-build', '--plist', '-o', tmpdir, '--intercept-first'],
['scan-build-py', '--plist', '-o', tmpdir, '--intercept-first'],
make)
self.assertTrue(os.path.isdir(outdir))
@ -89,21 +89,21 @@ class RunAnalyzerTest(unittest.TestCase):
def test_interposition_cc_works(self):
with libear.TemporaryDirectory() as tmpdir:
outdir = check_call_and_report(
['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
self.compile_empty_source_file(tmpdir, False))
self.assertEqual(self.get_plist_count(outdir), 1)
def test_interposition_cxx_works(self):
with libear.TemporaryDirectory() as tmpdir:
outdir = check_call_and_report(
['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
self.compile_empty_source_file(tmpdir, True))
self.assertEqual(self.get_plist_count(outdir), 1)
def test_intercept_cc_works(self):
with libear.TemporaryDirectory() as tmpdir:
outdir = check_call_and_report(
['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler',
'--intercept-first'],
self.compile_empty_source_file(tmpdir, False))
self.assertEqual(self.get_plist_count(outdir), 1)
@ -111,7 +111,7 @@ class RunAnalyzerTest(unittest.TestCase):
def test_intercept_cxx_works(self):
with libear.TemporaryDirectory() as tmpdir:
outdir = check_call_and_report(
['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler',
'--intercept-first'],
self.compile_empty_source_file(tmpdir, True))
self.assertEqual(self.get_plist_count(outdir), 1)

View File

@ -18,9 +18,9 @@ class ReportDirectoryTest(unittest.TestCase):
# scan-build can be easily matched up to compare results.
def test_directory_name_comparison(self):
with libear.TemporaryDirectory() as tmpdir, \
sut.report_directory(tmpdir, False) as report_dir1, \
sut.report_directory(tmpdir, False) as report_dir2, \
sut.report_directory(tmpdir, False) as report_dir3:
sut.report_directory(tmpdir, False, 'html') as report_dir1, \
sut.report_directory(tmpdir, False, 'html') as report_dir2, \
sut.report_directory(tmpdir, False, 'html') as report_dir3:
self.assertLess(report_dir1, report_dir2)
self.assertLess(report_dir2, report_dir3)