summaryrefslogtreecommitdiff
path: root/src/or/confparse.h
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2017-09-25 11:08:11 -0400
committerNick Mathewson <nickm@torproject.org>2017-09-26 12:24:04 -0400
commiteb54a856a298aff8b2cdadf87247a33a74921c49 (patch)
treecfd297e78927fe247341d3eafdb6c71e97b59058 /src/or/confparse.h
parent90e8d1f58fb77eb15c59c1bd846aabe1555b64f2 (diff)
downloadtor-eb54a856a298aff8b2cdadf87247a33a74921c49.tar.gz
tor-eb54a856a298aff8b2cdadf87247a33a74921c49.zip
Add test to make sure all confparse variables are well-typed
New approach, suggested by Taylor: During testing builds, we initialize a union member of an appropriate pointer type with the address of the member field we're trying to test, so we can make sure that the compiler doesn't warn. My earlier approach invoked undefined behavior.
Diffstat (limited to 'src/or/confparse.h')
-rw-r--r--src/or/confparse.h72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/or/confparse.h b/src/or/confparse.h
index 9eb46fab03..618fa70f2d 100644
--- a/src/or/confparse.h
+++ b/src/or/confparse.h
@@ -40,6 +40,36 @@ typedef enum config_type_t {
CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
} config_type_t;
+#ifdef TOR_UNIT_TESTS
+/**
+ * Union used when building in test mode typechecking the members of a type
+ * used with confparse.c. See CONF_CHECK_VAR_TYPE for a description of how
+ * it is used. */
+typedef union {
+ char **STRING;
+ char **FILENAME;
+ int *UINT; /* yes, really: Even though the confparse type is called
+ * "UINT", it still uses the C int type -- it just enforces that
+ * the values are in range [0,INT_MAX].
+ */
+ int *INT;
+ int *PORT;
+ int *INTERVAL;
+ int *MSEC_INTERVAL;
+ uint64_t *MEMUNIT;
+ double *DOUBLE;
+ int *BOOL;
+ int *AUTOBOOL;
+ time_t *ISOTIME;
+ smartlist_t **CSV;
+ smartlist_t **CSV_INTERVAL;
+ config_line_t **LINELIST;
+ config_line_t **LINELIST_S;
+ config_line_t **LINELIST_V;
+ routerset_t **ROUTERSET;
+} confparse_dummy_values_t;
+#endif
+
/** An abbreviation for a configuration option allowed on the command line. */
typedef struct config_abbrev_t {
const char *abbreviated;
@@ -64,8 +94,50 @@ typedef struct config_var_t {
* value. */
off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
const char *initvalue; /**< String (or null) describing initial value. */
+
+#ifdef TOR_UNIT_TESTS
+ /** Used for compiler-magic to typecheck the corresponding field in the
+ * corresponding struct. Only used in unit test mode, at compile-time. */
+ confparse_dummy_values_t var_ptr_dummy;
+#endif
} config_var_t;
+/* Macros to define extra members inside config_var_t fields, and at the
+ * end of a list of them.
+ */
+#ifdef TOR_UNIT_TESTS
+/* This is a somewhat magic type-checking macro for users of confparse.c.
+ * It initializes a union member "confparse_dummy_values_t.conftype" with
+ * the address of a static member "tp_dummy.member". This
+ * will give a compiler warning unless the member field is of the correct
+ * type.
+ *
+ * (This warning is mandatory, because a type mismatch here violates the type
+ * compatibility constraint for simple assignment, and requires a diagnostic,
+ * according to the C spec.)
+ *
+ * For example, suppose you say:
+ * "CONF_CHECK_VAR_TYPE(or_options_t, STRING, Address)".
+ * Then this macro will evaluate to:
+ * { .STRING = &or_options_t_dummy.Address }
+ * And since confparse_dummy_values_t.STRING has type "char **", that
+ * expression will create a warning unless or_options_t.Address also
+ * has type "char *".
+ */
+#define CONF_CHECK_VAR_TYPE(tp, conftype, member) \
+ { . conftype = &tp ## _dummy . member }
+#define CONF_TEST_MEMBERS(tp, conftype, member) \
+ , CONF_CHECK_VAR_TYPE(tp, conftype, member)
+#define END_OF_CONFIG_VARS \
+ { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, { .INT=NULL } }
+#define DUMMY_TYPECHECK_INSTANCE(tp) \
+ static tp tp ## _dummy
+#else
+#define CONF_TEST_MEMBERS(tp, conftype, member)
+#define END_OF_CONFIG_VARS { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
+#define DUMMY_TYPECHECK_INSTANCE(tp)
+#endif
+
/** Type of a callback to validate whether a given configuration is
* well-formed and consistent. See options_trial_assign() for documentation
* of arguments. */