Skip to content

Segfault due to using return pointer directly #34592

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

Closed
alexcrichton opened this issue Jun 30, 2016 · 5 comments
Closed

Segfault due to using return pointer directly #34592

alexcrichton opened this issue Jun 30, 2016 · 5 comments
Assignees
Labels
A-codegen Area: Code generation T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@alexcrichton
Copy link
Member

First reported at rust-lang-deprecated/rustc-serialize#154, it looks like the code in that issue will segfault on all platforms and isn't related to the allocator in question, it's just a bad free. It looks like the expansion of #[derive(RustcDecodable)] is the function that's segfaulting, specifically:

extern crate rustc_serialize;

use rustc_serialize::*;

pub struct Request {
    pub id: String,
    pub arg: String,
}

impl Decodable for Request {
    fn decode<D: Decoder>(d: &mut D) -> Result<Request, D::Error> {
        d.read_struct("Request", 2, |d| {
            Ok(Request {
                id: match d.read_struct_field("id", 0, Decodable::decode) {
                    Ok(v) => v,
                    Err(e) => return Err(e),
                },
                arg: match d.read_struct_field("arg", 1, Decodable::decode) {
                    Ok(v) => v,
                    Err(e) => return Err(e),
                },
            })
        })
    }
}

In this function the closure should detect that it has nested returns and therefore the closure should write intermediate results into a local alloca of what to return. Instead, though, no alloca is created an results are stored directly into the return pointer.

The fault looks like it happens when:

  • The decode function is called, read_struct is called, then the closure is called.
  • The first call to read_struct_field succeeds, so the string is stored in the id field directly into the return pointer
  • The second call to read_struct_field fails, returning an error
  • The compiler writes the result (Err(D::Error)) into the return pointer
  • The compiler then attempts to free the string stored to id

Basically at that point it's freeing arbitrary data because the string has already been paved over. I have been unable to reproduce this with a smaller example because everything I do seems to trigger usage of an alloca for the return value (which should be happening here). Maybe someone else knows though how to trigger this with a smaller example.

In any case though this segafult happens on nightly/beta/stable, but would be very good to fix!

cc @rust-lang/compiler

also nominating

@alexcrichton alexcrichton added I-nominated T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 30, 2016
@alexcrichton alexcrichton added the A-codegen Area: Code generation label Jun 30, 2016
@alexcrichton
Copy link
Member Author

Oh also worth pointing out that this is only a problem for old trans, MIR trans does not exhibit this segfault.

@arielb1 arielb1 added the I-wrong label Jul 1, 2016
@arielb1
Copy link
Contributor

arielb1 commented Jul 1, 2016

trans has way too many of these bugs, but we are moving to MIR-by-default soon anyway.

@luqmana luqmana self-assigned this Jul 5, 2016
@luqmana
Copy link
Member

luqmana commented Jul 5, 2016

Here is a smaller test case. Seems like it has to be a nested return in a closure in a generic cross crate fn.

pub struct Request {
    pub id: String,
    pub arg: String,
}

pub fn decode<T>() -> Result<Request, ()> {
    (|| {
        Ok(Request {
            id: "hi".to_owned(),
            arg: match Err(()) {
                Ok(v) => v,
                Err(e) => return Err(e)
            },
        })
    })()
}
extern crate test;

fn main() {
    assert!(test::decode::<()>().is_err());
}

I think I have a fix for it and I'll try to put it up soon.

bors added a commit that referenced this issue Jul 7, 2016
Just pass in NodeId to FunctionContext::new instead of looking it up.

Fixes #34592.
@posborne
Copy link
Contributor

@alexcrichton I'm running into this on 1.10 and it also fails on rustc 1.11.0-beta.1 (8dc253bcf 2016-07-05) (but not nightly). For me, my code crashes if I (or a user) provides invalid JSON that correct code tries to parse using . I would very much like to see a fix in 1.11 if possible. Any chance of that?

This bug would seems to breaks the canonical way of doing JSON parsing for the majority of users.

@alexcrichton
Copy link
Member Author

@posborne sure! I've nominated the PR for a beta backport at #34658 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants