@@ -401,12 +401,29 @@ fn allowed_dylibs_for_triple(triple: &str) -> Vec<MachOAllowedDylib> {
401
401
}
402
402
403
403
fn validate_elf (
404
+ json : & PythonJsonMain ,
404
405
target_triple : & str ,
405
406
python_major_minor : & str ,
406
407
path : & Path ,
407
408
elf : & goblin:: elf:: Elf ,
408
409
bytes : & [ u8 ] ,
409
410
) -> 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
+
410
427
let mut errors = vec ! [ ] ;
411
428
412
429
let wanted_cpu_type = match target_triple {
@@ -453,6 +470,47 @@ fn validate_elf(
453
470
if !allowed_libraries. contains ( & lib. to_string ( ) ) {
454
471
errors. push ( format ! ( "{} loads illegal library {}" , path. display( ) , lib) ) ;
455
472
}
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" )
478
+ && !lib. starts_with ( "libc" )
479
+ && !lib. starts_with ( "libgcc_s" ) ;
480
+
481
+ if requires_annotation {
482
+ if lib. starts_with ( "lib" ) {
483
+ if let Some ( index) = lib. rfind ( ".so" ) {
484
+ let lib_name = & lib[ 3 ..index] ;
485
+
486
+ // There should be a system links entry for this library in the JSON
487
+ // metadata.
488
+ //
489
+ // Nominally we would look at where this ELF came from and make sure
490
+ // the annotation is present in its section (e.g. core or extension).
491
+ // But this is more work.
492
+ if !system_links. contains ( lib_name) {
493
+ errors. push ( format ! (
494
+ "{} library load of {} does not have system link build annotation" ,
495
+ path. display( ) ,
496
+ lib
497
+ ) ) ;
498
+ }
499
+ } else {
500
+ errors. push ( format ! (
501
+ "{} library load of {} does not have .so extension" ,
502
+ path. display( ) ,
503
+ lib
504
+ ) ) ;
505
+ }
506
+ } else {
507
+ errors. push ( format ! (
508
+ "{} library load of {} does not begin with lib" ,
509
+ path. display( ) ,
510
+ lib
511
+ ) ) ;
512
+ }
513
+ }
456
514
}
457
515
458
516
let wanted_glibc_max_version = GLIBC_MAX_VERSION_BY_TRIPLE
@@ -581,6 +639,7 @@ fn validate_pe(path: &Path, pe: &goblin::pe::PE) -> Result<Vec<String>> {
581
639
582
640
/// Attempt to parse data as an object file and validate it.
583
641
fn validate_possible_object_file (
642
+ json : & PythonJsonMain ,
584
643
python_major_minor : & str ,
585
644
triple : & str ,
586
645
path : & Path ,
@@ -593,6 +652,7 @@ fn validate_possible_object_file(
593
652
match object {
594
653
goblin:: Object :: Elf ( elf) => {
595
654
errors. extend ( validate_elf (
655
+ json,
596
656
triple,
597
657
python_major_minor,
598
658
path. as_ref ( ) ,
@@ -727,17 +787,24 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
727
787
let mut entries = tf. entries ( ) ?;
728
788
729
789
let mut wanted_python_paths = BTreeSet :: new ( ) ;
790
+ let mut json = None ;
730
791
731
792
let mut entry = entries. next ( ) . unwrap ( ) ?;
732
793
if entry. path ( ) ?. display ( ) . to_string ( ) == "python/PYTHON.json" {
733
794
seen_paths. insert ( entry. path ( ) ?. to_path_buf ( ) ) ;
734
795
735
796
let mut data = Vec :: new ( ) ;
736
797
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) ) ) ;
798
+ json = Some ( parse_python_json ( & data) . context ( "parsing PYTHON.json" ) ?) ;
799
+ errors. extend ( validate_json ( json. as_ref ( ) . unwrap ( ) , triple, is_debug) ?) ;
800
+
801
+ wanted_python_paths. extend (
802
+ json. as_ref ( )
803
+ . unwrap ( )
804
+ . python_paths
805
+ . values ( )
806
+ . map ( |x| format ! ( "python/{}" , x) ) ,
807
+ ) ;
741
808
} else {
742
809
errors. push ( format ! (
743
810
"1st archive entry should be for python/PYTHON.json; got {}" ,
@@ -770,8 +837,13 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
770
837
let mut data = Vec :: new ( ) ;
771
838
entry. read_to_end ( & mut data) ?;
772
839
773
- let ( local_errors, local_seen_dylibs) =
774
- validate_possible_object_file ( python_major_minor, & triple, & path, & data) ?;
840
+ let ( local_errors, local_seen_dylibs) = validate_possible_object_file (
841
+ json. as_ref ( ) . unwrap ( ) ,
842
+ python_major_minor,
843
+ & triple,
844
+ & path,
845
+ & data,
846
+ ) ?;
775
847
errors. extend ( local_errors) ;
776
848
seen_dylibs. extend ( local_seen_dylibs) ;
777
849
@@ -790,6 +862,7 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
790
862
) ) ;
791
863
792
864
let ( local_errors, local_seen_dylibs) = validate_possible_object_file (
865
+ json. as_ref ( ) . unwrap ( ) ,
793
866
python_major_minor,
794
867
& triple,
795
868
& member_path,
@@ -801,8 +874,7 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
801
874
}
802
875
803
876
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) ?) ;
877
+ errors. push ( "python/PYTHON.json seen twice" . to_string ( ) ) ;
806
878
}
807
879
}
808
880
0 commit comments