Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

force casting Vec<T> to &[T] in Table::AsRef is causing trouble #145

Closed
david0u0 opened this issue Dec 2, 2022 · 12 comments
Closed

force casting Vec<T> to &[T] in Table::AsRef is causing trouble #145

david0u0 opened this issue Dec 2, 2022 · 12 comments

Comments

@david0u0
Copy link
Contributor

david0u0 commented Dec 2, 2022

The compiler version: rustc 1.67.0-nightly (c090c6880 2022-12-01)

image

As shown in the image in gdb:

  • $8 is a ref to Table
  • $7 is a ref to TableSlice, returned by Table::AsRef

They have identical pointer value, 0x7ffffff782e0, but the rows field in them are in different address. rows of Table is the correct one, while rows of TableSlice contains random data.

Further more, the rows of TableSlice has length = 93825009397280 (!!!).

The cause is in the implementation of Table::AsRef. It force casts a &Table into &TableSlice, and when the layout of these two types are not the same, it'll cause trouble.

impl<'a> AsRef<TableSlice<'a>> for Table {
    fn as_ref(&self) -> &TableSlice<'a> {
        unsafe {
            // All this is a bit hacky. Let's try to find something else
            let s = &mut *((self as *const Table) as *mut Table);
            s.rows.shrink_to_fit();
            &*(self as *const Table as *const TableSlice<'a>)
        }
    }
}
@david0u0 david0u0 changed the title force casting Box<T> to &T in Table::AsRef force casting Vec<T> to &[T] in Table::AsRef is causing trouble Dec 2, 2022
@david0u0
Copy link
Contributor Author

david0u0 commented Dec 2, 2022

More info:

  1. It was fine with rustc 1.60.0-nightly (88fb06a1f 2022-02-05). Only when I migrate to latest rustc did I see the bug.
  2. I added #[repr(C)] to both structures: now the rows field have the same address, but the length of TableSlice.rows is still corrupted.

@cschwan
Copy link

cschwan commented Dec 8, 2022

I have the same problem, see here: NNPDF/pineappl#195.

@david0u0
Copy link
Contributor Author

Also, the signature impl<'a> AsRef<TableSlice<'a>> for Table can lead to undefined behavior: what if 'a is 'static, and the table considered here is a local var?

So there's no way to fix it without breaking change, unless you leak memory indefinitely

consider following code:

    #[test]
    fn doom() {
        let s: super::TableSlice;
        {
            let t = Table::new();
            s = t.as_ref().clone();
        }
        println!("{:?}", s);
    }

This 100% safe rust will lead to segfault

@cschwan
Copy link

cschwan commented Dec 12, 2022

@david0u0 Would replacing &self with &'a self fix this? This is probably what the author meant.

@david0u0
Copy link
Contributor Author

@cschwan I think it won't compile, it will contradict the definition of AsRef

@andrewpollack
Copy link

+1 to this issue -- the following minimal test is leading to segfaults on nightly (and confirmed fixed by #146)

let _ = cell!(table!(
    ["a", "b"],
    ["c", "d"]
));

@obsgolem
Copy link

That entire function is a rats nest of undefined behavior. First, casting a reference to a mut reference is undefined behavior, you can easily get into a situation where you have both a &Table and and an &mut Table outstanding simultaneously, instantly rendering the program undefined. Additionally neither Table nor TableSlice are repr(C), and hence it is undefined behavior to try and access one via a pointer or reference to the other. The compiler may reorder structs arbitrarily, as seems to have happened here. A Vec is not guaranteed to have an initial sequence identical to a slice...

You can easily fix this by changing to something like

fn as_ref(&self) -> &TableSlice<'a> {
    TableSlice {
        format: &*self.format,
        titles: &*self.titles,
        rows: self.rows.as_slice()
    }
}

@pinkforest
Copy link
Collaborator

pinkforest commented Dec 27, 2022

Hey lovely Op, could you please do a informational = "unsound" PR at https://github.com/rustsec/advisory-db ?

I'll merge a fix for 1.0.0 - need to bring other stuff up-to-date as well.

Mark as fixed in 1.0.0 - pondering whether i should bother with a pre-release given a breaking change

Closing this when the release is out in crates.io and advisory is out.

@david0u0
Copy link
Contributor Author

@pinkforest now that the PR is merged, is it still required to mark it as unsound?

@pinkforest
Copy link
Collaborator

Yes. All the older version need to be marked as such in crates.io and get people moving to 1.0.0. I have some work to do to get to is-terminal and termcolor and do some lotto for MSRV

@david0u0
Copy link
Contributor Author

I create a PR at rustsec/advisory-db#1503

@pinkforest
Copy link
Collaborator

pinkforest commented Dec 27, 2022

0.10.0 Released and advisory is out 🥳

(I thought 1.0.0 was too premature)

facebook-github-bot pushed a commit to facebook/sapling that referenced this issue Feb 8, 2023
Summary:
`prettytable-rs-0.8.0` has unsafe code ([phsym/prettytable-rs#145][])
that is failing the sanitizers. This is fixed in
`prettytable-rs-0.10.0`. Updating `prettydiff` as well because it too
depends on `prettytable-rs-0.8.0`.

[phsym/prettytable-rs#145]: phsym/prettytable-rs#145

Reviewed By: dtolnay

Differential Revision: D43107083

fbshipit-source-id: a7887669201cab5fcf836bd0ed9d14c71180d92b
facebook-github-bot pushed a commit to facebookexperimental/hermit that referenced this issue Feb 8, 2023
Summary:
`prettytable-rs-0.8.0` has unsafe code ([phsym/prettytable-rs#145][])
that is failing the sanitizers. This is fixed in
`prettytable-rs-0.10.0`. Updating `prettydiff` as well because it too
depends on `prettytable-rs-0.8.0`.

[phsym/prettytable-rs#145]: phsym/prettytable-rs#145

Reviewed By: dtolnay

Differential Revision: D43107083

fbshipit-source-id: a7887669201cab5fcf836bd0ed9d14c71180d92b
lispc added a commit to privacy-scaling-explorations/zkevm-circuits that referenced this issue Feb 23, 2023
### Description

1. fix chain id and block number in testool.
2. upgrade "prettytable-rs". The current version will [break in future
nightly rust](phsym/prettytable-rs#145).

### Issue Link

[_link issue here_]

### Type of change

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update

### Contents

- [_item_]

### Rationale

[_design decisions and extended information_]

### How Has This Been Tested?

[_explanation_]

<hr>

## How to fill a PR description 

Please give a concise description of your PR.

The target readers could be future developers, reviewers, and auditors.
By reading your description, they should easily understand the changes
proposed in this pull request.

MUST: Reference the issue to resolve

### Single responsability

Is RECOMMENDED to create single responsibility commits, but not
mandatory.

Anyway, you MUST enumerate the changes in a unitary way, e.g.

```
This PR contains:
- Cleanup of xxxx, yyyy
- Changed xxxx to yyyy in order to bla bla
- Added xxxx function to ...
- Refactored ....
```

### Design choices

RECOMMENDED to:
- What types of design choices did you face?
- What decisions you have made?
- Any valuable information that could help reviewers to think critically
TeyKey1 added a commit to probe-rs/hive-software that referenced this issue Feb 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants