* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 19:24 ` Mark Mitchell
@ 2007-09-09 19:42 ` Joe Buck
2007-09-09 19:56 ` Mark Mitchell
2007-09-09 19:51 ` Richard Guenther
2007-09-09 21:22 ` Gabriel Dos Reis
2 siblings, 1 reply; 57+ messages in thread
From: Joe Buck @ 2007-09-09 19:42 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Richard Guenther, Ross Smith, GCC Mailing List
On Sun, Sep 09, 2007 at 12:24:13PM -0700, Mark Mitchell wrote:
> The term "cannot alias" is not fully defined. It could mean "cannot
> have the same value as any other pointer of the same type". It could
> mean "cannot have the same value as any other pointer, when both
> pointers are cast to `void *'". It could mean, a la "restrict", that
> "no store through an expression based on this pointer can modify the
> value read from via any expression based on any other pointer".
>
> In the case of "malloc", and assuming that all of the machinery for
> malloc is hidden away in some piece of the program we're not talking
> about, all three definitions apply. Each pointer returned by malloc is
> an island unto itself; there's no conforming way to get there except by
> using the pointer just returned.
The key point is that the mechanism is hidden away. This might become
more of an issue with LTO, so the question is how to make such guarantees
make sense to an optimizer that can see the full program.
> For, operator new, the same is true -- but we're more often able to see
> the machinery for the allocator. For example:
>
> char pool[N];
> size_t next;
>
> /* Never mind that the return memory isn't properly aligned here;
> fixing the implementation is left to the reader. */
> void *operator new(size_t s) {
> void *p = pool + next;
> next += s;
> return p;
> }
>
> bool f() {
> char *c = new char;
> return (c == pool);
> }
>
> Now, I don't think we should allow the compiler to optimize the return
> statement in "f" to "return false"? If operator new has attribute
> malloc, then it may in fact do so -- even though the value returned
> might be "pool" itself.
The issue seems to be that the mechanism is exposed. The operator new
pointers don't alias each other (when used to store objects that fit
within the size argument), but they do have a relationship with "pool".
It seems that there needs to be some sort of protection boundary.
If there's no LTO, then it would suffice to treat the file implementing
operator new as a black-box module, perhaps exporting a "first_allocation"
function to do the c == pool check.
> This seems like a useful optimization to me, and I understand that it
> will work 99.99% of the time, and it's in the spirit of the standard --
> but how do we actually make it safe? If the attribute only applied to
> other values returned from the same function, then it would be safe --
> but less useful. Can we do better?
Maybe "pool", if exported, would have to be marked as aliasing the "new"
calls, possibly with some new attribute "malloc_implementation" or
something like that. Working out the details would be tricky: calling
a malloc-attributed function might change storage marked
"malloc_implementation", and a return value might alias an implementation
value, but two calls would not alias each other.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 19:42 ` Joe Buck
@ 2007-09-09 19:56 ` Mark Mitchell
2007-09-09 20:04 ` Richard Guenther
2007-09-10 12:18 ` Martin Jambor
0 siblings, 2 replies; 57+ messages in thread
From: Mark Mitchell @ 2007-09-09 19:56 UTC (permalink / raw)
To: Joe Buck; +Cc: Richard Guenther, Ross Smith, GCC Mailing List
Joe Buck wrote:
>> In the case of "malloc", and assuming that all of the machinery for
>> malloc is hidden away in some piece of the program we're not talking
>> about, all three definitions apply. Each pointer returned by malloc is
>> an island unto itself; there's no conforming way to get there except by
>> using the pointer just returned.
>
> The key point is that the mechanism is hidden away. This might become
> more of an issue with LTO, so the question is how to make such guarantees
> make sense to an optimizer that can see the full program.
Correct. The "malloc" attribute is only applicable to "malloc" because
we can't see how "malloc" is implemented.
>> This seems like a useful optimization to me, and I understand that it
>> will work 99.99% of the time, and it's in the spirit of the standard --
>> but how do we actually make it safe? If the attribute only applied to
>> other values returned from the same function, then it would be safe --
>> but less useful. Can we do better?
>
> Maybe "pool", if exported, would have to be marked as aliasing the "new"
> calls, possibly with some new attribute "malloc_implementation" or
> something like that.
It's worse than that:
char *pool;
void set_pool(char *p) { pool = p; }
void *operator new(size_t s) { // return stuff from pool. }
bool f() {
char *p = new char[1024];
set_pool (p);
char *i = new char;
return (p == i);
}
In other words, pointers from any part of the program can potentially be
"laundered" through set_pool and return via the new operator. I don't
see any way to make this fully safe, in general, without the limitation
I imposed: the no-aliasing guarantee only applies to the values returned
from the function called.
For a particular implementation of "operator new" (such as the one in
libstdc++), you can of course make it safe in the same way as "malloc";
hide the implementation somewhere the rest of the program can't see it
(modulo LTO). But, to declare it with the "malloc" attribute in the
headers seems dangerous, since we have no way of knowing if the user
replaced it, off in some file somewhere we don't know about, but in such
a way that pointers in our source code are being laundered back to us.
Perhaps we could have an <ext/i_promise_i_will_not_define_new> header,
which you can include if you aren't overriding the operator...
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 19:56 ` Mark Mitchell
@ 2007-09-09 20:04 ` Richard Guenther
2007-09-09 20:22 ` Mark Mitchell
2007-09-09 21:25 ` Gabriel Dos Reis
2007-09-10 12:18 ` Martin Jambor
1 sibling, 2 replies; 57+ messages in thread
From: Richard Guenther @ 2007-09-09 20:04 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Ross Smith, GCC Mailing List
On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
> Joe Buck wrote:
>
> >> In the case of "malloc", and assuming that all of the machinery for
> >> malloc is hidden away in some piece of the program we're not talking
> >> about, all three definitions apply. Each pointer returned by malloc is
> >> an island unto itself; there's no conforming way to get there except by
> >> using the pointer just returned.
> >
> > The key point is that the mechanism is hidden away. This might become
> > more of an issue with LTO, so the question is how to make such guarantees
> > make sense to an optimizer that can see the full program.
>
> Correct. The "malloc" attribute is only applicable to "malloc" because
> we can't see how "malloc" is implemented.
>
> >> This seems like a useful optimization to me, and I understand that it
> >> will work 99.99% of the time, and it's in the spirit of the standard --
> >> but how do we actually make it safe? If the attribute only applied to
> >> other values returned from the same function, then it would be safe --
> >> but less useful. Can we do better?
> >
> > Maybe "pool", if exported, would have to be marked as aliasing the "new"
> > calls, possibly with some new attribute "malloc_implementation" or
> > something like that.
>
> It's worse than that:
>
> char *pool;
> void set_pool(char *p) { pool = p; }
> void *operator new(size_t s) { // return stuff from pool. }
>
> bool f() {
> char *p = new char[1024];
> set_pool (p);
> char *i = new char;
> return (p == i);
> }
>
> In other words, pointers from any part of the program can potentially be
> "laundered" through set_pool and return via the new operator. I don't
> see any way to make this fully safe, in general, without the limitation
> I imposed: the no-aliasing guarantee only applies to the values returned
> from the function called.
But in this case an access to *i through *p is invalid. [I suppose both
new calls are actually different implementations here] Each new
call starts lifetime of a new object, the previous object lifetime is
terminated. Even comparing both pointers here for this reason
would lead to undefined behavior.
I know it's easy to play games to trick optimizers into doing something,
but creating a not undefined testcase that goes wrong is hard ;) At
least iff you remember to transform 'malloc' attributes to a dynamic type
change if you inline a malloc.
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:04 ` Richard Guenther
@ 2007-09-09 20:22 ` Mark Mitchell
2007-09-09 20:27 ` Richard Guenther
2007-09-09 21:25 ` Gabriel Dos Reis
1 sibling, 1 reply; 57+ messages in thread
From: Mark Mitchell @ 2007-09-09 20:22 UTC (permalink / raw)
To: Richard Guenther; +Cc: Joe Buck, Ross Smith, GCC Mailing List
Richard Guenther wrote:
>> char *pool;
>> void set_pool(char *p) { pool = p; }
>> void *operator new(size_t s) { // return stuff from pool. }
>>
>> bool f() {
>> char *p = new char[1024];
>> set_pool (p);
>> char *i = new char;
>> return (p == i);
>> }
>>
>> In other words, pointers from any part of the program can potentially be
>> "laundered" through set_pool and return via the new operator. I don't
>> see any way to make this fully safe, in general, without the limitation
>> I imposed: the no-aliasing guarantee only applies to the values returned
>> from the function called.
>
> But in this case an access to *i through *p is invalid. [I suppose both
> new calls are actually different implementations here] Each new
> call starts lifetime of a new object, the previous object lifetime is
> terminated. Even comparing both pointers here for this reason
> would lead to undefined behavior.
I don't think there's necessarily agreement about that; you're into
what-is-an-object land here...
In any case, using new to allocate from a pool doesn't invalidate the
pointer to the pool itself. Even if you think reads/writes through *p
are undefined, do you think that comparing addresses is undefined? If
so, how can you still talk about "pool" at all, even in the
implementation of "new" and "delete" themselves, after the first
allocation?
If comparing addresses is allowed, it's weird to think that:
if (p == i)
*p = '\0';
is invalid, while:
if (p == i)
*i = '\0';
is valid, but I suppose it's possible.
Do we have any way to guarantee that aliasing information will not be
used when analyzing pointer comparisons, but only when analyzing stores
through pointers?
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:22 ` Mark Mitchell
@ 2007-09-09 20:27 ` Richard Guenther
2007-09-09 20:32 ` Mark Mitchell
2007-09-09 21:27 ` Gabriel Dos Reis
0 siblings, 2 replies; 57+ messages in thread
From: Richard Guenther @ 2007-09-09 20:27 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Ross Smith, GCC Mailing List
On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
> Richard Guenther wrote:
>
> >> char *pool;
> >> void set_pool(char *p) { pool = p; }
> >> void *operator new(size_t s) { // return stuff from pool. }
> >>
> >> bool f() {
> >> char *p = new char[1024];
> >> set_pool (p);
> >> char *i = new char;
> >> return (p == i);
> >> }
> >>
> >> In other words, pointers from any part of the program can potentially be
> >> "laundered" through set_pool and return via the new operator. I don't
> >> see any way to make this fully safe, in general, without the limitation
> >> I imposed: the no-aliasing guarantee only applies to the values returned
> >> from the function called.
> >
> > But in this case an access to *i through *p is invalid. [I suppose both
> > new calls are actually different implementations here] Each new
> > call starts lifetime of a new object, the previous object lifetime is
> > terminated. Even comparing both pointers here for this reason
> > would lead to undefined behavior.
>
> I don't think there's necessarily agreement about that; you're into
> what-is-an-object land here...
>
> In any case, using new to allocate from a pool doesn't invalidate the
> pointer to the pool itself. Even if you think reads/writes through *p
> are undefined, do you think that comparing addresses is undefined? If
> so, how can you still talk about "pool" at all, even in the
> implementation of "new" and "delete" themselves, after the first
> allocation?
>
> If comparing addresses is allowed, it's weird to think that:
>
> if (p == i)
> *p = '\0';
>
> is invalid, while:
>
> if (p == i)
> *i = '\0';
>
> is valid, but I suppose it's possible.
>
> Do we have any way to guarantee that aliasing information will not be
> used when analyzing pointer comparisons, but only when analyzing stores
> through pointers?
I don't know of any place we would use such information. At least
int *p = new int;
int *q = new int;
if (p == q)
cannot be simplified as both pointers may be NULL?
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:27 ` Richard Guenther
@ 2007-09-09 20:32 ` Mark Mitchell
2007-09-09 20:38 ` Richard Guenther
2007-09-09 21:27 ` Gabriel Dos Reis
1 sibling, 1 reply; 57+ messages in thread
From: Mark Mitchell @ 2007-09-09 20:32 UTC (permalink / raw)
To: Richard Guenther; +Cc: Joe Buck, Ross Smith, GCC Mailing List
Richard Guenther wrote:
> I don't know of any place we would use such information. At least
>
> int *p = new int;
> int *q = new int;
> if (p == q)
>
> cannot be simplified as both pointers may be NULL?
They cannot be NULL; new-expressions throw an exception if the
allocation fails. (Of course, they could be NULL if you called the
"nothrow" variant, or another "operator new" declared "throw()".)
We should optimize away things like:
int *p = new int;
if (!p)
cerr << "Could not allocate memory\n";
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:32 ` Mark Mitchell
@ 2007-09-09 20:38 ` Richard Guenther
2007-09-09 20:41 ` Richard Guenther
2007-09-09 20:46 ` Mark Mitchell
0 siblings, 2 replies; 57+ messages in thread
From: Richard Guenther @ 2007-09-09 20:38 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Ross Smith, GCC Mailing List
On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
> Richard Guenther wrote:
>
> > I don't know of any place we would use such information. At least
> >
> > int *p = new int;
> > int *q = new int;
> > if (p == q)
> >
> > cannot be simplified as both pointers may be NULL?
>
> They cannot be NULL; new-expressions throw an exception if the
> allocation fails. (Of course, they could be NULL if you called the
> "nothrow" variant, or another "operator new" declared "throw()".)
>
> We should optimize away things like:
>
> int *p = new int;
> if (!p)
> cerr << "Could not allocate memory\n";
We don't I believe. We'd optimize
int *p = new int;
*p;
if (!p)
cerr << "Could not allocate memory\n";
though ;) Well, at least malloc is allowed to return NULL, so unless
we want to force all malloc attributed functions in C++ to throw exceptions
we cannot assume they return non-NULL (just on the basis they have
malloc attribute, that is).
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:38 ` Richard Guenther
@ 2007-09-09 20:41 ` Richard Guenther
2007-09-09 21:05 ` Mark Mitchell
2007-09-09 20:46 ` Mark Mitchell
1 sibling, 1 reply; 57+ messages in thread
From: Richard Guenther @ 2007-09-09 20:41 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Ross Smith, GCC Mailing List
On 9/9/07, Richard Guenther <richard.guenther@gmail.com> wrote:
> On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
> > Richard Guenther wrote:
> >
> > > I don't know of any place we would use such information. At least
> > >
> > > int *p = new int;
> > > int *q = new int;
> > > if (p == q)
> > >
> > > cannot be simplified as both pointers may be NULL?
A better one:
int *p = new int;
foo(p);
int *q = new int;
if foo deletes p then q may be equal to p. But alias analysis still
(validly!) says they don't alias.
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:41 ` Richard Guenther
@ 2007-09-09 21:05 ` Mark Mitchell
0 siblings, 0 replies; 57+ messages in thread
From: Mark Mitchell @ 2007-09-09 21:05 UTC (permalink / raw)
To: Richard Guenther; +Cc: Joe Buck, Ross Smith, GCC Mailing List
Richard Guenther wrote:
> A better one:
>
> int *p = new int;
> foo(p);
> int *q = new int;
>
> if foo deletes p then q may be equal to p. But alias analysis still
> (validly!) says they don't alias.
Yes, I agree that this is safe. (Either "p" is still valid and
therefore different from "q", or it has been deleted and you may no
longer talk about it.) That's the case I mentioned of assuming that
distinct calls to "operator new" result in different values. But,
that's not as strong as assuming that "p" is distinct from all other
pointers in the program, which is what the "malloc" attribute says.
And, even here there's a corner case:
char *pool;
void *operator new(size_t) { // return memory from pool }
bool f() {
char *p = new char;
pool = p;
char *q = new char;
return p == q;
}
Here, we have the situation that two subsequent calls to the same
"operator new" returned the same pointer.
Why isn't that valid? For a more real-world example, use array-new for
the first call.
I don't think the GCC lists are actually the place to fix these kinds of
problems. These are fundamental problems with the C++ standard. It
simply is not sufficiently clear about all of these memory model issues
to allow us (as compiler vendors) to reason about them in the ways that
we "know" make sense.
I think the optimization we want to do here (i.e., assume that pointers
returned by operator new are all distinct, and distinct from all other
pointers we can see) is only safe for particular implementations of
operator new. So, I don't think we can put any attribute to that affect
in our standard headers. You need a command-line switch, macro, etc.,
for the user to use to say that they are using an implementation that
meets the requirements.
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:38 ` Richard Guenther
2007-09-09 20:41 ` Richard Guenther
@ 2007-09-09 20:46 ` Mark Mitchell
2007-09-09 21:00 ` Richard Guenther
2007-09-10 14:43 ` Tom Tromey
1 sibling, 2 replies; 57+ messages in thread
From: Mark Mitchell @ 2007-09-09 20:46 UTC (permalink / raw)
To: Richard Guenther; +Cc: Joe Buck, Ross Smith, GCC Mailing List
Richard Guenther wrote:
>> We should optimize away things like:
>>
>> int *p = new int;
>> if (!p)
>> cerr << "Could not allocate memory\n";
>
> We don't I believe.
That's a missed-optimization, and independent of any attributes on
"operator new". It's a property of the new *expression*, not of the
implementation of new. If the compiler treats:
int *p = new int;
any differently from:
int &r = *new int;
then we're missing an optimization opportunity.
> though ;) Well, at least malloc is allowed to return NULL, so unless
> we want to force all malloc attributed functions in C++ to throw exceptions
> we cannot assume they return non-NULL (just on the basis they have
> malloc attribute, that is).
Sure, we can have the attribute in C++ mean the same thing it does in C,
even if that's not the strongest declaration we can make. That's OK.
But, I don't think that even the C meaning is safe in C++ for use with
the library declaration of <new>. I'm also somewhat skeptical of the
idea that we will never do any optimization on pointer comparisons.
What design principle in the compiler is going to keep us from some day
introducing the obvious idea that "if modifying *p cannot affect the
value of *q, and p and q are of the same type, then p != q"?
I think that (a) either we have to weaken the meaning of the attribute
in some way, or (b) we let users use this attribute optionally, for
their implementations of operator new when they "know" it's OK to do so,
but do not actually put it in the standard headers.
I'm not arguing that the attribute is meaningless in C++, or does not
apply to the libstdc++ implementation; I'm just arguing that putting it
into <new> is not safe.
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:46 ` Mark Mitchell
@ 2007-09-09 21:00 ` Richard Guenther
2007-09-09 21:13 ` Mark Mitchell
2007-09-10 14:43 ` Tom Tromey
1 sibling, 1 reply; 57+ messages in thread
From: Richard Guenther @ 2007-09-09 21:00 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Ross Smith, GCC Mailing List
On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
>
> But, I don't think that even the C meaning is safe in C++ for use with
> the library declaration of <new>. I'm also somewhat skeptical of the
> idea that we will never do any optimization on pointer comparisons.
> What design principle in the compiler is going to keep us from some day
> introducing the obvious idea that "if modifying *p cannot affect the
> value of *q, and p and q are of the same type, then p != q"?
But that reasoning is not valid. Consider
void foo(int *q, double *p)
{
if (q != p)
abort ();
}
int main()
{
int i;
foo (&i, &i);
}
which would abort. Now, instead
void foo(int *q, double *p)
{
*q;
*p;
if (q != p)
abort ();
}
we can optimize the comparison to alwas true as in the case
of p == q the program invokes undefined behavior. The essence
is that we usually cannot tell anything about pointer values and
pointed-to types unless we see accesses through them.
> I think that (a) either we have to weaken the meaning of the attribute
> in some way, or (b) we let users use this attribute optionally, for
> their implementations of operator new when they "know" it's OK to do so,
> but do not actually put it in the standard headers.
> I'm not arguing that the attribute is meaningless in C++, or does not
> apply to the libstdc++ implementation; I'm just arguing that putting it
> into <new> is not safe.
Today we should be safe I believe. Even if we inline new (we'd lose
knowledge about the call in this case -- which we of course may
fix in future).
It would be nice to have some testcases in the testsuite with the ideas
that pop up around these discussions though :)
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 21:00 ` Richard Guenther
@ 2007-09-09 21:13 ` Mark Mitchell
2007-09-09 21:32 ` Richard Guenther
0 siblings, 1 reply; 57+ messages in thread
From: Mark Mitchell @ 2007-09-09 21:13 UTC (permalink / raw)
To: Richard Guenther; +Cc: Joe Buck, Ross Smith, GCC Mailing List
Richard Guenther wrote:
> On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
>> But, I don't think that even the C meaning is safe in C++ for use with
>> the library declaration of <new>. I'm also somewhat skeptical of the
>> idea that we will never do any optimization on pointer comparisons.
>> What design principle in the compiler is going to keep us from some day
>> introducing the obvious idea that "if modifying *p cannot affect the
>> value of *q, and p and q are of the same type, then p != q"?
>
> But that reasoning is not valid. Consider
>
> void foo(int *q, double *p)
> {
> if (q != p)
> abort ();
> }
> int main()
> {
> int i;
> foo (&i, &i);
> }
That doesn't type-check; did you want to have a cast somewhere? Note
that my statement above depends on the pointers having the same type.
What is an example program in that meets the requirements I gave above
-- i.e., allows the compiler to prove that two same-typed pointers do
not alias (whether by the compiler's cleverness, use of "restrict", or
whatever), but where the compiler must still assume that the values of
the pointers might be the same?
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 21:13 ` Mark Mitchell
@ 2007-09-09 21:32 ` Richard Guenther
2007-09-09 22:23 ` Mark Mitchell
0 siblings, 1 reply; 57+ messages in thread
From: Richard Guenther @ 2007-09-09 21:32 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Ross Smith, GCC Mailing List
On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
> Richard Guenther wrote:
> > On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
> >> But, I don't think that even the C meaning is safe in C++ for use with
> >> the library declaration of <new>. I'm also somewhat skeptical of the
> >> idea that we will never do any optimization on pointer comparisons.
> >> What design principle in the compiler is going to keep us from some day
> >> introducing the obvious idea that "if modifying *p cannot affect the
> >> value of *q, and p and q are of the same type, then p != q"?
> >
> > But that reasoning is not valid. Consider
> >
> > void foo(int *q, double *p)
> > {
> > if (q != p)
> > abort ();
> > }
> > int main()
> > {
> > int i;
> > foo (&i, &i);
> > }
>
> That doesn't type-check; did you want to have a cast somewhere? Note
> that my statement above depends on the pointers having the same type.
>
> What is an example program in that meets the requirements I gave above
> -- i.e., allows the compiler to prove that two same-typed pointers do
> not alias (whether by the compiler's cleverness, use of "restrict", or
> whatever), but where the compiler must still assume that the values of
> the pointers might be the same?
I see I misinterpreted your sentence. I don't think a testcase that
holds all your requirements can be constructed as they
contradict each other. Can you give one?
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 21:32 ` Richard Guenther
@ 2007-09-09 22:23 ` Mark Mitchell
2007-09-10 6:56 ` Richard Guenther
0 siblings, 1 reply; 57+ messages in thread
From: Mark Mitchell @ 2007-09-09 22:23 UTC (permalink / raw)
To: Richard Guenther; +Cc: Joe Buck, Ross Smith, GCC Mailing List
Richard Guenther wrote:
>> What is an example program in that meets the requirements I gave above
>> -- i.e., allows the compiler to prove that two same-typed pointers do
>> not alias (whether by the compiler's cleverness, use of "restrict", or
>> whatever), but where the compiler must still assume that the values of
>> the pointers might be the same?
>
> I see I misinterpreted your sentence. I don't think a testcase that
> holds all your requirements can be constructed as they
> contradict each other. Can you give one?
No -- I don't think any such test case should exist. But, IIUC, one of
your proposals could lead to the existence of such a test case. In
particular, I understood you to be suggesting that we might be able to
make the "malloc" attribute work for any implementation of "operator
new" by saying that while the compiler could assume that "*p" and "*q"
did not alias, the compiler was none-the-less not allowed to assume that
"p != q".
My point was that this seems like a very strange requirement to impose
on the compiler, and that the compiler -- now, or in future -- is very
likely to make exactly that deduction, since it is logically true. More
broadly, my point was that a universe in which "*p does not alias *q"
fails to imply "p != q", for "p" and "q" pointers of the same type, is a
weird place to be.
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 22:23 ` Mark Mitchell
@ 2007-09-10 6:56 ` Richard Guenther
2007-09-11 4:17 ` Mark Mitchell
0 siblings, 1 reply; 57+ messages in thread
From: Richard Guenther @ 2007-09-10 6:56 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Ross Smith, GCC Mailing List
On 9/10/07, Mark Mitchell <mark@codesourcery.com> wrote:
> Richard Guenther wrote:
>
> >> What is an example program in that meets the requirements I gave above
> >> -- i.e., allows the compiler to prove that two same-typed pointers do
> >> not alias (whether by the compiler's cleverness, use of "restrict", or
> >> whatever), but where the compiler must still assume that the values of
> >> the pointers might be the same?
> >
> > I see I misinterpreted your sentence. I don't think a testcase that
> > holds all your requirements can be constructed as they
> > contradict each other. Can you give one?
>
> No -- I don't think any such test case should exist. But, IIUC, one of
> your proposals could lead to the existence of such a test case. In
> particular, I understood you to be suggesting that we might be able to
> make the "malloc" attribute work for any implementation of "operator
> new" by saying that while the compiler could assume that "*p" and "*q"
> did not alias, the compiler was none-the-less not allowed to assume that
> "p != q".
>
> My point was that this seems like a very strange requirement to impose
> on the compiler, and that the compiler -- now, or in future -- is very
> likely to make exactly that deduction, since it is logically true. More
> broadly, my point was that a universe in which "*p does not alias *q"
> fails to imply "p != q", for "p" and "q" pointers of the same type, is a
> weird place to be.
Well, we have that now:
int *q = new int;
delete q;
int *p = new int;
delete p;
if (q != p)
cout << "different";
we cannot optimize the test to be always true. The point is that alias
analysis tells us something about accesses to *q and *p, but neither
on lifetime of *q and *p nor lifetime of q and p (and thus their value).
The only value analysis valid on pointers is non-NULLness which we
can derive from accesses to the pointed-to memory location (ok, assuming
the OS really traps on accesses to address zero, which is not true in
general).
I don't think my proposal opens up more "problems" in this area.
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-10 6:56 ` Richard Guenther
@ 2007-09-11 4:17 ` Mark Mitchell
2007-09-11 9:16 ` Richard Guenther
0 siblings, 1 reply; 57+ messages in thread
From: Mark Mitchell @ 2007-09-11 4:17 UTC (permalink / raw)
To: Richard Guenther; +Cc: Joe Buck, Ross Smith, GCC Mailing List
Richard Guenther wrote:
> Well, we have that now:
>
> int *q = new int;
> delete q;
> int *p = new int;
> delete p;
> if (q != p)
> cout << "different";
>
> we cannot optimize the test to be always true. The point is that alias
> analysis tells us something about accesses to *q and *p, but neither
> on lifetime of *q and *p nor lifetime of q and p (and thus their value).
That's an interesting example. Thanks for showing it to me. From
looking at the standard, I think I could be a language lawyer and try to
argue that the comparison is not defined -- but that would just be
weaselish; the comparison should be defined. So, yes, I concede that
you've found a counter-example to my claim that "*p does not alias *q"
=> "p != q". How odd. I would have to revise my claim to require that
"p" and "q" are valid pointers.
So, for something like:
char *pool;
void *operator new[] (size_t s) { /* return memory from pool */ }
...
pool = new char[1024];
char *c = new char[16];
IIUC, your claim is that if pool and c now have the same value, then any
indirection through pool is invalid (because the object with newest
lifetime at that location is the 16-byte array), so we can assume *pool
and *c do not alias? Do you also claim that:
((char (*)[16])pool)[0] = '\0';
is invalid because it is a pointer "based on" pool?
If you think it's OK to put the "malloc" attribute on operator new, why
did you say earlier that you can't implement "malloc" in C itself, for
exactly these kinds of reasons? Isn't the situation exactly analogous?
I think I'm getting confused. Perhaps you could sum up in a single
email the argument for why putting this attribute in our standard
headers is safe, even in view of possible replacement in user programs?
Sorry,
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-11 4:17 ` Mark Mitchell
@ 2007-09-11 9:16 ` Richard Guenther
2007-09-11 12:17 ` Gabriel Dos Reis
2007-09-11 22:09 ` Mark Mitchell
0 siblings, 2 replies; 57+ messages in thread
From: Richard Guenther @ 2007-09-11 9:16 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Ross Smith, GCC Mailing List
On 9/11/07, Mark Mitchell <mark@codesourcery.com> wrote:
> Richard Guenther wrote:
>
> > Well, we have that now:
> >
> > int *q = new int;
> > delete q;
> > int *p = new int;
> > delete p;
> > if (q != p)
> > cout << "different";
> >
> > we cannot optimize the test to be always true. The point is that alias
> > analysis tells us something about accesses to *q and *p, but neither
> > on lifetime of *q and *p nor lifetime of q and p (and thus their value).
>
> That's an interesting example. Thanks for showing it to me. From
> looking at the standard, I think I could be a language lawyer and try to
> argue that the comparison is not defined -- but that would just be
> weaselish; the comparison should be defined. So, yes, I concede that
> you've found a counter-example to my claim that "*p does not alias *q"
> => "p != q". How odd. I would have to revise my claim to require that
> "p" and "q" are valid pointers.
>
> So, for something like:
>
> char *pool;
> void *operator new[] (size_t s) { /* return memory from pool */ }
> ...
> pool = new char[1024];
> char *c = new char[16];
>
> IIUC, your claim is that if pool and c now have the same value, then any
> indirection through pool is invalid (because the object with newest
> lifetime at that location is the 16-byte array), so we can assume *pool
> and *c do not alias? Do you also claim that:
Yes.
> ((char (*)[16])pool)[0] = '\0';
>
> is invalid because it is a pointer "based on" pool?
Yes.
> If you think it's OK to put the "malloc" attribute on operator new, why
> did you say earlier that you can't implement "malloc" in C itself, for
> exactly these kinds of reasons? Isn't the situation exactly analogous?
It looks like, but C doesn't provide us with the notion of dynamic lifetime
of objects at the same memory location. That is, the "newest object"
argument doesn't work in C. In fact this is one reason why we should
not (or can't) put the malloc attribute on obstack_alloc -- it would be
valid to access the obstack memory through the pool pointer.
For C++ we can argue that 'new' starts lifetime of a new object at
the place of the old 'new'ed memory and accesses to the old object
invoke undefined behavior.
> I think I'm getting confused. Perhaps you could sum up in a single
> email the argument for why putting this attribute in our standard
> headers is safe, even in view of possible replacement in user programs?
My argument goes like "We can safely put attribute malloc on all overloads
of new as C++ starts lifetime of a new object in the target and accesses to
old objects at that location invoke undefined behavior". I claim that you
cannot construct a testcase with no undefined behavior that has two
pointers returned from a call to 'new' alias.
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-11 9:16 ` Richard Guenther
@ 2007-09-11 12:17 ` Gabriel Dos Reis
2007-09-11 12:24 ` Richard Guenther
2007-09-11 22:09 ` Mark Mitchell
1 sibling, 1 reply; 57+ messages in thread
From: Gabriel Dos Reis @ 2007-09-11 12:17 UTC (permalink / raw)
To: Richard Guenther; +Cc: Mark Mitchell, Joe Buck, Ross Smith, GCC Mailing List
"Richard Guenther" <richard.guenther@gmail.com> writes:
[...]
| > I think I'm getting confused. Perhaps you could sum up in a single
| > email the argument for why putting this attribute in our standard
| > headers is safe, even in view of possible replacement in user programs?
|
| My argument goes like "We can safely put attribute malloc on all overloads
^^^^^^^^^^^^^^^^^
| of new as C++ starts lifetime of a new object in the target and accesses to
| old objects at that location invoke undefined behavior". I claim that you
| cannot construct a testcase with no undefined behavior that has two
| pointers returned from a call to 'new' alias.
I don't think I understand the claim. The C++ does not say anything
about all overloads in terms of aliasing. IT makes claims about
specific `operator new's. Could you elaborate on why it is OK to
annotate all overloads?
-- Gaby
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-11 12:17 ` Gabriel Dos Reis
@ 2007-09-11 12:24 ` Richard Guenther
0 siblings, 0 replies; 57+ messages in thread
From: Richard Guenther @ 2007-09-11 12:24 UTC (permalink / raw)
To: Gabriel Dos Reis; +Cc: Mark Mitchell, Joe Buck, Ross Smith, GCC Mailing List
On 11 Sep 2007 07:24:44 -0500, Gabriel Dos Reis <gdr@cs.tamu.edu> wrote:
> "Richard Guenther" <richard.guenther@gmail.com> writes:
>
> [...]
>
> | > I think I'm getting confused. Perhaps you could sum up in a single
> | > email the argument for why putting this attribute in our standard
> | > headers is safe, even in view of possible replacement in user programs?
> |
> | My argument goes like "We can safely put attribute malloc on all overloads
> ^^^^^^^^^^^^^^^^^
> | of new as C++ starts lifetime of a new object in the target and accesses to
> | old objects at that location invoke undefined behavior". I claim that you
> | cannot construct a testcase with no undefined behavior that has two
> | pointers returned from a call to 'new' alias.
>
> I don't think I understand the claim. The C++ does not say anything
> about all overloads in terms of aliasing. IT makes claims about
> specific `operator new's. Could you elaborate on why it is OK to
> annotate all overloads?
Sorry for the wrong terminology, I think I mean all implementations of
void* operator new(std::size_t) throw (std::bad_alloc);
void* operator new[](std::size_t) throw (std::bad_alloc);
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();
that is, not only annotating libsupc++ implementation but assuring
the attribute is set by changing the C++ frontend.
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-11 9:16 ` Richard Guenther
2007-09-11 12:17 ` Gabriel Dos Reis
@ 2007-09-11 22:09 ` Mark Mitchell
1 sibling, 0 replies; 57+ messages in thread
From: Mark Mitchell @ 2007-09-11 22:09 UTC (permalink / raw)
To: Richard Guenther; +Cc: Joe Buck, Ross Smith, GCC Mailing List
Richard Guenther wrote:
>> So, for something like:
>>
>> char *pool;
>> void *operator new[] (size_t s) { /* return memory from pool */ }
>> ...
>> pool = new char[1024];
>> char *c = new char[16];
>>
>> IIUC, your claim is that if pool and c now have the same value, then any
>> indirection through pool is invalid (because the object with newest
>> lifetime at that location is the 16-byte array), so we can assume *pool
>> and *c do not alias? Do you also claim that:
>
> Yes.
>
>> ((char (*)[16])pool)[0] = '\0';
>>
>> is invalid because it is a pointer "based on" pool?
>
> Yes.
Thanks for explaining your argument. It's very well-reasoned.
However, it still leads to weird results. For example, you're now in a
situation where transforming:
if (p == q)
*p = 3;
to:
if (p == q)
*q = 3;
is not valid. I'd imagine most people to be somewhat surprised by that;
it's rather contrary to the idea of equality. Are we sure we want to go
there?
(This issue does not occur with "restrict", because if the pointers were
known not to alias due to use of "restrict", then the comparison is
always false, by hypothesis -- or else the program behavior is already
undefined.)
>> If you think it's OK to put the "malloc" attribute on operator new, why
>> did you say earlier that you can't implement "malloc" in C itself, for
>> exactly these kinds of reasons? Isn't the situation exactly analogous?
>
> It looks like, but C doesn't provide us with the notion of dynamic lifetime
> of objects at the same memory location.
I'm not really confident C++ does either. Or, rather, that even if it
does, we should take advantage of that. I'm concerned that we're going
to break a lot of code.
> My argument goes like "We can safely put attribute malloc on all overloads
> of new as C++ starts lifetime of a new object in the target and accesses to
> old objects at that location invoke undefined behavior". I claim that you
> cannot construct a testcase with no undefined behavior that has two
> pointers returned from a call to 'new' alias.
Actually, the claim for attribute "malloc" must be even stronger -- the
value returned must not alias *any* other pointer. I don't think that
affects your argument, but just for the sake of clarity, that must be
your claim.
I think my point of view on this is that, whether or not the standard
can be read to support your claim, I don't think we should put the
attribute in our standard headers. I'd rather let people who know what
they're doing put that in their own headers if they want to do so. And,
I'd certainly suggest that we ask the ISO committee before doing this.
Thanks,
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:46 ` Mark Mitchell
2007-09-09 21:00 ` Richard Guenther
@ 2007-09-10 14:43 ` Tom Tromey
2007-09-10 17:40 ` Daniel Berlin
1 sibling, 1 reply; 57+ messages in thread
From: Tom Tromey @ 2007-09-10 14:43 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Richard Guenther, Joe Buck, Ross Smith, GCC Mailing List
>>>>> "Mark" == Mark Mitchell <mark@codesourcery.com> writes:
Mark> If the compiler treats:
Mark> int *p = new int;
Mark> any differently from:
Mark> int &r = *new int;
Mark> then we're missing an optimization opportunity.
AFAIK we don't have a way to mark a function as "cannot return NULL".
This is PR 20318.
Tom
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-10 14:43 ` Tom Tromey
@ 2007-09-10 17:40 ` Daniel Berlin
0 siblings, 0 replies; 57+ messages in thread
From: Daniel Berlin @ 2007-09-10 17:40 UTC (permalink / raw)
To: tromey
Cc: Mark Mitchell, Richard Guenther, Joe Buck, Ross Smith, GCC Mailing List
On 9/10/07, Tom Tromey <tromey@redhat.com> wrote:
> >>>>> "Mark" == Mark Mitchell <mark@codesourcery.com> writes:
>
> Mark> If the compiler treats:
> Mark> int *p = new int;
> Mark> any differently from:
> Mark> int &r = *new int;
> Mark> then we're missing an optimization opportunity.
>
> AFAIK we don't have a way to mark a function as "cannot return NULL".
> This is PR 20318.
If someone reviewed zdenek's function attribute table patch (That
started adding info about arguments, etc and what happens to them), we
could simply extend it to do this in about 10 lines of code
>
> Tom
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:27 ` Richard Guenther
2007-09-09 20:32 ` Mark Mitchell
@ 2007-09-09 21:27 ` Gabriel Dos Reis
1 sibling, 0 replies; 57+ messages in thread
From: Gabriel Dos Reis @ 2007-09-09 21:27 UTC (permalink / raw)
To: Richard Guenther; +Cc: Mark Mitchell, Joe Buck, Ross Smith, GCC Mailing List
"Richard Guenther" <richard.guenther@gmail.com> writes:
[...]
| I don't know of any place we would use such information. At least
|
| int *p = new int;
| int *q = new int;
| if (p == q)
|
| cannot be simplified as both pointers may be NULL?
The above does not use the no-throw operator new, so neither can be
null -- except if the user used command-line -fno-exceptions.
-- Gaby
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:04 ` Richard Guenther
2007-09-09 20:22 ` Mark Mitchell
@ 2007-09-09 21:25 ` Gabriel Dos Reis
1 sibling, 0 replies; 57+ messages in thread
From: Gabriel Dos Reis @ 2007-09-09 21:25 UTC (permalink / raw)
To: Richard Guenther; +Cc: Mark Mitchell, Joe Buck, Ross Smith, GCC Mailing List
"Richard Guenther" <richard.guenther@gmail.com> writes:
[...]
| > It's worse than that:
| >
| > char *pool;
| > void set_pool(char *p) { pool = p; }
| > void *operator new(size_t s) { // return stuff from pool. }
| >
| > bool f() {
| > char *p = new char[1024];
| > set_pool (p);
| > char *i = new char;
| > return (p == i);
| > }
| >
| > In other words, pointers from any part of the program can potentially be
| > "laundered" through set_pool and return via the new operator. I don't
| > see any way to make this fully safe, in general, without the limitation
| > I imposed: the no-aliasing guarantee only applies to the values returned
| > from the function called.
|
| But in this case an access to *i through *p is invalid. [I suppose both
| new calls are actually different implementations here] Each new
| call starts lifetime of a new object, the previous object lifetime is
| terminated. Even comparing both pointers here for this reason
| would lead to undefined behavior.
I don't follow your reasoning here. 'char*' and 'void*' are special.
-- Gaby
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 19:56 ` Mark Mitchell
2007-09-09 20:04 ` Richard Guenther
@ 2007-09-10 12:18 ` Martin Jambor
1 sibling, 0 replies; 57+ messages in thread
From: Martin Jambor @ 2007-09-10 12:18 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Joe Buck, Richard Guenther, Ross Smith, GCC Mailing List
Hi,
On Sun, Sep 09, 2007 at 12:56:25PM -0700, Mark Mitchell wrote:
> For a particular implementation of "operator new" (such as the one in
> libstdc++), you can of course make it safe in the same way as "malloc";
> hide the implementation somewhere the rest of the program can't see it
> (modulo LTO). But, to declare it with the "malloc" attribute in the
> headers seems dangerous, since we have no way of knowing if the user
> replaced it, off in some file somewhere we don't know about, but in such
> a way that pointers in our source code are being laundered back to us.
All I attempted to do was to mark just one particular implementation
of the new operator which also happened to be the default built-in
one. From my experiments, it appears that marking it as malloc in the
libstc++ headers does not affect other implementations. However, as
Gabriel Dos Reis correctly pointed out, the attribute is not applied
to the new operator if the changed declaration is not somehow included
in the compiled source. Fixing this inconsistency requires some
changes in the FE. Nevertheless, so far I do not see problems with
declaring standard new implementation as malloc in the header file.
I hope you all agree that marking the default (and only the default),
implementation as malloc is worthwhile and will look into it(, even
though it is going to take some time).
Martin
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 19:24 ` Mark Mitchell
2007-09-09 19:42 ` Joe Buck
@ 2007-09-09 19:51 ` Richard Guenther
2007-09-09 20:08 ` Richard Guenther
2007-09-09 21:22 ` Gabriel Dos Reis
2 siblings, 1 reply; 57+ messages in thread
From: Richard Guenther @ 2007-09-09 19:51 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Ross Smith, GCC Mailing List
On 9/9/07, Mark Mitchell <mark@codesourcery.com> wrote:
> Richard Guenther wrote:
>
> >> Probably the most common use of a custom new is to allocate memory from
> >> a user-controlled pool instead of the standard free store. Somewhere in
> >> the program there will be a pointer to the complete pool, which aliases
> >> every pointer returned by that version of new. Any such pool-based new
> >> doesn't meet the requirements of the malloc attribute.
> >
> > That doesn't matter. What matters is object lifetime, which is properly
> > preserved by a conforming pool allocator.
>
> We have some terminology issues here. The definition of the malloc
> attribute is:
>
> > The `malloc' attribute is used to tell the compiler that a function
> > may be treated as if any non-`NULL' pointer it returns cannot
> > alias any other pointer valid when the function returns. This
> > will often improve optimization.
>
> The term "cannot alias" is not fully defined. It could mean "cannot
> have the same value as any other pointer of the same type". It could
> mean "cannot have the same value as any other pointer, when both
> pointers are cast to `void *'". It could mean, a la "restrict", that
> "no store through an expression based on this pointer can modify the
> value read from via any expression based on any other pointer".
It actually means that all accesses based on the returned pointer do
not alias accesses based on other pointers that are not derived. In
particular,
int *p;
int * __attribute__((malloc)) my_malloc() { return p; }
void foo(void)
{
int *q = my_malloc();
*p = 1;
*q = 0;
return *p;
}
will be optimized to return 1 if my_malloc is not inlined and 0 otherwise.
> In the case of "malloc", and assuming that all of the machinery for
> malloc is hidden away in some piece of the program we're not talking
> about, all three definitions apply. Each pointer returned by malloc is
> an island unto itself; there's no conforming way to get there except by
> using the pointer just returned.
>
> For, operator new, the same is true -- but we're more often able to see
> the machinery for the allocator. For example:
>
> char pool[N];
> size_t next;
>
> /* Never mind that the return memory isn't properly aligned here;
> fixing the implementation is left to the reader. */
> void *operator new(size_t s) {
> void *p = pool + next;
> next += s;
> return p;
> }
>
> bool f() {
> char *c = new char;
> return (c == pool);
> }
>
> Now, I don't think we should allow the compiler to optimize the return
> statement in "f" to "return false"? If operator new has attribute
> malloc, then it may in fact do so -- even though the value returned
> might be "pool" itself.
Yes, at least the first case would give different results based on inlining
decisions. But only for undefined cases I believe.
> The same issue occurs if you call malloc from within the file that
> defines malloc; the malloc attribute is saying something about what you
> can do *if you cannot see the pool out of which the allocation is
> occurring*. For malloc, which is fully squirreled away in libc
> somewhere, this is probably safe in practice -- until LTO.
Which brings back the fact that you cannot implement malloc in C
(you certainly remember the discussions about C++ placement new
handling wrt aliasing). To re-use the machinery we invented there
we would need to place a CHANGE_DYNAMIC_TYPE_EXPR for
the pointer assignment resulting from inlining a function with
attribute malloc set. As you say, unless we are inlining such functions
we are safe in practice.
> For operator
> new, it's a little dicier, since people do tend more often to replace it
> in their own programs, and to put those replacements in inline functions
> in header files where the compiler is liable to see more about what's
> going on.
>
> This seems like a useful optimization to me, and I understand that it
> will work 99.99% of the time, and it's in the spirit of the standard --
> but how do we actually make it safe? If the attribute only applied to
> other values returned from the same function, then it would be safe --
> but less useful. Can we do better?
See above - inlining an allocator function produces the need to change
the dynamic type of the pointed-to memory as we are basically exposing
a "placement new" operation to the optimizers.
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 19:51 ` Richard Guenther
@ 2007-09-09 20:08 ` Richard Guenther
2007-09-12 1:15 ` Ian Lance Taylor
0 siblings, 1 reply; 57+ messages in thread
From: Richard Guenther @ 2007-09-09 20:08 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Ross Smith, GCC Mailing List
On 9/9/07, Richard Guenther <richard.guenther@gmail.com> wrote:
>
> Which brings back the fact that you cannot implement malloc in C
> (you certainly remember the discussions about C++ placement new
> handling wrt aliasing). To re-use the machinery we invented there
> we would need to place a CHANGE_DYNAMIC_TYPE_EXPR for
> the pointer assignment resulting from inlining a function with
> attribute malloc set. As you say, unless we are inlining such functions
> we are safe in practice.
Actually this looks nice in general. We could implement placement
new in C this way:
extern inline T * __attribute__((malloc)) placement_new (void *p)
{ return p; }
if we can somehow encode the target type here. Note that only
type-based aliasing is a problem with this discussion - PTA will
be obviously fine if new is inlined as it will see that both pointers
are related and we loose the 'malloc' attribution on the target pointer
during inlining.
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 20:08 ` Richard Guenther
@ 2007-09-12 1:15 ` Ian Lance Taylor
2007-09-12 8:01 ` Richard Guenther
0 siblings, 1 reply; 57+ messages in thread
From: Ian Lance Taylor @ 2007-09-12 1:15 UTC (permalink / raw)
To: Richard Guenther; +Cc: Mark Mitchell, Ross Smith, GCC Mailing List
"Richard Guenther" <richard.guenther@gmail.com> writes:
> On 9/9/07, Richard Guenther <richard.guenther@gmail.com> wrote:
> >
> > Which brings back the fact that you cannot implement malloc in C
> > (you certainly remember the discussions about C++ placement new
> > handling wrt aliasing). To re-use the machinery we invented there
> > we would need to place a CHANGE_DYNAMIC_TYPE_EXPR for
> > the pointer assignment resulting from inlining a function with
> > attribute malloc set. As you say, unless we are inlining such functions
> > we are safe in practice.
>
> Actually this looks nice in general. We could implement placement
> new in C this way:
>
> extern inline T * __attribute__((malloc)) placement_new (void *p)
> { return p; }
>
> if we can somehow encode the target type here. Note that only
> type-based aliasing is a problem with this discussion - PTA will
> be obviously fine if new is inlined as it will see that both pointers
> are related and we loose the 'malloc' attribution on the target pointer
> during inlining.
CHANGE_DYNAMIC_TYPE_EXPR has the target type, of course. So perhaps
we need __attribute__ ((change_dynamic_type))?
Or actually of course __attribute__ ((malloc)) is fine but we could
throw in a CHANGE_DYNAMIC_TYPE_EXPR after any call to such a
function. That ought to do the right thing for C malloc
implementations as well, I think.
Ian
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-12 1:15 ` Ian Lance Taylor
@ 2007-09-12 8:01 ` Richard Guenther
2007-09-12 15:14 ` Ian Lance Taylor
0 siblings, 1 reply; 57+ messages in thread
From: Richard Guenther @ 2007-09-12 8:01 UTC (permalink / raw)
To: Ian Lance Taylor; +Cc: Mark Mitchell, Ross Smith, GCC Mailing List
On 11 Sep 2007 18:14:21 -0700, Ian Lance Taylor <iant@google.com> wrote:
> "Richard Guenther" <richard.guenther@gmail.com> writes:
>
> > On 9/9/07, Richard Guenther <richard.guenther@gmail.com> wrote:
> > >
> > > Which brings back the fact that you cannot implement malloc in C
> > > (you certainly remember the discussions about C++ placement new
> > > handling wrt aliasing). To re-use the machinery we invented there
> > > we would need to place a CHANGE_DYNAMIC_TYPE_EXPR for
> > > the pointer assignment resulting from inlining a function with
> > > attribute malloc set. As you say, unless we are inlining such functions
> > > we are safe in practice.
> >
> > Actually this looks nice in general. We could implement placement
> > new in C this way:
> >
> > extern inline T * __attribute__((malloc)) placement_new (void *p)
> > { return p; }
> >
> > if we can somehow encode the target type here. Note that only
> > type-based aliasing is a problem with this discussion - PTA will
> > be obviously fine if new is inlined as it will see that both pointers
> > are related and we loose the 'malloc' attribution on the target pointer
> > during inlining.
>
> CHANGE_DYNAMIC_TYPE_EXPR has the target type, of course. So perhaps
> we need __attribute__ ((change_dynamic_type))?
>
> Or actually of course __attribute__ ((malloc)) is fine but we could
> throw in a CHANGE_DYNAMIC_TYPE_EXPR after any call to such a
> function. That ought to do the right thing for C malloc
> implementations as well, I think.
We should need this only if inlining malloc functions in C.
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-12 8:01 ` Richard Guenther
@ 2007-09-12 15:14 ` Ian Lance Taylor
2007-09-12 15:18 ` Richard Guenther
0 siblings, 1 reply; 57+ messages in thread
From: Ian Lance Taylor @ 2007-09-12 15:14 UTC (permalink / raw)
To: Richard Guenther; +Cc: Mark Mitchell, Ross Smith, GCC Mailing List
"Richard Guenther" <richard.guenther@gmail.com> writes:
> > CHANGE_DYNAMIC_TYPE_EXPR has the target type, of course. So perhaps
> > we need __attribute__ ((change_dynamic_type))?
> >
> > Or actually of course __attribute__ ((malloc)) is fine but we could
> > throw in a CHANGE_DYNAMIC_TYPE_EXPR after any call to such a
> > function. That ought to do the right thing for C malloc
> > implementations as well, I think.
>
> We should need this only if inlining malloc functions in C.
Which we will presumably do at some point. After all, it's not just
malloc--it's any function with __attribute__ ((malloc)), which can
include user functions.
Ian
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-12 15:14 ` Ian Lance Taylor
@ 2007-09-12 15:18 ` Richard Guenther
0 siblings, 0 replies; 57+ messages in thread
From: Richard Guenther @ 2007-09-12 15:18 UTC (permalink / raw)
To: Ian Lance Taylor; +Cc: Mark Mitchell, Ross Smith, GCC Mailing List
On 12 Sep 2007 08:13:31 -0700, Ian Lance Taylor <iant@google.com> wrote:
> "Richard Guenther" <richard.guenther@gmail.com> writes:
>
> > > CHANGE_DYNAMIC_TYPE_EXPR has the target type, of course. So perhaps
> > > we need __attribute__ ((change_dynamic_type))?
> > >
> > > Or actually of course __attribute__ ((malloc)) is fine but we could
> > > throw in a CHANGE_DYNAMIC_TYPE_EXPR after any call to such a
> > > function. That ought to do the right thing for C malloc
> > > implementations as well, I think.
> >
> > We should need this only if inlining malloc functions in C.
>
> Which we will presumably do at some point. After all, it's not just
> malloc--it's any function with __attribute__ ((malloc)), which can
> include user functions.
Btw, I filed PR33407 to hint that we need the CHANGE_DYNAMIC_TYPE_EXPR
trick for the usual operator new
as well.
And yes, we would need to fix all __attribute__((malloc)) functions
in C with the same thing - the problem I see in C is that we don't
know the type we are "converting" to ;)
Richard.
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC] Marking C++ new operator as malloc?
2007-09-09 19:24 ` Mark Mitchell
2007-09-09 19:42 ` Joe Buck
2007-09-09 19:51 ` Richard Guenther
@ 2007-09-09 21:22 ` Gabriel Dos Reis
2 siblings, 0 replies; 57+ messages in thread
From: Gabriel Dos Reis @ 2007-09-09 21:22 UTC (permalink / raw)
To: Mark Mitchell; +Cc: Richard Guenther, Ross Smith, GCC Mailing List
Mark Mitchell <mark@codesourcery.com> writes:
[...]
| This seems like a useful optimization to me, and I understand that it
| will work 99.99% of the time
Except for people writing allocators :-)
-- Gaby
^ permalink raw reply [flat|nested] 57+ messages in thread