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

Value::take(&mut self) causes panic #1229

Open
akmitrich opened this issue Jan 18, 2025 · 1 comment
Open

Value::take(&mut self) causes panic #1229

akmitrich opened this issue Jan 18, 2025 · 1 comment

Comments

@akmitrich
Copy link

I have a code like this

fn main() {
    let obj = b"{\"key\":\"Small JSON-file with object.\"}";
    let mut json_obj_repr: serde_json::Value = serde_json::from_slice(obj).unwrap();
    let missing_key = json_obj_repr["Hello World!"].take();
    println!("From object I took {:?}", missing_key);
    let string = b"\"There is just a string in valid JSON-file.\"";
    let mut json_str_repr: serde_json::Value = serde_json::from_slice(string).unwrap();
    let invalid_operation = json_str_repr["Hello World!"].take();
    println!("Never reach this {:?}", invalid_operation);
}

First println!

Shows that taking from missing key returns Value::Null variant. And this is what we all expect from Value::take(&mut self).

Second take() panics

thread 'main' panicked at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.135/src/value/index.rs:102:18:
cannot access key "Hello World!" in JSON string

And second println! is never reached.

My toolchain is stable-x86_64-unknown-linux-gnu - rustc 1.84.0 (9fc6b4312 2025-01-07).

@akmitrich akmitrich changed the title Value::take(&mut self) cause panic Value::take(&mut self) causes panic Jan 18, 2025
@robsdedude
Copy link

What is the request?

To quote the docs

The get and get_mut methods of Value accept any type that implements Index, as does the square-bracket indexing operator. This trait is implemented for strings which are used as the index into a JSON map, and for usize which is used as the index into a JSON array.

So using the squar-bracket operator with any other combination of index type and Value variant isn't well-defined. The exact implementation seems a bit nuanced. Here's my assessment of what's going on:

  • You have a mutable Value::String
  • You try to access ["some_key"]. Regardless of what the semantics of that are, Rust's type system requires that to return a mutable reference to a Value (i.e., &mut Value).
  • Now since that key doesn't exist the best thing serde_json could give you is a Value::Null. But where to get a mutable reference to one from? If the Value on which you do the lookup is a map, serde_json will insert a Null under that key and then give you back a mutable reference. Easy. But there's nothing that can be done about that if the Value is a String.

Options forward:

  • Don't make the value mutable. In that case, serde_json will hand you a reference to a static Null Value if the key doesn't exist or you try to look something up in a Value variant that doesn't support that index type.
  • Alternatively, you can use Value::get to make sure you don't request a mutable reference. In that case, serde_json will hand you None if the lookup fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants