@@ -24,11 +24,10 @@ use middle::trans::common::gensym_name;
24
24
use middle:: ty;
25
25
use util:: common:: time;
26
26
use util:: ppaux;
27
+ use util:: sha2:: { Digest , Sha256 } ;
27
28
28
29
use std:: c_str:: ToCStr ;
29
30
use std:: char;
30
- use std:: hash:: Streaming ;
31
- use std:: hash;
32
31
use std:: os:: consts:: { macos, freebsd, linux, android, win32} ;
33
32
use std:: ptr;
34
33
use std:: run;
@@ -39,8 +38,8 @@ use syntax::abi;
39
38
use syntax:: ast;
40
39
use syntax:: ast_map:: { path, path_mod, path_name, path_pretty_name} ;
41
40
use syntax:: attr;
42
- use syntax:: attr:: { AttrMetaMethods } ;
43
- use syntax:: print :: pprust ;
41
+ use syntax:: attr:: AttrMetaMethods ;
42
+ use syntax:: pkgid :: PkgId ;
44
43
45
44
#[ deriving( Clone , Eq ) ]
46
45
pub enum output_type {
@@ -52,10 +51,6 @@ pub enum output_type {
52
51
output_type_exe,
53
52
}
54
53
55
- fn write_string < W : Writer > ( writer : & mut W , string : & str ) {
56
- writer. write ( string. as_bytes ( ) ) ;
57
- }
58
-
59
54
pub fn llvm_err ( sess : Session , msg : ~str ) -> ! {
60
55
unsafe {
61
56
let cstr = llvm:: LLVMRustGetLastError ( ) ;
@@ -413,217 +408,90 @@ pub mod write {
413
408
* - Symbols with the same name but different types need to get different
414
409
* linkage-names. We do this by hashing a string-encoding of the type into
415
410
* a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
416
- * we use SHA1 ) to "prevent collisions". This is not airtight but 16 hex
411
+ * we use SHA256 ) to "prevent collisions". This is not airtight but 16 hex
417
412
* digits on uniform probability means you're going to need 2**32 same-name
418
413
* symbols in the same process before you're even hitting birthday-paradox
419
414
* collision probability.
420
415
*
421
416
* - Symbols in different crates but with same names "within" the crate need
422
417
* to get different linkage-names.
423
418
*
424
- * So here is what we do:
419
+ * - The hash shown in the filename needs to be predictable and stable for
420
+ * build tooling integration. It also needs to be using a hash function
421
+ * which is easy to use from Python, make, etc.
425
422
*
426
- * - Separate the meta tags into two sets: exported and local. Only work with
427
- * the exported ones when considering linkage.
423
+ * So here is what we do:
428
424
*
429
- * - Consider two exported tags as special (and mandatory): name and vers.
430
- * Every crate gets them; if it doesn't name them explicitly we infer them
431
- * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
425
+ * - Consider the package id; every crate has one (specified with pkgid
426
+ * attribute). If a package id isn't provided explicitly, we infer a
427
+ * versionless one from the output name. The version will end up being 0.0
428
+ * in this case. CNAME and CVERS are taken from this package id. For
429
+ * example, github.com/mozilla/CNAME#CVERS.
432
430
*
433
- * - Define CMETA as all the non-name, non-vers exported meta tags in the
434
- * crate (in sorted order).
431
+ * - Define CMH as SHA256(pkgid).
435
432
*
436
- * - Define CMH as hash(CMETA + hashes of dependent crates) .
433
+ * - Define CMH8 as the first 8 characters of CMH .
437
434
*
438
- * - Compile our crate to lib CNAME-CMH -CVERS.so
435
+ * - Compile our crate to lib CNAME-CMH8 -CVERS.so
439
436
*
440
- * - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
437
+ * - Define STH(sym) as SHA256( CMH, type_str(sym))
441
438
*
442
439
* - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
443
440
* name, non-name metadata, and type sense, and versioned in the way
444
441
* system linkers understand.
445
- *
446
442
*/
447
443
448
444
pub fn build_link_meta ( sess : Session ,
449
445
c : & ast:: Crate ,
450
446
output : & Path ,
451
- symbol_hasher : & mut hash :: State )
447
+ symbol_hasher : & mut Sha256 )
452
448
-> LinkMeta {
453
- struct ProvidedMetas {
454
- name : Option < @str > ,
455
- vers : Option < @str > ,
456
- pkg_id : Option < @str > ,
457
- cmh_items : ~[ @ast:: MetaItem ]
458
- }
459
-
460
- fn provided_link_metas ( sess : Session , c : & ast:: Crate ) ->
461
- ProvidedMetas {
462
- let mut name = None ;
463
- let mut vers = None ;
464
- let mut pkg_id = None ;
465
- let mut cmh_items = ~[ ] ;
466
- let linkage_metas = attr:: find_linkage_metas ( c. attrs ) ;
467
- attr:: require_unique_names ( sess. diagnostic ( ) , linkage_metas) ;
468
- for meta in linkage_metas. iter ( ) {
469
- match meta. name_str_pair ( ) {
470
- Some ( ( n, value) ) if "name" == n => name = Some ( value) ,
471
- Some ( ( n, value) ) if "vers" == n => vers = Some ( value) ,
472
- Some ( ( n, value) ) if "package_id" == n => pkg_id = Some ( value) ,
473
- _ => cmh_items. push ( * meta)
474
- }
475
- }
476
-
477
- ProvidedMetas {
478
- name : name,
479
- vers : vers,
480
- pkg_id : pkg_id,
481
- cmh_items : cmh_items
482
- }
483
- }
484
-
485
449
// This calculates CMH as defined above
486
- fn crate_meta_extras_hash ( symbol_hasher : & mut hash:: State ,
487
- cmh_items : ~[ @ast:: MetaItem ] ,
488
- dep_hashes : ~[ @str ] ,
489
- pkg_id : Option < @str > ) -> @str {
490
- fn len_and_str ( s : & str ) -> ~str {
491
- format ! ( "{}_{}" , s. len( ) , s)
492
- }
493
-
494
- fn len_and_str_lit ( l : ast:: lit ) -> ~str {
495
- len_and_str ( pprust:: lit_to_str ( & l) )
496
- }
497
-
498
- let cmh_items = attr:: sort_meta_items ( cmh_items) ;
499
-
500
- fn hash ( symbol_hasher : & mut hash:: State , m : & @ast:: MetaItem ) {
501
- match m. node {
502
- ast:: MetaNameValue ( key, value) => {
503
- write_string ( symbol_hasher, len_and_str ( key) ) ;
504
- write_string ( symbol_hasher, len_and_str_lit ( value) ) ;
505
- }
506
- ast:: MetaWord ( name) => {
507
- write_string ( symbol_hasher, len_and_str ( name) ) ;
508
- }
509
- ast:: MetaList ( name, ref mis) => {
510
- write_string ( symbol_hasher, len_and_str ( name) ) ;
511
- for m_ in mis. iter ( ) {
512
- hash ( symbol_hasher, m_) ;
513
- }
514
- }
515
- }
516
- }
517
-
450
+ fn crate_hash ( symbol_hasher : & mut Sha256 , pkgid : & PkgId ) -> @str {
518
451
symbol_hasher. reset ( ) ;
519
- for m in cmh_items. iter ( ) {
520
- hash ( symbol_hasher, m) ;
521
- }
522
-
523
- for dh in dep_hashes. iter ( ) {
524
- write_string ( symbol_hasher, len_and_str ( * dh) ) ;
525
- }
526
-
527
- for p in pkg_id. iter ( ) {
528
- write_string ( symbol_hasher, len_and_str ( * p) ) ;
529
- }
530
-
531
- return truncated_hash_result ( symbol_hasher) . to_managed ( ) ;
532
- }
533
-
534
- fn warn_missing ( sess : Session , name : & str , default : & str ) {
535
- if !* sess. building_library { return ; }
536
- sess. warn ( format ! ( "missing crate link meta `{}`, using `{}` as default" ,
537
- name, default ) ) ;
538
- }
539
-
540
- fn crate_meta_name ( sess : Session , output : & Path , opt_name : Option < @str > )
541
- -> @str {
542
- match opt_name {
543
- Some ( v) if !v. is_empty ( ) => v,
544
- _ => {
545
- // to_managed could go away if there was a version of
546
- // filestem that returned an @str
547
- // FIXME (#9639): Non-utf8 filenames will give a misleading error
548
- let name = session:: expect ( sess,
549
- output. filestem_str ( ) ,
550
- || format ! ( "output file name `{}` doesn't\
551
- appear to have a stem",
552
- output. display( ) ) ) . to_managed ( ) ;
553
- if name. is_empty ( ) {
554
- sess. fatal ( "missing crate link meta `name`, and the \
555
- inferred name is blank") ;
556
- }
557
- warn_missing ( sess, "name" , name) ;
558
- name
559
- }
560
- }
452
+ symbol_hasher. input_str ( pkgid. to_str ( ) ) ;
453
+ truncated_hash_result ( symbol_hasher) . to_managed ( )
561
454
}
562
455
563
- fn crate_meta_vers ( sess : Session , opt_vers : Option < @ str > ) -> @ str {
564
- match opt_vers {
565
- Some ( v ) if !v . is_empty ( ) => v ,
566
- _ => {
567
- let vers = @" 0.0 " ;
568
- warn_missing ( sess , "vers" , vers ) ;
569
- vers
570
- }
456
+ let pkgid = match attr :: find_pkgid ( c . attrs ) {
457
+ None => {
458
+ let stem = session :: expect (
459
+ sess ,
460
+ output . filestem_str ( ) ,
461
+ || format ! ( "output file name '{}' doesn't appear to have a stem" ,
462
+ output . display ( ) ) ) ;
463
+ from_str ( stem ) . unwrap ( )
571
464
}
572
- }
573
-
574
- fn crate_meta_pkgid ( sess : Session , name : @str , opt_pkg_id : Option < @str > )
575
- -> @str {
576
- match opt_pkg_id {
577
- Some ( v) if !v. is_empty ( ) => v,
578
- _ => {
579
- let pkg_id = name. clone ( ) ;
580
- warn_missing ( sess, "package_id" , pkg_id) ;
581
- pkg_id
582
- }
583
- }
584
- }
465
+ Some ( s) => s,
466
+ } ;
585
467
586
- let ProvidedMetas {
587
- name : opt_name,
588
- vers : opt_vers,
589
- pkg_id : opt_pkg_id,
590
- cmh_items : cmh_items
591
- } = provided_link_metas ( sess, c) ;
592
- let name = crate_meta_name ( sess, output, opt_name) ;
593
- let vers = crate_meta_vers ( sess, opt_vers) ;
594
- let pkg_id = crate_meta_pkgid ( sess, name, opt_pkg_id) ;
595
- let dep_hashes = cstore:: get_dep_hashes ( sess. cstore ) ;
596
- let extras_hash =
597
- crate_meta_extras_hash ( symbol_hasher, cmh_items,
598
- dep_hashes, Some ( pkg_id) ) ;
468
+ let hash = crate_hash ( symbol_hasher, & pkgid) ;
599
469
600
470
LinkMeta {
601
- name : name,
602
- vers : vers,
603
- package_id : Some ( pkg_id) ,
604
- extras_hash : extras_hash
471
+ pkgid : pkgid,
472
+ crate_hash : hash,
605
473
}
606
474
}
607
475
608
- pub fn truncated_hash_result ( symbol_hasher : & mut hash :: State ) -> ~str {
476
+ pub fn truncated_hash_result ( symbol_hasher : & mut Sha256 ) -> ~str {
609
477
symbol_hasher. result_str ( )
610
478
}
611
479
612
480
613
481
// This calculates STH for a symbol, as defined above
614
482
pub fn symbol_hash ( tcx : ty:: ctxt ,
615
- symbol_hasher : & mut hash :: State ,
483
+ symbol_hasher : & mut Sha256 ,
616
484
t : ty:: t ,
617
- link_meta : LinkMeta ) -> @str {
485
+ link_meta : & LinkMeta ) -> @str {
618
486
// NB: do *not* use abbrevs here as we want the symbol names
619
487
// to be independent of one another in the crate.
620
488
621
489
symbol_hasher. reset ( ) ;
622
- write_string ( symbol_hasher, link_meta. name ) ;
623
- write_string ( symbol_hasher, "-" ) ;
624
- write_string ( symbol_hasher, link_meta. extras_hash ) ;
625
- write_string ( symbol_hasher, "-" ) ;
626
- write_string ( symbol_hasher, encoder:: encoded_ty ( tcx, t) ) ;
490
+ symbol_hasher. input_str ( link_meta. pkgid . name ) ;
491
+ symbol_hasher. input_str ( "-" ) ;
492
+ symbol_hasher. input_str ( link_meta. crate_hash ) ;
493
+ symbol_hasher. input_str ( "-" ) ;
494
+ symbol_hasher. input_str ( encoder:: encoded_ty ( tcx, t) ) ;
627
495
let mut hash = truncated_hash_result ( symbol_hasher) ;
628
496
// Prefix with 'h' so that it never blends into adjacent digits
629
497
hash. unshift_char ( 'h' ) ;
@@ -635,7 +503,7 @@ pub fn get_symbol_hash(ccx: &mut CrateContext, t: ty::t) -> @str {
635
503
match ccx. type_hashcodes . find ( & t) {
636
504
Some ( & h) => h,
637
505
None => {
638
- let hash = symbol_hash ( ccx. tcx , & mut ccx. symbol_hasher , t, ccx. link_meta ) ;
506
+ let hash = symbol_hash ( ccx. tcx , & mut ccx. symbol_hasher , t, & ccx. link_meta ) ;
639
507
ccx. type_hashcodes . insert ( t, hash) ;
640
508
hash
641
509
}
@@ -774,7 +642,7 @@ pub fn mangle_exported_name(ccx: &mut CrateContext,
774
642
let hash = get_symbol_hash ( ccx, t) ;
775
643
return exported_name ( ccx. sess , path,
776
644
hash,
777
- ccx. link_meta . vers ) ;
645
+ ccx. link_meta . pkgid . version_or_default ( ) ) ;
778
646
}
779
647
780
648
pub fn mangle_internal_name_by_type_only ( ccx : & mut CrateContext ,
@@ -813,8 +681,11 @@ pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str
813
681
mangle ( ccx. sess , path, None , None )
814
682
}
815
683
816
- pub fn output_lib_filename ( lm : LinkMeta ) -> ~str {
817
- format ! ( "{}-{}-{}" , lm. name, lm. extras_hash, lm. vers)
684
+ pub fn output_lib_filename ( lm : & LinkMeta ) -> ~str {
685
+ format ! ( "{}-{}-{}" ,
686
+ lm. pkgid. name,
687
+ lm. crate_hash. slice_chars( 0 , 8 ) ,
688
+ lm. pkgid. version_or_default( ) )
818
689
}
819
690
820
691
pub fn get_cc_prog ( sess : Session ) -> ~str {
@@ -848,7 +719,8 @@ pub fn get_cc_prog(sess: Session) -> ~str {
848
719
pub fn link_binary ( sess : Session ,
849
720
trans : & CrateTranslation ,
850
721
obj_filename : & Path ,
851
- out_filename : & Path ) {
722
+ out_filename : & Path ,
723
+ lm : & LinkMeta ) {
852
724
// If we're generating a test executable, then ignore all other output
853
725
// styles at all other locations
854
726
let outputs = if sess. opts . test {
@@ -858,7 +730,7 @@ pub fn link_binary(sess: Session,
858
730
} ;
859
731
860
732
for output in outputs. move_iter ( ) {
861
- link_binary_output ( sess, trans, output, obj_filename, out_filename) ;
733
+ link_binary_output ( sess, trans, output, obj_filename, out_filename, lm ) ;
862
734
}
863
735
864
736
// Remove the temporary object file and metadata if we aren't saving temps
@@ -881,8 +753,9 @@ fn link_binary_output(sess: Session,
881
753
trans : & CrateTranslation ,
882
754
output : session:: OutputStyle ,
883
755
obj_filename : & Path ,
884
- out_filename : & Path ) {
885
- let libname = output_lib_filename ( trans. link ) ;
756
+ out_filename : & Path ,
757
+ lm : & LinkMeta ) {
758
+ let libname = output_lib_filename ( lm) ;
886
759
let out_filename = match output {
887
760
session:: OutputRlib => {
888
761
out_filename. with_filename ( format ! ( "lib{}.rlib" , libname) )
0 commit comments