@@ -69,6 +69,7 @@ include(GNUInstallDirs) | |||
include(CMakePackageConfigHelpers) | |||
option(BUILD_SHARED_LIBS "Default to building shared libraries" ON) | |||
option(BUILD_STATIC_LIBS "Default to building static libraries" ON) | |||
# Generate a release merge and test it to verify the correctness of republishing the package. | |||
ADD_CUSTOM_TARGET(distcheck | |||
@@ -391,7 +392,7 @@ add_library(${PROJECT_NAME} | |||
set_target_properties(${PROJECT_NAME} PROPERTIES | |||
VERSION 5.0.0 | |||
SOVERSION 5) | |||
list(APPEND CMAKE_TARGETS ${PROJECT_NAME}) | |||
# If json-c is used as subroject it set to target correct interface -I flags and allow | |||
# to build external target without extra include_directories(...) | |||
target_include_directories(${PROJECT_NAME} | |||
@@ -400,6 +401,21 @@ target_include_directories(${PROJECT_NAME} | |||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}> | |||
) | |||
# Allow to build static and shared libraries at the same time | |||
if (BUILD_STATIC_LIBS) | |||
set(STATIC_LIB ${PROJECT_NAME}-static) | |||
add_library(${STATIC_LIB} STATIC | |||
${JSON_C_SOURCES} | |||
${JSON_C_HEADERS} | |||
) | |||
# rename the static library | |||
set_target_properties(${STATIC_LIB} PROPERTIES | |||
OUTPUT_NAME ${PROJECT_NAME} | |||
) | |||
list(APPEND CMAKE_TARGETS ${STATIC_LIB}) | |||
endif () | |||
# Always create new install dirs with 0755 permissions, regardless of umask | |||
set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS | |||
OWNER_READ | |||
@@ -411,7 +427,7 @@ set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS | |||
WORLD_EXECUTE | |||
) | |||
install(TARGETS ${PROJECT_NAME} | |||
install(TARGETS ${CMAKE_TARGETS} | |||
EXPORT ${PROJECT_NAME}-targets | |||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} | |||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | |||
@@ -97,7 +97,8 @@ Variable | Type | Description | |||
---------------------|--------|-------------- | |||
CMAKE_INSTALL_PREFIX | String | The install location. | |||
CMAKE_BUILD_TYPE | String | Defaults to "debug" | |||
BUILD_SHARED_LIBS | Bool | The default build generates a dynamic (dll/so) library. Set this to OFF to create a static library instead. | |||
BUILD_SHARED_LIBS | Bool | The default build generates a dynamic (dll/so) library. Set this to OFF to create a static library only. | |||
BUILD_STATIC_LIBS | Bool | The default build generates a static (lib/a) library. Set this to OFF to create a shared library only. | |||
ENABLE_RDRAND | Bool | Enable RDRAND Hardware RNG Hash Seed | |||
ENABLE_THREADING | Bool | Enable partial threading support | |||
DISABLE_WERROR | Bool | Disable use of -Werror | |||
@@ -106,7 +107,8 @@ DISABLE_BSYMBOLIC | Bool | Disable use of -Bsymbolic-functions | |||
Pass these options as `-D` on CMake's command-line. | |||
```sh | |||
cmake -DBUILD_SHARED_LIBS=OFF ... | |||
# build a static library only | |||
cmake -DBUILD_SHARED_LIBS=OFF .. | |||
``` | |||
### Building with partial threading support | |||
@@ -168,16 +168,15 @@ int main(int argc, char **argv) | |||
case 'n': show_output = 0; break; | |||
case 's': strict_mode = 1; break; | |||
case 'h': usage(argv[0], 0, NULL); | |||
default: /* '?' */ usage(argv[0], 1, "Unknown arguments"); | |||
default: /* '?' */ usage(argv[0], EXIT_FAILURE, "Unknown arguments"); | |||
} | |||
} | |||
if (optind >= argc) | |||
{ | |||
fprintf(stderr, "Expected argument after options\n"); | |||
exit(EXIT_FAILURE); | |||
usage(argv[0], EXIT_FAILURE, "Expected argument after options"); | |||
} | |||
fname = argv[optind]; | |||
int fd = open(argv[optind], O_RDONLY, 0); | |||
showmem(); | |||
if (parseit(fd, showobj) != 0) | |||
@@ -136,6 +136,9 @@ int array_list_del_idx(struct array_list *arr, size_t idx, size_t count) | |||
{ | |||
size_t i, stop; | |||
/* Avoid overflow in calculation with large indices. */ | |||
if (idx > SIZE_T_MAX - count) | |||
return -1; | |||
stop = idx + count; | |||
if (idx >= arr->length || stop > arr->length) | |||
return -1; | |||
@@ -77,29 +77,74 @@ done | |||
WORK="${RUNDIR}/work" | |||
mkdir -p "${WORK}" | |||
# XAX use a different data dir | |||
if [ ! -r "${WORK}/../canada.json" ] ; then | |||
curl -L -o "${WORK}/../canada.json" 'https://github.com/mloskot/json_benchmark/raw/master/data/canada.json' | |||
fi | |||
DATA="${RUNDIR}/data" | |||
mkdir -p "${DATA}" | |||
for file in citm_catalog.json twitter.json canada.json ; do | |||
if [ ! -r "${DATA}/${file}" ] ; then | |||
echo "Fetching ${file} from github.com/mloskot/json_benchmark" | |||
URL="https://github.com/mloskot/json_benchmark/raw/master/data/${file}" | |||
curl -s -L -o "${DATA}/${file}" "$URL" | |||
fi | |||
done | |||
echo | |||
# Identify "after" commit hash | |||
after_src_dir=$TOP | |||
after_commit= | |||
if [ ! -z "$after_arg" ] ; then | |||
# XXX decode this in more detail. | |||
# XXX for now, just assume it's a path | |||
after_src_dir=$after_arg | |||
# Identify "after" commit hash, in order of preference | |||
if [ ! -z "$after_arg" -a -d "$after_arg" ] ; then | |||
# Use provided directory | |||
after_src_dir="$after_arg" | |||
after_commit= | |||
else | |||
_commit= | |||
if [ ! -z "$after_arg" ] ; then | |||
# Use provided commit hash | |||
_commit=$(git rev-parse --verify "$after_arg") | |||
fi | |||
if [ ! -z "$_commit" ] ;then | |||
after_src_dir= # i.e. current tree | |||
after_commit="$_commit" | |||
else | |||
# Local changes in current working directory | |||
# ${cur_branch} | |||
after_src_dir=$TOP | |||
after_commit= | |||
fi | |||
fi | |||
# Identify "before" commit hash | |||
before_src_dir= | |||
#before_commit=origin/master | |||
before_commit=origin/json-c-0.14 | |||
if [ ! -z "$before_arg" ] ; then | |||
# XXX decode this in more detail | |||
# Identify "before" commit hash, in order of preference | |||
if [ ! -z "$before_arg" -a -d "$before_arg" ] ; then | |||
# Use provided directory | |||
before_src_dir="$before_arg" | |||
before_commit= | |||
else | |||
_commit= | |||
if [ ! -z "$before_arg" ] ; then | |||
# Use provided commit hash | |||
_commit=$(git rev-parse --verify "$before_arg") | |||
fi | |||
if [ ! -z "$_commit" ] ;then | |||
before_src_dir= # i.e. current tree | |||
before_commit="$_commit" | |||
else | |||
# Use origin/${cur_branch}, if different from ${after_commit} | |||
_cur_branch=$(git rev-parse --abbrev-ref HEAD) | |||
_commit= | |||
if [ ! -z "${_cur_branch}" ] ; then | |||
_commit=$(git rev-parse --verify "origin/${_cur_branch}") | |||
fi | |||
if [ "$_commit" = "${after_commit}" ] ; then | |||
_commit= | |||
fi | |||
fi | |||
if [ ! -z "$_commit" ] ; then | |||
before_src_dir= # i.e. current tree | |||
before_commit="$_commit" | |||
else | |||
# Use previous release | |||
before_src_dir= # i.e. current tree | |||
before_commit="$(git tag | sort | tail -1)" | |||
fi | |||
fi | |||
compile_benchmark() | |||
@@ -140,8 +185,16 @@ compile_benchmark() | |||
fi | |||
# else, use the provided $src_dir | |||
cd "${build_dir}" | |||
cmake -DCMAKE_INSTALL_PREFIX="${inst_dir}" "${src_dir}" | |||
if [ -e "${src_dir}/CMakeLists.txt" ] ; then | |||
cd "${build_dir}" | |||
cmake -DCMAKE_INSTALL_PREFIX="${inst_dir}" "${src_dir}" | |||
else | |||
# Old versions of json-c used automake/autoconf | |||
cd "${src_dir}" | |||
sh autogen.sh # always run it, configure doesn't always work | |||
cd "${build_dir}" | |||
"${src_dir}/configure" --prefix="${inst_dir}" | |||
fi | |||
make all install | |||
cd "${bench_dir}" | |||
@@ -162,7 +215,7 @@ run_benchmark() | |||
local inst_dir="${WORK}/$bname/install" | |||
local bench_dir="${WORK}/$bname/bench" | |||
local INPUT=${WORK}/../canada.json | |||
local INPUT=${DATA}/canada.json | |||
cd "${bench_dir}" | |||
mkdir -p results | |||
@@ -65,7 +65,7 @@ while [ $# -gt 0 ] ; do | |||
FLAGS+=(-DBUILD_SHARED_LIBS=ON) | |||
;; | |||
--enable-static) | |||
FLAGS+=(-DBUILD_SHARED_LIBS=OFF) | |||
FLAGS+=(-DBUILD_STATIC_LIBS=ON) | |||
;; | |||
--disable-Bsymbolic) | |||
FLAGS+=(-DDISABLE_BSYMBOLIC=ON) | |||
@@ -12,6 +12,7 @@ | |||
#include "config.h" | |||
#include <assert.h> | |||
#include <limits.h> | |||
#include <stdarg.h> | |||
#include <stddef.h> | |||
@@ -499,6 +500,8 @@ struct lh_table *lh_table_new(int size, lh_entry_free_fn *free_fn, lh_hash_fn *h | |||
int i; | |||
struct lh_table *t; | |||
/* Allocate space for elements to avoid divisions by zero. */ | |||
assert(size > 0); | |||
t = (struct lh_table *)calloc(1, sizeof(struct lh_table)); | |||
if (!t) | |||
return NULL; | |||
@@ -577,9 +580,12 @@ int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, con | |||
{ | |||
unsigned long n; | |||
if (t->count >= t->size * LH_LOAD_FACTOR) | |||
if (lh_table_resize(t, t->size * 2) != 0) | |||
if (t->count >= t->size * LH_LOAD_FACTOR) { | |||
/* Avoid signed integer overflow with large tables. */ | |||
int new_size = INT_MAX / 2 < t->size ? t->size * 2 : INT_MAX; | |||
if (t->size == INT_MAX || lh_table_resize(t, new_size) != 0) | |||
return -1; | |||
} | |||
n = h % t->size; | |||
@@ -15,6 +15,7 @@ | |||
#include "config.h" | |||
#include <limits.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
@@ -65,10 +66,16 @@ static int printbuf_extend(struct printbuf *p, int min_size) | |||
if (p->size >= min_size) | |||
return 0; | |||
new_size = p->size * 2; | |||
if (new_size < min_size + 8) | |||
/* Prevent signed integer overflows with large buffers. */ | |||
if (min_size > INT_MAX - 8) | |||
return -1; | |||
if (p->size > INT_MAX / 2) | |||
new_size = min_size + 8; | |||
else { | |||
new_size = p->size * 2; | |||
if (new_size < min_size + 8) | |||
new_size = min_size + 8; | |||
} | |||
#ifdef PRINTBUF_DEBUG | |||
MC_DEBUG("printbuf_memappend: realloc " | |||
"bpos=%d min_size=%d old_size=%d new_size=%d\n", | |||
@@ -83,6 +90,9 @@ static int printbuf_extend(struct printbuf *p, int min_size) | |||
int printbuf_memappend(struct printbuf *p, const char *buf, int size) | |||
{ | |||
/* Prevent signed integer overflows with large buffers. */ | |||
if (size > INT_MAX - p->bpos - 1) | |||
return -1; | |||
if (p->size <= p->bpos + size + 1) | |||
{ | |||
if (printbuf_extend(p, p->bpos + size + 1) < 0) | |||
@@ -100,6 +110,9 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) | |||
if (offset == -1) | |||
offset = pb->bpos; | |||
/* Prevent signed integer overflows with large buffers. */ | |||
if (len > INT_MAX - offset) | |||
return -1; | |||
size_needed = offset + len; | |||
if (pb->size < size_needed) | |||
{ | |||
@@ -43,12 +43,51 @@ static void do_cpuid(int regs[], int h) | |||
#if HAS_X86_CPUID | |||
static int get_rdrand_seed(void); | |||
/* Valid values are -1 (haven't tested), 0 (no), and 1 (yes). */ | |||
static int _has_rdrand = -1; | |||
static int has_rdrand(void) | |||
{ | |||
// CPUID.01H:ECX.RDRAND[bit 30] == 1 | |||
if (_has_rdrand != -1) | |||
{ | |||
return _has_rdrand; | |||
} | |||
/* CPUID.01H:ECX.RDRAND[bit 30] == 1 */ | |||
int regs[4]; | |||
do_cpuid(regs, 1); | |||
return (regs[2] & (1 << 30)) != 0; | |||
if (!(regs[2] & (1 << 30))) | |||
{ | |||
_has_rdrand = 0; | |||
return 0; | |||
} | |||
/* | |||
* Some CPUs advertise RDRAND in CPUID, but return 0xFFFFFFFF | |||
* unconditionally. To avoid locking up later, test RDRAND here. If over | |||
* 3 trials RDRAND has returned the same value, declare it broken. | |||
* Example CPUs are AMD Ryzen 3000 series | |||
* and much older AMD APUs, such as the E1-1500 | |||
* https://github.com/systemd/systemd/issues/11810 | |||
* https://linuxreviews.org/RDRAND_stops_returning_random_values_on_older_AMD_CPUs_after_suspend | |||
*/ | |||
_has_rdrand = 0; | |||
int prev = get_rdrand_seed(); | |||
for (int i = 0; i < 3; i++) | |||
{ | |||
int temp = get_rdrand_seed(); | |||
if (temp != prev) | |||
{ | |||
_has_rdrand = 1; | |||
break; | |||
} | |||
prev = temp; | |||
} | |||
return _has_rdrand; | |||
} | |||
#endif | |||
@@ -63,7 +102,7 @@ static int get_rdrand_seed(void) | |||
{ | |||
DEBUG_SEED("get_rdrand_seed"); | |||
int _eax; | |||
// rdrand eax | |||
/* rdrand eax */ | |||
/* clang-format off */ | |||
__asm__ __volatile__("1: .byte 0x0F\n" | |||
" .byte 0xC7\n" | |||
@@ -103,7 +142,7 @@ static int get_rdrand_seed(void) | |||
DEBUG_SEED("get_rdrand_seed"); | |||
int _eax; | |||
retry: | |||
// rdrand eax | |||
/* rdrand eax */ | |||
__asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 | |||
__asm jnc retry | |||
__asm mov _eax, eax | |||
@@ -177,6 +216,10 @@ static int get_dev_random_seed(void) | |||
/* clang-format off */ | |||
#include <windows.h> | |||
/* Caution: these blank lines must remain so clang-format doesn't reorder | |||
includes to put windows.h after wincrypt.h */ | |||
#include <wincrypt.h> | |||
/* clang-format on */ | |||
#ifndef __GNUC__ | |||