Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Is the aliasing rule symmetric?

Reply
Thread Tools

Is the aliasing rule symmetric?

 
 
Joshua Maurice
Guest
Posts: n/a
 
      01-21-2011
On Jan 21, 2:23*pm, (E-Mail Removed) wrote:
> In comp.std.c "Johannes Schaub (litb)" <(E-Mail Removed)> wrote:
>
>
>
> > The above changes two objects. The first has type int, and the second has
> > type int[1]. The change of a int[1] by an lvalue of type int is not covered
> > anywhere at 3.10 p15 in C++. It's not covered by the C rules either, it
> > seems.

>
> > Same situation with structs:

>
> > * * struct A { int a; };
> > * * A a;
> > * * int *p = &a.a;
> > * * *p = 0;

>
> > This changes the stored value of an A object by an lvalue of type int. Where
> > is this covered?

>
> I can't speak for C++, but those cases are both covered in C by the next
> to last rule in 6.5p7 ("an aggregate or union type that includes one of
> the aforementioned types...").


I can't speak to the exact standardeze offhand, but accessing an
object through an appropriately created lvalue referring to a sub-
object is perfectly sensible behavior. "*p" is an appropriately
obtained lvalue which refers to a sub-object of the complete object,
and it's perfectly fine to access the complete object through that
lvalue to sub-object.

By appropriately obtained, I mean that it actually "points to" the sub-
object. Ex:

struct Foo { int a; int b; };
int main()
{
Foo f;
int* x = reinterpret_cast<int*>(&f) + 1;
*x = 1;
return f.b;
}

The above is definitely not portable, and has undefined behavior on at
least some platforms. There's no guarantee that "*x" actually refers
to the sub-object "f.b". You need to obtain it through "appropriate"
means, such as:

struct Foo { int a; int b; };
int main()
{
Foo f;
int* x = & f.b;
*x = 1;
return f.b;
}
 
Reply With Quote
 
 
 
 
Johannes Schaub (litb)
Guest
Posts: n/a
 
      01-21-2011
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:

> In comp.std.c "Johannes Schaub (litb)" <(E-Mail Removed)> wrote:
>>
>> The above changes two objects. The first has type int, and the second has
>> type int[1]. The change of a int[1] by an lvalue of type int is not
>> covered anywhere at 3.10 p15 in C++. It's not covered by the C rules
>> either, it seems.
>>
>> Same situation with structs:
>>
>> struct A { int a; };
>> A a;
>> int *p = &a.a;
>> *p = 0;
>>
>> This changes the stored value of an A object by an lvalue of type int.
>> Where is this covered?

>
> I can't speak for C++, but those cases are both covered in C by the next
> to last rule in 6.5p7 ("an aggregate or union type that includes one of
> the aforementioned types...").


Well, that's the exact other way around. I'm using an int lvalue to access
the value of an object whose effective type is A. But that rule only grants
me to use an lvalue of type A to change the stored value of the member
object whose effective type is int.

Am I missing something?

 
Reply With Quote
 
 
 
 
James Kuyper
Guest
Posts: n/a
 
      01-22-2011
On 01/21/2011 05:30 PM, Ben Bacarisse wrote:
> Dag-Erling Smørgrav<(E-Mail Removed)> writes:
>
>> Ben Bacarisse<(E-Mail Removed)> writes:
>>> "Johannes Schaub (litb)"<(E-Mail Removed)> writes:
>>>> I mean to ask: If aliasing of an A object by an lvalue of type B is
>>>> OK, is aliasing of a B object by an lvalue of type A OK?
>>> No, not as far as I can see.

>>
>> The correct answer is "it depends". The OP used an example where B is
>> char and A is something larger, which is a special case that works in
>> one direction but not the other, but if e.g. A and B are struct types
>> with a common prefix, the answer is yes. A good real-world example is
>> the various flavors of struct sockaddr in the BSD socket API.

>
> Maybe there is C/C++ difference here but in C accessing a struct A as
> if it were a struct B is undefined[1].

....
> [1] There is a special clause in C about structs that share an initial
> segment when both are members of the same union, but that is not what
> you are talking about.


I think that this is precisely what he was was referring to as a "common
prefix".

--
James Kuyper
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      01-22-2011
On 01/21/2011 06:48 PM, Johannes Schaub (litb) wrote:
> (E-Mail Removed) wrote:
>
>> In comp.std.c "Johannes Schaub (litb)"<(E-Mail Removed)> wrote:
>>>
>>> The above changes two objects. The first has type int, and the second has
>>> type int[1]. The change of a int[1] by an lvalue of type int is not
>>> covered anywhere at 3.10 p15 in C++. It's not covered by the C rules
>>> either, it seems.
>>>
>>> Same situation with structs:
>>>
>>> struct A { int a; };
>>> A a;
>>> int *p =&a.a;
>>> *p = 0;
>>>
>>> This changes the stored value of an A object by an lvalue of type int.
>>> Where is this covered?

>>
>> I can't speak for C++, but those cases are both covered in C by the next
>> to last rule in 6.5p7 ("an aggregate or union type that includes one of
>> the aforementioned types...").

>
> Well, that's the exact other way around. I'm using an int lvalue to access
> the value of an object whose effective type is A. But that rule only grants
> me to use an lvalue of type A to change the stored value of the member
> object whose effective type is int.
>
> Am I missing something?


No - the reverse is not allowed: trying to access an object of type int
using an lvalue of type struct A has undefined behavior. Consider that
struct A might be padded to an alignment larger than sizeof(int), and
consider that many of the operations permitted on an lvalue of struct
type can access bytes that are part of that struct, but not part of the
'a' member.

It's unlikely to be true in this case, but it would be more likely if
'a' were a smaller non-character type, such as a 16-bit short, on a
machine with a large word size, say 64-bits. A compiler for such a
machine might pad a struct 'A' to 64 bits. Then, when writing the value
of the a member of a struct 'A', it might write the entire 64 bits,
confident that the extra 48 bits would end up in memory reserved for the
struct. That will cause problems if your lvalue of type struct A
actually refers to memory containing a short that was an element in an
array of shorts. In that case, those other 48 bits would contain other
elements of that array.

You can prove the existence of a similar aliasing problem involving
arrays and their elements, by simply exchanging the roles of the array
type and the struct type in the above argument.

--
James Kuyper
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      01-22-2011
On 01/21/2011 06:36 PM, Joshua Maurice wrote:
....
> No. Don't think about it as an aliasing rule. Think about it as a rule
> which restricts the types of lvalues with which you can legally access
> objects.


What distinction is there between an aliasing rule and that description?
That description seems, to me, to be a fairly good definition of what
"aliasing rule" means, at least in the context of C or C++.

> You can always access an object through a char or unsigned char
> lvalue. (Or maybe it's only for POD types - there's no consensus. I
> would only use char and unsigned char to access POD objects.)


I don't have a copy of the current C++ standard, nor of the latest draft
of the next standard - the closest that I have is n3035.pdf. In 3.10p15,
it makes the same exception for access through an lvalue of char and
unsigned char type that C does, and that exception is not tied to the
POD-ness of the dynamic type.

--
James Kuyper
 
Reply With Quote
 
Johannes Schaub (litb)
Guest
Posts: n/a
 
      01-22-2011
James Kuyper wrote:

> On 01/21/2011 06:48 PM, Johannes Schaub (litb) wrote:
>> (E-Mail Removed) wrote:
>>
>>> In comp.std.c "Johannes Schaub (litb)"<(E-Mail Removed)> wrote:
>>>>
>>>> The above changes two objects. The first has type int, and the second
>>>> has type int[1]. The change of a int[1] by an lvalue of type int is not
>>>> covered anywhere at 3.10 p15 in C++. It's not covered by the C rules
>>>> either, it seems.
>>>>
>>>> Same situation with structs:
>>>>
>>>> struct A { int a; };
>>>> A a;
>>>> int *p =&a.a;
>>>> *p = 0;
>>>>
>>>> This changes the stored value of an A object by an lvalue of type int.
>>>> Where is this covered?
>>>
>>> I can't speak for C++, but those cases are both covered in C by the next
>>> to last rule in 6.5p7 ("an aggregate or union type that includes one of
>>> the aforementioned types...").

>>
>> Well, that's the exact other way around. I'm using an int lvalue to
>> access the value of an object whose effective type is A. But that rule
>> only grants me to use an lvalue of type A to change the stored value of
>> the member object whose effective type is int.
>>
>> Am I missing something?

>
> No - the reverse is not allowed: trying to access an object of type int
> using an lvalue of type struct A has undefined behavior.


That's not true from an aliasing point of view. 3.10/15 explicitly allows
this:

an aggregate or union type that includes one of the aforementioned
types among its elements or non-static data members

> Consider that
> struct A might be padded to an alignment larger than sizeof(int), and
> consider that many of the operations permitted on an lvalue of struct
> type can access bytes that are part of that struct, but not part of the
> 'a' member.
>


We would then violate alignment requirements. This is a different thing from
aliasing requirement though.

 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      01-22-2011
On 2011-01-22, James Kuyper <(E-Mail Removed)> wrote:
> On 01/21/2011 06:36 PM, Joshua Maurice wrote:
> ...
>> No. Don't think about it as an aliasing rule. Think about it as a rule
>> which restricts the types of lvalues with which you can legally access
>> objects.


> What distinction is there between an aliasing rule and that description?
> That description seems, to me, to be a fairly good definition of what
> "aliasing rule" means, at least in the context of C or C++.


return foo(int *i1, int *i2) {
*i1 = 1;
*i2 = 2;
return *i1;
}

The reason this might return either 1 or 2 is aliasing, but has nothing
to do with the types with which you can legally access objects.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / (E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.
 
Reply With Quote
 
Joshua Maurice
Guest
Posts: n/a
 
      01-22-2011
On Jan 22, 11:36*am, Seebs <(E-Mail Removed)> wrote:
> On 2011-01-22, James Kuyper <(E-Mail Removed)> wrote:
>
> > On 01/21/2011 06:36 PM, Joshua Maurice wrote:
> > ...
> >> No. Don't think about it as an aliasing rule. Think about it as a rule
> >> which restricts the types of lvalues with which you can legally access
> >> objects.

> > What distinction is there between an aliasing rule and that description?
> > That description seems, to me, to be a fairly good definition of what
> > "aliasing rule" means, at least in the context of C or C++.

>
> * * * * return foo(int *i1, int *i2) {
> * * * * * * * * *i1 = 1;
> * * * * * * * * *i2 = 2;
> * * * * * * * * return *i1;
> * * * * }
>
> The reason this might return either 1 or 2 is aliasing, but has nothing
> to do with the types with which you can legally access objects.
>
> -s
> --
> Copyright 2010, all wrongs reversed. *Peter Seebach / (E-Mail Removed)://www.seebs.net/log/<-- lawsuits, religion, and funny pictureshttp://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
> I am not speaking for my employer, although they do rent some of my opinions.


Apparently it was cross-posted, and I didn't notice, and someone
replied without the cross posting, and I definitely didn't notice.

Seebs is right that
int foo(int *i1, int *i2) {
*i1 = 1;
*i2 = 2;
return *i1;
}
If i1 and i2 alias, then it returns 2. If they don't alias, then it
returns 1. This function doesn't have a violation of the "strict
aliasing rules", which would be better called "effective type access
rules".

Let's consider this function though:
int foo(int* x, short* y)
{
*x = 1;
*y = 2;
return 1;
}
int bar(int* x, short* y)
{
*x = 1;
*y = 2;
return *x;
}
Let's consider functions foo and bar. Let's suppose that x and y alias
in both. For function foo, there is no undefined behavior even though
both alias (at least according to what appears to be the prominent
interpretation of these rules). For function bar, if they alias, then
we have undefined behavior. Both have aliasing of short* and int*, but
only one has undefined behavior. It has undefined behavior because
there is a read of a short object through an int lvalue in function
bar.

Obviously aliasing is a required component of this analysis, but the
undefined behavior results from using an lvlaue to access an object.
You can use a char lvalue to access an int object, but you cannot use
an int lvalue to access a char object (or char array).
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-23-2011
James Kuyper <(E-Mail Removed)> writes:

> On 01/21/2011 05:30 PM, Ben Bacarisse wrote:
>> Dag-Erling Smørgrav<(E-Mail Removed)> writes:
>>
>>> Ben Bacarisse<(E-Mail Removed)> writes:
>>>> "Johannes Schaub (litb)"<(E-Mail Removed)> writes:
>>>>> I mean to ask: If aliasing of an A object by an lvalue of type B is
>>>>> OK, is aliasing of a B object by an lvalue of type A OK?
>>>> No, not as far as I can see.
>>>
>>> The correct answer is "it depends". The OP used an example where B is
>>> char and A is something larger, which is a special case that works in
>>> one direction but not the other, but if e.g. A and B are struct types
>>> with a common prefix, the answer is yes. A good real-world example is
>>> the various flavors of struct sockaddr in the BSD socket API.

>>
>> Maybe there is C/C++ difference here but in C accessing a struct A as
>> if it were a struct B is undefined[1].

> ...
>> [1] There is a special clause in C about structs that share an initial
>> segment when both are members of the same union, but that is not what
>> you are talking about.

>
> I think that this is precisely what he was was referring to as a
> "common prefix".


I don't see how it can be. For one thing, the various flavors of
struct sockaddr are not in a union object (at least they were not used
in that way the last time I used the BSD API).

But more importantly, the special exception is not an exception to the
effective type access rules. It is always possible (from the point of
view of these rules) to access a member of a union that is not the one
last stored -- the bits are simply reinterpreted (possibly as a value of
a different type. That is as true for structures that don't share a
common prefix as it is for ones that do (and it's true for non-structure
types as well). What 6.5.2.3 p5 does is ensure that there won't be any
surprises about what data you actually get when there is a common prefix.

If the exception given in 6.5.2.3 p5 were not there, the access itself
to these common prefix elements would not suddenly become undefined --
the only difference would be that you would not be able to rely on
getting the data you expect.

--
Ben.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      01-24-2011
On Jan 22, 12:08 pm, James Kuyper <(E-Mail Removed)> wrote:
> On 01/21/2011 06:36 PM, Joshua Maurice wrote:
> ...


> > No. Don't think about it as an aliasing rule. Think about it as a rule
> > which restricts the types of lvalues with which you can legally access
> > objects.


> What distinction is there between an aliasing rule and that description?
> That description seems, to me, to be a fairly good definition of what
> "aliasing rule" means, at least in the context of C or C++.


> > You can always access an object through a char or unsigned char
> > lvalue. (Or maybe it's only for POD types - there's no consensus. I
> > would only use char and unsigned char to access POD objects.)


> I don't have a copy of the current C++ standard, nor of the latest draft
> of the next standard - the closest that I have is n3035.pdf. In 3.10p15,
> it makes the same exception for access through an lvalue of char and
> unsigned char type that C does, and that exception is not tied to the
> POD-ness of the dynamic type.


The C++ standard makes the exception allowing access through
a char or unsigned char type in the case where "a program
attempts access the stored value of an object". I'm not sure of
the exact intent, but accessing the stored value means a read
access. The standard doesn't seem to say anything about
modifying, except for the case where the access is to
a nonmodifiable lvalue. I would hope that the intent would be
more or less:

float f = 3.14159;
unsigned char* pc = reinterpret_cast<unsigned char*>(&f);
printf("%u\n", *pc); // Legal.
*pc = 0xFF; // Legal? Or UB?
std::cout << f << std::endl; // UB (maybe a trapping NaN)

There is (or should be) a clear exception, however, for memcpy
like operations: the following must be legal:

float f = 3.14159;
unsigned char buff[sizeof(float)];
memcpy(buff, &f, sizeof(float));
float other;
memcpy(&other, buff, sizeof(float));
printf("%.5f\n", other); // Must output 3.14159

This is in §3.9/3 in the C++ standard, and only for PODs in
C++. In this case, I'm fairly certain that the intent is for
C and C++ to be compatible in this regard, at least for PODs.

At any rate, the above more or less corresponds to what actually
happens on existing hardware. (To have similar problems with
int, you need some fairly exotic hardware; I think a Univac MPS
might fill the bill.)

--
James Kanze
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Is the aliasing rule symmetric? Johannes Schaub (litb) C++ 68 02-06-2011 09:33 PM
Is the aliasing rule symmetric? Johannes Schaub (litb) C++ 2 01-21-2011 11:30 PM
how to add validation rule for url in the validation-rule.xml ,I added some thing like this but......... shailajabtech@gmail.com Java 0 10-12-2006 08:36 AM
Anti-aliasing GIF Images Kevin Bertman Java 4 11-29-2004 05:46 AM
LCD anti-aliasing in Java Tim Tyler Java 2 09-05-2003 09:01 AM



Advertisments