On Tue, Aug 12, 2014 at 5:59 PM, Benjamin Smedberg
<benja...@smedbergs.us> wrote:
> Just reading bug 1052477, and I'm wondering about what are intentions are
> for already_AddRefed.
>
> In that bug it's proposed to change the return type of NS_NewAtom from
> already_AddRefed to nsCOMPtr. I don't think that actually saves any
> addref/release pairs if done properly, since you'd typically .forget() into
> the return value anyway. But it does make it slightly safer at callsites,
> because the compiler will guarantee that the return value is always released
> instead of us relying on every already_AddRefed being saved into a nsCOMPtr.

Correct, it doesn't save addref/release pairs.  Some advantages of
converting already_AddRefed to just returning raw nsCOMPtr/nsRefPtr
are:

1) You can use the return value directly without assigning it to an
nsCOMPtr/nsRefPtr.  For instance, pass it to a function that wants a
raw pointer, or compare it against a different value.

2) It's easier to use, as evidenced by the patches in bugs 1015114 and
1052477.  No .forget() is needed, a raw pointer can be returned
directly, even things like do_QueryInterface can be returned directly
without a temporary nsCOMPtr (since the return type creates the
temporary for you).  You can just return whatever you like and the
compiler will figure out if an addref is needed.  There's a noticeable
decrease in LoC when converting to use it.

3) We can get rid of a class, which simplifies the codebase.

4) If the callee already holds a strong reference in a local variable,
it can just return that reference instead of a raw pointer.  This
saves an addref/release if the caller puts the result in an nsCOMPtr.
Currently you could do this by returning an already_AddRefed, but
that's annoying because of (1) above, so people don't always do so.

5) Callees that don't care about the risk of an extra addref/release
can just return nsCOMPtr instead of raw pointers across the board.
This avoids a potentially sec-critical use-after-free vulnerability
that can occur if a function returns a raw pointer, then the caller
passes it to a function that takes a raw pointer, then the second
function does something to release it.  This is very easy to do by
mistake, because the bug just looks like "SomeFunction(GetThing());".
Again, in theory you could already use already_AddRefed for this, but
this change makes it painless.

6) In theory, the compiler can use RVO to elide the construction of
the temporary altogether, although I'm not at all sure this is useful
in practice.

IMO, already_AddRefed is exactly the sort of use-case move
constructors are meant to solve, and it's no longer needed once we
have working move constructors for nsCOMPtr/nsRefPtr.  I was planning
to write up an informational post once bug 1015114 landed explaining
the benefits and telling people how to convert everything.

> But now that nsCOMPtr/nsRefPtr support proper move constructors, is there
> any reason for already_AddRefed to exist at all in our codebase? Could we
> replace every already_AddRefed return value with a nsCOMPtr?

I've put some thought into this.  Simple returns of already_AddRefed
can definitely be converted without much effort, and it reduces LoC
too.  A bit more thought will be needed to get rid of the class
entirely, I think.  For one thing, we'd need a replacement for
dont_AddRef().  Also, the move constructors themselves will need to be
rewritten, because they use .forget() (a few friend declarations
should do it).
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to