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

OsString::from_reg_value shouldn't preserve null terminator #34

Closed
AlyoshaVasilieva opened this issue Sep 23, 2020 · 1 comment
Closed

Comments

@AlyoshaVasilieva
Copy link

AlyoshaVasilieva commented Sep 23, 2020

Example code:

use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;

use winreg::enums::HKEY_CURRENT_USER;
use winreg::RegKey;

fn main() {
    let base = RegKey::predef(HKEY_CURRENT_USER);
    let desktop = base.open_subkey(r#"Control Panel\Desktop"#).unwrap();
    // read using OsString
    let wallpaper: OsString = desktop.get_value("WallPaper").unwrap();
    let path = PathBuf::from(wallpaper);
    println!("Wallpaper exists? {}, path is {:?}", path.exists(), path);
    // read using String
    let wallpaper: String = desktop.get_value("WallPaper").unwrap();
    let path = PathBuf::from(wallpaper);
    println!("Wallpaper exists? {}, path is {:?}", path.exists(), path);
    // read manually
    let wallpaper = desktop.get_raw_value("WallPaper").unwrap();
    let mut raw: Vec<u16> = wallpaper
        .bytes
        .chunks_exact(2)
        .into_iter()
        .map(|c| u16::from_le_bytes([c[0], c[1]]))
        .collect();
    while raw.ends_with(&[0]) {
        raw.pop();
    }
    let path = PathBuf::from(OsString::from_wide(&raw));
    println!("Wallpaper exists? {}, path is {:?}", path.exists(), path);
}

On my machine this prints:

Wallpaper exists? false, path is "C:\\Users\\X\\AppData\\Local\\Packages\\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\\LocalState\\Assets\\0659d89079d32d12eab382d73089f7997f00ee80d8d6c053dc879e956600804b\u{0}"
Wallpaper exists? true, path is "C:\\Users\\X\\AppData\\Local\\Packages\\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\\LocalState\\Assets\\0659d89079d32d12eab382d73089f7997f00ee80d8d6c053dc879e956600804b"
Wallpaper exists? true, path is "C:\\Users\\X\\AppData\\Local\\Packages\\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\\LocalState\\Assets\\0659d89079d32d12eab382d73089f7997f00ee80d8d6c053dc879e956600804b"

(these may all print false on your machine as internally it caches elsewhere; I just needed a simpler repro)

The null terminator on the OsString causes the PathBuf to have a path to a non-existent file. As a result, I have to choose between using a String (lossy if Unicode is ill-formed) or manually turning the registry's bytes into an OsString (lossless but complex, not sure my method is 100% correct).

From the OsString docs:

OsString and OsStr bridge this gap by simultaneously representing Rust and platform-native string values, and in particular allowing a Rust string to be converted into an "OS" string with no cost if possible. A consequence of this is that OsString instances are not NUL terminated; in order to pass to e.g., Unix system call, you should create a CStr.

@gentoo90
Copy link
Owner

I specifically intended OsString to be NUL terminated and be a replacement for CString, which cannot be used with WinAPI functions because they use UTF-16. widestring crate could probably be used for that but that's an additional dependency. And I also haven't found any clean way to get rid of NULs in OsString. Seems like they're not intended to be editable.

using a String (lossy if Unicode is ill-formed)

Do you have any specific example of that?

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

2 participants