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

Replace which with a manual implementation using SearchPathW #96

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

zadjii-msft
Copy link
Member

@zadjii-msft zadjii-msft commented Aug 7, 2024

This pull request removes our dependency on which, which Kenny so helpfully pointed out we don't need: https://gist.github.com/kennykerr/a4375597c7507182570576cf9e7b6ae5

sudo/src/run_handler.rs Outdated Show resolved Hide resolved
sudo/src/run_handler.rs Outdated Show resolved Hide resolved
Comment on lines +195 to +204
fn get_path_extensions() -> Vec<String> {
env::var("PATHEXT")
.unwrap_or_else(|_| {
// If PATHEXT isn't set, use the default
".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC".to_string()
})
.split(';')
.map(|ext| ext.to_string())
.collect()
}
Copy link
Member

@lhecker lhecker Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this was inside search_path_with_extensions it wouldn't need to collect into a vector first, nor allocate each string chunk.

Like this:

let pathext = env::var("PATHEXT");
let extensions = pathext
    .as_deref()
    // If PATHEXT isn't set, use the default
    .unwrap_or(".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC")
    .split(';');

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about it some more, I think it'd be preferable if we still did this, but it's not something I would block over.

// the path, including the terminating null character.
//
// Includes some padding just in case and because it's cheap.
buffer.resize((len + 64) as usize, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, doesn't this mean that if it fails to fit in the buffer we will move on to the next extension after growing the buffer? That doesn't seem correct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah. I didn't even catch this! My initial suggestion had a loop, so this looked quite similar. 😅 But it needs a loop in a loop.

let extension_hstring = HSTRING::from(extension);
// SearchPathW will ignore the extension if the filename already has one.
let len: u32 =
unsafe { SearchPathW(None, &filename, &extension_hstring, Some(&mut buffer), None) };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fairly certain that SearchPathW doesn't take an HSTRING o_O

Is this a weird rust-win32ism?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SearchPathW expects a 16-bit wide string but you're starting with a UTF-8 string. HSTRING provides a 16-bite wide string and comprehensive conversion from various Rust Standard Library types, so it's very convenient in cases like this.

Copy link
Member

@DHowett DHowett Aug 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike BSTR, HSTRING is not compatible when passed as a LPWSTR. It does not point directly to the character data. Why is passing it like a LPWSTR to an API that expects LPWSTR OK, in contravention of all Windows API design to-date?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I am happy to accept “there are magic conversions in the rust Windows crate,” but that is exactly what I mean when I ask if it is a weirdness. I also want somebody to say it on-record.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume by LPWSTR you really mean PCWSTR. 😉

In which case, HSTRING is actually a far better choice than BSTR. While BSTR is literally the pointer, that pointer is far more dangerous in general and BSTR semantics are far more nebulous than HSTRING. An HSTRING is perfectly compatible with PCWSTR and even has an API for that - WindowsGetStringRawBuffer - but I implemented it inline for both C++/WinRT and Rust and there is thus no performance penalty for pointer access. HSTRING is generally more efficient, can avoid heap allocations, and while windows-strings does provide all kinds of conveniences for both HSTRING and BSTR, the former is preferred.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Aug 9, 2024
@lhecker lhecker self-requested a review August 9, 2024 20:44
// not including the terminating null character.
if len < buffer.len() as u32 {
buffer.truncate(len as usize);
return Ok(String::from_utf16(&buffer)?);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW you could also consider returning an OsString or even better Path here, as that would be consistent with other parts of Rust and this app. It would also allow you to revert the change to absolute_path below.

@DHowett

This comment was marked as outdated.

@DHowett DHowett changed the title Replace cargo feed with Azure Artifacts feed Replace which with a manual implementation using SearchPathW Aug 13, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Aug 20, 2024
@zadjii-msft zadjii-msft removed No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Aug 22, 2024
@zadjii-msft zadjii-msft self-assigned this Aug 22, 2024
@zadjii-msft
Copy link
Member Author

(sshhh bot, I was on vacation)

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

Successfully merging this pull request may close these issues.

4 participants