Bug 1809492 Comment 25 Edit History

Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.

Sorry, what I wrote was (again) wrong.

The main point is wanted to convey is that `0x7ffffffff0de7fff` is not a random value. It is the result of calling `mozWritePoison()`. This is a crucial hint that we can use for solving this crash.

When we free most objects, we will use `e5` repeatedly to poison them. This is what [`arena_dalloc()`'s `MaybePoison()`](https://searchfox.org/mozilla-central/source/memory/build/mozjemalloc.cpp#3767) does. This is how the object behind `mView.mRawPtr` gets poisoned after it gets freed. Hence the problem is not with that object (contrary to what I wrote before).

In a few locations, we do a similar kind of poisoning, except we do it with pattern `0x7ffffffff0de7fff` and not `e5`. In particular, `0x7ffffffff0de7fff` is used to poison `nsTreeBodyFrame` objects after they are destroyed. This goes through the following path:
- [`nsTreeBodyFrame::DestroyFrom()` calls `SimpleXULLeafFrame::DestroyFrom()`](https://searchfox.org/mozilla-central/source/layout/xul/tree/nsTreeBodyFrame.cpp#330) (the `nsTreeBodyFrame*` is `this`);
- `SimpleXULLeafFrame::DestroyFrom()` is actually `nsIFrame::DestroyFrom()` (the `nsTreeBodyFrame*` is `this`);
- [`nsIFrame::DestroyFrom()` calls `mozilla::PresShell::FreeFrame()`](https://searchfox.org/mozilla-central/source/layout/generic/nsIFrame.cpp#926) (the `nsTreeBodyFrame*` is `aPtr`);
- this [ends up calling `mozWritePoison()`](https://searchfox.org/mozilla-central/source/layout/base/nsPresArena.cpp#112) on the `nsTreeBodyFrame` object.

So, with high confidence this time, what we see in these crashes is that the layout of our `nsTreeBodyFrame` object has already been poisoned after it was freed through `nsTreeBodyFrame::DestroyFrom()`. Yet, we are now handling a blur event, that ends up calling `nsTreeBodyFrame::SetFocused()` on that same freed (and poisoned) `nsTreeBodyFrame` object. So, when we try to access its `mView.mRawPtr`, the value we get back is `(nsITreeView*)0x7ffffffff0de7fff`. When we try to use that pointer, we crash.

I think [this is the JavaScript handler definition](https://searchfox.org/mozilla-central/source/toolkit/content/widgets/tree.js#850-859) that ends up calling into `nsTreeBodyFrame::SetFocused()`:

```JavaScript
      this.addEventListener(
        "blur",
        event => {
          this.focused = false;
          if (event.target == this.inputField) {
            this.stopEditing(true);
          }
        },
        true
      );
```

This calls into [`XULTreeElement::SetFocused()`](https://searchfox.org/mozilla-central/source/dom/xul/XULTreeElement.cpp#157-162), which calls `nsTreeBodyFrame::SetFocused()` on the `nsTreeBodyFrame*` returned by `XULTreeElement::GetTreeBodyFrame()`.

```
void XULTreeElement::SetFocused(bool aFocused) {
  nsTreeBodyFrame* body = GetTreeBodyFrame();
  if (body) {
    body->SetFocused(aFocused);
  }
}
```

There, `XULTreeElement::GetTreeBodyFrame` will most likely return the cached pointer value stored in the `mTreeBodyFrame` field of the `XULTreeElement`. But this field is a raw pointer and I don't see any ref counting occur when the pointer is cached.

I think that the `nsFocusManager` could be properly retaining the `XULTreeElement`, but that then the `XULTreeElement` would fails to guarantee that the pointer in `mTreeBodyFrame` lives for at least as long as the `XULTreeElement` itself, which would then result in this crash.
Sorry, what I wrote was (again) wrong.

The main point is wanted to convey is that `0x7ffffffff0de7fff` is not a random value. It is the result of calling `mozWritePoison()`. This is a crucial hint that we should try to use for solving this crash.

When we free most objects, we will use `e5` repeatedly to poison them. This is what [`arena_dalloc()`'s `MaybePoison()`](https://searchfox.org/mozilla-central/source/memory/build/mozjemalloc.cpp#3767) does. This is how the object behind `mView.mRawPtr` gets poisoned after it gets freed. Hence the problem is not with that object (contrary to what I wrote before).

In a few locations, we do a similar kind of poisoning, except we do it with pattern `0x7ffffffff0de7fff` and not `e5`. In particular, `0x7ffffffff0de7fff` is used to poison `nsTreeBodyFrame` objects after they are destroyed. This goes through the following path:
- [`nsTreeBodyFrame::DestroyFrom()` calls `SimpleXULLeafFrame::DestroyFrom()`](https://searchfox.org/mozilla-central/source/layout/xul/tree/nsTreeBodyFrame.cpp#330) (the `nsTreeBodyFrame*` is `this`);
- `SimpleXULLeafFrame::DestroyFrom()` is actually `nsIFrame::DestroyFrom()` (the `nsTreeBodyFrame*` is `this`);
- [`nsIFrame::DestroyFrom()` calls `mozilla::PresShell::FreeFrame()`](https://searchfox.org/mozilla-central/source/layout/generic/nsIFrame.cpp#926) (the `nsTreeBodyFrame*` is `aPtr`);
- this [ends up calling `mozWritePoison()`](https://searchfox.org/mozilla-central/source/layout/base/nsPresArena.cpp#112) on the `nsTreeBodyFrame` object.

So, with high confidence this time, what we see in these crashes is that the layout of our `nsTreeBodyFrame` object has already been poisoned after it was freed through `nsTreeBodyFrame::DestroyFrom()`. Yet, we are now handling a blur event, that ends up calling `nsTreeBodyFrame::SetFocused()` on that same freed (and poisoned) `nsTreeBodyFrame` object. So, when we try to access its `mView.mRawPtr`, the value we get back is `(nsITreeView*)0x7ffffffff0de7fff`. When we try to use that pointer, we crash.

I think [this is the JavaScript handler definition](https://searchfox.org/mozilla-central/source/toolkit/content/widgets/tree.js#850-859) that ends up calling into `nsTreeBodyFrame::SetFocused()`:

```JavaScript
      this.addEventListener(
        "blur",
        event => {
          this.focused = false;
          if (event.target == this.inputField) {
            this.stopEditing(true);
          }
        },
        true
      );
```

This calls into [`XULTreeElement::SetFocused()`](https://searchfox.org/mozilla-central/source/dom/xul/XULTreeElement.cpp#157-162), which calls `nsTreeBodyFrame::SetFocused()` on the `nsTreeBodyFrame*` returned by `XULTreeElement::GetTreeBodyFrame()`.

```
void XULTreeElement::SetFocused(bool aFocused) {
  nsTreeBodyFrame* body = GetTreeBodyFrame();
  if (body) {
    body->SetFocused(aFocused);
  }
}
```

There, `XULTreeElement::GetTreeBodyFrame` will most likely return the cached pointer value stored in the `mTreeBodyFrame` field of the `XULTreeElement`. But this field is a raw pointer and I don't see any ref counting occur when the pointer is cached.

I think that the `nsFocusManager` could be properly retaining the `XULTreeElement`, but that then the `XULTreeElement` would fails to guarantee that the pointer in `mTreeBodyFrame` lives for at least as long as the `XULTreeElement` itself, which would then result in this crash.
Sorry, what I wrote was (again) wrong.

The main point is wanted to convey is that `0x7ffffffff0de7fff` is not a random value. It is the result of calling `mozWritePoison()`. This is a crucial hint that we should try to use for solving this crash.

When we free most objects, we will use `e5` repeatedly to poison them. This is what [`arena_dalloc()`'s `MaybePoison()`](https://searchfox.org/mozilla-central/source/memory/build/mozjemalloc.cpp#3767) does. This is how the object behind `mView.mRawPtr` gets poisoned after it gets freed. Hence the problem is not with that object (contrary to what I wrote before).

In a few locations, we do a similar kind of poisoning, except we do it with pattern `0x7ffffffff0de7fff` and not `e5`. In particular, `0x7ffffffff0de7fff` is used to poison `nsTreeBodyFrame` objects after they are destroyed. This goes through the following path:
- [`nsTreeBodyFrame::DestroyFrom()` calls `SimpleXULLeafFrame::DestroyFrom()`](https://searchfox.org/mozilla-central/source/layout/xul/tree/nsTreeBodyFrame.cpp#330) (the `nsTreeBodyFrame*` is `this`);
- `SimpleXULLeafFrame::DestroyFrom()` is actually `nsIFrame::DestroyFrom()` (the `nsTreeBodyFrame*` is `this`);
- [`nsIFrame::DestroyFrom()` calls `mozilla::PresShell::FreeFrame()`](https://searchfox.org/mozilla-central/source/layout/generic/nsIFrame.cpp#926) (the `nsTreeBodyFrame*` is `aPtr`);
- this [ends up calling `mozWritePoison()`](https://searchfox.org/mozilla-central/source/layout/base/nsPresArena.cpp#112) on the `nsTreeBodyFrame` object.

So, with high confidence this time, what we see in these crashes is that the layout of our `nsTreeBodyFrame` object has already been poisoned after it was freed through `nsTreeBodyFrame::DestroyFrom()`. Yet, we are now handling a blur event, that ends up calling `nsTreeBodyFrame::SetFocused()` on that same freed (and poisoned) `nsTreeBodyFrame` object. So, when we try to access its `mView.mRawPtr`, the value we get back is `(nsITreeView*)0x7ffffffff0de7fff`. When we try to use that pointer, we crash.

I think [this is the JavaScript handler definition](https://searchfox.org/mozilla-central/source/toolkit/content/widgets/tree.js#850-859) that ends up calling into `nsTreeBodyFrame::SetFocused()`:

```JavaScript
      this.addEventListener(
        "blur",
        event => {
          this.focused = false;
          if (event.target == this.inputField) {
            this.stopEditing(true);
          }
        },
        true
      );
```

This calls into [`XULTreeElement::SetFocused()`](https://searchfox.org/mozilla-central/source/dom/xul/XULTreeElement.cpp#157-162), which calls `nsTreeBodyFrame::SetFocused()` on the `nsTreeBodyFrame*` returned by `XULTreeElement::GetTreeBodyFrame()`.

```
void XULTreeElement::SetFocused(bool aFocused) {
  nsTreeBodyFrame* body = GetTreeBodyFrame();
  if (body) {
    body->SetFocused(aFocused);
  }
}
```

There, `XULTreeElement::GetTreeBodyFrame` will most likely return the cached pointer value stored in the `mTreeBodyFrame` field of the `XULTreeElement`. But this field is a raw pointer and I don't see any ref counting occur when the pointer is cached.

I think that the `nsFocusManager` could be properly retaining the `XULTreeElement`, but that then the `XULTreeElement` would fail to guarantee that the pointer in `mTreeBodyFrame` lives for at least as long as the `XULTreeElement` itself, which would then result in this crash.
Sorry, what I wrote was (again) wrong.

The main point is wanted to convey is that `0x7ffffffff0de7fff` is not a random value. It is the result of calling `mozWritePoison()`. This is a crucial hint that we should try to use for solving this crash.

When we free most objects, we will use `e5` repeatedly to poison them. This is what [`arena_dalloc()`'s `MaybePoison()`](https://searchfox.org/mozilla-central/source/memory/build/mozjemalloc.cpp#3767) does. This is how the object behind `mView.mRawPtr` gets poisoned after it gets freed. Hence the problem is not with that object (contrary to what I wrote before).

In a few locations, we do a similar kind of poisoning, except we do it with pattern `0x7ffffffff0de7fff` and not `e5`. In particular, `0x7ffffffff0de7fff` is used to poison `nsTreeBodyFrame` objects after they are destroyed. This goes through the following path:
- [`nsTreeBodyFrame::DestroyFrom()` calls `SimpleXULLeafFrame::DestroyFrom()`](https://searchfox.org/mozilla-central/source/layout/xul/tree/nsTreeBodyFrame.cpp#330) (the `nsTreeBodyFrame*` is `this`);
- `SimpleXULLeafFrame::DestroyFrom()` is actually `nsIFrame::DestroyFrom()` (the `nsTreeBodyFrame*` is `this`);
- [`nsIFrame::DestroyFrom()` calls `mozilla::PresShell::FreeFrame()`](https://searchfox.org/mozilla-central/source/layout/generic/nsIFrame.cpp#926) (the `nsTreeBodyFrame*` is `aPtr`);
- this [ends up calling `mozWritePoison()`](https://searchfox.org/mozilla-central/source/layout/base/nsPresArena.cpp#112) on the `nsTreeBodyFrame` object.

So, with high confidence this time, what we see in these crashes is that the layout of our `nsTreeBodyFrame` object has already been poisoned after it was freed through `nsTreeBodyFrame::DestroyFrom()`. Yet, we are now handling a blur event, that ends up calling `nsTreeBodyFrame::SetFocused()` on that same freed (and poisoned) `nsTreeBodyFrame` object. So, when we try to access its `mView.mRawPtr`, the value we get back is `(nsITreeView*)0x7ffffffff0de7fff`. When we try to use that pointer, we crash.

I think [this is the JavaScript handler definition](https://searchfox.org/mozilla-central/source/toolkit/content/widgets/tree.js#850-859) that ends up calling into `nsTreeBodyFrame::SetFocused()`:

```JavaScript
      this.addEventListener(
        "blur",
        event => {
          this.focused = false;
          if (event.target == this.inputField) {
            this.stopEditing(true);
          }
        },
        true
      );
```

This calls into [`XULTreeElement::SetFocused()`](https://searchfox.org/mozilla-central/source/dom/xul/XULTreeElement.cpp#157-162), which calls `nsTreeBodyFrame::SetFocused()` on the `nsTreeBodyFrame*` returned by `XULTreeElement::GetTreeBodyFrame()`.

```
void XULTreeElement::SetFocused(bool aFocused) {
  nsTreeBodyFrame* body = GetTreeBodyFrame();
  if (body) {
    body->SetFocused(aFocused);
  }
}
```

There, `XULTreeElement::GetTreeBodyFrame` will most likely return the cached pointer value stored in the `mTreeBody` field of the `XULTreeElement`. But this field is a raw pointer and I don't see any ref counting occur when the pointer is cached.

I think that the `nsFocusManager` could be properly retaining the `XULTreeElement`, but that then the `XULTreeElement` would fail to guarantee that the pointer in `mTreeBody` lives for at least as long as the `XULTreeElement` itself, which would then result in this crash.
Sorry, what I wrote was (again) wrong.

The main point is wanted to convey is that `0x7ffffffff0de7fff` is not a random value. It is the result of calling `mozWritePoison()`. This is a crucial hint that we should try to use for solving this crash.

When we free most objects, we will use `e5` repeatedly to poison them. This is what [`arena_dalloc()`'s `MaybePoison()`](https://searchfox.org/mozilla-central/source/memory/build/mozjemalloc.cpp#3767) does. This is how the object behind `mView.mRawPtr` gets poisoned after it gets freed. Hence the problem is not with that object (contrary to what I wrote before).

In a few locations, we do a similar kind of poisoning, except we do it with pattern `0x7ffffffff0de7fff` and not `e5`. In particular, `0x7ffffffff0de7fff` is used to poison `nsTreeBodyFrame` objects after they are destroyed. This goes through the following path:
- [`nsTreeBodyFrame::DestroyFrom()` calls `SimpleXULLeafFrame::DestroyFrom()`](https://searchfox.org/mozilla-central/source/layout/xul/tree/nsTreeBodyFrame.cpp#330) (the `nsTreeBodyFrame*` is `this`);
- `SimpleXULLeafFrame::DestroyFrom()` is actually `nsIFrame::DestroyFrom()` (the `nsTreeBodyFrame*` is `this`);
- [`nsIFrame::DestroyFrom()` calls `mozilla::PresShell::FreeFrame()`](https://searchfox.org/mozilla-central/source/layout/generic/nsIFrame.cpp#926) (the `nsTreeBodyFrame*` is `aPtr`);
- this [ends up calling `mozWritePoison()`](https://searchfox.org/mozilla-central/source/layout/base/nsPresArena.cpp#112) on the `nsTreeBodyFrame` object.

So, with high confidence this time, what we see in these crashes is that the layout of our `nsTreeBodyFrame` object has already been poisoned after it was freed through `nsTreeBodyFrame::DestroyFrom()`. Yet, we are now handling a blur event, that ends up calling `nsTreeBodyFrame::SetFocused()` on that same freed (and poisoned) `nsTreeBodyFrame` object. So, when we try to access its `mView.mRawPtr`, the value we get back is `(nsITreeView*)0x7ffffffff0de7fff`. When we try to use that pointer, we crash.

I think [this is the JavaScript handler definition](https://searchfox.org/mozilla-central/source/toolkit/content/widgets/tree.js#850-859) that ends up calling into `nsTreeBodyFrame::SetFocused()`:

```JavaScript
      this.addEventListener(
        "blur",
        event => {
          this.focused = false;
          if (event.target == this.inputField) {
            this.stopEditing(true);
          }
        },
        true
      );
```

This calls into [`XULTreeElement::SetFocused()`](https://searchfox.org/mozilla-central/source/dom/xul/XULTreeElement.cpp#157-162), which calls `nsTreeBodyFrame::SetFocused()` on the `nsTreeBodyFrame*` returned by `XULTreeElement::GetTreeBodyFrame()`.

```
void XULTreeElement::SetFocused(bool aFocused) {
  nsTreeBodyFrame* body = GetTreeBodyFrame();
  if (body) {
    body->SetFocused(aFocused);
  }
}
```

There, `XULTreeElement::GetTreeBodyFrame()` will most often return the cached pointer value stored in the `mTreeBody` field of the `XULTreeElement`. But this field is a raw pointer and I don't see any ref counting occur when the pointer is cached.

I think that the `nsFocusManager` could be properly retaining the `XULTreeElement`, but that then the `XULTreeElement` would fail to guarantee that the pointer in `mTreeBody` lives for at least as long as the `XULTreeElement` itself, which would then result in this crash.

Back to Bug 1809492 Comment 25