Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-08 Thread Aryeh Gregor
On Tue, Jul 7, 2015 at 6:10 PM, Michael Layzell mich...@thelayzells.com wrote:
 No, I never checked if it happens on an optimized build, but as C++ follows
 an as-if principal, which means that code has to execute as if those
 temporaries had been created. Unfortunately, AddRef and Release are virtual,
 which, I'm pretty sure, means that the compiler can't optimize them out as
 they may have arbitrary side effects :(.

 So the temporaries are probably eliminated, but the calls to AddRef and
 Release are probably not. I could be wrong on this though.

This is true except in special cases where copy elision is allowed, in
which case the temporary may be removed entirely, with its constructor
and destructor.  According to 12.8.32 of
http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/2011/n3242.pdf,
one of those cases is

when a temporary class object that has not been bound to a reference
(12.2) would be copied/moved to a class object with the same
cv-unqualified type, the copy/move operation can be omitted by
constructing the temporary object directly into the target of the
omitted copy/move

I'm not an expert in C++-ese, but this looks like exactly that, so
compilers should be allowed to remove the AddRef/Release.  Whether
they do or not is a separate question -- I'd hope so, in such a
simple-looking case.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-08 Thread Seth Fowler
I brought this up on IRC, but I think this is worth taking to the list:

Replacing TemporaryRef with already_AddRefed has already caused at least one 
leak because already_AddRefed does not call Release() on the pointer it holds 
if nothing takes ownership of that pointer before its destructor runs. 
TemporaryRef did do that, and this seems like a strictly safer approach.

My question is: why doesn’t already_AddRefed call Release() in its destructor? 
The fact that it doesn’t seems to me to be a profoundly unintuitive footgun.

I don’t think we can trust reviewers to catch this, either. The fact that Foo() 
is declared as:

already_AddRefedBar Foo();

won’t necessarily be obvious from a call site, where the reviewer will just see:

Foo();

That call will leak, and if we don’t happen to hit that code path in our tests, 
we may not find out about it until after shipping it.

I’d prefer that already_AddRefed just call Release(), but if there are 
performance arguments against that, then we should be checking for this pattern 
with static analysis. I don’t think the situation as it stands should be 
allowed to remain for long.

- Seth

 On Jun 30, 2015, at 12:02 PM, Nathan Froyd nfr...@mozilla.com wrote:
 
 Bug 1161627 has landed on inbound, which converts all uses of
 mozilla::TemporaryRef to already_AddRefed and removes TemporaryRef.
 (already_AddRefed moved to MFBT several months ago, in case you were
 wondering about the spreading of XPCOM concepts.)  TemporaryRef was added
 for easier porting of code from other engines, but as it has not been used
 much for that purpose and it led to somewhat less efficient code in places,
 it was deemed a failed experiment.
 
 -Nathan
 ___
 dev-platform mailing list
 dev-platform@lists.mozilla.org
 https://lists.mozilla.org/listinfo/dev-platform

___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-08 Thread Kyle Huey
On Tue, Jul 7, 2015 at 9:59 AM, Seth Fowler mfow...@mozilla.com wrote:

 I brought this up on IRC, but I think this is worth taking to the list:

 Replacing TemporaryRef with already_AddRefed has already caused at least
 one leak because already_AddRefed does not call Release() on the pointer it
 holds if nothing takes ownership of that pointer before its destructor
 runs. TemporaryRef did do that, and this seems like a strictly safer
 approach.

 My question is: why doesn’t already_AddRefed call Release() in its
 destructor? The fact that it doesn’t seems to me to be a profoundly
 unintuitive footgun.


We have a version of already_AddRefed that automatically releases the value
it holds when it's destroyed; it's called nsCOMPtr.

I don’t think we can trust reviewers to catch this, either. The fact that
 Foo() is declared as:

 already_AddRefedBar Foo();

 won’t necessarily be obvious from a call site, where the reviewer will
 just see:

 Foo();


Foo should be MOZ_WARN_UNUSED_RESULT (or whatever that annotation is) then,
as should anything that returns an already_AddRefed.

That call will leak, and if we don’t happen to hit that code path in our
 tests, we may not find out about it until after shipping it.


Ensuring that code that is untested works is in general a hard thing to
do.  I'd prefer that people wrote tests. (yes, there may be edge cases in
which this isn't possible)

I’d prefer that already_AddRefed just call Release(), but if there are
 performance arguments against that, then we should be checking for this
 pattern with static analysis. I don’t think the situation as it stands
 should be allowed to remain for long.


There is currently a dynamic analysis (in the form of a fatal assertion) in
the already_AddRefed dtor that I added last year.

- Kyle
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-08 Thread Michael Layzell
We're already working on a static analysis in 
https://bugzilla.mozilla.org/show_bug.cgi?id=1180993 which will prevent 
code like that from passing try.


Hopefully that will help with your concerns.

On 2015-07-07 12:59 PM, Seth Fowler wrote:

I brought this up on IRC, but I think this is worth taking to the list:

Replacing TemporaryRef with already_AddRefed has already caused at least one 
leak because already_AddRefed does not call Release() on the pointer it holds 
if nothing takes ownership of that pointer before its destructor runs. 
TemporaryRef did do that, and this seems like a strictly safer approach.

My question is: why doesn’t already_AddRefed call Release() in its destructor? 
The fact that it doesn’t seems to me to be a profoundly unintuitive footgun.

I don’t think we can trust reviewers to catch this, either. The fact that Foo() 
is declared as:

already_AddRefedBar Foo();

won’t necessarily be obvious from a call site, where the reviewer will just see:

Foo();

That call will leak, and if we don’t happen to hit that code path in our tests, 
we may not find out about it until after shipping it.

I’d prefer that already_AddRefed just call Release(), but if there are 
performance arguments against that, then we should be checking for this pattern 
with static analysis. I don’t think the situation as it stands should be 
allowed to remain for long.

- Seth


On Jun 30, 2015, at 12:02 PM, Nathan Froyd nfr...@mozilla.com wrote:

Bug 1161627 has landed on inbound, which converts all uses of
mozilla::TemporaryRef to already_AddRefed and removes TemporaryRef.
(already_AddRefed moved to MFBT several months ago, in case you were
wondering about the spreading of XPCOM concepts.)  TemporaryRef was added
for easier porting of code from other engines, but as it has not been used
much for that purpose and it led to somewhat less efficient code in places,
it was deemed a failed experiment.

-Nathan
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-07 Thread Michael Layzell

On 2015-07-07 6:37 AM, Aryeh Gregor wrote:

Did you check whether this actually occurs in an optimized build?  C++
allows temporaries to be optimized away under some circumstances,
e.g., when returning a local variable.  It would make a lot of sense
to me if it allowed the temporary created by a ternary operator to be
optimized away.
No, I never checked if it happens on an optimized build, but as C++ 
follows an as-if principal, which means that code has to execute as if 
those temporaries had been created. Unfortunately, AddRef and Release 
are virtual, which, I'm pretty sure, means that the compiler can't 
optimize them out as they may have arbitrary side effects :(.


So the temporaries are probably eliminated, but the calls to AddRef and 
Release are probably not. I could be wrong on this though.


___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-07 Thread Aryeh Gregor
On Fri, Jul 3, 2015 at 6:22 PM, Michael Layzell mich...@thelayzells.com wrote:
 So the ternary actually causes an unnecessary AddRef/Release pair, neat.

Did you check whether this actually occurs in an optimized build?  C++
allows temporaries to be optimized away under some circumstances,
e.g., when returning a local variable.  It would make a lot of sense
to me if it allowed the temporary created by a ternary operator to be
optimized away.

 The problem here appears to be that when deciding the type of the ternary,
 c++ chooses nsRefPtrFoo, rather than Foo*. Adding the get() makes C++
 choose the correct type for the ternary, and avoids the cast of the rvalue
 reference.

I think it's pretty clear that nsRefPtrFoo must be the type of the
ternary expression.  I would be rather surprised if the type of the
ternary depended on what you did with the result!
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-05 Thread Aryeh Gregor
On Fri, Jul 3, 2015 at 3:56 PM, Neil n...@parkwaycc.co.uk wrote:
 Aryeh Gregor wrote:

 we still want a new type for function parameters that accepts implicit
 conversions from nsRefPtr/nsCOMPtr, to use instead of raw pointers.

 Sure, but that won't stop someone from writing ArgFoo foo = ReturnFoo2();
 will it?

No, but that's an extremely obvious bug that should be caught in
review.  If you want to be sure, you could do static analysis of some
kind, but I don't expect it's necessary.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-03 Thread Michael Layzell
On Fri, Jul 3, 2015 at 8:56 AM, Neil n...@parkwaycc.co.uk wrote:

 Sure, but that won't stop someone from writing ArgFoo foo =
 ReturnFoo2(); will it?

 Something like that is fairly trivial for a static analysis system like
our clang plugin to catch, if we want to create a type like that.
Restricting certain types to only exist in temporaries and parameter
declarations would not be too hard.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-03 Thread Neil

Nathan Froyd wrote:


I guess we could fix this in current m-c to be smarter about the parameter passing, perhaps by declaring that 
ParameterStoragensCOMPtrT is StoreCopyPassByConstLRefnsCOMPtrT?  (Similarly 
for nsRefPtrT.)


So what's StorensRefPtrPassByPtr for?

--
Warning: May contain traces of nuts.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-03 Thread Neil

Aryeh Gregor wrote:


we still want a new type for function parameters that accepts implicit 
conversions from nsRefPtr/nsCOMPtr, to use instead of raw pointers.

Sure, but that won't stop someone from writing ArgFoo foo = 
ReturnFoo2(); will it?


--
Warning: May contain traces of nuts.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-03 Thread Aryeh Gregor
On Thu, Jul 2, 2015 at 3:50 PM, Neil n...@parkwaycc.co.uk wrote:
 Would you mind reminding me what the failure case this avoids is?

already_AddRefedFoo
ReturnFoo1()
{
  nsRefPtrFoo foo = new Foo();
  return foo.forget();
}

nsRefPtrFoo
ReturnFoo2()
{
  return new Foo();
}

// This doesn't compile
Foo* foo = ReturnFoo1();

// This happily compiles and causes use-after-free
Foo* foo = ReturnFoo2();


Naturally, the hard-to-catch case is when the function returns
something that usually has a refcount above one, so it works fine, but
sometimes will return something with a refcount of exactly one, which
causes a sec-critical arbitrary code execution on Firefox stable.

It's worth pointing out that if we only remove the implicit conversion
to T* for rvalues, you still won't be able to directly pass the
returned value to a function that wants T*, even though this is
perfectly safe (because the destructor for the temporary won't be
called until the function call returns, IIUC).  So we still want a new
type for function parameters that accepts implicit conversions from
nsRefPtr/nsCOMPtr, to use instead of raw pointers.  But you can't pass
an already_AddRefed directly to such a function right now anyway, so
this isn't actually a disadvantage relative to the status quo.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-02 Thread Nathan Froyd
On Thu, Jul 2, 2015 at 9:21 AM, Neil n...@parkwaycc.co.uk wrote:

 Nathan Froyd wrote:

 I tried this, fixed a few compilation errors, then decided this wasn't
 worth it just yet and threw my work into a bug.  Comments appreciated:

 https://bugzilla.mozilla.org/show_bug.cgi?id=1179451


   1. It's because QueryInterface has to addref, so we can't directly
  pass the returned pointer. (But otherwise it's effectively the
  same as 4.)


Sure.  This also comes up when passing the results of nsCOMPtrT-returning
functions to other things, or returning them as raw pointers.  This might
point to a deficiency in APIs, of course.


   2. Ugh, standard MSVC optimisation doesn't compile an nsCOMPtr in a
  ternary at all well. (If my x86_64 is up to scratch then I think
  it creates an internal flag so it remembers which arm of the
  ternary was constructed.)


Hooray for forcing people to write the efficient code, then? :)


   3. Why isn't the const nsCOMPtrT converting to a T*? (There's too
  much indirection for my liking, so I can't work out which storage
  class is getting applied to the argument.)


Because for something like:

nsCOMPtrnsIRunnable event =
  NS_NewRunnableMethodWithArgnsCOMPtrnsIDOMHTMLInputElement
  (this, nsFormFillController::MaybeStartControllingInput,
focusedInput);

the nsCOMPtrnsIDOMHTMLInputElement gets the storage class
StoreCopyPassByValuensCOMPtrT, which means that the argument gets
passed as a (copied!) nsCOMPtr.  And that's a temporary, so the implicit
conversion to T* is disallowed.

I guess we could fix this in current m-c to be smarter about the parameter
passing, perhaps by declaring that ParameterStoragensCOMPtrT is
StoreCopyPassByConstLRefnsCOMPtrT?  (Similarly for nsRefPtrT.)  If
people want something else, they can explicitly ask for it.


   4. Maybe I'm confused, but isn't this the pattern we're trying to
  avoid so that we can remove already_AddRefed and use moves instead?


That's a good point, I didn't consider that when just trying to make things
compile.  In the particular case I remember fixing (calling
nsIDocument::GetBaseURI), the result was stored as a T* (!), so we would
have had to construct something explicitly anyway.

-Nathan
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-02 Thread Neil

Nathan Froyd wrote:


I tried this, fixed a few compilation errors, then decided this wasn't worth it 
just yet and threw my work into a bug.  Comments appreciated:

https://bugzilla.mozilla.org/show_bug.cgi?id=1179451
 


  1. It's because QueryInterface has to addref, so we can't directly
 pass the returned pointer. (But otherwise it's effectively the
 same as 4.)
  2. Ugh, standard MSVC optimisation doesn't compile an nsCOMPtr in a
 ternary at all well. (If my x86_64 is up to scratch then I think
 it creates an internal flag so it remembers which arm of the
 ternary was constructed.)
  3. Why isn't the const nsCOMPtrT converting to a T*? (There's too
 much indirection for my liking, so I can't work out which storage
 class is getting applied to the argument.)
  4. Maybe I'm confused, but isn't this the pattern we're trying to
 avoid so that we can remove already_AddRefed and use moves instead?

--
Warning: May contain traces of nuts.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-02 Thread Neil

Jeff Muizelaar wrote:


I believe this is predicated on removing the implicit conversion from 
nsRefPtrT to T*


Would you mind reminding me what the failure case this avoids is?

--
Warning: May contain traces of nuts.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-01 Thread Aryeh Gregor
On Wed, Jul 1, 2015 at 6:24 AM, Joshua Cranmer  pidgeo...@gmail.com wrote:

 You'd get the same benefit, I think, by making operator T*()  = delete;, 
 syntax which is accepted on gcc 4.8.1+, clang, and MSVC 2015 IIRC.

I once tried this and found it had problematic side effects that made
deploying it difficult in practice.  I think one involved the ternary
operator.  Unfortunately, I can't remember exactly what they were.  :(
 Anyone who's interested can try for themselves by just adding that
line to nsCOMPtr.h, recompiling, and seeing what breaks.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-07-01 Thread Nathan Froyd
On Wed, Jul 1, 2015 at 7:39 AM, Aryeh Gregor a...@aryeh.name wrote:

 On Wed, Jul 1, 2015 at 6:24 AM, Joshua Cranmer  pidgeo...@gmail.com
 wrote:
  You'd get the same benefit, I think, by making operator T*()  =
 delete;, syntax which is accepted on gcc 4.8.1+, clang, and MSVC 2015 IIRC.

 I once tried this and found it had problematic side effects that made
 deploying it difficult in practice.  I think one involved the ternary
 operator.  Unfortunately, I can't remember exactly what they were.  :(
  Anyone who's interested can try for themselves by just adding that
 line to nsCOMPtr.h, recompiling, and seeing what breaks.


I tried this, fixed a few compilation errors, then decided this wasn't
worth it just yet and threw my work into a bug.  Comments appreciated:

https://bugzilla.mozilla.org/show_bug.cgi?id=1179451

-Nathan
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform


Re: mozilla::TemporaryRef is gone; please use already_AddRefed

2015-06-30 Thread Robert O'Callahan
Will it ever be possible to eliminate TemporaryRef and use moves instead?

Rob
-- 
oIo otoeololo oyooouo otohoaoto oaonoyooonoeo owohooo oioso oaonogoroyo
owoiotoho oao oboroootohoeoro oooro osoiosotoeoro owoiololo oboeo
osouobojoeocoto otooo ojouodogomoeonoto.o oAogoaoiono,o oaonoyooonoeo
owohooo
osoaoyoso otooo oao oboroootohoeoro oooro osoiosotoeoro,o o‘oRoaocoao,o’o
oioso
oaonosowoeoroaoboloeo otooo otohoeo ocooouoroto.o oAonodo oaonoyooonoeo
owohooo
osoaoyoso,o o‘oYooouo ofolo!o’o owoiololo oboeo oiono odoaonogoeoro
ooofo
otohoeo ofoioroeo ooofo ohoeololo.
___
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform