aboutsummaryrefslogtreecommitdiff
path: root/libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2013-01-23 11:41:33 +0000
committerKostya Serebryany <kcc@gcc.gnu.org>2013-01-23 11:41:33 +0000
commit2660d12d0a69539959dc1f77648f9f29f5e0edf8 (patch)
tree80989bd161e60d01560788cb7427eb644b227884 /libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
parentb39968989d6ae4289c01202c45268b5651d1c222 (diff)
downloadgcc-2660d12d0a69539959dc1f77648f9f29f5e0edf8.zip
gcc-2660d12d0a69539959dc1f77648f9f29f5e0edf8.tar.gz
gcc-2660d12d0a69539959dc1f77648f9f29f5e0edf8.tar.bz2
libsanitizer merge from upstream r173241
From-SVN: r195404
Diffstat (limited to 'libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc')
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc144
1 files changed, 144 insertions, 0 deletions
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
new file mode 100644
index 0000000..f7cab5f
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
@@ -0,0 +1,144 @@
+//===-- sanitizer_common_interceptors_scanf.inc -----------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Scanf implementation for use in *Sanitizer interceptors.
+//
+//===----------------------------------------------------------------------===//
+#include <stdarg.h>
+
+#ifdef _WIN32
+#define va_copy(dst, src) ((dst) = (src))
+#endif // _WIN32
+
+struct ScanfSpec {
+ char c;
+ unsigned size;
+};
+
+// One-letter specs.
+static const ScanfSpec scanf_specs[] = {
+ {'p', sizeof(void *)},
+ {'e', sizeof(float)},
+ {'E', sizeof(float)},
+ {'a', sizeof(float)},
+ {'f', sizeof(float)},
+ {'g', sizeof(float)},
+ {'d', sizeof(int)},
+ {'i', sizeof(int)},
+ {'o', sizeof(int)},
+ {'u', sizeof(int)},
+ {'x', sizeof(int)},
+ {'X', sizeof(int)},
+ {'n', sizeof(int)},
+ {'t', sizeof(PTRDIFF_T)},
+ {'z', sizeof(SIZE_T)},
+ {'j', sizeof(INTMAX_T)},
+ {'h', sizeof(short)}
+};
+
+static const unsigned scanf_specs_cnt =
+ sizeof(scanf_specs) / sizeof(scanf_specs[0]);
+
+// %ll?, %L?, %q? specs
+static const ScanfSpec scanf_llspecs[] = {
+ {'e', sizeof(long double)},
+ {'f', sizeof(long double)},
+ {'g', sizeof(long double)},
+ {'d', sizeof(long long)},
+ {'i', sizeof(long long)},
+ {'o', sizeof(long long)},
+ {'u', sizeof(long long)},
+ {'x', sizeof(long long)}
+};
+
+static const unsigned scanf_llspecs_cnt =
+ sizeof(scanf_llspecs) / sizeof(scanf_llspecs[0]);
+
+// %l? specs
+static const ScanfSpec scanf_lspecs[] = {
+ {'e', sizeof(double)},
+ {'f', sizeof(double)},
+ {'g', sizeof(double)},
+ {'d', sizeof(long)},
+ {'i', sizeof(long)},
+ {'o', sizeof(long)},
+ {'u', sizeof(long)},
+ {'x', sizeof(long)},
+ {'X', sizeof(long)},
+};
+
+static const unsigned scanf_lspecs_cnt =
+ sizeof(scanf_lspecs) / sizeof(scanf_lspecs[0]);
+
+static unsigned match_spec(const struct ScanfSpec *spec, unsigned n, char c) {
+ for (unsigned i = 0; i < n; ++i)
+ if (spec[i].c == c)
+ return spec[i].size;
+ return 0;
+}
+
+static void scanf_common(void *ctx, const char *format, va_list ap_const) {
+ va_list aq;
+ va_copy(aq, ap_const);
+
+ const char *p = format;
+ unsigned size;
+
+ while (*p) {
+ if (*p != '%') {
+ ++p;
+ continue;
+ }
+ ++p;
+ if (*p == '*' || *p == '%' || *p == 0) {
+ ++p;
+ continue;
+ }
+ if (*p == '0' || (*p >= '1' && *p <= '9')) {
+ size = internal_atoll(p);
+ // +1 for the \0 at the end
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size + 1);
+ ++p;
+ continue;
+ }
+
+ if (*p == 'L' || *p == 'q') {
+ ++p;
+ size = match_spec(scanf_llspecs, scanf_llspecs_cnt, *p);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
+ continue;
+ }
+
+ if (*p == 'l') {
+ ++p;
+ if (*p == 'l') {
+ ++p;
+ size = match_spec(scanf_llspecs, scanf_llspecs_cnt, *p);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
+ continue;
+ } else {
+ size = match_spec(scanf_lspecs, scanf_lspecs_cnt, *p);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
+ continue;
+ }
+ }
+
+ if (*p == 'h' && *(p + 1) == 'h') {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), sizeof(char));
+ p += 2;
+ continue;
+ }
+
+ size = match_spec(scanf_specs, scanf_specs_cnt, *p);
+ if (size) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
+ ++p;
+ continue;
+ }
+ }
+ va_end(aq);
+}