@@ -1113,17 +1113,34 @@ void check_shlib_undefined(Context<E> &ctx) {
11131113 return false ;
11141114 };
11151115
1116- // Obtain a list of known shared library names.
1117- std::unordered_set<std::string_view> sonames;
1116+ // We want to skip a file that (either directly or indirectly) depends
1117+ // on another .so file we know nothing about. This is because missing
1118+ // symbols might be provided by that unknown file.
1119+ //
1120+ // We need recursion for indirect dependencies.
1121+ std::unordered_map<std::string_view, std::vector<std::string_view>> deps;
11181122 for (std::unique_ptr<SharedFile<E>> &file : ctx.dso_pool )
1119- sonames.insert (file->soname );
1123+ deps[file->soname ] = file->get_dt_needed (ctx);
1124+
1125+ std::function<bool (std::string_view, i64 )> can_check;
1126+ can_check = [&](std::string_view soname, i64 depth) -> bool {
1127+ if (depth == deps.size ())
1128+ Fatal (ctx) << " --no-allow-shlib-defined: mutually-recursive .so detected: "
1129+ << soname;
1130+
1131+ auto it = deps.find (soname);
1132+ if (it == deps.end ())
1133+ return false ;
1134+ for (std::string_view needed : it->second )
1135+ if (!can_check (needed, depth + 1 ))
1136+ return false ;
1137+ return true ;
1138+ };
11201139
11211140 tbb::parallel_for_each (ctx.dsos , [&](SharedFile<E> *file) {
11221141 // Skip the file if it depends on a file that we know nothing about.
1123- // This is because missing symbols may be provided by that unknown file.
1124- for (std::string_view needed : file->get_dt_needed (ctx))
1125- if (!sonames.contains (needed))
1126- return ;
1142+ if (!can_check (file->soname , 0 ))
1143+ return ;
11271144
11281145 // Check if all undefined symbols have been resolved.
11291146 for (i64 i = 0 ; i < file->elf_syms .size (); i++) {
0 commit comments