Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #138077 > unrolled thread
| Started by | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| First post | 2018-11-17 14:38 +0300 |
| Last post | 2018-11-19 14:33 -0800 |
| Articles | 20 on this page of 134 — 18 participants |
Back to article view | Back to comp.lang.c
Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-17 14:38 +0300
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-17 17:37 +0300
Re: Pointer conversion and alignment Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-17 21:01 +0000
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 00:43 +0300
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 01:20 +0300
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-17 18:12 -0500
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 02:32 +0300
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-17 18:59 -0500
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 12:40 +0300
Re: Pointer conversion and alignment Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-18 02:14 +0000
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 13:23 +0300
Re: Pointer conversion and alignment Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-18 11:28 +0000
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 15:31 +0300
Re: Pointer conversion and alignment Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-18 15:03 +0000
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 23:00 +0300
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 00:49 +0300
Re: Pointer conversion and alignment Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2018-11-17 06:52 -0800
Re: Pointer conversion and alignment Ian Collins <ian-news@hotmail.com> - 2018-11-18 09:18 +1300
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-11-17 13:49 -0800
Re: Pointer conversion and alignment Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2018-11-17 13:57 -0800
Re: Pointer conversion and alignment Ian Collins <ian-news@hotmail.com> - 2018-11-18 11:08 +1300
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 01:13 +0300
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-11-17 18:37 -0800
Re: Pointer conversion and alignment Philipp Klaus Krause <pkk@spth.de> - 2018-11-18 14:14 +0100
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-17 10:05 -0500
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 01:08 +0300
Re: Pointer conversion and alignment "Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid> - 2018-11-17 14:31 -0800
Re: Pointer conversion and alignment "Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid> - 2018-11-17 16:10 -0800
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-18 15:01 +0300
Re: Pointer conversion and alignment James Kuyper <jameskuyper@alumni.caltech.edu> - 2018-11-18 07:25 -0500
Re: Pointer conversion and alignment "Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid> - 2018-11-19 21:30 -0800
Re: Pointer conversion and alignment "Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid> - 2018-11-20 14:20 -0800
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-17 18:04 -0500
Re: Pointer conversion and alignment Philipp Klaus Krause <pkk@spth.de> - 2018-11-18 14:18 +0100
Re: Pointer conversion and alignment scott@slp53.sl.home (Scott Lurndal) - 2018-11-18 19:49 +0000
Re: Pointer conversion and alignment Tim Rentsch <txr@alumni.caltech.edu> - 2018-11-23 18:27 -0800
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-23 21:59 -0500
Re: Pointer conversion and alignment Tim Rentsch <txr@alumni.caltech.edu> - 2018-11-24 00:32 -0800
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-24 08:17 -0500
Re: Pointer conversion and alignment Tim Rentsch <txr@alumni.caltech.edu> - 2018-11-29 09:55 -0800
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-29 21:48 -0500
Re: Pointer conversion and alignment Tim Rentsch <txr@alumni.caltech.edu> - 2018-12-05 04:14 -0800
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-12-05 08:14 -0500
Re: Pointer conversion and alignment Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2018-12-05 05:29 -0800
Re: Pointer conversion and alignment David Brown <david.brown@hesbynett.no> - 2018-12-05 14:44 +0100
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-12-05 21:58 -0500
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-12-05 16:38 +0300
Re: Pointer conversion and alignment scott@slp53.sl.home (Scott Lurndal) - 2018-12-05 14:23 +0000
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-12-05 14:35 -0800
Re: Pointer conversion and alignment Tim Rentsch <txr@alumni.caltech.edu> - 2018-12-08 19:28 -0800
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-12-09 08:18 -0500
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-12-09 14:35 -0500
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-12-09 14:04 -0800
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-12-09 20:40 -0500
Re: Pointer conversion and alignment Tim Rentsch <txr@alumni.caltech.edu> - 2018-12-17 07:18 -0800
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-12-17 12:35 -0800
Re: Pointer conversion and alignment Tim Rentsch <txr@alumni.caltech.edu> - 2018-12-17 12:48 -0800
Re: Pointer conversion and alignment "Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid> - 2018-11-24 18:33 -0800
My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-19 02:26 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-19 11:08 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-19 15:37 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-19 15:39 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-19 15:07 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-19 22:24 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jameskuyper@alumni.caltech.edu - 2018-11-19 12:33 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-20 00:34 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jameskuyper@alumni.caltech.edu - 2018-11-19 14:38 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-20 00:43 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] James Kuyper <jameskuyper@alumni.caltech.edu> - 2018-11-19 21:44 -0500
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jadill33@gmail.com - 2018-11-20 07:11 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] bart4858@gmail.com - 2018-11-20 10:02 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-19 22:20 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-20 14:01 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Melzzzzz <Melzzzzz@zzzzz.com> - 2018-11-20 11:07 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-20 15:12 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] James Kuyper <jameskuyper@alumni.caltech.edu> - 2018-11-20 08:15 -0500
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-20 23:08 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jameskuyper@alumni.caltech.edu - 2018-11-20 14:13 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-21 16:38 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] James Kuyper <jameskuyper@alumni.caltech.edu> - 2018-11-21 09:05 -0500
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-21 20:28 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jameskuyper@alumni.caltech.edu - 2018-11-21 12:58 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-22 01:47 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jameskuyper@alumni.caltech.edu - 2018-11-21 15:50 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-24 19:37 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-21 21:22 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-21 01:15 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-19 15:06 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] mark.bluemel@gmail.com - 2018-11-19 08:05 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] scott@slp53.sl.home (Scott Lurndal) - 2018-11-19 16:49 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jameskuyper@alumni.caltech.edu - 2018-11-19 10:35 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-20 00:45 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jameskuyper@alumni.caltech.edu - 2018-11-19 14:24 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-20 15:05 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] James Kuyper <jameskuyper@alumni.caltech.edu> - 2018-11-20 08:31 -0500
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Richard Damon <Richard@Damon-Family.org> - 2018-11-20 20:02 -0500
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-21 22:47 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] jameskuyper@alumni.caltech.edu - 2018-11-21 13:08 -0800
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-22 00:31 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-21 21:36 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-19 16:04 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-19 14:56 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-24 19:24 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-24 21:31 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-24 21:46 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-25 01:12 +0300
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-11-25 01:39 +0000
Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] Anton Shepelev <anton.txt@gmail.com> - 2018-11-25 14:19 +0300
Re: Pointer conversion and alignment jadill33@gmail.com - 2018-11-19 08:44 -0800
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-20 00:02 +0300
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-11-19 13:51 -0800
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-20 01:08 +0300
Re: Pointer conversion and alignment jameskuyper@alumni.caltech.edu - 2018-11-19 14:31 -0800
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-20 15:21 +0300
Re: Pointer conversion and alignment James Kuyper <jameskuyper@alumni.caltech.edu> - 2018-11-20 08:59 -0500
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-11-20 11:06 -0800
Re: Pointer conversion and alignment jameskuyper@alumni.caltech.edu - 2018-11-20 12:43 -0800
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-11-20 14:33 -0800
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-21 14:33 +0300
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-21 07:49 -0500
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-11-21 12:42 -0800
Re: Pointer conversion and alignment James Kuyper <jameskuyper@alumni.caltech.edu> - 2018-11-21 08:41 -0500
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-25 15:06 +0300
Re: Pointer conversion and alignment James Kuyper <jameskuyper@alumni.caltech.edu> - 2018-11-25 10:47 -0500
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@g{oogle}mail.com> - 2018-11-26 12:42 +0300
Re: Pointer conversion and alignment Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2018-11-26 03:07 -0800
Re: Pointer conversion and alignment Keith Thompson <kst-u@mib.org> - 2018-11-26 12:56 -0800
Re: Pointer conversion and alignment Richard Damon <Richard@Damon-Family.org> - 2018-11-26 18:17 -0500
Re: Pointer conversion and alignment jameskuyper@alumni.caltech.edu - 2018-11-26 09:06 -0800
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-26 23:52 +0300
Re: Pointer conversion and alignment jameskuyper@alumni.caltech.edu - 2018-11-26 13:13 -0800
Re: Pointer conversion and alignment Anton Shepelev <anton.txt@gmail.com> - 2018-11-27 00:31 +0300
Re: Pointer conversion and alignment jameskuyper@alumni.caltech.edu - 2018-11-26 14:15 -0800
Re: Pointer conversion and alignment jadill33@gmail.com - 2018-11-19 14:33 -0800
Page 5 of 7 — ← Prev page 1 2 3 4 [5] 6 7 Next page →
| From | Anton Shepelev <anton.txt@g{oogle}mail.com> |
|---|---|
| Date | 2018-11-21 20:28 +0300 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <20181121202812.8be0eaa6e3119eee8161c874@g{oogle}mail.com> |
| In reply to | #138177 |
Thanks you very much for the answers, James.
>>Is it correct that malloc creates a single allocated
>>object?
>
>Yes.
But you say below that this allcoated object may comprise
many smaller allocated objects, even in a hierarchical
manner, as would seem to be the case with a nested struct.
So malloc can be seen as returning as many objects as there
are junctures of a sequence of n elements into non-empty
contagious regions. I can't calculate it right now, but for
n=2 it is 2: 1) a single two-byte region and 2) two one-byte
regions. It may be nitpicking, but I am trying to
understand the letter of the Standard.
>>How many effective types can a single allocated object
>>have? I think it is one or zero.
>
>Different parts of an allocated object can have different
>types.
I don't see how the Standard even hints at this important
property of objects, except very indirecly.
>This is particularly obvious if it is used to store a
>struct containing members of different types,
My initial understanding was that the effective type of such
an (allocated) object is the type of the struct and that
accesses through struct members have the effective of the
struct rather than of the members. Now I know I was wrong,
but yet I fail to derive it from the standard.
>but you can also write objects of different types to
>different parts of allocated memory, giving those parts of
>the memory different effective types.
Ok.
>>Can an object be considered as consisting of smaller
>>objects, e.g. (assuming a 4-byte int and a 2-byte short
>>int) a 4-byte object as two contiguous 2-byte objects
>>(when I use it to store two short ints) or four contiguous
>>singe-byte objects (when I use it to store four
>>characters)?
>
>Yes - there's three different ways in which a C object can
>contain smaller sub-objects: Arrays contain smaller
>objects, which are the elements of the array. Every object,
>regardless of type, can be accessed as an array of
>character type; the individual characters of that array are
>sub-objects of the entire object. Finally, structs may be
>used to create heterogeneous collections of sub-objects of
>different types.
And a fourth way is the one mentioned above: writing
different types of data to different parts of the same
allocated object.
>>Is effective type associated with whatever address range
>>is accessed rather than with the whole object returned by
>>malloc()? If so, it must take a lot of space for the
>>compiler to track the effective type of every single byte
>>of allocated memory.
>
>I believe it is not necessary for a compiler to store such
>information. The distinction is relevant primarily to
>which optimizations an implementation is permitted to
>perform, but what's relevant to those optimizations is the
>types of individual expressions in a piece of code. If
>pointers to two types that are permitted to alias each
>other are in scope in the same block of code, the compiler
>can always simply not perform optimizations that would fail
>if they did alias each other.
Understood, but in this way the compiler misses opimisation
opprotunities when no aliasing is evident in local scope
(i.e. when no second incompatible pointer coexists). For
example, a read access is made through a pointer to int to a
memory block set via a pointer to double at a completely
different place in code and moment in time:
#include <stdlib.h>
#include <stdio.h>
void* vP;
void bye( void )
{ int i = *(int*)vP; /* this should be UB */
printf("i = %i\n", i);
}
int main(int argc, char** argv)
{ vP = malloc( sizeof( double ) );
*(double*)vP = 11.11;
/* ... */
atexit( &bye );
}
In other words, the compiler you described checks a
sufficient condition of aliasing violation, missing some
violations. Is it possible to implement a compiler that
would be able make a program that terminated upon each and
every effective type mismatch according to the letter of the
Standard? Terminating with a run-time error in case of UB
is a good idea as a compiler option.
>Alternatively, it could check the values of those pointers
>at run-time to determine whether they alias each other, and
>executed an optimized version of the code only if they
>don't.
This, again, is but a sufficient condition of aliasing and
will miss cases when one pointer is modified after the
acccess so that at no moment do the two pointers contain the
same byte address, although they access the same location in
memory and therefore alias.
>They could also, in some cases, perform a compile-time
>check to confirm that it's not possible for them to alias
>each other. To do this in the general case could be
>arbitrarily hard. as implied by your question (I'm sure it
>can be proven equivalent to the halting problem). However,
>compilers are not obligated to perform such analysis, and
>in real world compilers they only perform such analysis
>when it's easy.
Indeed, but GCC seems not such a compiler, becauses it
optimises accesses when aliasing is obvious:
https://blog.regehr.org/archives/1307
>> /* assuming sizeof(int) = 4 and sizeof(short)=2 */
>> void *vP = malloc( sizeof( int ) );
>> int *iP = vP;
>> short *sP = vP;
>>
>> *iP = 5; /* Q1: the effective type of the whole region becomes int? */
>No. Only *iP is written to, so only *iP acquires the
>effective type of "int";
But *iP occupies the whole allocated region because I passed
sizeof(int) to malloc.
>> sP++;
>> *sP = 12;
>> /* Q2: effective type of the latter half of the region in short? */
>
>Correct. Every write to a piece of dynamically allocated
>memory can give it a new, and possibly different, effective
>type.
Now, the last two bytes of allocated object have turned into
a sub-object of type short.
>>/* Q3: what about the effective type of the first half, still int? */
>
>Assuming that sizeof(short) < sizeof(int) (which need not
>be true), then ->
I prefixed the example with:
/* assuming sizeof(int) = 4 and sizeof(short)=2 */
>-> the answer is "No". The effective type applies to the
>entire "int" object. Any write that gives any part of that
>object a new effective type erases the original effective
>type.
In other words, upon writing though int*, we had the
following effective type for our 4-byte allocated object:
1 2 3 4
int int int int
After modifying the latter two bytes through short* it
became:
1 2 3 4
N/A N/A short short
Looks pretty non-trivial to follow in an implementation that
takes the Standard literally... Using sufficient conditions
of effective type mimatch instead of an exact criterium is a
relaxation that prevent the compiler from catching all
isntances of UB.
--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | jameskuyper@alumni.caltech.edu |
|---|---|
| Date | 2018-11-21 12:58 -0800 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <c7742990-d823-4243-9a94-534216f4a2db@googlegroups.com> |
| In reply to | #138179 |
On Wednesday, November 21, 2018 at 12:28:21 PM UTC-5, Anton Shepelev wrote:
> Thanks you very much for the answers, James.
>
> >>Is it correct that malloc creates a single allocated
> >>object?
> >
> >Yes.
>
> But you say below that this allcoated object may comprise
> many smaller allocated objects, even in a hierarchical
> manner, as would seem to be the case with a nested struct.
> So malloc can be seen as returning as many objects as there
> are junctures of a sequence of n elements into non-empty
> contagious regions. I can't calculate it right now, but for
> n=2 it is 2: 1) a single two-byte region and 2) two one-byte
> regions. It may be nitpicking, but I am trying to
> understand the letter of the Standard.
I don't know if I can help you with that, since I don't understand why
you find it a stumbling block. A single object can be sub-divided into
multiple sub-objects in many different ways - that fact doesn't make it
any less of a single object. This is exactly analogous to the fact that
there are many different ways to subdivide a line segment into a group
of smaller line segments. It is still, itself, a single line segment.
...
> >Different parts of an allocated object can have different
> >types.
>
> I don't see how the Standard even hints at this important
> property of objects, except very indirecly.
"If a value is stored into an object having no declared type through an
lvalue having a type that is not a character type, then 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." (6.5p6)
Note that it is ONLY the object written to that acquires that effective
type. Higher level objects that happen to contain the object written to
don't acquire an effective time just because a sub-object did.
=To a considerable extent, the fact that you're allowed to take
advantage of this fact to give different pieces of a block different
effective types, is due primarily to the lack of a prohibition on doing
so. It's pretty hard to cite the text that fails to prohibit it - think
about it.
> >This is particularly obvious if it is used to store a
> >struct containing members of different types,
>
> My initial understanding was that the effective type of such
> an (allocated) object is the type of the struct and that
> accesses through struct members have the effective of the
> struct rather than of the members. Now I know I was wrong,
> but yet I fail to derive it from the standard.
Writing to memory that has no declared type gives that memory an
effective type which matches the type of the lvalue you used to write
it. If you write individual members of a struct, you give each piece of
memory the effective type of the corresponding piece. However, if you
write an entire struct using a single lvalue, as in my example with
*now = empty;
then that entire piece of memory has the effective type of that struct,
which is a better match to your expectations.
...
> >Yes - there's three different ways in which a C object can
> >contain smaller sub-objects: Arrays contain smaller
> >objects, which are the elements of the array. Every object,
> >regardless of type, can be accessed as an array of
> >character type; the individual characters of that array are
> >sub-objects of the entire object. Finally, structs may be
> >used to create heterogeneous collections of sub-objects of
> >different types.
>
> And a fourth way is the one mentioned above: writing
> different types of data to different parts of the same
> allocated object.
I meant to mention that, and forgot.
...
> >I believe it is not necessary for a compiler to store such
> >information. The distinction is relevant primarily to
> >which optimizations an implementation is permitted to
> >perform, but what's relevant to those optimizations is the
> >types of individual expressions in a piece of code. If
> >pointers to two types that are permitted to alias each
> >other are in scope in the same block of code, the compiler
> >can always simply not perform optimizations that would fail
> >if they did alias each other.
>
> Understood, but in this way the compiler misses opimisation
> opprotunities when no aliasing is evident in local scope
> (i.e. when no second incompatible pointer coexists). For
> example, a read access is made through a pointer to int to a
> memory block set via a pointer to double at a completely
> different place in code and moment in time:
>
> #include <stdlib.h>
> #include <stdio.h>
>
> void* vP;
> void bye( void )
> { int i = *(int*)vP; /* this should be UB */
> printf("i = %i\n", i);
> }
>
> int main(int argc, char** argv)
> { vP = malloc( sizeof( double ) );
> *(double*)vP = 11.11;
> /* ... */
> atexit( &bye );
> }
>
> In other words, the compiler you described checks a
> sufficient condition of aliasing violation, missing some
> violations. ...
No - it's checking for sufficient conditions for the ABSENCE of aliasing violations; that's equivalent to NOT finding necessary conditions for an aliasing violation.
Since I can see that this code violates aliasing rules, a sufficiently
sophisticated compiler could do so as well. However, it's not clear to
me what optimization opportunities it would miss by failing to identify
that fact. It might help me to understand your point if you could
identify such an opportunity. How would the optimizaed version of the
code differ from the unoptimized version?
> ... Is it possible to implement a compiler that
> would be able make a program that terminated upon each and
> every effective type mismatch according to the letter of the
> Standard?
I believe it can be shown that identifying every effective type mismatch
with no false positives or false negatives would be equivalent to
solving the halting problem. The basic approach to this proof is to have
execution of one of the two statements that makes it a mismatch depend
upon whether or not a given piece of code halts.
> ... Terminating with a run-time error in case of UB
> is a good idea as a compiler option.
Many of the things that qualify as UB do so, precisely because it is
unduly difficult to identify all possible cases where they come up. It
is quite common for identifying such cases with no false positives and
no false negatives, to be equivalent to solving the halting problem.
The usual way that UB is used is NOT to explicitly identify occurrences.
Instead, the compiler sets up conditions for performing a given
optimization. Those conditions are chosen so that any code that meets
those conditions, but would be broken by the optimization, must have
undefined behavior. A typical example that applies here:
void replace_match_with_0(size_t n, int *x, int *y)
{
for(size_t i = 0; i<n; i++)
if(x[i] == (int)*y)
x[i] = 0;
}
It might seem that this code can be optimized by evaluating *y only once,
prior to the start of the loop, rather than repeatedly evaluating it
during each pass through the loop. However, if x[i], for some value of i
from 0 to n-1, refers to the same object as *y, then that optimization
would be invalid. Such code has well-defined behavior, which causes the
value of *y to change from whatever it was originally to 0, as soon as
the loop executes for that value of i, and that changed value of *y
would be used for all subsequent passes through the loop. That
optimization would incorrectly continue using the original value of *y
instead of the new one, and is therefore not allowed.
Note: the "well-defined" behavior described above might NOT be what was
intended - the optimized version might be what was actually intended. In
that case, moving evaluation of *y out of the loop should be done
explicitly by the developer, not implicitly by the implementation.
If, on the other hand, y were changed to "short *y", then the
optimization would be perfectly valid, because it would have undefined
behavior if *y aliased x[i]. That undefined behavior would take the form
of having the change to the value of *y go unnoticed. Notice that
compiler doesn't have any need to determine whether or not the behavior
is undefined. It uses only the fact that *y has a type that cannot be
used to alias x[i], to determine that the optimization is valid.
...
> >> /* assuming sizeof(int) = 4 and sizeof(short)=2 */
> >> void *vP = malloc( sizeof( int ) );
> >> int *iP = vP;
> >> short *sP = vP;
> >>
> >> *iP = 5; /* Q1: the effective type of the whole region becomes int? */
> >No. Only *iP is written to, so only *iP acquires the
> >effective type of "int";
>
> But *iP occupies the whole allocated region because I passed
> sizeof(int) to malloc.
My apologies - I hadn't noticed that you were allocating only a single int object. "The whole region" and "only *iP" refer to same thing, so we're actually in agreement, but I would have chosen different wording if I'd noticed.
> >> sP++;
> >> *sP = 12;
> >> /* Q2: effective type of the latter half of the region in short? */
> >
> >Correct. Every write to a piece of dynamically allocated
> >memory can give it a new, and possibly different, effective
> >type.
>
> Now, the last two bytes of allocated object have turned into
> a sub-object of type short.
>
> >>/* Q3: what about the effective type of the first half, still int? */
> >
> >Assuming that sizeof(short) < sizeof(int) (which need not
> >be true), then ->
>
> I prefixed the example with:
>
> /* assuming sizeof(int) = 4 and sizeof(short)=2 */
Sorry - I also passed over that comment without reading it.
> >-> the answer is "No". The effective type applies to the
> >entire "int" object. Any write that gives any part of that
> >object a new effective type erases the original effective
> >type.
>
> In other words, upon writing though int*, we had the
> following effective type for our 4-byte allocated object:
>
> 1 2 3 4
> int int int int
>
> After modifying the latter two bytes through short* it
> became:
>
> 1 2 3 4
> N/A N/A short short
>
> Looks pretty non-trivial to follow in an implementation that
> takes the Standard literally... Using sufficient conditions
> of effective type mimatch instead of an exact criterium is a
> relaxation that prevent the compiler from catching all
> isntances of UB.
You're thinking about UB incorrectly. A compiler is not obligated to
catch all instances of UB, which is good, because it's provably
impossible to catch all such instances. That fact, in turn, is part of
the reason why many things have undefined behavior rather than being
constraint violations: If an implementation is supposed to positively
identify all occurrences of a given problem, and to never falsely
identify the problem, the problem is usually tagged as a constraint
violation, not as UB.
The proper way to make use of the concept of UB is outlined in my
discussion of replace_match_with_0() above.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2018-11-22 01:47 +0300 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <20181122014730.7dbd2738a258fdaf91f1b5fb@gmail.com> |
| In reply to | #138183 |
Thanks for your very detailed answers, James:
> I don't know if I can help you with that, since I don't
> understand why you find it a stumbling block. A single
> object can be sub-divided into multiple sub-objects in
> many different ways -- that fact doesn't make it any less
> of a single object. This is exactly analogous to the fact
> that there are many different ways to subdivide a line
> segment into a group of smaller line segments. It is
> still, itself, a single line segment.
I understand the analogy and even have used its discrete
version to calculate the number of such subdivisions. I
failed, however, to deduce the possibility of this
subdivision from the Standard.
> > I don't see how the Standard even hints at this
> > important property of objects, except very indirecly.
>
> "If a value is stored into an object having no declared
> type through an lvalue having a type that is not a
> character type, then 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."
> (6.5p6)
I wrongly assumed that in `(*mydata).field' the lvalue used
for the access is `*mydata'. I stand corrected.
> Note that it is ONLY the object written to that acquires
> that effective type. Higher level objects that happen to
> contain the object written to don't acquire an effective
> time just because a sub-object did.
That is difficult. Writing to an `int' field of a struct
through a `short' pointer breaks the effective type of the
field, but keeps the effectvie type of the whole struct?
Remember my earlier example of overwriting the upper two
bytes of a (4-byte) int through a pointer to short (assumed
two bytes wide) -- you said this access broke the effective
type of the whole int object -- a contradition?
> =To a considerable extent, the fact that you're allowed to
> take advantage of this fact to give different pieces of a
> block different effective types, is due primarily to the
> lack of a prohibition on doing so. It's pretty hard to
> cite the text that fails to prohibit it - think about it.
Did you mean "to cite the text that prohibits it"?
> Writing to memory that has no declared type gives that
> memory an effective type which matches the type of the
> lvalue you used to write it. If you write individual
> members of a struct, you give each piece of memory the
> effective type of the corresponding piece. However, if you
> write an entire struct using a single lvalue, as in my
> example with
>
> *now = empty;
>
> then that entire piece of memory has the effective type of
> that struct, which is a better match to your expectations.
And the result is an allocated object with a hierarchical
sturcture of effective types.
> > > I believe it is not necessary for a compiler to store
> > > such information. The distinction is relevant
> > > primarily to which optimizations an implementation is
> > > permitted to perform, but what's relevant to those
> > > optimizations is the types of individual expressions
> > > in a piece of code. If pointers to two types that are
> > > permitted to alias each other are in scope in the same
> > > block of code, the compiler can always simply not
> > > perform optimizations that would fail if they did
> > > alias each other.
> >
> > [...]
> > In other words, the compiler you described checks a
> > sufficient condition of aliasing violation, missing some
> > violations.
>
> No -- it's checking for sufficient conditions for the
> ABSENCE of aliasing violations; that's equivalent to NOT
> finding necessary conditions for an aliasing violation.
A sufficient condition is one that, when satisfied, makes
you certain that some statement is true. When the compiler
sees two incompatible pointers used in some code block, it
assumes that they do not alias, even though in fact they
modify the same memory area. This is an aliasing violation
amenable to aliasing optimisation. Since this does not
apply to the case when the pointers do actually not alias
(so nothing is volated), it is more correct to say that the
compiler checks for a sufficient condition that a pair of
pointers may be considered as not alisaing each other. Feel
free to ignore this terminologica nitpick, for we seem to
understand each other.
> > #include <stdlib.h>
> > #include <stdio.h>
> >
> > void* vP;
> > void bye( void )
> > { int i = *(int*)vP; /* this should be UB */
> > printf("i = %i\n", i);
> > }
> >
> > int main(int argc, char** argv)
> > { vP = malloc( sizeof( double ) );
> > *(double*)vP = 11.11;
> > /* ... */
> > atexit( &bye );
> > }
>
> Since I can see that this code violates aliasing rules, a
> sufficiently sophisticated compiler could do so as well.
> However, it's not clear to me what optimization
> opportunities it would miss by failing to identify that
> fact. It might help me to understand your point if you
> could identify such an opportunity. How would the
> optimizaed version of the code differ from the unoptimized
> version?
For example, the optimised version might desist from
generating any machine code for this line:
int i = *(int*)vP;
and supply the following printf() with an arbitrary hard-
code value -- UB in action!
> > Is it possible to implement a compiler that would be
> > able make a program that terminated upon each and every
> > effective type mismatch according to the letter of the
> > Standard?
>
> I believe it can be shown that identifying every effective
> type mismatch with no false positives or false negatives
> would be equivalent to solving the halting problem. The
> basic approach to this proof is to have execution of one
> of the two statements that makes it a mismatch depend upon
> whether or not a given piece of code halts.
I am sure it is true of detecting UB at compile time, but
surely not at run-time, i.e. during the execution of the
compiled program?
> > Terminating with a run-time error in case of UB is a
> > good idea as a compiler option.
>
> Many of the things that qualify as UB do so, precisely
> because it is unduly difficult to identify all possible
> cases where they come up. It is quite common for
> identifying such cases with no false positives and no
> false negatives, to be equivalent to solving the halting
> problem.
What sort of UB cannot be deteced at run-time?
> The usual way that UB is used is NOT to explicitly
> identify occurrences. Instead, the compiler sets up
> conditions for performing a given optimization. Those
> conditions are chosen so that any code that meets those
> conditions, but would be broken by the optimization, must
> have undefined behavior.
Well, so far I fail to see why you can't simultaneously
optimise and detect UB at run-time.
> void replace_match_with_0(size_t n, int *x, int *y)
> {
> for(size_t i = 0; i<n; i++)
> if(x[i] == (int)*y)
> x[i] = 0;
> }
> It might seem that this code can be optimized by
> evaluating *y only once, prior to the start of the loop,
> rather than repeatedly evaluating it during each pass
> through the loop. However, if x[i], for some value of i
> from 0 to n-1, refers to the same object as *y, then that
> optimization would be invalid. Such code has well-defined
> behavior, which causes the value of *y to change from
> whatever it was originally to 0, as soon as the loop
> executes for that value of i, and that changed value of *y
> would be used for all subsequent passes through the loop.
> That optimization would incorrectly continue using the
> original value of *y instead of the new one, and is
> therefore not allowed.
The (type-based) sufficient condition that the pointers can
be considered as not aliasing each other is not met.
> If, on the other hand, y were changed to "short *y", then
> the optimization would be perfectly valid, because it
> would have undefined behavior if *y aliased x[i].
In other words, the pointers can be considered as not
aliasing each other, although they may in fact point to the
same location in memory.
> That undefined behavior would take the form of having the
> change to the value of *y go unnoticed. Notice that
> compiler doesn't have any need to determine whether or not
> the behavior is undefined. It uses only the fact that *y
> has a type that cannot be used to alias x[i], to determine
> that the optimization is valid.
Yes: a simple sufficient conditon.
> > But *iP occupies the whole allocated region because I
> > passed sizeof(int) to malloc.
>
> My apologies - I hadn't noticed that you were allocating
> only a single int object. "The whole region" and "only
> *iP" refer to same thing, so we're actually in agreement,
> but I would have chosen different wording if I'd noticed.
Do feel free to correct my terminology.
> > In other words, upon writing through int*, we had the
> > following effective type for our 4-byte allocated
> > object:
> > 1 2 3 4
> > int int int int
> >
> > After modifying the latter two bytes through short* it
> > became:
> > 1 2 3 4
> > N/A N/A short short
> >
> > Looks pretty non-trivial to follow in an implementation
> > that takes the Standard literally... Using sufficient
> > conditions of effective type mimatch instead of an exact
> > criterium is a relaxation that prevents the compiler
> > from catching all isntances of UB.
>
> You're thinking about UB incorrectly. A compiler is not
> obligated to catch all instances of UB,->
I understand that, and think that run-time detection of all
UB (it is impossible at compile-time) would be a good option
for the complier. A test with full code coverage will then
help to eliminate the majority of UB in a program.
For the sake of curiosity and completeness, could you answer
my question about the int/short example above: did I
correctly deduce the final effective type of the allocated
object?
> -> which is good, because it's provably impossible to
> catch all such instances.
Impossible through static analysis at compile-time, but I
think possible at run-time.
> That fact, in turn, is part of the reason why many things
> have undefined behavior rather than being constraint
> violations: If an implementation is supposed to positively
> identify all occurrences of a given problem, and to never
> falsely identify the problem, the problem is usually
> tagged as a constraint violation, not as UB.
I think the reason is that detecting UB at run-time is
possible but hard and makes the program slower by executing
intrumental code of which the only purpose is the detection
of UB.
> The proper way to make use of the concept of UB is
> outlined in my discussion of replace_match_with_0() above.
Which is: use optimisation if the behavior without UB is
unaffected.
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | jameskuyper@alumni.caltech.edu |
|---|---|
| Date | 2018-11-21 15:50 -0800 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <64f78acb-7de9-4eb2-9ec9-eb0efde61481@googlegroups.com> |
| In reply to | #138190 |
On Wednesday, November 21, 2018 at 5:47:38 PM UTC-5, Anton Shepelev wrote:
...
> > Note that it is ONLY the object written to that acquires
> > that effective type. Higher level objects that happen to
> > contain the object written to don't acquire an effective
> > time just because a sub-object did.
>
> That is difficult. Writing to an `int' field of a struct
> through a `short' pointer breaks the effective type of the
> field, but keeps the effectvie type of the whole struct?
I didn't discuss that case, but I believe that such a write would cause the memory to lose the struct type as it's effective type.
> Remember my earlier example of overwriting the upper two
> bytes of a (4-byte) int through a pointer to short (assumed
> two bytes wide) -- you said this access broke the effective
> type of the whole int object -- a contradition?
No, I would reach the same conclusion in both cases.
> > =To a considerable extent, the fact that you're allowed to
> > take advantage of this fact to give different pieces of a
> > block different effective types, is due primarily to the
> > lack of a prohibition on doing so. It's pretty hard to
> > cite the text that fails to prohibit it - think about it.
>
> Did you mean "to cite the text that prohibits it"?
No, I meant precisely what I said. If the standard prohibited such code, it would be easy to cite the text containing the prohibition. It's precisely the fact that the standard fails to prohibit it, that makes it difficult to cite the text where it fails to do so. You can guess which section the prohibition would have been in, if it had existed, and then point to that section and say "see, it's not there". However, that's a very weak argument, because the prohibition might, in fact, exist, and just be located in a different section than the one you expected it to be in.
...
> > > #include <stdlib.h>
> > > #include <stdio.h>
> > >
> > > void* vP;
> > > void bye( void )
> > > { int i = *(int*)vP; /* this should be UB */
> > > printf("i = %i\n", i);
> > > }
> > >
> > > int main(int argc, char** argv)
> > > { vP = malloc( sizeof( double ) );
> > > *(double*)vP = 11.11;
> > > /* ... */
> > > atexit( &bye );
> > > }
> >
> > Since I can see that this code violates aliasing rules, a
> > sufficiently sophisticated compiler could do so as well.
> > However, it's not clear to me what optimization
> > opportunities it would miss by failing to identify that
> > fact. It might help me to understand your point if you
> > could identify such an opportunity. How would the
> > optimizaed version of the code differ from the unoptimized
> > version?
>
> For example, the optimised version might desist from
> generating any machine code for this line:
>
> int i = *(int*)vP;
>
> and supply the following printf() with an arbitrary hard-
> code value -- UB in action!
To what benefit? All real-life optimizations are intended to make well-formed code work better in some way - usually by making it faster; that they cause problems for ill-formed code is just an unintended side effect. It's a permissible side-effect, since the code is ill-formed, but causing such problems is not the purpose of the optimization. What is the well-formed code that would be improved by such an optimization?
> > > Is it possible to implement a compiler that would be
> > > able make a program that terminated upon each and every
> > > effective type mismatch according to the letter of the
> > > Standard?
> >
> > I believe it can be shown that identifying every effective
> > type mismatch with no false positives or false negatives
> > would be equivalent to solving the halting problem. The
> > basic approach to this proof is to have execution of one
> > of the two statements that makes it a mismatch depend upon
> > whether or not a given piece of code halts.
>
> I am sure it is true of detecting UB at compile time, but
> surely not at run-time, i.e. during the execution of the
> compiled program?
I suppose that would be possible, but very expensive. For example, in the case of aliasing violations, detecting it at run-time would require precisely the measure that you mentioned earlier: keeping track somewhere of the current effective type of every piece of memory. That would tend to make all memory accesses very slow.
...
> > Many of the things that qualify as UB do so, precisely
> > because it is unduly difficult to identify all possible
> > cases where they come up. It is quite common for
> > identifying such cases with no false positives and no
> > false negatives, to be equivalent to solving the halting
> > problem.
>
> What sort of UB cannot be deteced at run-time?
Sorry - I missed the "run-time" specification. Writing my response took a long time, and I was running short of time, so I didn't pay as close attention as I should have.
I've seen so many people advocate compile-time detection of UB that I just assumed that's what you were doing. For most cases of UB that I can think of off-hand, there are incredibly inefficient but feasible ways of detecting it at run time.
> > The usual way that UB is used is NOT to explicitly
> > identify occurrences. Instead, the compiler sets up
> > conditions for performing a given optimization. Those
> > conditions are chosen so that any code that meets those
> > conditions, but would be broken by the optimization, must
> > have undefined behavior.
>
> Well, so far I fail to see why you can't simultaneously
> optimise and detect UB at run-time.
You certainly could. In general, I'd expect you to lose far more time detecting the UB than you'd save with your optimizations, but if run-time detection of UB is your priority, the optimizations would help to reduce the cost.
> > void replace_match_with_0(size_t n, int *x, int *y)
> > {
> > for(size_t i = 0; i<n; i++)
> > if(x[i] == (int)*y)
> > x[i] = 0;
> > }
> > It might seem that this code can be optimized by
> > evaluating *y only once, prior to the start of the loop,
> > rather than repeatedly evaluating it during each pass
> > through the loop. However, if x[i], for some value of i
> > from 0 to n-1, refers to the same object as *y, then that
> > optimization would be invalid. Such code has well-defined
> > behavior, which causes the value of *y to change from
> > whatever it was originally to 0, as soon as the loop
> > executes for that value of i, and that changed value of *y
> > would be used for all subsequent passes through the loop.
> > That optimization would incorrectly continue using the
> > original value of *y instead of the new one, and is
> > therefore not allowed.
>
> The (type-based) sufficient condition that the pointers can
> be considered as not aliasing each other is not met.
Correct - this function doesn't involve aliasing violations. I include it only for comparison with the modified version where aliasing violations are possible:
> > If, on the other hand, y were changed to "short *y", then
> > the optimization would be perfectly valid, because it
> > would have undefined behavior if *y aliased x[i].
>
> In other words, the pointers can be considered as not
> aliasing each other, although they may in fact point to the
> same location in memory.
Correct. if they do alias, the standard imposes no requirements on the behavior of such code, so the fact that such an optimization is likely to have unintended consequences isn't a conformance problem.
...
> > My apologies - I hadn't noticed that you were allocating
> > only a single int object. "The whole region" and "only
> > *iP" refer to same thing, so we're actually in agreement,
> > but I would have chosen different wording if I'd noticed.
>
> Do feel free to correct my terminology.
It was my wording I would have corrected, if I'd read your message properly. Your terminology was fine.
> > > In other words, upon writing through int*, we had the
> > > following effective type for our 4-byte allocated
> > > object:
> > > 1 2 3 4
> > > int int int int
> > >
> > > After modifying the latter two bytes through short* it
> > > became:
> > > 1 2 3 4
> > > N/A N/A short short
...
> For the sake of curiosity and completeness, could you answer
> my question about the int/short example above: did I
> correctly deduce the final effective type of the allocated
> object?
As I understand it, yes. I'm a pretty good source of information on such issues, but not authoritative, and most certainly not infallible.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2018-11-24 19:37 +0300 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <20181124193738.df8fa078c3e1fba7e6485575@gmail.com> |
| In reply to | #138191 |
James Kuyper to Anton Shepelev:
> > James Kuyper:
> >
> > > To a considerable extent, the fact that you're allowed
> > > to take advantage of this fact to give different
> > > pieces of a block different effective types, is due
> > > primarily to the lack of a prohibition on doing so.
> > > It's pretty hard to cite the text that fails to
> > > prohibit it -- think about it.
> >
> > Did you mean "to cite the text that prohibits it"?
>
> No, I meant precisely what I said. If the standard
> prohibited such code, it would be easy to cite the text
> containing the prohibition. It's precisely the fact that
> the standard fails to prohibit it, that makes it difficult
> to cite the text where it fails to do so. You can guess
> which section the prohibition would have been in, if it
> had existed, and then point to that section and say "see,
> it's not there". However, that's a very weak argument,
> because the prohibition might, in fact, exist, and just be
> located in a different section than the one you expected
> it to be in.
This is the kind of negative statement that is hard to
prove. The Standard could be more clear in describing the
properties of objects.
> > #include <stdlib.h>
> > #include <stdio.h>
> >
> > void* vP;
> > void bye( void )
> > { int i = *(int*)vP; /* this should be UB */
> > printf("i = %i\n", i);
> > }
> >
> > int main(int argc, char** argv)
> > { vP = malloc( sizeof( double ) );
> > *(double*)vP = 11.11;
> > /* ... */
> > atexit( &bye );
> > }
> > For example, the optimised version might desist from
> > generating any machine code for this line:
> >
> > int i = *(int*)vP;
> >
> > and supply the following printf() with an arbitrary
> > hard- code value -- UB in action!
>
> To what benefit? All real-life optimizations are intended
> to make well-formed code work better in some
> way -- usually by making it faster; that they cause
> problems for ill-formed code is just an unintended side
> effect. It's a permissible side-effect, since the code is
> ill-formed, but causing such problems is not the purpose
> of the optimization. What is the well-formed code that
> would be improved by such an optimization?
None I think, you are right.
> > I am sure it is true of detecting UB at compile time,
> > but surely not at run-time, i.e. during the execution of
> > the compiled program?
>
> I suppose that would be possible, but very expensive. For
> example, in the case of aliasing violations, detecting it
> at run-time would require precisely the measure that you
> mentioned earlier: keeping track somewhere of the current
> effective type of every piece of memory. That would tend
> to make all memory accesses very slow.
This could be used during testing and disabled in release
mode.
> Sorry -- I missed the "run-time" specification. Writing my
> response took a long time, and I was running short of
> time, so I didn't pay as close attention as I should have.
Thanks for the time.
> I've seen so many people advocate compile-time detection
> of UB that I just assumed that's what you were doing.
I too am all for compile-time detection of UB, but
unfortunately only a small portion of UB is amenable to it.
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2018-11-21 21:22 +0000 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <8736ruceht.fsf@bsb.me.uk> |
| In reply to | #138179 |
Anton Shepelev <anton.txt@g{oogle}mail.com> writes:
> Thanks you very much for the answers, James.
>
>>>Is it correct that malloc creates a single allocated
>>>object?
>>
>>Yes.
>
> But you say below that this allcoated object may comprise
> many smaller allocated objects, even in a hierarchical
> manner, as would seem to be the case with a nested struct.
> So malloc can be seen as returning as many objects as there
> are junctures of a sequence of n elements into non-empty
> contagious regions. I can't calculate it right now, but for
> n=2 it is 2: 1) a single two-byte region and 2) two one-byte
> regions. It may be nitpicking, but I am trying to
> understand the letter of the Standard.
Yes:
3.15
object
region of data storage in the execution environment, the contents of
which can represent values
NOTE When referenced, an object may be interpreted as having a
particular type; see 6.3.2.1.
The interpretation of the type comes from the expression used to access
a region of storage:
6.3.2.1 Lvalues, arrays, and function designators
An lvalue is an expression (with an object type other than void) that
potentially designates an object; if an lvalue does not designate an
object when it is evaluated, the behavior is undefined. When an object
is said to have a particular type, the type is specified by the lvalue
used to designate the object.
So an object is just some memory. It has no type of its own. The type
is associated with the expression used to access the storage.
Objects can (and more do) have an effective type. This is most often
simply the declared type of the object.
The key thing is that objects don't have a type but they usually have an
effective type that limits how they can be accessed. It's expressions
that have a type in C, not objects.
>>>How many effective types can a single allocated object
>>>have? I think it is one or zero.
It can change over time but it is never more than 1.
>>Different parts of an allocated object can have different
>>types.
>
> I don't see how the Standard even hints at this important
> property of objects, except very indirecly.
It's in 6.3.2.1 quoted above. An object (some storage) only has a type
in so far as some lvalue is used to access it.
Now this very general permission is curtailed in all sorts of ways. The
most significant being the effective type rules. This new concept is
used to limit how a program can access storage.
Here's a commentary on the key paragraph, 6.5 para 6:
The effective type of an object for an access to its stored value
is the declared type of the object, if any.
So for
int i = 42;
the `sizeof i` bytes that make up the int have effective type int. The
expresson `i` accesses that object via an lvalue of type int. The
effective type of the object and the type of the accessing expression
are the same. That's permitted.
After
char *cp = (void *)&i;
we can access one of the sub-objects in `i` using the lvalue `*cp`.
This accesses a char object that is part of the int. This access is
specifically permitted in the next paragraph since an lavlue expression
of type char can be used to access an object with any effective type.
That char object has, I believe, no declared type but that's one part I
am not 100% sure of. It does not matter to this example because the
access is permitted not matter what effective type that single but might
have.
Paragraph 6 continues by laying how you determine the effective type of
objects that have no declared type what are, most importantly, allocated
storage.
If a value is stored into an object having no declared type through an
lvalue having a type that is not a character type, then 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.
So you can simply set the effective type (other that char) by modifying
the storage, so
int *ip = malloc(sizeof (int) + sizeof (float));
*ip = 42;
gives the first few bytes of the allocated storage the effective type
int. And
float *fp = (void *)(ip + 1);
*fp = 99;
gives the rest the effective type float. Now this access might be
undefined due to alignment, but that's not the point here. The point
here is that you can paint the storage with any type you like just by
using it.
Paragraph 6 continues by explaining the effect of the memory copying
functions:
If a value is copied into an object having no declared type using
memcpy or memmove, or is copied as an array of character type, then
the effective type of the modified object for that access and for
subsequent accesses that do not modify the value is the effective type
of the object from which the value is copied, if it has one.
And then a catch-all final remark:
For all other accesses to an object having no declared type, the
effective type of the object is simply the type of the lvalue used for
the access.
It's paragraph 7 that allows `*cp` and which disallows `*sp` after
int i = 42;
char *cp = (void *)&i;
short *sp = (void *)&i;
because access through an lvalue expression of "a character type" is
always allowed, but whatever the effective type if the initial
sizeof(short) bytes of i is, it is not "a type compatible with the
effective type of the object".
I think from what you go on to write, you have got the main ideas
already so I apologise if this is too much or too basic, but others
might find it useful.
<snip>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2018-11-21 01:15 +0000 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <87efbfdyed.fsf@bsb.me.uk> |
| In reply to | #138147 |
Anton Shepelev <anton.txt@g{oogle}mail.com> writes:
> Ben Bacarisse:
<snip>
>>I have posted code. If it's wrong, please tell me why. It
>>does fairly standard things.
>
> Thanks for the code, Ben. Below is my understanding why it
> is wrong:
>
>>struct da_meta_data {
>> size_t capacity, length, element_size;
>> max_align_t data[];
>>};
>>
>>
>>static struct da_meta_data *da_alloc(void *a, size_t cap, size_t size)
>>{
>> if (a) a = (struct da_meta_data *)a - 1;
>> struct da_meta_data *new = realloc(a, sizeof *new + cap * size);
>> if (new)
>> new->capacity = cap;
>> else free(a);
>> return new;
>>}
>
> So, da_alloc will set the effective type to
> struct da_meta_data.
I don't think so. There is only one modifying access to an object here,
and it sets the effective type of the first size_t to be size_t.
I'd prefer to start with this and work it through before moving on to
the other points. Is that OK?
<snip other points of contention for now>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2018-11-19 15:06 +0000 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <87y39pgl8q.fsf@bsb.me.uk> |
| In reply to | #138112 |
Anton Shepelev <anton.txt@g{oogle}mail.com> writes:
> Ben Bacarisse to Anton Sheplev:
>
>>Only the size element might be a problem -- the others are
>>guaranteed to be aligned. And below, I argue that all
>>three should be of the same type anyway and hence they will
>>all be aligned.
>
> What problem can there be if I access all three through a
> char*? My only consideration about their alignment was that
> of performance. Is it the problem you refer to?
Yes. Only the size (in the header) might be misaligned, so only the
size needs special access.
The data are also possibly miss-aligned. If you want to use old C, you
will probably have to say what assumptions you are prepared to make.
>>Alignment might be an issue for the data, though. From the
>>point of view of portable access the optimal layout is
>>
>> +----------+----------+----------+---+--- ------ --+
>> | length | capacity | size |...| ... data ... |
>> +----------+----------+----------+---+--- ------ --+
>> ^
>> | padding
>>
>>where a possibly zero-sized gap is left after the three
>>equal-sized meta-data items so as to re-gain maximal
>>alignment.
>
> I hadn't thought of this. Is it right that a pointer to int
> cannot contain an arbitrary byte address and work correctly?
> In other words, can I access an allocated object throught a
> pointer to int from an arbitrary byte offset?
Not in 100% portable code.
>>The simplest way to achieve this in modern C define a
>>struct for the header:
>>
>> struct meta_data {
>> int length;
>> int capacity;
>> size_t size;
>> max_align_t data[];
>> };
>
> Do you propose to use this header for the calculation of
> offsets or for the actual access to the array's data and
> metadata?
For the access. Why would you not use the C features that are designed
for this purpose? Calculating offsets and converting pointers looks so
last century!
<snip>
>>>union intalias
>>>{ char cdata[sizeof(int)];
>>> int idata;
>>>};
>>
>>I don't see the point of this union. The effective type of
>>the allocated storage is determined by the first modifying
>>access, so if you store an int at start, that will be the
>>effective type of that part of the storage.
>
> As far I as have understood, the effective type is
> determined by the *last* non-character modyfying access,
> which is why I have gone to great length to access metadata
> exclusively through a char*. I have found no other way to
> access metadata without breaking the rules of aliasing.
But why not access it as what it is? It's int (or size_t) data so use
an lvalue expression of that type.
<snip>
>>>#define SHIFT(A,S) (((char*)A) - (S))
>>>#define OFFSET ( sizeof(size_t) + 2*sizeof(int))
>>>#define ORIGIN(A) SHIFT(A, OFFSET)
>>>#define GETLEN(A) getint (ORIGIN(A))
>>>#define GETSIZE(A) getsize(SHIFT((A),sizeof(size_t)))
>>>#define GETCAP(A) getint (SHIFT((A),sizeof(size_t)+sizeof(int)))
>>>#define SETLEN(A,L) setint (ORIGIN(A),(L))
>>>#define SETSIZE(A,S) setsize(SHIFT((A),sizeof(size_t)),S)
>>>#define SETCAP(A,C) setint (SHIFT((A),sizeof(size_t)+sizeof(int)),(C))
>>
>>I'd simplify all this with a struct for the header.
>
> I am sure the rules of aliasing allow it.
Yes, so am I. I may not follow every detail, but if you allocate a
struct (even with some extra data added on) you can certainly access the
members of such a struct at the start of the allocated storage.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | mark.bluemel@gmail.com |
|---|---|
| Date | 2018-11-19 08:05 -0800 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <3d1737b8-156d-49fd-92f2-d7b0872f5ef8@googlegroups.com> |
| In reply to | #138112 |
On Monday, 19 November 2018 12:37:43 UTC, Anton Shepelev wrote: > Ben Bacarisse to Anton Sheplev: > > >Only the size element might be a problem -- the others are > >guaranteed to be aligned. And below, I argue that all > >three should be of the same type anyway and hence they will > >all be aligned. > > What problem can there be if I access all three through a > char*? My only consideration about their alignment was that > of performance. Is it the problem you refer to? > > >Alignment might be an issue for the data, though. From the > >point of view of portable access the optimal layout is > > > > +----------+----------+----------+---+--- ------ --+ > > | length | capacity | size |...| ... data ... | > > +----------+----------+----------+---+--- ------ --+ > > ^ > > | padding > > > >where a possibly zero-sized gap is left after the three > >equal-sized meta-data items so as to re-gain maximal > >alignment. > > I hadn't thought of this. Is it right that a pointer to int > cannot contain an arbitrary byte address and work correctly? > In other words, can I access an allocated object throught a > pointer to int from an arbitrary byte offset? I think you could hit SIGBUS - see <https://en.wikipedia.org/wiki/Bus_error#Unaligned_access>
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2018-11-19 16:49 +0000 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <fQBID.909316$LK2.340468@fx36.iad> |
| In reply to | #138118 |
mark.bluemel@gmail.com writes: >On Monday, 19 November 2018 12:37:43 UTC, Anton Shepelev wrote: >> Ben Bacarisse to Anton Sheplev: >> >> >Only the size element might be a problem -- the others are >> >guaranteed to be aligned. And below, I argue that all >> >three should be of the same type anyway and hence they will >> >all be aligned. >> >> What problem can there be if I access all three through a >> char*? My only consideration about their alignment was that >> of performance. Is it the problem you refer to? >> >> >Alignment might be an issue for the data, though. From the >> >point of view of portable access the optimal layout is >> > >> > +----------+----------+----------+---+--- ------ --+ >> > | length | capacity | size |...| ... data ... | >> > +----------+----------+----------+---+--- ------ --+ >> > ^ >> > | padding >> > >> >where a possibly zero-sized gap is left after the three >> >equal-sized meta-data items so as to re-gain maximal >> >alignment. >> >> I hadn't thought of this. Is it right that a pointer to int >> cannot contain an arbitrary byte address and work correctly? >> In other words, can I access an allocated object throught a >> pointer to int from an arbitrary byte offset? > >I think you could hit SIGBUS - see ><https://en.wikipedia.org/wiki/Bus_error#Unaligned_access> That's entirely dependent upon the execution environment. x86 generally allows unaligned accesses to cacheable virtual addresses unless the AF flag is set (which will cause an alignment fault instead). Unaligned accessess are generally disallowed for uncachable memory (e.g. as programmed in the MTRRs). ARM64 can be programmed to either allow or deny unaligned accesses to virtual addresses with a non-device memory type. Unaligned accesses are never allowed to virtual addresses that map to device-type physical addresses. Alpha didn't allow unaligned accesses at all.
[toc] | [prev] | [next] | [standalone]
| From | jameskuyper@alumni.caltech.edu |
|---|---|
| Date | 2018-11-19 10:35 -0800 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <4654f0ff-b45f-4e4d-96b8-144fa834586b@googlegroups.com> |
| In reply to | #138112 |
On Monday, November 19, 2018 at 7:37:43 AM UTC-5, Anton Shepelev wrote: ... > I hadn't thought of this. Is it right that a pointer to int > cannot contain an arbitrary byte address and work correctly? > In other words, can I access an allocated object throught a > pointer to int from an arbitrary byte offset? It would be more accurate to say that there's no way write code with defined behavior for which that behavior is to create a pointer to int with an arbitrary byte address. On platforms where it's possible, you can write (int*)0x12345678, but here's what the C standard says about such conversions: "Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation 67)" (6.3.2.3p6). "as specified previously" corresponds to the exceptions this rule. However, "arbitrary byte offsets", by definition, includes offsets that aren't exceptions to 6.3.2.3p6. Alternatively, you could use (int*)(buffer+offset), where c is a character array. Here's what the standard has to say about that conversion: "If the resulting pointer is not correctly aligned68) for the referenced type, the behavior is undefined." (6.3.2.3p7). Once any of the bad things mentioned in either of those paragraphs goes wrong, you're potentially in trouble with any use you make of the value resulting from the conversion, so in principle you're right about that. However, the important point is that it's the conversion itself that's problematic.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2018-11-20 00:45 +0300 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <20181120004546.f7e51c9afe2dc3146cd4b6f1@gmail.com> |
| In reply to | #138128 |
James Kuyper: > It would be more accurate to say that there's no way write > code with defined behavior for which that behavior is to > create a pointer to int with an arbitrary byte address. On > platforms where it's possible, you can write > (int*)0x12345678, but here's what the C standard says > about such conversions: "Except as previously specified, > the result is implementation-defined, might not be > correctly aligned, might not point to an entity of the > referenced type, and might be a trap representation 67)" > (6.3.2.3p6). "as specified previously" corresponds to the > exceptions this rule. However, "arbitrary byte offsets", > by definition, includes offsets that aren't exceptions to > 6.3.2.3p6. > > Alternatively, you could use (int*)(buffer+offset), where > c is a character array. Here's what the standard has to > say about that conversion: "If the resulting pointer is > not correctly aligned68) for the referenced type, the > behavior is undefined." (6.3.2.3p7). That answers my question about the meaning of a pointer correctly alinged for a type. It is simply a pointer storing a byte address that is a multiple of the type's alignment, right? > Once any of the bad things mentioned in either of those > paragraphs goes wrong, you're potentially in trouble with > any use you make of the value resulting from the > conversion, so in principle you're right about that. > However, the important point is that it's the conversion > itself that's problematic. So it looks from the Standard's perspective, thanks. -- () ascii ribbon campaign -- against html e-mail /\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | jameskuyper@alumni.caltech.edu |
|---|---|
| Date | 2018-11-19 14:24 -0800 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <274720c1-99ec-4f48-ad91-c8c1b0b87f23@googlegroups.com> |
| In reply to | #138134 |
On Monday, November 19, 2018 at 4:45:55 PM UTC-5, Anton Shepelev wrote: > James Kuyper: ... > > Alternatively, you could use (int*)(buffer+offset), where > > c is a character array. Here's what the standard has to > > say about that conversion: "If the resulting pointer is > > not correctly aligned68) for the referenced type, the > > behavior is undefined." (6.3.2.3p7). > > That answers my question about the meaning of a pointer > correctly alinged for a type. It is simply a pointer storing > a byte address that is a multiple of the type's alignment, > right? Correct.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@g{oogle}mail.com> |
|---|---|
| Date | 2018-11-20 15:05 +0300 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <20181120150538.057a3beae9aea05920bba5fc@g{oogle}mail.com> |
| In reply to | #138139 |
James Kuyper: >>That answers my question about the meaning of a pointer >>correctly alinged for a type. It is simply a pointer >>storing a byte address that is a multiple of the type's >>alignment, right? > >Correct. Thank you. Antoher problem is that the Standard does not seem to guarantee that the byte address is preservied in one-way pointer conversion, although in case of a successful hobbit-conversion (there and back again) it is. -- () ascii ribbon campaign - against html e-mail /\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2018-11-20 08:31 -0500 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <pt12bu$3rp$1@dont-email.me> |
| In reply to | #138149 |
On 11/20/18 07:05, Anton Shepelev wrote: > James Kuyper: > >>> That answers my question about the meaning of a pointer >>> correctly alinged for a type. It is simply a pointer >>> storing a byte address that is a multiple of the type's >>> alignment, right? >> >> Correct. > > Thank you. Antoher problem is that the Standard does not > seem to guarantee that the byte address is preservied in > one-way pointer conversion, ... In general, you're right - and I consider that a defect in the standard because it seems to be universally assumed that all pointer conversions that the standard allows result in a pointer to the same memory location - it would be nice if the standard actually said so. However, the standard does actually say it in one important case: "When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object."(6.3.2.3p7). A committee member once claimed to me that you could conclude from 6.3.2.3p7 that, for all permitted pointer conversions, (T*)p points at an object whose first byte is in the same location as the first byte of the object pointed at by p itself. I don't follow that logic, and asked him to support that claim, without getting a meaningful response. I suspect he was assuming that there was a rule for chained pointer conversions: if (T*)(U*) is permitted, then it is guaranteed to be equivalent to (T*). No such rule is stated anywhere in the standard. Conversion chains involving arithmetic types certainly don't obey (T)(U) being equivalent to (U).
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2018-11-20 20:02 -0500 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <Y82JD.862645$3L2.839482@fx44.iad> |
| In reply to | #138149 |
On 11/20/18 7:05 AM, Anton Shepelev wrote: > James Kuyper: > >>> That answers my question about the meaning of a pointer >>> correctly alinged for a type. It is simply a pointer >>> storing a byte address that is a multiple of the type's >>> alignment, right? >> >> Correct. > > Thank you. Antoher problem is that the Standard does not > seem to guarantee that the byte address is preservied in > one-way pointer conversion, although in case of a successful > hobbit-conversion (there and back again) it is. > There are pointer conversions that can loose information. In particular, for a machine where the fundamental address mode is NOT bytes, but something bigger, and void* and char* (and maybe some other small type) have a fundamental pointer + additional information to store which byte within the addressable word. In such a case, taking a char* pointer that did NOT start from something word aligned, and converting it into a word pointer (like int*) WILL normally lose the byte information, otherwise ALL pointers need that extra overhead. The original question mentioning 'byte address' had this error, on some machines pointers do not inherently have 'byte addresses' but word addresses, and you need special augmented pointers to handle byte addresses.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2018-11-21 22:47 +0300 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <20181121224726.4d5f9fdbe0a3d3912dc49c3a@gmail.com> |
| In reply to | #138166 |
Anton Shepelev: That answers my question about the meaning of a pointer correctly alinged for a type. It is simply a pointer storing a byte address that is a multiple of the type's alignment, right? James Kuyper: Correct. Anton Shepelev: Thank you. Antoher problem is that the Standard does not seem to guarantee that the byte address is preservied in one-way pointer conversion, although in case of a successful hobbit-conversion (there and back again) it is. Richard Damon: There are pointer conversions that can loose information. In particular, for a machine where the fundamental address mode is NOT bytes, but something bigger, and void* and char* (and maybe some other small type) have a fundamental pointer + additional information to store which byte within the addressable word. In such a case, taking a char* pointer that did NOT start from something word aligned, and converting it into a word pointer (like int*) WILL normally lose the byte information, otherwise ALL pointers need that extra overhead. I did not know about this architechture/implementation detail. Even on machines where the fundametal address mode *is* bytes, the compiler is free to do whatever it wants with such conversions because they are UB. Therefore, It is only through the courtesy of compiler writers that sometimes you can convert char* to int*, and dereference the latter with meaningful results. > The original question mentioning 'byte address' had this > error, on some machines pointers do not inherently have > 'byte addresses' but word addresses, and you need special > augmented pointers to handle byte addresses. A word address is a byte address, but not vice versa. The Standard implies that each pointer contains a byte address, even though it be a multiple of an integer greater than unity. -- Anton Shepelev
[toc] | [prev] | [next] | [standalone]
| From | jameskuyper@alumni.caltech.edu |
|---|---|
| Date | 2018-11-21 13:08 -0800 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <b8598fcf-7fb0-464b-a261-97d4fdd56d15@googlegroups.com> |
| In reply to | #138180 |
On Wednesday, November 21, 2018 at 2:47:36 PM UTC-5, Anton Shepelev wrote: ... > Richard Damon: > There are pointer conversions that can loose information. > In particular, for a machine where the fundamental > address mode is NOT bytes, but something bigger, and > void* and char* (and maybe some other small type) have a > fundamental pointer + additional information to store > which byte within the addressable word. In such a case, > taking a char* pointer that did NOT start from something > word aligned, and converting it into a word pointer (like > int*) WILL normally lose the byte information, otherwise > ALL pointers need that extra overhead. > > I did not know about this architechture/implementation > detail. Even on machines where the fundametal address mode > *is* bytes, the compiler is free to do whatever it wants > with such conversions because they are UB. Therefore, It is > only through the courtesy of compiler writers that sometimes > you can convert char* to int*, and dereference the latter > with meaningful results. Not quite. You can always convert a dereferencable int* to a char*, and then back to an int*. The resulting pointer is absolutely guaranteed to be just as dereferenceable as the original - you're not relying upon the courtesy of compiler writers to make that happen. There's other standard-guaranteed ways of obtaining a char* value that can be converted to derefereceable int*. For instance, a pointer to the first byte of struct object also points at the first byte of the first member of that struct object. If that member has type int, converting that char* to an int* also produces a dereferenceable pointer. The same is true of a pointer to the first byte of an array of int. Your job, as a developer, is to make sure that every char* you convert to an int* was the result of some such conversion. Do NOT write code which assumes that an arbitrary char* pointer can be converted to an int*.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2018-11-22 00:31 +0300 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <20181122003159.fdb81378a5823cb0b5f98d49@gmail.com> |
| In reply to | #138184 |
James Kuyper to Anton Shepelev: > > Richard Damon: > > > > > There are pointer conversions that can loose > > > information. In particular, for a machine where the > > > fundamental address mode is NOT bytes, but something > > > bigger, and void* and char* (and maybe some other > > > small type) have a fundamental pointer + additional > > > information to store which byte within the addressable > > > word. In such a case, taking a char* pointer that did > > > NOT start from something word aligned, and converting > > > it into a word pointer (like int*) WILL normally lose > > > the byte information, otherwise ALL pointers need that > > > extra overhead. > > > > I did not know about this architechture/implementation > > detail. Even on machines where the fundametal address > > mode *is* bytes, the compiler is free to do whatever it > > wants with such conversions because they are UB. > > Therefore, It is only through the courtesy of compiler > > writers that sometimes you can convert char* to int*, > > and dereference the latter with meaningful results. > > Not quite. You can always convert a dereferencable int* to > a char*, and then back to an int*. The resulting pointer > is absolutely guaranteed to be just as dereferenceable as > the original - you're not relying upon the courtesy of > compiler writers to make that happen. Thanks for the correction. I meant the situation that Richard described, where the char pointer cannot have been converted from an int pointer, but neglected to indicate it. -- () ascii ribbon campaign -- against html e-mail /\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2018-11-21 21:36 +0000 |
| Subject | Re: My dynamic arrays module [was:Re: Pointer conversion and alignment] |
| Message-ID | <87wop6aza2.fsf@bsb.me.uk> |
| In reply to | #138180 |
Anton Shepelev <anton.txt@gmail.com> writes:
Richard:
>> The original question mentioning 'byte address' had this
>> error, on some machines pointers do not inherently have
>> 'byte addresses' but word addresses, and you need special
>> augmented pointers to handle byte addresses.
>
> A word address is a byte address, but not vice versa. The
> Standard implies that each pointer contains a byte address,
> even though it be a multiple of an integer greater than
> unity.
No (though maybe it's an issue of wording). A word address may very
well not be a byte address, but if the machine has a C compiler, a word
address can always be /converted/ to a byte address. The reverse is not
always possible (at least in any useful way).
To take an example I know well
union {
unsigned int address;
int *ip;
char *cp;
} u;
int i;
u.ip = &i;
printf("%u ", u.address);
u.cp = (char *)&i;
printf("%u\n", u.address);
u.cp += 1;
printf("%u ", u.address);
u.ip = (int *)u.cp;
printf("%u\n", u.address);
might print
402 804 805 402
A word address converts to a bytes address by being shifted left, the
bottom bit indicating which byte is being addressed. The conversion
back is a right shift, losing the bottom bit.
--
Ben.
[toc] | [prev] | [next] | [standalone]
Page 5 of 7 — ← Prev page 1 2 3 4 [5] 6 7 Next page →
Back to top | Article view | comp.lang.c
csiph-web