Skip to content

Should bound-checking when converting to slices do something different than panic? #194

@Fuuzetsu

Description

@Fuuzetsu

There's a lot of code similar to this, on ArrayVec:

fn deref(&self) -> &Self::Target {
    &self.data.as_slice()[..self.len as usize]
  }

We invoke something like this every single time we try to get a slice, directly or indirectly (such as via .iter()).

In world of unsafe implementations, one would normally maintain the invariant that len <= self.data.len() and unsafely create the slice. This is against what tinyvec tries to achieve. Sadly, the trade-off is that this will basically always insert panic into the generated code.

In practice, this panic can only happen if there's a bug in ArrayVec (forgetting to update len properly, missed assumption) or user does something sketchy like unsafely modify the field.

There is a different option however: change the function to look more like

fn deref(&self) -> &Self::Target {
  let len = self.len as usize;
  let s = &self.data.as_slice();
  if len < s.len() {
    &s[..len]
  } else {
    s
  }
}

This (presumably) compiles to code that doesn't have a panic and it behaves the same as usual in non-weird code. The only change in behaviour is that instead of crashing on ArrayVec bug or due to some unsafe user code (when self.len grows past capacity), it'll now give the full capacity. For all currently-working code it stays working, but probably faster (not slower, for sure...). Any currently-broken code is presumably already crashing, if such code even exists.

We can recover slight bit of previous behaviour with debug asserts I suppose...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions