aboutsummaryrefslogtreecommitdiff
path: root/scripts/coccinelle
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/coccinelle')
-rwxr-xr-xscripts/coccinelle/apply.sh9
-rwxr-xr-xscripts/coccinelle/check_cocci_parse.sh53
-rw-r--r--scripts/coccinelle/exceptions.txt24
-rwxr-xr-xscripts/coccinelle/test-operator-cleanup13
-rw-r--r--scripts/coccinelle/tor-coccinelle.h60
-rwxr-xr-xscripts/coccinelle/try_parse.sh46
6 files changed, 205 insertions, 0 deletions
diff --git a/scripts/coccinelle/apply.sh b/scripts/coccinelle/apply.sh
new file mode 100755
index 0000000000..f531d7fa32
--- /dev/null
+++ b/scripts/coccinelle/apply.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# apply.sh:
+# run spatch with appropriate includes and builtins for the Tor source code
+
+top="$(dirname "$0")/../.."
+
+spatch -macro_file_builtins "$top"/scripts/coccinelle/tor-coccinelle.h \
+ -I "$top" -I "$top"/src -I "$top"/ext --defined COCCI "$@"
diff --git a/scripts/coccinelle/check_cocci_parse.sh b/scripts/coccinelle/check_cocci_parse.sh
new file mode 100755
index 0000000000..220b405940
--- /dev/null
+++ b/scripts/coccinelle/check_cocci_parse.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+# If we have coccinelle installed, run try_parse.sh on every filename passed
+# as an argument. If no filenames are supplied, scan a standard Tor 0.3.5 or
+# later directory layout.
+#
+# Uses the default coccinelle exceptions file, or $TOR_COCCI_EXCEPTIONS_FILE,
+# if it is set.
+#
+# Use TOR_COCCI_EXCEPTIONS_FILE=/dev/null check_cocci_parse.sh to disable
+# the default exception file.
+#
+# If spatch is not installed, remind the user to install it, but exit with
+# a success error status.
+
+scripts_cocci="$(dirname "$0")"
+top="$scripts_cocci/../.."
+try_parse="$scripts_cocci/try_parse.sh"
+
+exitcode=0
+
+export TOR_COCCI_EXCEPTIONS_FILE="${TOR_COCCI_EXCEPTIONS_FILE:-$scripts_cocci/exceptions.txt}"
+
+if ! command -v spatch; then
+ echo "Install coccinelle's spatch to check cocci C parsing!"
+ exit "$exitcode"
+fi
+
+if test $# -ge 1 ; then
+ "$try_parse" "$@"
+ exitcode=$?
+else
+ cd "$top" || exit 1
+ # This is the layout in 0.3.5
+ "$try_parse" \
+ src/lib/*/*.[ch] \
+ src/core/*/*.[ch] \
+ src/feature/*/*.[ch] \
+ src/app/*/*.[ch] \
+ src/test/*.[ch] \
+ src/test/*/*.[ch] \
+ src/tools/*.[ch]
+ exitcode=$?
+fi
+
+if test "$exitcode" != 0 ; then
+ echo "Please fix these cocci parsing errors in the above files"
+ echo "Set VERBOSE=1 for more details"
+ echo "Try running test-operator-cleanup or 'make autostyle-operators'"
+ echo "As a last resort, you can modify scripts/coccinelle/exceptions.txt"
+fi
+
+exit "$exitcode"
diff --git a/scripts/coccinelle/exceptions.txt b/scripts/coccinelle/exceptions.txt
new file mode 100644
index 0000000000..473f4b22c5
--- /dev/null
+++ b/scripts/coccinelle/exceptions.txt
@@ -0,0 +1,24 @@
+# A list of exception patterns for check_cocci_parse.sh
+# Passed to 'grep -f'
+src/lib/cc/compat_compiler.h
+src/lib/container/handles.h
+src/lib/container/map.c
+src/lib/container/map.h
+src/lib/container/order.c
+src/lib/crypt_ops/crypto_rand.c
+src/lib/fs/files.h
+src/lib/log/util_bug.c
+src/lib/pubsub/pubsub_macros.h
+src/lib/smartlist_core/smartlist_foreach.h
+src/lib/testsupport/testsupport.h
+src/lib/tls/tortls.h
+src/lib/tls/tortls_openssl.c
+src/lib/tls/x509.h
+src/lib/version/version.c
+src/core/mainloop/connection.c
+src/core/or/reasons.c
+src/feature/dirclient/dirclient.c
+src/feature/nodelist/networkstatus.c
+src/test/test_address.c
+src/test/test_hs_cache.c
+src/test/test_hs_descriptor.c
diff --git a/scripts/coccinelle/test-operator-cleanup b/scripts/coccinelle/test-operator-cleanup
index e7822542a4..28b4d4f588 100755
--- a/scripts/coccinelle/test-operator-cleanup
+++ b/scripts/coccinelle/test-operator-cleanup
@@ -1,4 +1,17 @@
#!/usr/bin/perl -w -p -i
+#
+# Copyright (c) 2001 Matej Pfajfar.
+# Copyright (c) 2001-2004, Roger Dingledine.
+# Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+# Copyright (c) 2007-2019, The Tor Project, Inc.
+# See LICENSE for licensing information
+
+# This script looks for instances of C comparison operators as macro arguments,
+# and replaces them with our OP_* equivalents.
+#
+# Some macros that take operators are our tt_int_op() testing macro, and the
+# standard timercmp() macro. Coccinelle can't handle their syntax, however,
+# unless we give them their operators as a macro too.
next if m#^ */\*# or m#^ *\* #;
diff --git a/scripts/coccinelle/tor-coccinelle.h b/scripts/coccinelle/tor-coccinelle.h
index 8f625dcee4..44d79325eb 100644
--- a/scripts/coccinelle/tor-coccinelle.h
+++ b/scripts/coccinelle/tor-coccinelle.h
@@ -1,3 +1,63 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/*
+ * This file looks like a C header, but its purpose is a bit different.
+ *
+ * We never include it from our real C files; we only tell Coccinelle
+ * about it in apply.sh.
+ *
+ * It tells the Coccinelle semantic patching tool how to understand
+ * things that would otherwise not be good C syntax, or which would
+ * otherwise not make sense to it as C. It doesn't need to produce
+ * semantically equivalent C, or even correct C: it only has to produce
+ * syntactically valid C.
+ */
+
+#define MOCK_DECL(a, b, c) a b c
#define MOCK_IMPL(a, b, c) a b c
#define CHECK_PRINTF(a, b)
+#define CHECK_SCANF(a, b)
#define STATIC static
+#define EXTERN(a,b) extern a b;
+
+#define STMT_BEGIN do {
+#define STMT_END } while (0)
+
+#define BUG(x) (x)
+#define IF_BUG_ONCE(x) if (x)
+
+#define ATTR_NORETURN
+#define ATTR_UNUSED
+#define ATTR_CONST
+#define ATTR_MALLOC
+#define ATTR_WUR
+#define DISABLE_GCC_WARNING(x)
+#define ENABLE_GCC_WARNING(x)
+
+#define HANDLE_DECL(a,b,c)
+#define HANDLE_IMPL(a,b,c)
+#define HT_ENTRY(x) void *
+#define HT_HEAD(a,b) struct ht_head
+#define HT_INITIALIZER() { }
+#define X509 struct x509_st
+#define STACK_OF(x) struct foo_stack_t
+#define TOR_TAILQ_HEAD(a,b) struct tailq_head
+#define TOR_TAILQ_ENTRY(a) struct tailq_entry
+#define TOR_SIMPLEQ_HEAD(a,b) struct simpleq_entry
+#define TOR_SIMPLEQ_ENTRY(a) struct simpleq_entry
+#define TOR_LIST_HEAD(a,b) struct list_head
+#define TOR_LIST_ENTRY(a) struct list_entry
+#define TOR_SLIST_HEAD(a,b) struct slist_head
+#define TOR_SLIST_ENTRY(a) struct slist_entry
+
+#define NS_DECL(a, b, c) a b c
+#define NS(a) a
+
+#define CONF_TEST_MEMBERS(a,b,c)
+#define DUMMY_CONF_TEST_MEMBERS
+
+#define EAT_SEMICOLON extern int dummy__;
diff --git a/scripts/coccinelle/try_parse.sh b/scripts/coccinelle/try_parse.sh
new file mode 100755
index 0000000000..a90e51b4aa
--- /dev/null
+++ b/scripts/coccinelle/try_parse.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# Echo the name of every argument of this script that is not "perfect"
+# according to coccinelle's --parse-c.
+#
+# If $TOR_COCCI_EXCEPTIONS_FILE is non-empty, skip any files that match the
+# patterns in the exception file, according to "grep -f"
+#
+# If VERBOSE is non-empty, log spatch errors and skipped files.
+
+top="$(dirname "$0")/../.."
+
+exitcode=0
+
+for fn in "$@"; do
+
+ if test "${TOR_COCCI_EXCEPTIONS_FILE}" ; then
+ skip_fn=$(echo "$fn" | grep -f "${TOR_COCCI_EXCEPTIONS_FILE}")
+ if test "${skip_fn}" ; then
+ if test "${VERBOSE}" != ""; then
+ echo "Skipping '${skip_fn}'"
+ fi
+ continue
+ fi
+ fi
+
+ if spatch --macro-file-builtins \
+ "$top"/scripts/coccinelle/tor-coccinelle.h \
+ --defined COCCI \
+ --parse-c "$fn" \
+ 2>/dev/null | grep "perfect = 1" > /dev/null; then
+ : # it's perfect
+ else
+ echo "$fn"
+ if test "${VERBOSE}" != ""; then
+ spatch --macro-file-builtins \
+ "$top"/scripts/coccinelle/tor-coccinelle.h \
+ --defined COCCI \
+ --parse-c "$fn"
+ fi
+ exitcode=1
+ fi
+
+done
+
+exit "$exitcode"