Working with unsafe block

I wrote the below code to check if pg is installed on my pc or not:

    use std::process::Command;
    let mut cmd = Command::new("psql");
    cmd.arg("-V");
    let pg = match cmd.output(){
                Ok(o) => unsafe {
                        //    println!("Output: {}", String::from_utf8_unchecked(o.stdout));
                        &String::from_utf8_unchecked(o.stdout);
                    },
                    Err(e) => {
                        &format!("There was an error {}", e);
                    }
                };

    println!("{:?}", pg);

The output I got is:

    Finished dev [unoptimized + debuginfo] target(s) in 13.20s
     Running `target\debug\css.exe`
()

Which means the returned is (), while I actually expect to get some understandable feedback.

NOTE
The commented statement in the above code, is working fine once it is uncommented, and it gives the correct answer

println!("Output: {}", String::from_utf8_unchecked(o.stdout));

correct output:

Output: psql (PostgreSQL) 11.1

Semicolon gives (). Watch out for the semicolon after the String.

Also note that {&String::from()} can't work because it means:

  1. Make a string
  2. Throw away the string at the }
  3. Return a reference to the string that has just been destroyed

You'll need to return an owned value rather than a temporary borrow, or assign the string to a variable in a higher level scope and return reference to that longer lived variable.

3 Likes

I strongly recommend you just use String::from_utf8. Given that you're executing a system command, I'm sure there's no meaningful performance benefit to be gained from from_utf8_unchecked. unsafe should be a last resort.

3 Likes

Apparently from_utf8 returns result while from_utf8_unchecked returns String

Thanks a lot

yes, so you can just .unwrap() the result (a panic is better than undefined behavior), or handle errors some other way if you want.

1 Like

Thanks, it works fine, even I do not need to use the unsafe block by this:

   |
31 |                 Ok(o) => unsafe {
   |                          ^^^^^^ unnecessary `unsafe` block
   |

   = note: #[warn(unused_unsafe)] on by default

So, I re-wrote the code as:

let pg = match cmd.output(){
               Ok(o) =>  String::from_utf8(o.stdout).expect("sorry, an error occured"),
               Err(e) => format!("There was an error {}", e)
            };

Depending on the context, you might be able to make this even simpler:

let pg = String::from_utf8(cmd.output()?.stdout)?;