cli: check glibc version more correctly on gnu (#166622)

Fixes https://github.com/microsoft/vscode-remote-release/issues/7495
pull/166649/head
Connor Peet 2022-11-17 11:16:30 -08:00 committed by GitHub
parent 061e7540cd
commit 9dd6dc2874
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 57 additions and 26 deletions

View File

@ -17,6 +17,7 @@ use super::errors::AnyError;
lazy_static! {
static ref LDCONFIG_STDC_RE: Regex = Regex::new(r"libstdc\+\+.* => (.+)").unwrap();
static ref LDD_VERSION_RE: BinRegex = BinRegex::new(r"^ldd.*(.+)\.(.+)\s").unwrap();
static ref GENERIC_VERSION_RE: Regex = Regex::new(r"^([0-9]+)\.([0-9]+)$").unwrap();
static ref LIBSTD_CXX_VERSION_RE: BinRegex =
BinRegex::new(r"GLIBCXX_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?").unwrap();
static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 18);
@ -116,13 +117,23 @@ async fn check_musl_interpreter() -> Result<(), String> {
#[allow(dead_code)]
async fn check_glibc_version() -> Result<(), String> {
let ldd_version = capture_command("ldd", ["--version"])
.await
.ok()
.and_then(|o| extract_ldd_version(&o.stdout));
#[cfg(target_env = "gnu")]
let version = {
let v = unsafe { libc::gnu_get_libc_version() };
let v = unsafe { std::ffi::CStr::from_ptr(v) };
let v = v.to_str().unwrap();
extract_generic_version(v)
};
#[cfg(not(target_env = "gnu"))]
let version = {
capture_command("ldd", ["--version"])
.await
.ok()
.and_then(|o| extract_ldd_version(&o.stdout))
};
if let Some(v) = ldd_version {
return if v.gte(&MIN_LDD_VERSION) {
if let Some(v) = version {
return if v >= *MIN_LDD_VERSION {
Ok(())
} else {
Err(format!(
@ -181,7 +192,7 @@ fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<(), String
})
.collect();
if !all_versions.iter().any(|v| MIN_CXX_VERSION.gte(v)) {
if !all_versions.iter().any(|v| &*MIN_CXX_VERSION >= v) {
return Err(format!(
"find GLIBCXX >= 3.4.18 (but found {} instead) for GNU environments",
all_versions
@ -195,6 +206,7 @@ fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<(), String
Ok(())
}
#[allow(dead_code)]
fn extract_ldd_version(output: &[u8]) -> Option<SimpleSemver> {
LDD_VERSION_RE.captures(output).map(|m| SimpleSemver {
major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())),
@ -203,6 +215,15 @@ fn extract_ldd_version(output: &[u8]) -> Option<SimpleSemver> {
})
}
#[allow(dead_code)]
fn extract_generic_version(output: &str) -> Option<SimpleSemver> {
GENERIC_VERSION_RE.captures(output).map(|m| SimpleSemver {
major: m.get(1).map_or(0, |s| s.as_str().parse().unwrap()),
minor: m.get(2).map_or(0, |s| s.as_str().parse().unwrap()),
patch: 0,
})
}
fn extract_libstd_from_ldconfig(output: &[u8]) -> Option<String> {
String::from_utf8_lossy(output)
.lines()
@ -215,13 +236,35 @@ fn u32_from_bytes(b: &[u8]) -> u32 {
String::from_utf8_lossy(b).parse::<u32>().unwrap_or(0)
}
#[derive(Debug, PartialEq)]
#[derive(Debug, Default, PartialEq, Eq)]
struct SimpleSemver {
major: u32,
minor: u32,
patch: u32,
}
impl PartialOrd for SimpleSemver {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SimpleSemver {
fn cmp(&self, other: &Self) -> Ordering {
let major = self.major.cmp(&other.major);
if major != Ordering::Equal {
return major;
}
let minor = self.minor.cmp(&other.minor);
if minor != Ordering::Equal {
return minor;
}
self.patch.cmp(&other.patch)
}
}
impl From<&SimpleSemver> for String {
fn from(s: &SimpleSemver) -> Self {
format!("v{}.{}.{}", s.major, s.minor, s.patch)
@ -243,18 +286,6 @@ impl SimpleSemver {
patch,
}
}
fn gte(&self, other: &SimpleSemver) -> bool {
match self.major.cmp(&other.major) {
Ordering::Greater => true,
Ordering::Less => false,
Ordering::Equal => match self.minor.cmp(&other.minor) {
Ordering::Greater => true,
Ordering::Less => false,
Ordering::Equal => self.patch >= other.patch,
},
}
}
}
#[cfg(test)]
@ -284,13 +315,13 @@ mod tests {
#[test]
fn test_gte() {
assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 2, 3)));
assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(0, 10, 10)));
assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 1, 10)));
assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(1, 2, 3));
assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(0, 10, 10));
assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(1, 1, 10));
assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 2, 10)));
assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 3, 1)));
assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(2, 2, 1)));
assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(1, 2, 10));
assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(1, 3, 1));
assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(2, 2, 1));
}
#[test]