Skip to content

Where to document allocation size upper bound? #465

Closed
@joshlf

Description

@joshlf

It's common knowledge that a "Rust object" or "Rust allocation" can't have a size which overflows isize. This is relied upon in a lot of APIs such as the raw pointer add method. However, the only place it seems to be documented as a general property is on the reference page for numeric types:

The isize type is a signed integer type with the same number of bits as the platform's pointer type. The theoretical upper bound on object and array size is the maximum isize value. This ensures that isize can be used to calculate differences between pointers into an object or array and can address every byte within an object along with one byte past the end.

I see a few issues with this description:

  • Being on the page for numeric types makes this text not that discoverable for people looking for general guarantees about types and allocations.
  • It uses imprecise language: what are "objects" and "arrays"? Is the latter used in the sense of the type system - a [T; N]?
  • Some allocations are neither native Rust objects nor native Rust arrays. E.g., the allocation backing a Vec doesn't have a type (at least not in its API). If it's guaranteed that &T can't refer to an object of more than isize bytes, then vec.as_slice() can't return a reference which violates this guarantee. However, that doesn't prevent the addresses of vec[0] and vec[N] from being more than isize bytes apart. Various Vec APIs strongly hint that this is impossible, but none actually guarantee it, and the Vec top-level docs make no guarantee about the interactions between various APIs (such as the vec[0]/vec[N] problem).

Based on my understanding of the current state of the language, here's a stab at a more complete set of guarantees; do these sound reasonable?

  • For all T, given t: T, the size of t is guaranteed to fit in an isize
  • For all T, given t: &T, the size of t's referent is guaranteed to fit in an isize
  • With respect to non-builtin types like Vec, I could see a few approaches:
    • Each such type documents its own guarantees
    • We define a formal notion of an "allocation", and document that t: T and t: &T are instances of allocations. Beyond that, we leave it up to non-builtin types to document their own guarantees by making reference to the docs for "allocation".
    • We define a formal notion of an "allocation", and make it clear in the definition itself that it covers non-builtin things like Vec. That seems iffy; I'm not sure how you'd formally specify the set of objects that are covered by a definition like this (e.g., do we want to make guarantees about the memory backing a HashMap?).

cc @jswrenn

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions