Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #93474 > unrolled thread

Sugestions for runtime polymorphism

Started byThiago Adams <thiago.adams@gmail.com>
First post2016-09-14 12:01 -0700
Last post2016-09-15 11:23 -0700
Articles 20 on this page of 99 — 14 participants

Back to article view | Back to comp.lang.c


Contents

  Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 12:01 -0700
    Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 13:15 -0700
    Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 13:27 -0700
      Re: Sugestions for runtime polymorphism Richard Heathfield <rjh@cpax.org.uk> - 2016-09-14 21:50 +0100
        Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 14:20 -0700
          Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-14 17:32 -0400
            Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-14 16:30 -0700
              Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-14 17:54 -0400
            Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 17:34 -0700
              Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 17:58 -0700
                Re: Sugestions for runtime polymorphism Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-14 19:50 -0700
                  Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 05:03 -0700
                Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-15 10:43 +0100
                  Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 05:29 -0700
                    Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-15 19:49 +0100
                      Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 11:58 -0700
                        Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-15 20:29 +0100
                          Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 14:00 -0700
                            Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-16 07:27 -0700
                              Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-16 16:34 +0100
                                Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-16 09:36 -0700
                                  Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-20 12:59 -0700
                                    Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-20 14:08 -0700
                                      Re: Sugestions for runtime polymorphism Ian Collins <ian-news@hotmail.com> - 2016-09-21 15:53 +1200
                                        Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-21 07:38 -0700
                                          Re: Sugestions for runtime polymorphism Ian Collins <ian-news@hotmail.com> - 2016-09-23 09:12 +1200
                                      Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-21 05:26 -0700
                                        Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-21 05:35 -0700
                                        Re: Sugestions for runtime polymorphism Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-21 06:01 -0700
                                        Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-22 01:44 -0700
                                          Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-22 13:16 +0100
                                            Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-22 08:02 -0700
                                              Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-22 11:44 -0700
                                                Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-22 09:52 -0700
                                                  Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-23 09:49 +0200
                                                    Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-23 07:55 -0700
                                                      Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-24 16:29 +0200
                                                        Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-24 15:56 +0100
                                                          Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-24 17:50 +0200
                                                            Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-24 13:45 -0400
                                                              Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-24 11:26 -0700
                                                                Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 10:38 -0700
                                                            Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-24 21:03 +0100
                                                              Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 12:43 +0200
                                                                Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-25 11:48 -0400
                                                                  Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 18:39 +0200
                                                                    Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-25 13:14 -0400
                                                                      Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-25 13:47 -0700
                                                                        Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 10:39 -0700
                                                                      Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 23:25 +0200
                                                                    Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-25 13:10 -0700
                                                                  Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-25 12:55 -0700
                                                                Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-25 20:38 +0100
                                                                  Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 23:20 +0200
                                                                  Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 07:15 -0700
                                                                    Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-28 21:29 +0200
                                                          Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-24 10:52 -0700
                                                        Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-24 10:33 -0700
                                                          Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 12:46 +0200
                                                      Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-24 13:58 -0700
                                                        Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 04:46 -0700
                                                    Re: Sugestions for runtime polymorphism Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-24 00:07 -0700
                                            Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-23 08:52 -0700
                                              Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-23 09:56 -0700
                                                Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-23 12:00 -0700
                                      Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-22 08:45 -0700
                                        Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-22 09:36 -0700
                                          Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-23 12:06 -0700
                                            Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-23 15:29 -0700
                              Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-29 07:56 -0700
                                Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-30 10:54 -0700
                                  Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-30 11:18 -0700
                                    Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-30 19:26 +0100
                                    Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-30 12:41 -0700
                                      Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-30 21:07 +0100
                                  Re: Sugestions for runtime polymorphism Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-30 23:30 -0700
                                    Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-01 11:35 +0100
                                    Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-10-01 14:44 -0700
          Re: Sugestions for runtime polymorphism Richard Heathfield <rjh@cpax.org.uk> - 2016-09-14 22:56 +0100
            Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-15 13:19 +0200
              Re: Sugestions for runtime polymorphism James Kuyper <jameskuyper@verizon.net> - 2016-09-15 08:07 -0400
                Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-15 14:24 +0200
                  Re: Sugestions for runtime polymorphism Richard Heathfield <rjh@cpax.org.uk> - 2016-09-15 15:34 +0100
              Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 05:10 -0700
            Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-15 09:12 -0700
          Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-14 23:32 +0100
          Re: Sugestions for runtime polymorphism "Chris M. Thomasson" <invalid@invalid.invalid> - 2016-09-14 17:35 -0700
          Re: Sugestions for runtime polymorphism Ian Collins <ian-news@hotmail.com> - 2016-09-15 16:24 +1200
            Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-15 10:31 -0700
      Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-14 22:53 +0100
        Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-14 16:56 -0700
          Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-14 15:58 -0700
            Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-14 18:49 -0700
    Re: Sugestions for runtime polymorphism luser droog <luser.droog@gmail.com> - 2016-09-14 14:17 -0700
      Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 14:25 -0700
        Re: Sugestions for runtime polymorphism luser droog <luser.droog@gmail.com> - 2016-09-14 14:40 -0700
        Re: Sugestions for runtime polymorphism luser droog <luser.droog@gmail.com> - 2016-09-14 14:57 -0700
        Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-14 23:10 +0100
    Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-15 11:23 -0700

Page 3 of 5 — ← Prev page 1 2 [3] 4 5  Next page →


#93987

Fromsupercat@casperkitty.com
Date2016-09-24 11:26 -0700
Message-ID<85ffb276-ff44-44cb-b1c9-0844fe649ed3@googlegroups.com>
In reply to#93985
On Saturday, September 24, 2016 at 12:45:56 PM UTC-5, James R. Kuyper wrote:
> 4p2 says "Undefined behavior is otherwise indicated ... by the omission 
> of any explicit definition of the behavior". But you have to be careful 
> about applying that rule. Nowhere in the standard does it say explicitly 
> what the behavior of the expression 1+1 is if executed on Friday the 
> 13th at 13:13:13. However, it does say "The result of the binary + 
> operator is the sum of the operands.". That applies regardless of what 
> the values of the operands are, and regardless of the time of day. 
> Therefore, there is no "omission of any explicit definition", just 
> because there is no mention of Friday the 13th. The definition of the 
> behavior covers the possibility of time-dependent behavior by failing to 
> mention any time dependence, rendering time-dependent behavior 
> impermissible.

I don't think anything in the Standard would forbid an implementation from
having right-shifts of negative values use sign extension if __DATE__
identifies a Friday the 13th, or zero-fill on other days, if documentation
for the implementation describes that behavior.  The behavior of integer
arithmetic, however, is rigidly specified by the Standard for additions
that don't overflow, along with almost all cases, however.

> That code accesses the object many times using an incompatible type, but 
> whenever it does so, it is writing a new value for the object. Those 
> accesses do not qualify as accessing the "stored value" of the object.
> Every time that code accesses by reading the stored value, the read is 
> preceded by a write to that object through an lvalue of the same type as 
> the read. For an object with no declared type (which is what you create 
> by calling malloc()), the effective type is always the same as the type 
> of the last write to that memory through an lvalue that is not of 
> character type.

Yup.

> <pedantic>
> There is one obscure case which is not covered by the first item on 
> 6.5p7's list. If CHAR_BIT==64, it's possible for T2 to be a character 
> type. As a result, the effective type would only change as a result of 
> writing through lvalues with type T1. In that case, the first item on 
> the list for 6.5p7 doesn't apply when reading through lvalues of type 
> T2. Instead, the sixth item on that list applies: "a character type", 
> since that's what T2 is in that case.
> </pedantic>

Even in that obscure case, behavior would still be defined--if an object
has no declared type, writing it via character-type pointer will unset
any pre-existing Effective Type (since operations that set the ET only
do so until the next time an object is modified) and leave the object
with no effective type (I'm assuming the horrible "copied as an array
of character type" language--whatever that means--isn't applicable here)
and consequently can be read as any type.

[toc] | [prev] | [next] | [standalone]


#94202

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-28 10:38 -0700
Message-ID<kfneg43c4cd.fsf@x-alumni2.alumni.caltech.edu>
In reply to#93987
supercat@casperkitty.com writes:

> [...] if an object
> has no declared type, writing it via character-type pointer will unset
> any pre-existing Effective Type (since operations that set the ET only
> do so until the next time an object is modified) and leave the object
> with no effective type [...]

I believe this is a misreading.  If an object with no declared
type is written through a non-character type, "the type of the
lvalue becomes the effective type of the object for that access
and for subsequent accesses that do not modify the stored value."
There is nothing that says that effective type stops being in
force when a value is stored using a character type, that just
isn't the effective type for the store access.  For reads after
the through-character-type store is done, those are subsequent
to the previous non-character-type store, and so have that type
as their effective type.  The Standard doesn't say anything about
"erasing" an effective type.

[toc] | [prev] | [next] | [standalone]


#93991

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-24 21:03 +0100
Message-ID<87h995f4lm.fsf@bsb.me.uk>
In reply to#93982
David Brown <david.brown@hesbynett.no> writes:

> On 24/09/16 16:56, Ben Bacarisse wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> On 23/09/16 16:55, supercat@casperkitty.com wrote:
<snip>
>>>>       typedef long long T1;
>>>>       typedef int64_t T2;
>>>>       #define T1FMT "%lld"
>>>>       #define T1VALUE 1
>>>>       #define T2VALUE 2
>>>>
>>>>       T1 blah3(void *p1, void *p2)
>>>>       {
>>>>         T1 *t1p, *t1p2;
>>>>         T2 *t2p;
>>>>         T1 temp;
>>>>
>>>>         t1p = p1;
>>>>         t2p = p2;
>>>>         *t1p = T1VALUE;   // Write as T1
>>>>         *t2p = T2VALUE;   // Write as T2
>>>>         temp = *t2p;      // Read as T2
>>>>         t1p2 = (T1*)t2p;  // Visible T2 to T1 pointer conversion
>>>>         *t1p2 = temp;     // Write as T1
>>>>         return *t1p;      // Read as T1
>>>>       }
>>>>
>>>>       T1 test3(void)
>>>>       {
>>>>         void *p = malloc(sizeof (T1) + sizeof (T2));
>>>>         T1 result = blah3(p,p);
>>>>         free(p);
>>>>         return result;
>>>>       }
<snip>
>>> If T1 and T2 are compatible types (as might be the case, such as on
>>> Windows), then the answer will be 2.  If they are incompatible types,
>>> such as on 64-bit Linux, the answer is undefined - you are trying to
>>> access the same object through pointers to two incompatible types.
>>
>> That's not a thing!  There are rules about how you can access objects,
>> but they are much more complex that this summary and I'm not sure where
>> you think the violation occurs.  Can you point to the line and give the
>> rule being broken?
>
> I am thinking of the rules in 6.5, paragraph 7 about how "an object
> shall have its stored value accessed".  It does not explicitly say
> that accessing the same data through pointers to incompatible types is
> undefined

In fact, it explicitly permits it in many ways, but I know you are not
talking about those permissions.  More to the point, when paragraph 6 is
taken into account there are even more ways in which accesses to the
same data through pointers to incompatible types are permitted.

> - but it is implicitly undefined behaviour by virtue of not
> being defined behaviour.

If we ignore the initialisation of the two pointers (surely not at
issue) the code in question has only 9 object accesses, four of which
are simple mentions of a local object.  Which one (or ones) of these 9,
fall foul (possibly by omission, if that is indeed the case) of the
rules in 6.5 p7?  (The second sentence of paragraph 6 matters here too,
of course, to determine what the effective types are at each point in
the code.)

> But I could be wrong - and if this really is incorrect behaviour from
> gcc, then it needs reported and fixed.

And *I* could be wrong, but I've gone though all 9 object accesses and
every one appears to be explicitly permitted by p6 and p7 of section
6.5.

<snip>
>> My gcc (5.2.1 20151010) gives 2 for all -Ox.  Presumably you have a
>> newer version?
>
> I am testing here with <https://gcc.godbolt.org/> for convenience.  It
> is targeting 64-bit Linux, and the result is 1 for -O2 and above, on
> gcc 4.7 onwards.  gcc 4.5 and 4.6 give 2.

Including 5.2?  My system is 64-bit Linux.  (I could not see how to get
that site to show me the output.)

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#94018

FromDavid Brown <david.brown@hesbynett.no>
Date2016-09-25 12:43 +0200
Message-ID<ns89ok$lj2$1@dont-email.me>
In reply to#93991
On 24/09/16 22:03, Ben Bacarisse wrote:
> David Brown <david.brown@hesbynett.no> writes:
<snip>
>> But I could be wrong - and if this really is incorrect behaviour from
>> gcc, then it needs reported and fixed.
>
> And *I* could be wrong, but I've gone though all 9 object accesses and
> every one appears to be explicitly permitted by p6 and p7 of section
> 6.5.
>
> <snip>
>>> My gcc (5.2.1 20151010) gives 2 for all -Ox.  Presumably you have a
>>> newer version?
>>
>> I am testing here with <https://gcc.godbolt.org/> for convenience.  It
>> is targeting 64-bit Linux, and the result is 1 for -O2 and above, on
>> gcc 4.7 onwards.  gcc 4.5 and 4.6 give 2.
>
> Including 5.2?  My system is 64-bit Linux.  (I could not see how to get
> that site to show me the output.)
>
> <snip>
>

My test on gcc.godbolt.org is here:

<https://gcc.godbolt.org/#compilers:!((compiler:g520,options:'-O2+-Wall+-Wextra+-x+c',sourcez:FAAjGIEsDsGMBsCuATApiAPAZwC7JjgHQAWAfKGCFHEmprgE4wDmJ5lVMCK62e8kAEZsKELrV658AexGiQOAJ4AHVGgBmIeNOjMtOvQBUAjAG55S1RpAEAbABYA%2BjhCGATOY7gNMdCYBiALKGIABEAKTw8Mih8t6o6r6uxgBqAIIAMgCqAKIgxgAMBXE%2B0H5u6dl5bkXA8iYggvAAhsQAzAAUAG7SkMggAFTKxgA0ID19g8puAJTyAN7yYA0DOMbKY6vrHkuuboM4bsqeHMkKqAC2x3WnCusgALwgwycch8qPzzu3Wx9PJpVcqZKAB6EEgADqTBw6GaWGSu1WR0%2B7kBOWBYDBkOhsPh7l2MKunyRx1uWIASqhmv04XsCdtPh0TAMZu8MViUpAsEJ4OUFNIzspetAYQwQLAdF1UAxuTpEWtpp9CaSOFioZAYSBaSZdgxUDhEAxoAd1hjVeDKdStXjjPIAL43SgNGG4ToTZBzDiLW7uqafC7NKLSWAdbkAL1Q0k0TOMMxAAGoQOHI9H3DMZq8ncYQHqsIh4C4nk1Wp0NsoM7t1HrUB1y5mwHqDUac6g8wXMw6OAQQAGYN1eh6FrsGrn84Xzq6OhXbsomCL1B1QoZiOhRwWbPDQskgoYxmucNPTo3DcaCmbKPagAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3>

I changed the values of T1VALUE and T2VALUE to 100 and 200, to make it 
easier to spot them in the resulting assembly code.


The details of the standards here is getting beyond me.  When you and 
James both think the answer should be 1, and 2 is not allowed, then I am 
far from confident about 2 being allowable - you are both more better at 
"language lawyering" than me.  But I do know that gcc will do this sort 
of transformation in practice, and in real code - you need to be very 
careful in mixing pointers to different integer types even when you know 
they are the same underlying hardware types.

Maybe it's time to pass this on to the gcc mailing lists, and ask how 
they interpret it?


[toc] | [prev] | [next] | [standalone]


#94031

From"James R. Kuyper" <jameskuyper@verizon.net>
Date2016-09-25 11:48 -0400
Message-ID<c7e2e2a0-678b-292c-08db-0feab65420fe@verizon.net>
In reply to#94018
On 09/25/2016 06:43 AM, David Brown wrote:
...
> My test on gcc.godbolt.org is here:
>
> <https://gcc.godbolt.org/#compilers:!((compiler:g520,options:'-O2+-Wall+-Wextra+-x+c',sourcez:FAAjGIEsDsGMBsCuATApiAPAZwC7JjgHQAWAfKGCFHEmprgE4wDmJ5lVMCK62e8kAEZsKELrV658AexGiQOAJ4AHVGgBmIeNOjMtOvQBUAjAG55S1RpAEAbABYA%2BjhCGATOY7gNMdCYBiALKGIABEAKTw8Mih8t6o6r6uxgBqAIIAMgCqAKIgxgAMBXE%2B0H5u6dl5bkXA8iYggvAAhsQAzAAUAG7SkMggAFTKxgA0ID19g8puAJTyAN7yYA0DOMbKY6vrHkuuboM4bsqeHMkKqAC2x3WnCusgALwgwycch8qPzzu3Wx9PJpVcqZKAB6EEgADqTBw6GaWGSu1WR0%2B7kBOWBYDBkOhsPh7l2MKunyRx1uWIASqhmv04XsCdtPh0TAMZu8MViUpAsEJ4OUFNIzspetAYQwQLAdF1UAxuTpEWtpp9CaSOFioZAYSBaSZdgxUDhEAxoAd1hjVeDKdStXjjPIAL43SgNGG4ToTZBzDiLW7uqafC7NKLSWAdbkAL1Q0k0TOMMxAAGoQOHI9H3DMZq8ncYQHqsIh4C4nk1Wp0NsoM7t1HrUB1y5mwHqDUac6g8wXMw6OAQQAGYN1eh6FrsGrn84Xzq6OhXbsomCL1B1QoZiOhRwWbPDQskgoYxmucNPTo3DcaCmbKPagAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3>
>
> I changed the values of T1VALUE and T2VALUE to 100 and 200, to make it
> easier to spot them in the resulting assembly code.
>
>
> The details of the standards here is getting beyond me.  When you and
> James both think the answer should be 1, and 2 is not allowed, ...

I never said what the answer should be. Ben said gcc gave him 2 for all 
optimization levels. I'm not sure why you think we've claimed the answer 
should be 1.

Here's the original code that I was talking about, in order of execution:

main:
        ... test3();

test3:
        void *p = malloc(sizeof (T1) + sizeof (T2));
/* p now points at a buffer; for convenience I'll refer to that buffer
using 'p' even in contexts where 'p' is not in scope.
*/
        ... blah3(p,p);

blah3:
      T1 blah3(void *p1, void *p2)
      {
/* p1 and p2 are both set equal to p */
        t1p = p1;
        t2p = p2;
/* t1p and t2p both point at the same location as p */
        *t1p = T1VALUE;   // Write as T1
/* The sizeof(T1) bytes starting at p now contain a representation of
T1VALUE as an object of type T1, which is now the effective type of
that memory.
*/
        *t2p = T2VALUE;   // Write as T2
/* The sizeof(T2) bytes starting at p now contain a representation of 
T2VALUE as an object of type T2, which is now the effective type of
that memory.
*/
        temp = *t2p;      // Read as T2
/* Since *t2p has the type T2, which matches the effective type of that
memory, there is no problem reading the value T2VALUE from that
memory, which is then stored in temp.
*/
        t1p2 = (T1*)t2p;  // Visible T2 to T1 pointer conversion
/* I missed this point: conversion from T2* to T1* is allowed, since
this particular pointer is guaranteed to be correctly aligned for
either type. However, technically, the standard says nothing about
where t1p2 actually points. In principle, the only thing that is 
guaranteed about the value of t1p2 is that if you convert it back to 
T2*; the result will compare equal to t2p. For instance, the forward 
conversion could add 1024 bytes to the position, so long as the reverse 
conversion subtracted the same amount.
In practice, on virtually every real world implementation of C, t1p2 
will point at the same location as all of the other object pointers in 
this program, and I believe it was the committee's intent that this be 
true. However, I haven't managed to convince anyone in authority that 
there's any need to change the wording to reflect that intent.
*/
        *t1p2 = temp;     // Write as T1
/* T2VALUE is converted to type T1, and stored in the sizeof(T1) bytes 
starting at p. The effective type of that memory is now T1.
*/
        return *t1p;      // Read as T1
/* *t1p has the type T1, matching the current effective type of that
memory. As a result, there's no problem retrieving T2VALUE from that
memory and returning it as the value of blah3.
*/

test3:
        T1 result = blah3(p,p);
/* result now contains T2value */
        free(p);
        return result;
/* T2VALUE is now returned as the value of test3. */

main:
        T1 result = test3();
/* result now has the value T2VALUE */
        printf("The result is " T1FMT, result);
/* Which is then printed out */

T2VALUE is 2. By what argument would anyone claim that a value of 1 
could be printed out?

> ... then I am
> far from confident about 2 being allowable - you are both more better at
> "language lawyering" than me.  But I do know that gcc will do this sort
> of transformation in practice, and in real code - you need to be very
> careful in mixing pointers to different integer types even when you know
> they are the same underlying hardware types.

At no point does this code do anything which relies upon the assumption 
that long long and int64_t are the same underlying type. It would work 
equally well if T2 were any integer type other than _Bool. It would even 
work if T2 were a floating point type, except for the theoretical 
possibility of floating point roundoff errors, but in practice that 
would never happen with integers smaller than 1.0/FLT_EPSILON.

[toc] | [prev] | [next] | [standalone]


#94035

FromDavid Brown <david.brown@hesbynett.no>
Date2016-09-25 18:39 +0200
Message-ID<ns8ujt$qi8$1@dont-email.me>
In reply to#94031
On 25/09/16 17:48, James R. Kuyper wrote:
> On 09/25/2016 06:43 AM, David Brown wrote:
> ...
>> My test on gcc.godbolt.org is here:
>>
>> <https://gcc.godbolt.org/#compilers:!((compiler:g520,options:'-O2+-Wall+-Wextra+-x+c',sourcez:FAAjGIEsDsGMBsCuATApiAPAZwC7JjgHQAWAfKGCFHEmprgE4wDmJ5lVMCK62e8kAEZsKELrV658AexGiQOAJ4AHVGgBmIeNOjMtOvQBUAjAG55S1RpAEAbABYA%2BjhCGATOY7gNMdCYBiALKGIABEAKTw8Mih8t6o6r6uxgBqAIIAMgCqAKIgxgAMBXE%2B0H5u6dl5bkXA8iYggvAAhsQAzAAUAG7SkMggAFTKxgA0ID19g8puAJTyAN7yYA0DOMbKY6vrHkuuboM4bsqeHMkKqAC2x3WnCusgALwgwycch8qPzzu3Wx9PJpVcqZKAB6EEgADqTBw6GaWGSu1WR0%2B7kBOWBYDBkOhsPh7l2MKunyRx1uWIASqhmv04XsCdtPh0TAMZu8MViUpAsEJ4OUFNIzspetAYQwQLAdF1UAxuTpEWtpp9CaSOFioZAYSBaSZdgxUDhEAxoAd1hjVeDKdStXjjPIAL43SgNGG4ToTZBzDiLW7uqafC7NKLSWAdbkAL1Q0k0TOMMxAAGoQOHI9H3DMZq8ncYQHqsIh4C4nk1Wp0NsoM7t1HrUB1y5mwHqDUac6g8wXMw6OAQQAGYN1eh6FrsGrn84Xzq6OhXbsomCL1B1QoZiOhRwWbPDQskgoYxmucNPTo3DcaCmbKPagAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3>
>>
>>
>> I changed the values of T1VALUE and T2VALUE to 100 and 200, to make it
>> easier to spot them in the resulting assembly code.
>>
>>
>> The details of the standards here is getting beyond me.  When you and
>> James both think the answer should be 1, and 2 is not allowed, ...
>
> I never said what the answer should be. Ben said gcc gave him 2 for all
> optimization levels. I'm not sure why you think we've claimed the answer
> should be 1.


My apologies - I meant to say "think the answer should be /2/, and /1/ 
is not allowed".  That was a rather unhelpful mixup on my part!

I should also have written "I think they think...", since it was my 
interpretation of what you wrote, rather than your exact words.

>
> Here's the original code that I was talking about, in order of execution:
>
> main:
>         ... test3();
>
> test3:
>         void *p = malloc(sizeof (T1) + sizeof (T2));
> /* p now points at a buffer; for convenience I'll refer to that buffer
> using 'p' even in contexts where 'p' is not in scope.
> */
>         ... blah3(p,p);
>
> blah3:
>       T1 blah3(void *p1, void *p2)
>       {
> /* p1 and p2 are both set equal to p */
>         t1p = p1;
>         t2p = p2;
> /* t1p and t2p both point at the same location as p */
>         *t1p = T1VALUE;   // Write as T1
> /* The sizeof(T1) bytes starting at p now contain a representation of
> T1VALUE as an object of type T1, which is now the effective type of
> that memory.
> */
>         *t2p = T2VALUE;   // Write as T2
> /* The sizeof(T2) bytes starting at p now contain a representation of
> T2VALUE as an object of type T2, which is now the effective type of
> that memory.
> */
>         temp = *t2p;      // Read as T2
> /* Since *t2p has the type T2, which matches the effective type of that
> memory, there is no problem reading the value T2VALUE from that
> memory, which is then stored in temp.
> */

OK so far...

>         t1p2 = (T1*)t2p;  // Visible T2 to T1 pointer conversion
> /* I missed this point: conversion from T2* to T1* is allowed, since
> this particular pointer is guaranteed to be correctly aligned for
> either type. However, technically, the standard says nothing about
> where t1p2 actually points. In principle, the only thing that is
> guaranteed about the value of t1p2 is that if you convert it back to
> T2*; the result will compare equal to t2p. For instance, the forward
> conversion could add 1024 bytes to the position, so long as the reverse
> conversion subtracted the same amount.
> In practice, on virtually every real world implementation of C, t1p2
> will point at the same location as all of the other object pointers in
> this program, and I believe it was the committee's intent that this be
> true. However, I haven't managed to convince anyone in authority that
> there's any need to change the wording to reflect that intent.
> */

gcc appears to be optimising on the basis that the only defined 
behaviour for t1p2 is that you can covert it back to a T2* and get the 
same pointer as t2p.  The assembly it generates is (with my comments):

blah3:
         movq    $1, (%rdi)	// Store 1 in *t1p
         movl    $1, %eax	// The return value 1
         movq    $2, (%rsi)	// Store 2 in *t2p
         ret

test3:
         movl    $1, %eax
         ret


>         *t1p2 = temp;     // Write as T1
> /* T2VALUE is converted to type T1, and stored in the sizeof(T1) bytes
> starting at p. The effective type of that memory is now T1.
> */
>         return *t1p;      // Read as T1
> /* *t1p has the type T1, matching the current effective type of that
> memory. As a result, there's no problem retrieving T2VALUE from that
> memory and returning it as the value of blah3.
> */
>
> test3:
>         T1 result = blah3(p,p);
> /* result now contains T2value */
>         free(p);
>         return result;
> /* T2VALUE is now returned as the value of test3. */
>
> main:
>         T1 result = test3();
> /* result now has the value T2VALUE */
>         printf("The result is " T1FMT, result);
> /* Which is then printed out */
>
> T2VALUE is 2. By what argument would anyone claim that a value of 1
> could be printed out?

It is the result gcc gives.

This is either a valid result due to the conversion of pointer types 
mentioned above (and claims about "virtually every real world 
implementation of C" are simply incorrect, because gcc is a pretty major 
exception), or gcc has a bug here.

To be clear, I would be happier if gcc gave 2 here - the same result as 
other compilers on <gcc.godbolt.org>, and the result one would 
reasonably expect.  I would prefer if the C standards said that types 
such as "long", "long long", and "int64_t" were all considered 
"compatible" if they are all the same size (and similarly for "int", 
"long", "int32_t").  Or at least, I would prefer it if gcc had this as 
documented implementation-dependent behaviour.

The question is, is this a bug in gcc?  Or is it just a case of 
optimising from undefined behaviour in a way that might surprise people?

>
>> ... then I am
>> far from confident about 2 being allowable - you are both more better at
>> "language lawyering" than me.  But I do know that gcc will do this sort
>> of transformation in practice, and in real code - you need to be very
>> careful in mixing pointers to different integer types even when you know
>> they are the same underlying hardware types.
>
> At no point does this code do anything which relies upon the assumption
> that long long and int64_t are the same underlying type. It would work
> equally well if T2 were any integer type other than _Bool. It would even
> work if T2 were a floating point type, except for the theoretical
> possibility of floating point roundoff errors, but in practice that
> would never happen with integers smaller than 1.0/FLT_EPSILON.

[toc] | [prev] | [next] | [standalone]


#94038

From"James R. Kuyper" <jameskuyper@verizon.net>
Date2016-09-25 13:14 -0400
Message-ID<a48fe888-76ca-6342-34f3-26952ab98bef@verizon.net>
In reply to#94035
On 09/25/2016 12:39 PM, David Brown wrote:
> On 25/09/16 17:48, James R. Kuyper wrote:
...
>> Here's the original code that I was talking about, in order of execution:
>>
>> main:
>>         ... test3();
>>
>> test3:
>>         void *p = malloc(sizeof (T1) + sizeof (T2));
>> /* p now points at a buffer; for convenience I'll refer to that buffer
>> using 'p' even in contexts where 'p' is not in scope.
>> */
>>         ... blah3(p,p);
>>
>> blah3:
>>       T1 blah3(void *p1, void *p2)
>>       {
>> /* p1 and p2 are both set equal to p */
>>         t1p = p1;
>>         t2p = p2;
>> /* t1p and t2p both point at the same location as p */
>>         *t1p = T1VALUE;   // Write as T1
>> /* The sizeof(T1) bytes starting at p now contain a representation of
>> T1VALUE as an object of type T1, which is now the effective type of
>> that memory.
>> */
>>         *t2p = T2VALUE;   // Write as T2
>> /* The sizeof(T2) bytes starting at p now contain a representation of
>> T2VALUE as an object of type T2, which is now the effective type of
>> that memory.
>> */
>>         temp = *t2p;      // Read as T2
>> /* Since *t2p has the type T2, which matches the effective type of that
>> memory, there is no problem reading the value T2VALUE from that
>> memory, which is then stored in temp.
>> */
>
> OK so far...
>
>>         t1p2 = (T1*)t2p;  // Visible T2 to T1 pointer conversion
>> /* I missed this point: conversion from T2* to T1* is allowed, since
>> this particular pointer is guaranteed to be correctly aligned for
>> either type. However, technically, the standard says nothing about
>> where t1p2 actually points. In principle, the only thing that is
>> guaranteed about the value of t1p2 is that if you convert it back to
>> T2*; the result will compare equal to t2p. For instance, the forward
>> conversion could add 1024 bytes to the position, so long as the reverse
>> conversion subtracted the same amount.
>> In practice, on virtually every real world implementation of C, t1p2
>> will point at the same location as all of the other object pointers in
>> this program, and I believe it was the committee's intent that this be
>> true. However, I haven't managed to convince anyone in authority that
>> there's any need to change the wording to reflect that intent.
>> */
>
> gcc appears to be optimising on the basis that the only defined
> behaviour for t1p2 is that you can covert it back to a T2* and get the
> same pointer as t2p.  The assembly it generates is (with my comments):
>
> blah3:
>          movq    $1, (%rdi)	// Store 1 in *t1p
>          movl    $1, %eax	// The return value 1
>          movq    $2, (%rsi)	// Store 2 in *t2p
>          ret
>
> test3:
>          movl    $1, %eax
>          ret

I doubt that the t1p2 conversion is the justification used by gcc for 
generating this code. That's a purely pedantic issue that bothers only 
me - it's not something real implementations handle in any fashion 
different from the committee's intent.

I've long assumed that the purpose of the anti-aliasing rules was to 
gave implementations considerable freedom to reorder code using pointers 
to different types, if the code consisted of a read from one type and a 
write to a different type, if that pair of types was not connected by 
one of the rules listed in 6.5p7.
However, after analyzing the code above, I realized that the 
implementation's freedom is seriously restricted by the possibility that 
the pointers point at dynamically allocated memory, due to the fact that 
the effective type can change with each write. In fact, I'm wondering if 
the anti-aliasing rules give implementations any freedom at all to 
reorder such code - could I be misunderstanding either 6.5p6 and p7?

The optimization you show above would be permitted if the two pointers 
didn't point at dynamically allocated memory, and I'm wondering if gcc's 
mistake was in failing to consider that possibility.

>>         *t1p2 = temp;     // Write as T1
>> /* T2VALUE is converted to type T1, and stored in the sizeof(T1) bytes
>> starting at p. The effective type of that memory is now T1.
>> */
>>         return *t1p;      // Read as T1

...
>> T2VALUE is 2. By what argument would anyone claim that a value of 1
>> could be printed out?
>
> It is the result gcc gives.

Not on Ben's machine. Have the two of you resolved which of you is using 
the later version of gcc?

> This is either a valid result due to the conversion of pointer types
> mentioned above (and claims about "virtually every real world
> implementation of C" are simply incorrect, because gcc is a pretty major
> exception), or gcc has a bug here.
>
> To be clear, I would be happier if gcc gave 2 here - the same result as
> other compilers on <gcc.godbolt.org>, and the result one would
> reasonably expect.  ...

> ... I would prefer if the C standards said that types
> such as "long", "long long", and "int64_t" were all considered
> "compatible" if they are all the same size (and similarly for "int",
> "long", "int32_t"). ...

The C standard currently allows integer types with the same size and 
same signedness to use different byte orders, and even different bit 
orders (it allows this by the simple expedient of failing to specify 
anything relevant about the byte order or bit order). I believe this 
freedom is intentional, though I'm not sure if any real-world 
implementation takes advantage of this freedom. I would oppose mandating 
that they be compatible.

[toc] | [prev] | [next] | [standalone]


#94048

Fromsupercat@casperkitty.com
Date2016-09-25 13:47 -0700
Message-ID<5e6c367f-b103-4ac7-a40b-abff0c10e8c7@googlegroups.com>
In reply to#94038
On Sunday, September 25, 2016 at 12:14:26 PM UTC-5, James R. Kuyper wrote:
> I've long assumed that the purpose of the anti-aliasing rules was to 
> gave implementations considerable freedom to reorder code using pointers 
> to different types, if the code consisted of a read from one type and a 
> write to a different type, if that pair of types was not connected by 
> one of the rules listed in 6.5p7.

Based upon the C89 rationale, I had assumed that the purpose was to allow
compilers to keep variables in registers when accessing pointers of different
types, and where there was no reason why the compiler should expect aliasing.
The authors of the Standard wanted to make it clear that given something like:

    int x;
    int foo(unsigned *p, unsigned q)
    {
      x=234;
      *p = q;
      return x;
    }

a compiler couldn't use the fact that "x" was signed and "*p" was unsigned
as justification to keep x in a register across the write to "p", but they
also didn't want to mandate that compilers regard the behavior as defined
if the bit pattern of q (as an unsigned) would be a trap representation for
"int".  Especially considering the heavy use of global variables by code of
that era, register-caching those represented easy low-hanging fruit for a
compiler.

> However, after analyzing the code above, I realized that the 
> implementation's freedom is seriously restricted by the possibility that 
> the pointers point at dynamically allocated memory, due to the fact that 
> the effective type can change with each write. In fact, I'm wondering if 
> the anti-aliasing rules give implementations any freedom at all to 
> reorder such code - could I be misunderstanding either 6.5p6 and p7?

It is not possible to have one set of rules which will be suitable for both
systems programming and high-end computing without adding directives to
control aliasing.  The present rules tie the hands of both compilers and
programmers needlessly.

The solution would be to have some distinct recognized aliasing modes,
most of which have precisely-defined requirements for programmers and
implementations, but with the default mode being relatively open-ended.
All implementations would be required to support a mode in which writing
anything of any type will behave as though all the bytes it occupies have
the object's defined representation written to them, and reading anything
of any type will interpret the last values written to the underlying bytes
in the manner defined for that type, and would be required to accept
directives indicating that code can work with other modes [any other mode
could be supported in compliant--though not necessarily performant--fashion
by any compiler simply by having it use the "baseline" mode if it has no
faster mode that complies with the requirements of the mode specified].

Adding aliasing modes would make it possible for compilers to rid themselves
of any need to recognize the possibility that code might repurpose storage
without notifying the compiler.  Provided that adequate means existed to
let the compiler know when aliasing must be expected, and code was allowed to
use aliasing once notice was given, even a very aggressive mode could be
suitable for writing new systems-programming code (less aggressive modes
would be needed mainly to handle code which hasn't yet had the appropriate
notifications added to it).

> The optimization you show above would be permitted if the two pointers 
> didn't point at dynamically allocated memory, and I'm wondering if gcc's 
> mistake was in failing to consider that possibility.

I'm pretty sure that gcc's mistake is in regarding the write to *t1p2 as a
no-op on the basis that the 64 bits being stored are known to match precisely
the 64 bits the storage already contains.  I consider the bug quite serious,
however, since it would be entirely reasonable for someone who has to pass
data between different APIs to do something like:

    void *p = malloc(100 * sizeof (long long))
    get_data_as_longs(p); // void get_data_as_longs(long *p);
    for (i=100-1; i>=0; i--)  // long long should be at least as large as long
      ((long long*)p)[i] = ((long*)p)[i];
    use_data_as_long_long(p);

In the event that "long" and "long long" have the same representation, it
would be good for a compiler to omit the middle loop, but not for it to
allow whole-program optimization to sequence the reads of "long long" in
the "use" function ahead of the writes of "long" in the "get" function.
I would not consider the above pattern obscure, but given the way gcc works
I wouldn't consider it safe.

> The C standard currently allows integer types with the same size and 
> same signedness to use different byte orders, and even different bit 
> orders (it allows this by the simple expedient of failing to specify 
> anything relevant about the byte order or bit order). I believe this 
> freedom is intentional, though I'm not sure if any real-world 
> implementation takes advantage of this freedom. I would oppose mandating 
> that they be compatible.

If hardware supports two different 64-bit types, it would be reasonable for
a C implementation *on that hardware* to treat "long" and "long long" as
incompatible 64-bit types, and there would be little benefit on such a
platform to treating pointers to those types as alias-compatible.

I would question the judgment, however, of anyone who thinks that on
platforms where both types have *the same documented data format*, the value
of having a compiler's default behavior treat the types as not being alias-
compatible outweighs the difficulties such a design will impose on code that
needs to exchange data between different APIs.

Any benefit that could be achieved by having "long" and "long long" be
distinct types could be achieved, better and more safely, by defining a
#pragma or other directive which would tell the compiler that certain
typedefs should be regarded as incompatible with others even when both
have the same underlying type, and should be alias-compatible with certain
others whether or not they have the same underlying type.

[toc] | [prev] | [next] | [standalone]


#94204

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-28 10:39 -0700
Message-ID<kfna8erc49c.fsf@x-alumni2.alumni.caltech.edu>
In reply to#94048
supercat@casperkitty.com writes:

> On Sunday, September 25, 2016 at 12:14:26 PM UTC-5, James R.  Kuyper wrote:
>> I've long assumed that the purpose of the anti-aliasing rules was to
>> gave implementations considerable freedom to reorder code using pointers
>> to different types, if the code consisted of a read from one type and a
>> write to a different type, if that pair of types was not connected by
>> one of the rules listed in 6.5p7.
>
> Based upon the C89 rationale, I had assumed that the purpose was to allow
> compilers to keep variables in registers when accessing pointers of different
> types, [...]

Presumably that is one motivation, but it certainly is not the only
motivation.

[toc] | [prev] | [next] | [standalone]


#94056

FromDavid Brown <david.brown@hesbynett.no>
Date2016-09-25 23:25 +0200
Message-ID<ns9fcj$orn$1@dont-email.me>
In reply to#94038
On 25/09/16 19:14, James R. Kuyper wrote:
> On 09/25/2016 12:39 PM, David Brown wrote:
>> On 25/09/16 17:48, James R. Kuyper wrote:
> ...
>>> Here's the original code that I was talking about, in order of
>>> execution:
>>>
>>> main:
>>>         ... test3();
>>>
>>> test3:
>>>         void *p = malloc(sizeof (T1) + sizeof (T2));
>>> /* p now points at a buffer; for convenience I'll refer to that buffer
>>> using 'p' even in contexts where 'p' is not in scope.
>>> */
>>>         ... blah3(p,p);
>>>
>>> blah3:
>>>       T1 blah3(void *p1, void *p2)
>>>       {
>>> /* p1 and p2 are both set equal to p */
>>>         t1p = p1;
>>>         t2p = p2;
>>> /* t1p and t2p both point at the same location as p */
>>>         *t1p = T1VALUE;   // Write as T1
>>> /* The sizeof(T1) bytes starting at p now contain a representation of
>>> T1VALUE as an object of type T1, which is now the effective type of
>>> that memory.
>>> */
>>>         *t2p = T2VALUE;   // Write as T2
>>> /* The sizeof(T2) bytes starting at p now contain a representation of
>>> T2VALUE as an object of type T2, which is now the effective type of
>>> that memory.
>>> */
>>>         temp = *t2p;      // Read as T2
>>> /* Since *t2p has the type T2, which matches the effective type of that
>>> memory, there is no problem reading the value T2VALUE from that
>>> memory, which is then stored in temp.
>>> */
>>
>> OK so far...
>>
>>>         t1p2 = (T1*)t2p;  // Visible T2 to T1 pointer conversion
>>> /* I missed this point: conversion from T2* to T1* is allowed, since
>>> this particular pointer is guaranteed to be correctly aligned for
>>> either type. However, technically, the standard says nothing about
>>> where t1p2 actually points. In principle, the only thing that is
>>> guaranteed about the value of t1p2 is that if you convert it back to
>>> T2*; the result will compare equal to t2p. For instance, the forward
>>> conversion could add 1024 bytes to the position, so long as the reverse
>>> conversion subtracted the same amount.
>>> In practice, on virtually every real world implementation of C, t1p2
>>> will point at the same location as all of the other object pointers in
>>> this program, and I believe it was the committee's intent that this be
>>> true. However, I haven't managed to convince anyone in authority that
>>> there's any need to change the wording to reflect that intent.
>>> */
>>
>> gcc appears to be optimising on the basis that the only defined
>> behaviour for t1p2 is that you can covert it back to a T2* and get the
>> same pointer as t2p.  The assembly it generates is (with my comments):
>>
>> blah3:
>>          movq    $1, (%rdi)    // Store 1 in *t1p
>>          movl    $1, %eax    // The return value 1
>>          movq    $2, (%rsi)    // Store 2 in *t2p
>>          ret
>>
>> test3:
>>          movl    $1, %eax
>>          ret
>
> I doubt that the t1p2 conversion is the justification used by gcc for
> generating this code. That's a purely pedantic issue that bothers only
> me - it's not something real implementations handle in any fashion
> different from the committee's intent.
>
> I've long assumed that the purpose of the anti-aliasing rules was to
> gave implementations considerable freedom to reorder code using pointers
> to different types, if the code consisted of a read from one type and a
> write to a different type, if that pair of types was not connected by
> one of the rules listed in 6.5p7.
> However, after analyzing the code above, I realized that the
> implementation's freedom is seriously restricted by the possibility that
> the pointers point at dynamically allocated memory, due to the fact that
> the effective type can change with each write. In fact, I'm wondering if
> the anti-aliasing rules give implementations any freedom at all to
> reorder such code - could I be misunderstanding either 6.5p6 and p7?
>
> The optimization you show above would be permitted if the two pointers
> didn't point at dynamically allocated memory, and I'm wondering if gcc's
> mistake was in failing to consider that possibility.

I know /I/ failed to consider the effect of dynamically allocated 
memory.  It is possible that gcc does so too, especially since it has 
eliminated the dynamic allocation.

>
>>>         *t1p2 = temp;     // Write as T1
>>> /* T2VALUE is converted to type T1, and stored in the sizeof(T1) bytes
>>> starting at p. The effective type of that memory is now T1.
>>> */
>>>         return *t1p;      // Read as T1
>
> ...
>>> T2VALUE is 2. By what argument would anyone claim that a value of 1
>>> could be printed out?
>>
>> It is the result gcc gives.
>
> Not on Ben's machine. Have the two of you resolved which of you is using
> the later version of gcc?

Yes.  He had some other flags that affected the compilation.

>
>> This is either a valid result due to the conversion of pointer types
>> mentioned above (and claims about "virtually every real world
>> implementation of C" are simply incorrect, because gcc is a pretty major
>> exception), or gcc has a bug here.
>>
>> To be clear, I would be happier if gcc gave 2 here - the same result as
>> other compilers on <gcc.godbolt.org>, and the result one would
>> reasonably expect.  ...
>
>> ... I would prefer if the C standards said that types
>> such as "long", "long long", and "int64_t" were all considered
>> "compatible" if they are all the same size (and similarly for "int",
>> "long", "int32_t"). ...
>
> The C standard currently allows integer types with the same size and
> same signedness to use different byte orders, and even different bit
> orders (it allows this by the simple expedient of failing to specify
> anything relevant about the byte order or bit order). I believe this
> freedom is intentional, though I'm not sure if any real-world
> implementation takes advantage of this freedom. I would oppose mandating
> that they be compatible.

If an implementation had different byte orderings for two equally sized 
types, then I would happily agree that pointers should be incompatible. 
  (I would also be pleased to see such a feature - sometimes in my 
programming I need to deal with non-native byte ordering.  gcc now has 
support for non-native byte ordering in structs, which is nice.)

[toc] | [prev] | [next] | [standalone]


#94045

Fromsupercat@casperkitty.com
Date2016-09-25 13:10 -0700
Message-ID<fe48733e-7d15-4442-9a6e-449ea39b9827@googlegroups.com>
In reply to#94035
On Sunday, September 25, 2016 at 11:39:43 AM UTC-5, David Brown wrote:
> gcc appears to be optimising on the basis that the only defined 
> behaviour for t1p2 is that you can covert it back to a T2* and get the 
> same pointer as t2p.  The assembly it generates is (with my comments):

Casting the pointer to void* would be required to yield a pointer matching
the one passed into the function, and casting that to T1 would be guaranteed
to yield a pointer to the same storage.  The Standard may not explicitly
describe the effect of casting a pointer directly from (T2*) to (T1*), but
in cases where a cast from (T2*) to (void*) would be defined, and likewise
a cast from the resulting (void*) to (T1*), it would seem curious that the
Standard would mandate that compilers accept a direct cast syntactically
if it didn't intend that behavior be defined, and I can't think of any
resulting pointer value the authors of the Standard would have intended to
allow that would differ from that of casting through void*.

I can imagine implementations where an explicit cast through (void*) might
offer semantic guarantees beyond those which the Standard requires, and
which it would not offer on a direct cast from (T2*) to (*T1), but this
scenario doesn't involve any such guarantees.

[toc] | [prev] | [next] | [standalone]


#94043

Fromsupercat@casperkitty.com
Date2016-09-25 12:55 -0700
Message-ID<cb58001a-2327-4cc4-ae1e-8e6926f1af59@googlegroups.com>
In reply to#94031
On Sunday, September 25, 2016 at 10:48:26 AM UTC-5, James R. Kuyper wrote:
> At no point does this code do anything which relies upon the assumption 
> that long long and int64_t are the same underlying type. It would work 
> equally well if T2 were any integer type other than _Bool.

So far as I can tell, the code *would* work if T1 and T2 were anything
other than a 64-bit "long" and 64-bit "long long"--I made them typedefs
to facilitate testing other types, but the cases where the code works
aren't interesting.

What's interesting is the case where the code fails.  When using direct
assignment, the only case I've noticed that fails is when using two 64-bit
integer types with the same representation, though if I knew how to
configure the x86 ARM to make "long" be 32 bits it might be interesting to
try with "int" and "long".  If I recall, both "long double" and "double"
had the same 64-bit representation, but the compiler generated correct code
in that case.  I didn't test whether gcc is treating them as distinct types
for aliasing purposes, however.

[toc] | [prev] | [next] | [standalone]


#94042

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-25 20:38 +0100
Message-ID<87lgyfepnc.fsf@bsb.me.uk>
In reply to#94018
David Brown <david.brown@hesbynett.no> writes:

> On 24/09/16 22:03, Ben Bacarisse wrote:
>> David Brown <david.brown@hesbynett.no> writes:
> <snip>
>>> But I could be wrong - and if this really is incorrect behaviour from
>>> gcc, then it needs reported and fixed.
>>
>> And *I* could be wrong, but I've gone though all 9 object accesses and
>> every one appears to be explicitly permitted by p6 and p7 of section
>> 6.5.
>>
>> <snip>
>>>> My gcc (5.2.1 20151010) gives 2 for all -Ox.  Presumably you have a
>>>> newer version?
>>>
>>> I am testing here with <https://gcc.godbolt.org/> for convenience.  It
>>> is targeting 64-bit Linux, and the result is 1 for -O2 and above, on
>>> gcc 4.7 onwards.  gcc 4.5 and 4.6 give 2.
>>
>> Including 5.2?  My system is 64-bit Linux.  (I could not see how to get
>> that site to show me the output.)
>>
>> <snip>
>>
>
> My test on gcc.godbolt.org is here:

<big link snipped>

My tests were local because I could not see how to get the program to
run at gcc.godbolt.org -- presumably that's not permitted.

Anyway, it turns out that other compiler options were undoing the
effects of -O2 (I turn the sanitizer on by default) so I now see what
you see.

> The details of the standards here is getting beyond me.

I fond that surprising.  The relevant parts just say that the effective
type of object in allocated storage is set by a write operation, and the
code only ever reads an object after a write operation has been done
using that same type.  It all looks fine to me.

> When you and
> James both think the answer should be 1, and 2 is not allowed,

For my part, it's the other way round.  I'm, saying that there is no
undefined behaviour regardless of what type int64_t actually is.  That
means that 1 is not permitted and blah3 must return 2.  But (despite
your kind words below), I'm not much of a language lawyer.  I find the
effective type rules to be often baffling.  It just seems to me that
they are quite clear in this particular case.

> then I
> am far from confident about 2 being allowable

I thought you were saying that anything was allowable in the case where
int64_t and long long int were not compatible types?

> - you are both more
> better at "language lawyering" than me.  But I do know that gcc will
> do this sort of transformation in practice, and in real code - you
> need to be very careful in mixing pointers to different integer types
> even when you know they are the same underlying hardware types.

Well, yes, we can all now see that gcc will do this!  Being very careful
may then something of an understatement, since it seems that programmers
must not only take care to stick to the C standard, but must also avoid
these other issues.

> Maybe it's time to pass this on to the gcc mailing lists, and ask how
> they interpret it?

That would be interesting.  It's obviously a long-standing optimisation,
but I don't see on what basis it is being done.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#94055

FromDavid Brown <david.brown@hesbynett.no>
Date2016-09-25 23:20 +0200
Message-ID<ns9f32$o08$1@dont-email.me>
In reply to#94042
On 25/09/16 21:38, Ben Bacarisse wrote:
> David Brown <david.brown@hesbynett.no> writes:
>
>> On 24/09/16 22:03, Ben Bacarisse wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>> <snip>
>>>> But I could be wrong - and if this really is incorrect behaviour from
>>>> gcc, then it needs reported and fixed.
>>>
>>> And *I* could be wrong, but I've gone though all 9 object accesses and
>>> every one appears to be explicitly permitted by p6 and p7 of section
>>> 6.5.
>>>
>>> <snip>
>>>>> My gcc (5.2.1 20151010) gives 2 for all -Ox.  Presumably you have a
>>>>> newer version?
>>>>
>>>> I am testing here with <https://gcc.godbolt.org/> for convenience.  It
>>>> is targeting 64-bit Linux, and the result is 1 for -O2 and above, on
>>>> gcc 4.7 onwards.  gcc 4.5 and 4.6 give 2.
>>>
>>> Including 5.2?  My system is 64-bit Linux.  (I could not see how to get
>>> that site to show me the output.)
>>>
>>> <snip>
>>>
>>
>> My test on gcc.godbolt.org is here:
>
> <big link snipped>
>
> My tests were local because I could not see how to get the program to
> run at gcc.godbolt.org -- presumably that's not permitted.
>

I was not actually running the code - merely compiling it and looking at 
the generated assembly.  I am not an expert at x86 assembly, but I can 
read it well enough to see the value being returned by the functions and 
the value being printed out by main (especially when I change the 
constants to 100 and 200 rather than 1 and 2).  gcc.godbolt.org makes it 
easy to test a variety of compilers - more than I have installed locally.

> Anyway, it turns out that other compiler options were undoing the
> effects of -O2 (I turn the sanitizer on by default) so I now see what
> you see.

OK, that explains it.

>
>> The details of the standards here is getting beyond me.
>
> I fond that surprising.  The relevant parts just say that the effective
> type of object in allocated storage is set by a write operation, and the
> code only ever reads an object after a write operation has been done
> using that same type.  It all looks fine to me.
>

To be more accurate, I mean we are touching on an area where I am not 
entirely confident, and I think it is quite likely that I am missing 
something subtle.  I hadn't thought about the difference made by the 
buffers being dynamically allocated, for example.

>> When you and
>> James both think the answer should be 1, and 2 is not allowed,
>
> For my part, it's the other way round.

Yes, I am sorry I got that mixed up!  (See my post to James.)

> I'm, saying that there is no
> undefined behaviour regardless of what type int64_t actually is.  That
> means that 1 is not permitted and blah3 must return 2.  But (despite
> your kind words below), I'm not much of a language lawyer.  I find the
> effective type rules to be often baffling.  It just seems to me that
> they are quite clear in this particular case.
>
>> then I
>> am far from confident about 2 being allowable

Please pretend I wrote "1" there.

>
> I thought you were saying that anything was allowable in the case where
> int64_t and long long int were not compatible types?

That is what I thought, yes.  But when you and James think otherwise, I 
can't be confident any more.

>
>> - you are both more
>> better at "language lawyering" than me.  But I do know that gcc will
>> do this sort of transformation in practice, and in real code - you
>> need to be very careful in mixing pointers to different integer types
>> even when you know they are the same underlying hardware types.
>
> Well, yes, we can all now see that gcc will do this!  Being very careful
> may then something of an understatement, since it seems that programmers
> must not only take care to stick to the C standard, but must also avoid
> these other issues.
>
>> Maybe it's time to pass this on to the gcc mailing lists, and ask how
>> they interpret it?
>
> That would be interesting.  It's obviously a long-standing optimisation,
> but I don't see on what basis it is being done.
>

I'll ask, and report back.

[toc] | [prev] | [next] | [standalone]


#94186

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-28 07:15 -0700
Message-ID<kfnvaxgaz66.fsf@x-alumni2.alumni.caltech.edu>
In reply to#94042
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> David Brown <david.brown@hesbynett.no> writes:
> [discussing a particular case of gcc behavior w.r.t. effective
>  type rules]
>
>> Maybe it's time to pass this on to the gcc mailing lists, and ask
>> how they interpret it?
>
> That would be interesting.  It's obviously a long-standing
> optimisation, but I don't see on what basis it is being done.

I am hoping not to be involved in this discussion too deeply, but
would like to make a few remarks.

I agree with your conclusion that the example code conforms to
the letter of the Standard.  AFAICT that code satisfies the
requirements of effective type rules (but let me emphasize,
as I read what the words say, which may not be the same as
what is meant).

I too would like to see this case (perhaps with simpler code)
submitted as a gcc bug report (and maybe also mailing lists,
but IMO an official response is important).

A response to a bug report might be either "yes this is a bug and
we will fix it", or might be "this isn't a bug because what the
Standard means is X".  The second possibility occurring would
not surprise me greatly.

IMO this example also deserves filing a Defect Report.  I call it
a defect because either the Standard doesn't mean what it says,
which is obviously a defect, or it produces a conclusion that
is highly surprising and probably not what some implementors
expect.  Either way, a clarification is warranted.

I wouldn't be surprised if an official committee response to a
Defect Report reached a different conclusion about whether the
behavior in the example code is undefined behavior.  I'm sure
many people remember the earlier discussions, before C11 was
done, about the phrase "may be read only to determine the value
to be stored" (or something like that).  We now know that the
"literal meaning" of that phrase is not what was intended.  A
similar situation may apply in this case.  At the end of the
day the only thing that matters is what WG14 intended, and
the only way to be sure here is to ask them.

[toc] | [prev] | [next] | [standalone]


#94213

FromDavid Brown <david.brown@hesbynett.no>
Date2016-09-28 21:29 +0200
Message-ID<nsh5lu$il5$1@dont-email.me>
In reply to#94186
On 28/09/16 16:15, Tim Rentsch wrote:
> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>
>> David Brown <david.brown@hesbynett.no> writes:
>> [discussing a particular case of gcc behavior w.r.t. effective
>>   type rules]
>>
>>> Maybe it's time to pass this on to the gcc mailing lists, and ask
>>> how they interpret it?
>>
>> That would be interesting.  It's obviously a long-standing
>> optimisation, but I don't see on what basis it is being done.

I posted to the gcc help mailing list.  I hope people here can have a 
look at the answers from the gcc community and developers, and consider 
the matter.  Maybe a defect report is the right way to go, or perhaps 
others (such as you, Tim) would like to add to the gcc thread.  The 
mailing list is on gmane as gmane.comp.gcc.help for those that prefer a 
Usenet interface to a mailing list.  You can also post to 
gcc-help@gcc.gnu.org without joining the list (the traffic is not too high).

<https://gcc.gnu.org/ml/gcc-help/2016-09/msg00087.html>


>
> I am hoping not to be involved in this discussion too deeply, but
> would like to make a few remarks.
>
> I agree with your conclusion that the example code conforms to
> the letter of the Standard.  AFAICT that code satisfies the
> requirements of effective type rules (but let me emphasize,
> as I read what the words say, which may not be the same as
> what is meant).
>
> I too would like to see this case (perhaps with simpler code)
> submitted as a gcc bug report (and maybe also mailing lists,
> but IMO an official response is important).
>
> A response to a bug report might be either "yes this is a bug and
> we will fix it", or might be "this isn't a bug because what the
> Standard means is X".  The second possibility occurring would
> not surprise me greatly.
>
> IMO this example also deserves filing a Defect Report.  I call it
> a defect because either the Standard doesn't mean what it says,
> which is obviously a defect, or it produces a conclusion that
> is highly surprising and probably not what some implementors
> expect.  Either way, a clarification is warranted.
>
> I wouldn't be surprised if an official committee response to a
> Defect Report reached a different conclusion about whether the
> behavior in the example code is undefined behavior.  I'm sure
> many people remember the earlier discussions, before C11 was
> done, about the phrase "may be read only to determine the value
> to be stored" (or something like that).  We now know that the
> "literal meaning" of that phrase is not what was intended.  A
> similar situation may apply in this case.  At the end of the
> day the only thing that matters is what WG14 intended, and
> the only way to be sure here is to ask them.
>

[toc] | [prev] | [next] | [standalone]


#93986

Fromsupercat@casperkitty.com
Date2016-09-24 10:52 -0700
Message-ID<b04f3d50-36d9-4f06-9880-7690ed99d19a@googlegroups.com>
In reply to#93980
On Saturday, September 24, 2016 at 9:56:08 AM UTC-5, Ben Bacarisse wrote:
> My gcc (5.2.1 20151010) gives 2 for all -Ox.  Presumably you have a
> newer version?

The code is for x86-64 (as found on godbolt.org), where both "long" and
"long long" are 64 bits.  If the two types have different representations,
then reading a value of one type and writing it as the other will be
recognized as having an effect.

I think that what is happening is that gcc's code generation is being
inconsistent with regard to whether the two 64-bit types should be
considered interchangeable.  If the types are interchangeable, then the
act of reading storage as T2 and writing the same storage as T1 may be
omitted entirely, but the earlier write as T2 would need to be visible
to the subsequent read as T1.  If the types are not interchange-able,
then the read and write need not generate any actual machine code,
but must behave as a read of type T2 followed by a write of T1.

[toc] | [prev] | [next] | [standalone]


#93984

Fromsupercat@casperkitty.com
Date2016-09-24 10:33 -0700
Message-ID<42564e5d-31d4-4686-b994-7d58e6ddeaba@googlegroups.com>
In reply to#93977
On Saturday, September 24, 2016 at 9:29:38 AM UTC-5, David Brown wrote:
> If T1 and T2 are compatible types (as might be the case, such as on 
> Windows), then the answer will be 2.  If they are incompatible types, 
> such as on 64-bit Linux, the answer is undefined - you are trying to 
> access the same object through pointers to two incompatible types.

No, I am not.  The rules allow storage with no declared type to be written
as any type, and the write sets the Effective Type until the storage is
written again.  The code I posted always reads the storage as the last type
written (i.e. its Effective Type).

While one could argue that the Effective Type T2 remains effective because
the bit patterns written to storage will match what's already there, and
the second write consequently doesn't "modify the value", such a reading
would directly contradict the definition of "modify" in 3.2 (and would
also contradict the language which says that storing a value of type T1
would set the Effective Type to T1).

>  Some 
> compiler and optimisation options will give 2, others will give 1, 
> others could, in theory, give something else - but I think that's 
> unlikely in practice.

The code does not invoke UB.

> gcc gives 1 with optimisation -O2 and above, on 64-bit Linux.  There is 
> no bug here in gcc as far as I can see - your code is incorrect.

It tests whether reading an object via T2*, converting the value to T1,
and writing the converted value via T1* is properly recognized as setting
the Effective Type of the object to type T1.

> > Since you wanted me to dig it up, here's the example I posted before.
> >
> > https://godbolt.org/g/75oLGx
> 
> Maybe the link is not working as expected - it appeared to have the code:
> 
> // Type your code here, or load an example.
> int square(int num) {
>    return num * num;
> }

I don't think the "short link" function on godbolt is supposed to require
cookies, so I'm not sure why the link would simply show the default example
program on your machine.  I posted the source text above, however, and will
paste it below for convenience:

    #include <stdint.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>

    typedef long long T1;
    typedef int64_t T2;
    #define T1FMT "%lld"
    #define T1VALUE 1
    #define T2VALUE 2

    T1 blah3(void *p1, void *p2)
    {
      T1 *t1p, *t1p2;
      T2 *t2p;
      T1 temp;

      t1p = p1;
      t2p = p2;
      *t1p = T1VALUE;   // Write as T1
      *t2p = T2VALUE;   // Write as T2
      temp = *t2p;      // Read as T2
      t1p2 = (T1*)t2p;  // Visible T2 to T1 pointer conversion
      *t1p2 = temp;     // Write as T1
      return *t1p;      // Read as T1
    }

    T1 test3(void)
    {
      void *p = malloc(sizeof (T1) + sizeof (T2));
      T1 result = blah3(p,p);
      free(p);
      return result;
    }
    int main(void)
    {
      T1 result = test3();
      printf("The result is " T1FMT, result);
      return 0;      
    }

> I don't see how this relates to your point.

The default demo program for godbolt has nothing to do with my point; I have
no idea why it would show up on your end.

[toc] | [prev] | [next] | [standalone]


#94019

FromDavid Brown <david.brown@hesbynett.no>
Date2016-09-25 12:46 +0200
Message-ID<ns89tu$lj2$2@dont-email.me>
In reply to#93984
On 24/09/16 19:33, supercat@casperkitty.com wrote:
> On Saturday, September 24, 2016 at 9:29:38 AM UTC-5, David Brown wrote:

>>> Since you wanted me to dig it up, here's the example I posted before.
>>>
>>> https://godbolt.org/g/75oLGx
>>
>> Maybe the link is not working as expected - it appeared to have the code:
>>
>> // Type your code here, or load an example.
>> int square(int num) {
>>     return num * num;
>> }
>
> I don't think the "short link" function on godbolt is supposed to require
> cookies, so I'm not sure why the link would simply show the default example
> program on your machine.  I posted the source text above, however, and will
> paste it below for convenience:
>
>> I don't see how this relates to your point.
>
> The default demo program for godbolt has nothing to do with my point; I have
> no idea why it would show up on your end.
>

OK.  I thought you were giving a link to a different example.  Maybe the 
short links don't work, or maybe the problem is on my browser.  When I 
posted a link in a different post, I tried a full link to see if that 
works better.

Sorry for the confusion here.

[toc] | [prev] | [next] | [standalone]


#93994

FromKeith Thompson <kst-u@mib.org>
Date2016-09-24 13:58 -0700
Message-ID<lnfuopuia5.fsf@kst-u.example.com>
In reply to#93948
supercat@casperkitty.com writes:
> On Friday, September 23, 2016 at 2:49:43 AM UTC-5, David Brown wrote:
>> On 22/09/16 18:52, supercat wrote:
>> Your first claim was that gcc (6.2) incorrectly handles code in a way
>> that goes against the unambiguous rules of the standards.  This is a
>> serious allegation, and should be backed up with concrete examples and
>> bug reports.  The gcc team take all "incorrect code generation" bugs
>> extremely seriously.  And while /you/ might not use gcc, millions of
>> others do use it.  Someone here (such as me) will happily file a bug
>> report if you have a specific bug.
>> 
>> But now you have modified back to your usual "gcc optimises too well -
>> it follows the requirements of the real C standards, rather than my
>> imaginary specifications of thirty years ago".
>> 
>> So which is it?  Can you give us a concrete example of buggy code, that
>> we can paste into <http://gcc.godbolt.org/#> and compare results with
>> different gcc versions and different compilers?  You can't just refer to
>> "I've posted about it before" - you have posted hundreds or thousands of
>> snippets in this group.
>
>     #include <stdint.h>
>     #include <string.h>
>     #include <stdlib.h>
>     #include <stdio.h>
>
>     typedef long long T1;
>     typedef int64_t T2;
>     #define T1FMT "%lld"
>     #define T1VALUE 1
>     #define T2VALUE 2
>
>     T1 blah3(void *p1, void *p2)
>     {
>       T1 *t1p, *t1p2;
>       T2 *t2p;
>       T1 temp;
>
>       t1p = p1;
>       t2p = p2;
>       *t1p = T1VALUE;   // Write as T1
>       *t2p = T2VALUE;   // Write as T2
>       temp = *t2p;      // Read as T2
>       t1p2 = (T1*)t2p;  // Visible T2 to T1 pointer conversion
>       *t1p2 = temp;     // Write as T1
>       return *t1p;      // Read as T1
>     }
>
>     T1 test3(void)
>     {
>       void *p = malloc(sizeof (T1) + sizeof (T2));
>       T1 result = blah3(p,p);
>       free(p);
>       return result;
>     }
>     int main(void)
>     {
>       T1 result = test3();
>       printf("The result is " T1FMT, result);
>       return 0;      
>     }
[...]
> So there's a sample of buggy code.  Similar thing can happen if there are
> two structure types that have the same representation.

I found that the typedefs and macros made the code difficult to read;
YMMV.

Here's my version, which I believe is equivalent -- assuming
that long and long long have the same size and representation,
and that int64_t is a typedef for long.  (I also added a newline
to the output.)

On my x86_64 system, using gcc 6.2.0, I get "The result is 2"
with -O0 and -O1, and "The result is 1" with -O2 and -O3.

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

long long func1(void *p1, void *p2) {
    long long *llp1 = p1;
    long *lp = p2;
    *llp1 = 1;             // Write as long long
    *lp = 2;               // Write as long
    long long temp = *lp;  // Read as long
    long long *llp2 = (long long*)lp;  // Visible long to long long
    pointer conversion
    *llp2 = temp;          // Write as long long
    return *llp1;          // Read as long long
}

long long func2(void) {
    void *p = malloc(sizeof (long long) + sizeof (long));
    long long result = func1(p,p);
    free(p);
    return result;
}

int main(void) {
    assert(sizeof (long) == sizeof (long long));
    printf("The result is %lld\n", func2());
}

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


Page 3 of 5 — ← Prev page 1 2 [3] 4 5  Next page →

Back to top | Article view | comp.lang.c


csiph-web