summaryrefslogtreecommitdiff
path: root/src/rtcheck.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtcheck.c')
-rw-r--r--src/rtcheck.c278
1 files changed, 278 insertions, 0 deletions
diff --git a/src/rtcheck.c b/src/rtcheck.c
new file mode 100644
index 0000000..d9f623c
--- /dev/null
+++ b/src/rtcheck.c
@@ -0,0 +1,278 @@
+/*
+ * Additional runtime checks
+ * Copyright Jan Engelhardt, 2011
+ *
+ * This file is part of libHX. libHX is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU Lesser
+ * General Public License as published by the Free Software Foundation;
+ * either version 2.1 or (at your option) any later version.
+ *
+ * libHX_rtcheck.so is a library supposed to be used together with the
+ * LD_PRELOAD environment variable to dynamically add extra checks.
+ */
+#define _GNU_SOURCE 1
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#ifdef RTLD_NEXT
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <libHX.h>
+#include "internal.h"
+
+#define call_next(f) \
+ ((__typeof__(f) *)dlsym(RTLD_NEXT, #f))
+
+#define stub_head(f, args, invoke) \
+ EXPORT_SYMBOL __typeof__(f invoke) f args \
+ { \
+ if (HXrefchk_count <= 0) \
+ fprintf(stderr, "%s: HX_init has not been called!\n", \
+ __func__);
+
+#define stub_tail(f, params) \
+ return call_next(f) params; \
+ }
+
+#define stub(f, args, invoke, params) \
+ stub_head(f, args, invoke) \
+ stub_tail(f, params)
+
+#define stubv(f, args, params) \
+ EXPORT_SYMBOL void f args \
+ { \
+ if (HXrefchk_count <= 0) \
+ fprintf(stderr, "%s: HX_init has not been called!\n", \
+ __func__); \
+ call_next(f) params; \
+ }
+
+#define stub0(f) stub(f, (void), (), ())
+#define stub1(f, args) stub(f, args, (0), (a))
+#define stub1v(f, args) stubv(f, args, (a))
+#define stub2(f, args) stub(f, args, (0, 0), (a, b))
+#define stub2v(f, args) stubv(f, args, (a, b))
+#define stub3(f, args) stub(f, args, (0, 0, 0), (a, b, c))
+#define stub3v(f, args) stubv(f, args, (a, b, c))
+#define stub4(f, args) stub(f, args, (0, 0, 0, 0), (a, b, c, d))
+#define stub5(f, args) stub(f, args, (0, 0, 0, 0, 0), (a, b, c, d, e))
+
+static pthread_mutex_t HXrefchk_lock = PTHREAD_MUTEX_INITIALIZER;
+static unsigned long HXrefchk_count;
+
+EXPORT_SYMBOL int HX_init(void)
+{
+ /*
+ * The real HX_init has its own reference count check, but that
+ * variable is not exported that we could test it, so the counter needs
+ * to be replicated here.
+ */
+ pthread_mutex_lock(&HXrefchk_lock);
+ if (HXrefchk_count == 0) {
+ printf("# " PACKAGE_NAME " " PACKAGE_VERSION
+ " runtime checker active\n");
+ call_next(HX_init)();
+ }
+ ++HXrefchk_count;
+ pthread_mutex_unlock(&HXrefchk_lock);
+ return 1;
+}
+
+EXPORT_SYMBOL void HX_exit(void)
+{
+ pthread_mutex_lock(&HXrefchk_lock);
+ if (HXrefchk_count == 0)
+ fprintf(stderr, "%s: reference count is already zero!\n", __func__);
+ else
+ --HXrefchk_count;
+ pthread_mutex_unlock(&HXrefchk_lock);
+ call_next(HX_exit)();
+}
+
+/* deque.h */
+stub0(HXdeque_init);
+stub2(HXdeque_push, (struct HXdeque *a, const void *b));
+stub2(HXdeque_unshift, (struct HXdeque *a, const void *b));
+stub1(HXdeque_pop, (struct HXdeque *a));
+stub1(HXdeque_shift, (struct HXdeque *a));
+stub2(HXdeque_move, (struct HXdeque_node *a, struct HXdeque_node *b));
+stub2(HXdeque_find, (struct HXdeque *a, const void *b));
+stub2(HXdeque_get, (struct HXdeque *a, const void *b));
+stub1(HXdeque_del, (struct HXdeque_node *a));
+stub1v(HXdeque_free, (struct HXdeque *a));
+stub2v(HXdeque_genocide2, (struct HXdeque *a, void (*b)(void *)));
+stub2(HXdeque_to_vec, (const struct HXdeque *a, unsigned int *b));
+
+/* io.h */
+stub1(HXdir_open, (const char *a));
+stub1(HXdir_read, (struct HXdir *a));
+stub1v(HXdir_close, (struct HXdir *a));
+/* HX_copy_dir: has varargs */
+/* HX_copy_file: has varargs */
+stub2(HX_mkdir, (const char *a, unsigned int b));
+stub2(HX_readlink, (hxmc_t **a, const char *b));
+stub3(HX_realpath, (hxmc_t **a, const char *b, unsigned int c));
+stub1(HX_rrmdir, (const char *a));
+
+stub3(HXio_fullread, (int a, void *b, size_t c));
+stub3(HXio_fullwrite, (int a, const void *b, size_t c));
+
+/* map.h */
+stub2(HXmap_init, (enum HXmap_type a, unsigned int b));
+stub5(HXmap_init5, (enum HXmap_type a, unsigned int b,
+ const struct HXmap_ops *c, size_t d, size_t e));
+stub3(HXmap_add, (struct HXmap *a, const void *b, const void *c));
+stub2(HXmap_find, (const struct HXmap *a, const void *b));
+stub2(HXmap_get, (const struct HXmap *a, const void *b));
+stub2(HXmap_del, (struct HXmap *a, const void *b));
+stub1(HXmap_keysvalues, (const struct HXmap *a));
+stub2(HXmap_travinit, (const struct HXmap *a, unsigned int b));
+stub1(HXmap_traverse, (struct HXmap_trav *a));
+stub1v(HXmap_travfree, (struct HXmap_trav *a));
+stub3v(HXmap_qfe, (const struct HXmap *a,
+ bool (*b)(const struct HXmap_node *, void *), void *c));
+stub1v(HXmap_free, (struct HXmap *a));
+
+/* misc.h */
+stub1(HX_dlopen, (const char *a));
+stub2(HX_dlsym, (void *a, const char *b));
+stub1v(HX_dlclose, (void *a));
+stub0(HX_dlerror);
+
+stub1(HX_ffs, (unsigned long a));
+stub1(HX_fls, (unsigned long a));
+stub3(HX_hexdump, (FILE *a, const void *b, unsigned int c));
+stub3(HX_timespec_add, (struct timespec *a, const struct timespec *b,
+ const struct timespec *c));
+stub1(HX_timespec_isneg, (const struct timespec *a));
+stub3(HX_timespec_mul, (struct timespec *a, const struct timespec *b, int c));
+stub3(HX_timespec_mulf, (struct timespec *a, const struct timespec *b,
+ double c));
+stub2(HX_timespec_neg, (struct timespec *a, const struct timespec *b));
+stub3(HX_timespec_sub, (struct timespec *a, const struct timespec *b,
+ const struct timespec *c));
+stub3(HX_diff_timespec, (struct timespec *a, const struct timespec *b,
+ const struct timespec *c));
+stub3(HX_timeval_sub, (struct timeval *a, const struct timeval *b,
+ const struct timeval *c));
+stub3(HX_diff_timeval, (struct timeval *a, const struct timeval *b,
+ const struct timeval *c));
+stub3(HX_time_compare, (const struct stat *a, const struct stat *b, char c));
+stub1v(HX_zvecfree, (char **a));
+
+stub0(HX_rand);
+stub2(HX_irand, (unsigned int a, unsigned int b));
+stub2(HX_drand, (double a, double b));
+
+/* option.h */
+stub0(HXformat_init);
+stub1v(HXformat_free, (struct HXformat_map *a));
+stub4(HXformat_add, (struct HXformat_map *a, const char *b, const void *c,
+ unsigned int d));
+stub3(HXformat_aprintf, (const struct HXformat_map *a, hxmc_t **b,
+ const char *c));
+stub4(HXformat_sprintf, (const struct HXformat_map *a, char *b, size_t c,
+ const char *d));
+stub3(HXformat_fprintf, (const struct HXformat_map *a, FILE *b,
+ const char *c));
+
+stub4(HX_getopt, (const struct HXoption *a, int *b, const char ***c,
+ unsigned int d));
+/* HX_getopt_help: not really public */
+/* HX_getopt_help_cb: not really public */
+/* HX_getopt_usage: not really public */
+/* HX_getopt_usage_cb: not really public */
+stub2(HX_shconfig, (const char *a, const struct HXoption *b));
+stub1(HX_shconfig_map, (const char *a));
+stub4(HX_shconfig_pv, (const char **a, const char *b, const struct HXoption *c,
+ unsigned int d));
+stub1v(HX_shconfig_free, (const struct HXoption *a));
+
+/* proc.h */
+stub2(HXproc_run_async, (const char *const *a, struct HXproc *b));
+stub2(HXproc_run_sync, (const char *const *a, unsigned int b));
+stub1(HXproc_wait, (struct HXproc *a));
+
+/* string.h */
+static __inline__ struct memcont *HXmc_base(const hxmc_t *p)
+{
+ return containerof(p, struct memcont, data);
+}
+
+static __inline__ void HXmc_check(const char *func, const void *cv)
+{
+ const struct memcont *c;
+
+ if (cv == NULL)
+ return;
+ c = HXmc_base(cv);
+ if (c->id != HXMC_IDENT)
+ fprintf(stderr, "%s: %p is not a HXmc object!\n", func, cv);
+}
+
+stub1(HXmc_strinit, (const char *a));
+stub2(HXmc_meminit, (const void *a, size_t b));
+
+stub_head(HXmc_strcpy, (hxmc_t **a, const char *b), (0, 0))
+{
+ if (*a != NULL)
+ HXmc_check(__func__, *a);
+}
+stub_tail(HXmc_strcpy, (a, b))
+
+stub_head(HXmc_memcpy, (hxmc_t **a, const void *b, size_t c), (0, 0, 0))
+{
+ if (*a != NULL)
+ HXmc_check(__func__, *a);
+}
+stub_tail(HXmc_memcpy, (a, b, c))
+
+stub_head(HXmc_length, (const hxmc_t *a), (0))
+{
+ if (a != NULL)
+ HXmc_check(__func__, a);
+}
+stub_tail(HXmc_length, (a))
+
+stub2(HXmc_setlen, (hxmc_t **a, size_t b));
+stub2(HXmc_trunc, (hxmc_t **a, size_t b));
+stub2(HXmc_strcat, (hxmc_t **a, const char *b));
+stub3(HXmc_memcat, (hxmc_t **a, const void *b, size_t c));
+stub2(HXmc_strpcat, (hxmc_t **a, const char *b));
+stub3(HXmc_mempcat, (hxmc_t **a, const void *b, size_t c));
+stub3(HXmc_strins, (hxmc_t **a, size_t b, const char *c));
+stub4(HXmc_memins, (hxmc_t **a, size_t b, const void *c, size_t d));
+stub3(HXmc_memdel, (hxmc_t *a, size_t b, size_t c));
+stub1v(HXmc_free, (hxmc_t *a));
+stub1v(HXmc_zvecfree, (hxmc_t **a));
+
+stub1(HX_basename, (const char *a));
+stub1(HX_basename_exact, (const char *a));
+stub1(HX_chomp, (char *a));
+stub1(HX_dirname, (const char *a));
+stub2(HX_getl, (hxmc_t **a, FILE *b));
+stub4(HX_memmem, (const void *a, size_t b, const void *c, size_t d));
+stub4(HX_split, (const char *a, const char *b, int *c, int d));
+stub4(HX_split4, (char *a, const char *b, int *c, int d));
+stub4(HX_split5, (char *a, const char *b, int c, char **d));
+stub1(HX_stpltrim, (const char *a));
+stub1(HX_stprtrim, (char *a));
+stub3(HX_strbchr, (const char *a, const char *b, char c));
+stub2(HX_strclone, (char **a, const char *b));
+stub1(HX_strlower, (char *a));
+stub1(HX_strltrim, (char *a));
+stub3(HX_strmid, (const char *a, long b, long c));
+stub2(HX_strndup, (const char *a, size_t b));
+stub2(HX_strnlen, (const char *a, size_t b));
+stub3(HX_strquote, (const char *a, unsigned int b, char **c));
+stub2(HX_strrcspn, (const char *a, const char *b));
+stub1(HX_strrev, (char *a));
+stub1(HX_strrtrim, (char *a));
+stub2(HX_strsep, (char **a, const char *b));
+stub2(HX_strsep2, (char **a, const char *b));
+stub1(HX_strupper, (char *a));
+
+#endif /* RTLD_NEXT */
+#endif /* HAVE_DLFCN_H */