Catch circular dependency when resolving loading shared libraries
This patch implements tree-based data-structure for catching circular dependency where libA.so will depen on arbitrarily long chain (including zero length) of libNs.so one of which will depend on libA.so again. The main intention of this patch was merely capturing the dependency tree to prioterize which Elf's .init_array and which .fini_array should run first, but as a side effect it can capture circular dependencies as well.
This commit is contained in:
+19
-10
@@ -1,6 +1,6 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
collections::BTreeMap,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
@@ -59,6 +59,8 @@ pub struct Linker {
|
||||
mmaps: BTreeMap<String, &'static mut [u8]>,
|
||||
verbose: bool,
|
||||
tls_index_offset: usize,
|
||||
// used to detect circular dependencies in the Linker::load function
|
||||
cir_dep: BTreeSet<String>,
|
||||
}
|
||||
|
||||
impl Linker {
|
||||
@@ -71,6 +73,7 @@ impl Linker {
|
||||
mmaps: BTreeMap::new(),
|
||||
verbose,
|
||||
tls_index_offset: 0,
|
||||
cir_dep: BTreeSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +81,14 @@ impl Linker {
|
||||
if self.verbose {
|
||||
println!("load {}: {}", name, path);
|
||||
}
|
||||
if self.cir_dep.contains(name) {
|
||||
return Err(Error::Malformed(format!(
|
||||
"Circular dependency: {} is a dependency of itself",
|
||||
name
|
||||
)));
|
||||
}
|
||||
|
||||
self.cir_dep.insert(name.to_string());
|
||||
let mut data = Vec::new();
|
||||
|
||||
let path_c = CString::new(path)
|
||||
@@ -91,19 +102,17 @@ impl Linker {
|
||||
file.read_to_end(&mut data)
|
||||
.map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
|
||||
}
|
||||
|
||||
self.load_data(name, data.into_boxed_slice())
|
||||
let result = self.load_data(name, data.into_boxed_slice());
|
||||
self.cir_dep.remove(name);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn load_data(&mut self, name: &str, data: Box<[u8]>) -> Result<()> {
|
||||
//TODO: Prevent failures due to recursion
|
||||
{
|
||||
let elf = Elf::parse(&data)?;
|
||||
//println!("{:#?}", elf);
|
||||
let elf = Elf::parse(&data)?;
|
||||
//println!("{:#?}", elf);
|
||||
|
||||
for library in elf.libraries.iter() {
|
||||
self.load_library(library)?;
|
||||
}
|
||||
for library in elf.libraries.iter() {
|
||||
self.load_library(library)?;
|
||||
}
|
||||
|
||||
self.objects.insert(name.to_string(), data);
|
||||
|
||||
Reference in New Issue
Block a user