alexcrichton opened issue #12199:
There's some more discussion here, but I personally think we should strive to extend this error with the contextual number of bytes that were attempted to be allocated. Implementation-wise this will be tricky, however, so it'll require deliberate design.
alexcrichton added the wasmtime:api label to Issue #12199.
fitzgen commented on issue #12199:
How does this sound?
- Bitpack the size and layout into the
&OutOfMemorypointer.- Add a
pub fn OutOfMemory::layout(&self) -> Layoutmethod that reads the bitpacked data.- Do _not_ have a public ctor for
OutOfMemory(and I guess also remove the clone/copy derives?)- Instead have
pub fn Error::out_of_memory(layout: Layout) -> Error, which does the bitpacking and wrapping up into anError.So with this setup, you are generally only ever dealing with
&OutOfMemoryor anErrorwrapping anOutOfMemory, but not an ownedOutOfMemorythat isn't inside anError. So you can still ask things likeerror.is<OutOfMemory>()and doerror.downcast_ref::<OutOfMemory>().unwrap().layout()and all that, which is / will be (probably?) the most common uses ofOutOfMemory.However, the one tricky thing is that
error.downcast::<OutOfMemory>().unwrap()will give you an ownedOutOfMemory, but because it isn't a pointer into anError, you will lose the bitpacked layout info, and soOutOfMemory::layoutwill need to return an option or a zero-sized layout or something. Perhaps even worse is that we have no guarantee that taking a reference to an ownedOutOfMemorywill produce a pointer that won't "accidentally" have non-zero data in our bitpacked areas, so we could just return arbitrary (and incorrect) layouts in this case.FWIW, we could also avoid this one last edge case by moving the
layoutmethod toError, so you can only get the layout info from anErrorthat wraps anOutOfMemory(presumably; we'd still have an option for the non-OOMErrorcase, but we wouldn't have to worry about arbitrary/incorrect layout data). This is probably the way to go, despite the API being a bit funkier...
fitzgen commented on issue #12199:
However, the one tricky thing is that
error.downcast::<OutOfMemory>().unwrap()will give you an ownedOutOfMemoryWe could also just make
error.downcast::<OutOfMemory>()always fail too. This might actually be the best option, since that way we can use the bitpacked layout information inside the display and debug impls forOutOfMemory, which having the layout accessors onErrorwouldn't allow.
alexcrichton commented on issue #12199:
Wouldn't we want a public constructor of
OutOfMemoryfor collection-based APIs which'd returnResult<T, OutOfMemory>?
fitzgen commented on issue #12199:
Wouldn't we want a public constructor of
OutOfMemoryfor collection-based APIs which'd returnResult<T, OutOfMemory>?Yeah I just ran into this as I started investigating further.
New idea: make
OutOfMemorya newtype wrapper aroundErrorwhere the wrappedErroris guaranteed to be bitpacked with layout info and have a discriminant appropriately set to mark that it is not a boxed dyn error (as it already does today).
alexcrichton commented on issue #12199:
I may not quite be following something, or I think I'm missing something? I would expect
OutOfMemoryto containNonZero<usize>and thenError's internalNonNull<T>which it contains would be transmuted toNonZero<usize>for getting&OutOfMemoryor something like that. I also don't think we can deal with a fullLayout(size + align) and can only deal with the size for now, I don't know how to bitpack the alignment into the payload.
fitzgen commented on issue #12199:
I would expect
OutOfMemoryto containNonZero<usize>and thenError's internalNonNull<T>which it contains would be transmuted toNonZero<usize>for getting&OutOfMemoryor something like that.Yeah, this is basically equivalent to my newtype idea.
I also don't think we can deal with a full
Layout(size + align) and can only deal with the size for now, I don't know how to bitpack the alignment into the payload.I think you are correct. I was thinking that, because the alloc size is limited to
isize::MAXwe had half the bits for the layout, but we have half theusizerange which is only one bit. Mixing up domains.
alexcrichton commented on issue #12199:
On second thought -- I don't think that
&NonNull<T>can be safely coerced to&NonZero<usize>. What with provenance and CHERI I suspect that's an explicitly unsupported operation, and that might sink this entire endeavour
fitzgen commented on issue #12199:
We can have
OutOfMemorywrap aNonNull<()>or whatever and bit pack in the address
fitzgen commented on issue #12199:
(Or be a newtype of
Error, as originally suggested)
alexcrichton commented on issue #12199:
Good point, and ok yeah that seems reasonable (
struct OutOfMemory(Error)) with some extra guarantees perhaps or something like that
fitzgen closed issue #12199:
There's some more discussion here, but I personally think we should strive to extend this error with the contextual number of bytes that were attempted to be allocated. Implementation-wise this will be tricky, however, so it'll require deliberate design.
Last updated: Feb 24 2026 at 05:28 UTC