Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 41 additions & 17 deletions crates/edit/src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,26 +439,50 @@ pub fn icu_detect_renaming_suffix(arena: &Arena, handle: NonNull<c_void>) -> BSt
return res;
}

// In the versions (63-76) and distributions (Arch/Debian) I tested,
// this symbol seems to be always present. This allows us to call `dladdr`.
// It's the `UCaseMap::~UCaseMap()` destructor which for some reason isn't
// in a namespace. Thank you ICU maintainers for this oversight.
let proc = match get_proc_address::<T>(handle, c"_ZN8UCaseMapD1Ev".as_ptr()) {
Ok(proc) => proc,
Err(_) => return res,
};
#[allow(dead_code)]
const TARGET_LIBICU: &str = "libicuuc";

// `dladdr` is specific to GNU's libc unfortunately.
let mut info: libc::Dl_info = mem::zeroed();
let ret = libc::dladdr(proc, &mut info);
if ret == 0 {
return res;
#[allow(unused_mut)]
let mut dli_fname: Option<&str> = None;

#[cfg(not(target_vendor = "apple"))]
{
extern "C" fn dl_callback(
info: *mut libc::dl_phdr_info,
_size: usize,
data: *mut c_void,
) -> c_int {
let file_path = unsafe { &mut *(data as *mut Option<&str>) };

if info.is_null() || unsafe { (*info).dlpi_name.is_null() } {
return 0;
}

let dlpi_str = unsafe { std::ffi::CStr::from_ptr((*info).dlpi_name) };

if let Ok(s) = dlpi_str.to_str() {
if s.contains(TARGET_LIBICU) {
*file_path = Some(s);
return 1;
}
}

0
}

let ret = libc::dl_iterate_phdr(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Whether or not we should do this: dl_iterate_phdr is apparently Linux-specific, and this project works fine on other Unixes e.g. NetBSD

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

definition from GNU.
dl_iterate_phdr - walk through list of shared objects

In callback you receive structure dl_phdr_info which include filename of shared object. Once callback return non zero value dl_iterate_phdr finishes it job.

As I check docs dl_iterate_phdr is also implemented on BSD Unix operation systems.

I know Ubuntu 14.04 is old but looks that also 16.04 has same problem. Canonical still supports 14.04 in pro program.

Problem on Ubuntu14.04 originates that symbol "_ZN8UCaseMapD1Ev "is not present in libicu library.

Some(dl_callback),
&mut dli_fname as *mut Option<&str> as *mut c_void,
);

if ret == 0 {
return res;
}
}

// The library path is in `info.dli_fname`.
let path = match std::ffi::CStr::from_ptr(info.dli_fname).to_str() {
Ok(name) => name,
Err(_) => return res,
let path = match dli_fname {
Some(name) => name,
None => return res,
};

let path = match std::fs::read_link(path) {
Expand Down