[Mesa-dev] [PATCH v2] glsls: Modify exec_list to avoid strict-aliasing violations
davmac at davmac.org
Fri Jun 26 08:32:06 PDT 2015
On 26/06/15 15:29, Erik Faye-Lund wrote:
> On Fri, Jun 26, 2015 at 4:16 PM, Davin McCall <davmac at davmac.org> wrote:
>> On 26/06/15 14:53, Erik Faye-Lund wrote:
>>> On Fri, Jun 26, 2015 at 3:05 PM, Davin McCall <davmac at davmac.org> wrote:
>>> It is. In fact, it's not even possible to violate strict-aliasing
>>> without doing at least two operations. You cannot validate operations
>>> in a vacuum, because that's not how strict-aliasing is defined.
>> Any pointer dereference can violate strict aliasing - that's one operation.
>> If you mean that it's first necessary to construct a pointer value in such a
>> way that de-referencing it will be an aliasing violation, then yes, I agree
>> with this statement.
> Yes, I mean exactly the latter. You cannot look at one operation in
> isolation, you need to look at the whole program.
>>>> As I have pointed out, with your reading,
>>>> pretty much any pointer cast constitutes an aliasing violation.
>>> No, only those violating the strict aliasing rules I posted before.
>> ... which would only allow changing const/volatile qualifiers, not the
>> pointed-to type.
> You can change the pointed to type in terms of signedness, you can
> cast it to a compatible type, you can cast a void-pointer or
> char-pointer to any type. But you need to make sure you don't violate
> the strict-aliasing rules in some other way while doing the latter.
A cast by itself simply can't cause an aliasing violation, because it
doesn't "access the stored value of an object". The aliasing violation
has to happen either before or after the cast.
> Aliasing *is* hard. But let's not go shopping for that reason.
Agreed, though maybe this is getting to the point where we should take
>> Your reading also disallows casting an 'int' variable to type 'long',
>> because that isn't on the list.
>>>> The strict aliasing rules specify what kind of reference you can use to
>>>> access an object of a particular type. They say nothing about how that
>>>> reference is obtained.
>>> Which means that it applies regardless of how you obtain it.
>>> "If a program attempts to access the stored value of an object through
>>> a glvalue of other than one of the following types the behavior is
>>> It says "if a *program* attempts", not "if a *statement* attempts" or
>>> "if an *opreation* attempts". This is a whole-program deal, not
>>> limited to one operation in isolation.
>> The key part of the wording is "through a glvalue":
>> "If a program attempts to access the stored value of an object *through
>> a glvalue* of other than one of the following types ..."
> This is exactly what makes this invalid AFAICT, see below.
>> Going back to the original example:
>> return ((const struct exec_node **)n)
>> The glvalue used to access the object in n is n itself. (I do not think that
>> '(const struct exec_node **)n' is even a glvalue).
> Bur 'n' *is* an lvalue, which also makes it an glvalue (for reference,
> a glvalue is a "generalized lvalue", which means that it's either an
> lvalue or an xvalue).
'n' is an lvalue, yes. Its type is 'struct exec node *' (disregarding
const for now). So when the object that is in 'n' is accessed, it is
accessed via an appropriate type. The cast does not itself cause an
access and the cast expression as a whole is not an lvalue.
The fact that n is an lvalue does not mean that it can appear anywhere
on the left-hand-side of an assignment expression; the entire
left-hand-side expression must be an lvalue. So when you then say:
> You can write stuff like:
> "((const struct exec_node **)n) = foo;"
> ...so it can appear on the left-hand side of an assignment, which
> makes it an lvalue.
... it is not quite correct. The fact that you could put n itself on the
left-hand side of an assignment (eg "n = NULL") makes it an lvalue, not
the fact that it appears *within* a larger expression that is on the
left-hand side of an assignment.
In fact, the whole of '((const struct exec_node **)n)' is an lvalue.
However, '(const struct exec_node **)n' is not an lvalue.
I do believe you have some sort of misconception, and I'm trying hard to
understand the nature of this misconception. Let's start with some stuff
that I hope we can agree on (ignore the 'const' for now as it doesn't
make much difference, unless you disagree?). Assume that the type of the
variable 'n' is 'struct exec_node *'.
1. The expression '((struct exec_node **)n) = foo' accesses two
objects - one is that represented by the variable 'n', and another that
is pointed-to by the pointer value in 'n'.
2. In (1), the first access is a read, the other is due to the
3. The object represented by the variable 'n' is not modified by the
expression (unless 'n' has been made to point to itself).
4. The type of the 'n' object is 'struct exec_node *'
5. The type of the sub-expression 'n' is also 'struct exec_node *'.
6. The type of the sub-expression '(struct exec_node **)n' is 'struct
7. The type of the whole expression, '((struct exec_node **)n) =
foo', is 'struct exec_node *'.
I think you would say the following (though I'd disagree):
8. The expression '((struct exec_node **)n) = foo' necessarily causes
an aliasing violation, assuming it doesn't cause undefined behavior for
any other reason (i.e. assuming n is not null and is a valid pointer etc).
9. The statement 'return ((struct exec_node **)n);' necessarily
causes an aliasing violation, assuming it doesn't cause undefined
behavior for any other reason.
10. The reason that (6) and (7) cause an aliasing violation is
essentially the same.
Now if you do indeed believe (6) is true, the difficulty I'm having is
understanding why. So, some questions:
Do you also believe the following would violate strict aliasing (and if
so, on which line)?
struct exec_node ** m = (struct exec_node *) n;
How about this (and on which line)?
struct exec_node ** m = (struct exec_node *) n;
n = NULL;
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the mesa-dev