Commit 8a597d63 authored by Paul E. McKenney's avatar Paul E. McKenney

doc: No longer allowed to use rcu_dereference on non-pointers

There are too many ways for the compiler to optimize (that is, break)
dependencies carried via integer values, so it is now permissible to
carry dependencies only via pointers.  This commit catches up some of
the documentation on this point.
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent 764f8079
...@@ -25,35 +25,35 @@ o You must use one of the rcu_dereference() family of primitives ...@@ -25,35 +25,35 @@ o You must use one of the rcu_dereference() family of primitives
for an example where the compiler can in fact deduce the exact for an example where the compiler can in fact deduce the exact
value of the pointer, and thus cause misordering. value of the pointer, and thus cause misordering.
o You are only permitted to use rcu_dereference on pointer values.
The compiler simply knows too much about integral values to
trust it to carry dependencies through integer operations.
There are a very few exceptions, namely that you can temporarily
cast the pointer to uintptr_t in order to:
o Set bits and clear bits down in the must-be-zero low-order
bits of that pointer. This clearly means that the pointer
must have alignment constraints, for example, this does
-not- work in general for char* pointers.
o XOR bits to translate pointers, as is done in some
classic buddy-allocator algorithms.
It is important to cast the value back to pointer before
doing much of anything else with it.
o Avoid cancellation when using the "+" and "-" infix arithmetic o Avoid cancellation when using the "+" and "-" infix arithmetic
operators. For example, for a given variable "x", avoid operators. For example, for a given variable "x", avoid
"(x-x)". There are similar arithmetic pitfalls from other "(x-(uintptr_t)x)" for char* pointers. The compiler is within its
arithmetic operators, such as "(x*0)", "(x/(x+1))" or "(x%1)". rights to substitute zero for this sort of expression, so that
The compiler is within its rights to substitute zero for all of subsequent accesses no longer depend on the rcu_dereference(),
these expressions, so that subsequent accesses no longer depend again possibly resulting in bugs due to misordering.
on the rcu_dereference(), again possibly resulting in bugs due
to misordering.
Of course, if "p" is a pointer from rcu_dereference(), and "a" Of course, if "p" is a pointer from rcu_dereference(), and "a"
and "b" are integers that happen to be equal, the expression and "b" are integers that happen to be equal, the expression
"p+a-b" is safe because its value still necessarily depends on "p+a-b" is safe because its value still necessarily depends on
the rcu_dereference(), thus maintaining proper ordering. the rcu_dereference(), thus maintaining proper ordering.
o Avoid all-zero operands to the bitwise "&" operator, and
similarly avoid all-ones operands to the bitwise "|" operator.
If the compiler is able to deduce the value of such operands,
it is within its rights to substitute the corresponding constant
for the bitwise operation. Once again, this causes subsequent
accesses to no longer depend on the rcu_dereference(), causing
bugs due to misordering.
Please note that single-bit operands to bitwise "&" can also
be dangerous. At this point, the compiler knows that the
resulting value can only take on one of two possible values.
Therefore, a very small amount of additional information will
allow the compiler to deduce the exact value, which again can
result in misordering.
o If you are using RCU to protect JITed functions, so that the o If you are using RCU to protect JITed functions, so that the
"()" function-invocation operator is applied to a value obtained "()" function-invocation operator is applied to a value obtained
(directly or indirectly) from rcu_dereference(), you may need to (directly or indirectly) from rcu_dereference(), you may need to
...@@ -61,25 +61,6 @@ o If you are using RCU to protect JITed functions, so that the ...@@ -61,25 +61,6 @@ o If you are using RCU to protect JITed functions, so that the
This issue arises on some systems when a newly JITed function is This issue arises on some systems when a newly JITed function is
using the same memory that was used by an earlier JITed function. using the same memory that was used by an earlier JITed function.
o Do not use the results from the boolean "&&" and "||" when
dereferencing. For example, the following (rather improbable)
code is buggy:
int *p;
int *q;
...
p = rcu_dereference(gp)
q = &global_q;
q += p != &oom_p1 && p != &oom_p2;
r1 = *q; /* BUGGY!!! */
The reason this is buggy is that "&&" and "||" are often compiled
using branches. While weak-memory machines such as ARM or PowerPC
do order stores after such branches, they can speculate loads,
which can result in misordering bugs.
o Do not use the results from relational operators ("==", "!=", o Do not use the results from relational operators ("==", "!=",
">", ">=", "<", or "<=") when dereferencing. For example, ">", ">=", "<", or "<=") when dereferencing. For example,
the following (quite strange) code is buggy: the following (quite strange) code is buggy:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment