[llvm-branch-commits] [compiler-rt] f625ab2 - [sanitizer] Intercept glibc's argp_parse()
Ilya Leoshkevich via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Mar 2 10:22:23 PST 2023
Author: Ilya Leoshkevich
Date: 2023-02-24T14:15:58+01:00
New Revision: f625ab2c6943b1c381ff17fed0f4d5abc0bc10f3
URL: https://github.com/llvm/llvm-project/commit/f625ab2c6943b1c381ff17fed0f4d5abc0bc10f3
DIFF: https://github.com/llvm/llvm-project/commit/f625ab2c6943b1c381ff17fed0f4d5abc0bc10f3.diff
LOG: [sanitizer] Intercept glibc's argp_parse()
Glibc provides the argp_parse() function for parsing command line
arguments [1].
Indicate that argc/argv are read from and arg_index is written to.
Strictly speaking, we also need to indicate that argp is read from,
but this would require describing its layout, and most people use a
static initializer there, so it's not worth the effort.
[1] https://www.gnu.org/software/libc/manual/html_node/Argp.html
Differential Revision: https://reviews.llvm.org/D143330
Added:
compiler-rt/test/sanitizer_common/TestCases/Linux/argp_parse.c
Modified:
compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
Removed:
################################################################################
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 9fc56238a64fc..51703a34f0e9b 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -10375,6 +10375,25 @@ INTERCEPTOR(void, hexdump, const void *ptr, int length, const char *header, int
#define INIT_HEXDUMP
#endif
+#if SANITIZER_INTERCEPT_ARGP_PARSE
+INTERCEPTOR(int, argp_parse, const struct argp *argp, int argc, char **argv,
+ unsigned flags, int *arg_index, void *input) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, argp_parse, argp, argc, argv, flags, arg_index,
+ input);
+ for (int i = 0; i < argc; i++)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, argv[i], internal_strlen(argv[i]) + 1);
+ int res = REAL(argp_parse)(argp, argc, argv, flags, arg_index, input);
+ if (!res && arg_index)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg_index, sizeof(int));
+ return res;
+}
+
+#define INIT_ARGP_PARSE COMMON_INTERCEPT_FUNCTION(argp_parse);
+#else
+#define INIT_ARGP_PARSE
+#endif
+
#include "sanitizer_common_interceptors_netbsd_compat.inc"
static void InitializeCommonInterceptors() {
@@ -10694,6 +10713,7 @@ static void InitializeCommonInterceptors() {
INIT_UNAME;
INIT___XUNAME;
INIT_HEXDUMP;
+ INIT_ARGP_PARSE;
INIT___PRINTF_CHK;
}
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 814ff462d1cf5..eb39fabfd5983 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -592,6 +592,7 @@
#define SANITIZER_INTERCEPT_FLOPEN SI_FREEBSD
#define SANITIZER_INTERCEPT_PROCCTL SI_FREEBSD
#define SANITIZER_INTERCEPT_HEXDUMP SI_FREEBSD
+#define SANITIZER_INTERCEPT_ARGP_PARSE SI_GLIBC
// This macro gives a way for downstream users to override the above
// interceptor macros irrespective of the platform they are on. They have
diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/argp_parse.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/argp_parse.c
new file mode 100644
index 0000000000000..b3e57cf5c8971
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/argp_parse.c
@@ -0,0 +1,57 @@
+// RUN: %clang %s -o %t && %run %t -o baz
+
+#include <argp.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct test {
+ const char *option_value;
+};
+
+static const struct argp_option options[] = {
+ {"option", 'o', "OPTION", 0, "Option", 0},
+ {NULL, 0, NULL, 0, NULL, 0},
+};
+
+static error_t parser(int key, char *arg, struct argp_state *state) {
+ if (key == 'o') {
+ ((struct test *)(state->input))->option_value = arg;
+ return 0;
+ }
+ return ARGP_ERR_UNKNOWN;
+}
+
+static struct argp argp = {.options = options, .parser = parser};
+
+void test_nulls(char *argv0) {
+ char *argv[] = {argv0, NULL};
+ int res = argp_parse(NULL, 1, argv, 0, NULL, NULL);
+ assert(res == 0);
+}
+
+void test_synthetic(char *argv0) {
+ char *argv[] = {argv0, "-o", "foo", "bar", NULL};
+ struct test t = {NULL};
+ int arg_index;
+ int res = argp_parse(&argp, 4, argv, 0, &arg_index, &t);
+ assert(res == 0);
+ assert(arg_index == 3);
+ assert(strcmp(t.option_value, "foo") == 0);
+}
+
+void test_real(int argc, char **argv) {
+ struct test t = {NULL};
+ int arg_index;
+ int res = argp_parse(&argp, argc, argv, 0, &arg_index, &t);
+ assert(res == 0);
+ assert(arg_index == 3);
+ assert(strcmp(t.option_value, "baz") == 0);
+}
+
+int main(int argc, char **argv) {
+ test_nulls(argv[0]);
+ test_synthetic(argv[0]);
+ test_real(argc, argv);
+ return EXIT_SUCCESS;
+}
More information about the llvm-branch-commits
mailing list