Fix: change method used by _rcu_dereference to strip type constness
authorSimon Marchi <simon.marchi@efficios.com>
Wed, 17 Aug 2022 15:24:25 +0000 (11:24 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 17 Aug 2022 17:50:02 +0000 (13:50 -0400)
Commit 1e41ec3b07e4 ("Make temporary variable in _rcu_dereference
non-const") used the trick to add 0 to the pointer passed as a parameter
to the macro to get rid of its constness, should it be const (with the
end goal of avoiding compiler warnings).  This is problematic (as shown
in [1]) if it is a pointer to an opaque type though, as the compiler
cannot perform pointer arithmetic on such a pointer (even though it
wouldn't really need to here, as we add 0).

Change it to use another trick to strip away the constness, that
shouldn't hit this problem.  It was found in the same stackoverflow post
as the original trick [2].  It consists of using a statement expression
like so:

    __typeof__(({ const int foo; foo; }))

The statement expression yields a value of type `int`.  Statement
expressions are extensions to the C language, but we already use them
here.

The test_build* binaries now need to be linked against the urcu library,
otherwise they would be missing the rcu_dereference_sym symbol.

[1] https://lists.lttng.org/pipermail/lttng-dev/2022-August/030247.html
[2] https://stackoverflow.com/a/54016713

Change-Id: Ic73590ef4beaa1832161aa05a6df37e467f85116
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
include/urcu/static/pointer.h
tests/unit/Makefile.am
tests/unit/test_build.c

index 465a6101bcb12b5708ccfb90334b00969bf6b0c3..c276e68ef770c13c6d6b0c1cf79b9bd055ae4ee0 100644 (file)
@@ -93,12 +93,15 @@ extern "C" {
 /*
  * If p is const (the pointer itself, not what it points to), using
  * __typeof__(p) would declare a const variable, leading to
- * -Wincompatible-pointer-types errors.  Using `+ 0` makes it an rvalue and
- * gets rid of the const-ness.
+ * -Wincompatible-pointer-types errors.  Using the statement expression
+ * makes it an rvalue and gets rid of the const-ness.
  */
 #ifdef __URCU_DEREFERENCE_USE_ATOMIC_CONSUME
 # define _rcu_dereference(p) __extension__ ({                                          \
-                               __typeof__(p + 0) _________p1;                          \
+                               __typeof__(__extension__ ({                             \
+                                       __typeof__(p) _________p0 = { 0 };              \
+                                       _________p0;                                    \
+                               })) _________p1;                                        \
                                __atomic_load(&(p), &_________p1, __ATOMIC_CONSUME);    \
                                (_________p1);                                          \
                        })
index 233fdbd2328de6cb4452b051169ce5c02bf0a49d..29f61112ff50ae596f1a1dc743a4647f5ed15cbe 100644 (file)
@@ -171,9 +171,9 @@ test_build_cxx_LDADD = $(URCU_COMMON_LIB) $(URCU_CDS_LIB) $(TAP_LIB)
 test_build_dynlink_SOURCES = \
        test_build.c
 test_build_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-test_build_dynlink_LDADD = $(URCU_COMMON_LIB) $(URCU_CDS_LIB) $(TAP_LIB)
+test_build_dynlink_LDADD = $(URCU_LIB) $(URCU_COMMON_LIB) $(URCU_CDS_LIB) $(TAP_LIB)
 
 test_build_dynlink_cxx_SOURCES = \
        test_build_cxx.cpp
 test_build_dynlink_cxx_CXXFLAGS = -DDYNAMIC_LINK_TEST $(AM_CXXFLAGS)
-test_build_dynlink_cxx_LDADD = $(URCU_COMMON_LIB) $(URCU_CDS_LIB) $(TAP_LIB)
+test_build_dynlink_cxx_LDADD = $(URCU_LIB) $(URCU_COMMON_LIB) $(URCU_CDS_LIB) $(TAP_LIB)
index 7f062f19a236d85f99e1a3402dec9ad467b34582..f6b667ce2b3d9ab08dc64704337f9960d923ab68 100644 (file)
@@ -115,6 +115,26 @@ void test_urcu_tls(void)
        URCU_TLS(my_tls_struct).void1 = NULL;
 }
 
+struct an_opaque_struct;
+struct a_clear_struct
+{
+       int x;
+};
+
+static
+void test_build_rcu_dereference(void)
+{
+       static struct an_opaque_struct *opaque = NULL;
+       static struct an_opaque_struct *const opaque_const = NULL;
+       static struct a_clear_struct *clear = NULL;
+       static struct a_clear_struct *const clear_const = NULL;
+
+       rcu_dereference(opaque);
+       rcu_dereference(opaque_const);
+       rcu_dereference(clear);
+       rcu_dereference(clear_const);
+}
+
 int main(void)
 {
        plan_tests(3);
@@ -124,6 +144,7 @@ int main(void)
        test_wfcqueue();
        test_build_cds_list_head_init();
        test_urcu_tls();
+       test_build_rcu_dereference();
 
        return exit_status();
 }
This page took 0.0277 seconds and 4 git commands to generate.