@@ -401,12 +401,29 @@ fn allowed_dylibs_for_triple(triple: &str) -> Vec<MachOAllowedDylib> {
401401}
402402
403403fn validate_elf (
404+ json : & PythonJsonMain ,
404405 target_triple : & str ,
405406 python_major_minor : & str ,
406407 path : & Path ,
407408 elf : & goblin:: elf:: Elf ,
408409 bytes : & [ u8 ] ,
409410) -> Result < Vec < String > > {
411+ let mut system_links = BTreeSet :: new ( ) ;
412+ for link in & json. build_info . core . links {
413+ if link. system . unwrap_or_default ( ) {
414+ system_links. insert ( link. name . as_str ( ) ) ;
415+ }
416+ }
417+ for extension in json. build_info . extensions . values ( ) {
418+ for variant in extension {
419+ for link in & variant. links {
420+ if link. system . unwrap_or_default ( ) {
421+ system_links. insert ( link. name . as_str ( ) ) ;
422+ }
423+ }
424+ }
425+ }
426+
410427 let mut errors = vec ! [ ] ;
411428
412429 let wanted_cpu_type = match target_triple {
@@ -453,6 +470,48 @@ fn validate_elf(
453470 if !allowed_libraries. contains ( & lib. to_string ( ) ) {
454471 errors. push ( format ! ( "{} loads illegal library {}" , path. display( ) , lib) ) ;
455472 }
473+
474+ // Most linked libraries should have an annotation in the JSON metadata.
475+ let requires_annotation = !lib. contains ( "libpython" )
476+ && !lib. starts_with ( "ld-linux" )
477+ && !lib. starts_with ( "ld64.so" )
478+ && !lib. starts_with ( "ld.so" )
479+ && !lib. starts_with ( "libc.so" )
480+ && !lib. starts_with ( "libgcc_s.so" ) ;
481+
482+ if requires_annotation {
483+ if lib. starts_with ( "lib" ) {
484+ if let Some ( index) = lib. rfind ( ".so" ) {
485+ let lib_name = & lib[ 3 ..index] ;
486+
487+ // There should be a system links entry for this library in the JSON
488+ // metadata.
489+ //
490+ // Nominally we would look at where this ELF came from and make sure
491+ // the annotation is present in its section (e.g. core or extension).
492+ // But this is more work.
493+ if !system_links. contains ( lib_name) {
494+ errors. push ( format ! (
495+ "{} library load of {} does not have system link build annotation" ,
496+ path. display( ) ,
497+ lib
498+ ) ) ;
499+ }
500+ } else {
501+ errors. push ( format ! (
502+ "{} library load of {} does not have .so extension" ,
503+ path. display( ) ,
504+ lib
505+ ) ) ;
506+ }
507+ } else {
508+ errors. push ( format ! (
509+ "{} library load of {} does not begin with lib" ,
510+ path. display( ) ,
511+ lib
512+ ) ) ;
513+ }
514+ }
456515 }
457516
458517 let wanted_glibc_max_version = GLIBC_MAX_VERSION_BY_TRIPLE
@@ -581,6 +640,7 @@ fn validate_pe(path: &Path, pe: &goblin::pe::PE) -> Result<Vec<String>> {
581640
582641/// Attempt to parse data as an object file and validate it.
583642fn validate_possible_object_file (
643+ json : & PythonJsonMain ,
584644 python_major_minor : & str ,
585645 triple : & str ,
586646 path : & Path ,
@@ -593,6 +653,7 @@ fn validate_possible_object_file(
593653 match object {
594654 goblin:: Object :: Elf ( elf) => {
595655 errors. extend ( validate_elf (
656+ json,
596657 triple,
597658 python_major_minor,
598659 path. as_ref ( ) ,
@@ -727,17 +788,24 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
727788 let mut entries = tf. entries ( ) ?;
728789
729790 let mut wanted_python_paths = BTreeSet :: new ( ) ;
791+ let mut json = None ;
730792
731793 let mut entry = entries. next ( ) . unwrap ( ) ?;
732794 if entry. path ( ) ?. display ( ) . to_string ( ) == "python/PYTHON.json" {
733795 seen_paths. insert ( entry. path ( ) ?. to_path_buf ( ) ) ;
734796
735797 let mut data = Vec :: new ( ) ;
736798 entry. read_to_end ( & mut data) ?;
737- let json = parse_python_json ( & data) . context ( "parsing PYTHON.json" ) ?;
738- errors. extend ( validate_json ( & json, triple, is_debug) ?) ;
739-
740- wanted_python_paths. extend ( json. python_paths . values ( ) . map ( |x| format ! ( "python/{}" , x) ) ) ;
799+ json = Some ( parse_python_json ( & data) . context ( "parsing PYTHON.json" ) ?) ;
800+ errors. extend ( validate_json ( json. as_ref ( ) . unwrap ( ) , triple, is_debug) ?) ;
801+
802+ wanted_python_paths. extend (
803+ json. as_ref ( )
804+ . unwrap ( )
805+ . python_paths
806+ . values ( )
807+ . map ( |x| format ! ( "python/{}" , x) ) ,
808+ ) ;
741809 } else {
742810 errors. push ( format ! (
743811 "1st archive entry should be for python/PYTHON.json; got {}" ,
@@ -770,8 +838,13 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
770838 let mut data = Vec :: new ( ) ;
771839 entry. read_to_end ( & mut data) ?;
772840
773- let ( local_errors, local_seen_dylibs) =
774- validate_possible_object_file ( python_major_minor, & triple, & path, & data) ?;
841+ let ( local_errors, local_seen_dylibs) = validate_possible_object_file (
842+ json. as_ref ( ) . unwrap ( ) ,
843+ python_major_minor,
844+ & triple,
845+ & path,
846+ & data,
847+ ) ?;
775848 errors. extend ( local_errors) ;
776849 seen_dylibs. extend ( local_seen_dylibs) ;
777850
@@ -790,6 +863,7 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
790863 ) ) ;
791864
792865 let ( local_errors, local_seen_dylibs) = validate_possible_object_file (
866+ json. as_ref ( ) . unwrap ( ) ,
793867 python_major_minor,
794868 & triple,
795869 & member_path,
@@ -801,8 +875,7 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
801875 }
802876
803877 if path == PathBuf :: from ( "python/PYTHON.json" ) {
804- let json = parse_python_json ( & data) . context ( "parsing PYTHON.json" ) ?;
805- errors. extend ( validate_json ( & json, triple, is_debug) ?) ;
878+ errors. push ( "python/PYTHON.json seen twice" . to_string ( ) ) ;
806879 }
807880 }
808881
0 commit comments