@@ -22,6 +22,9 @@ use cargo_util::Sha256;
2222use crate :: CargoResult ;
2323use crate :: CARGO_ENV ;
2424
25+ /// The current format version of [`EncodedDepInfo`].
26+ const CURRENT_ENCODED_DEP_INFO_VERSION : u8 = 1 ;
27+
2528/// The representation of the `.d` dep-info file generated by rustc
2629#[ derive( Default ) ]
2730pub struct RustcDepInfo {
@@ -61,20 +64,36 @@ pub enum DepInfoPathType {
6164/// Currently the format looks like:
6265///
6366/// ```text
64- /// +------------+------------+---------------+---------------+
65- /// | # of files | file paths | # of env vars | env var pairs |
66- /// +------------+------------+---------------+---------------+
67+ /// +--------+---------+-------- ----+------------+---------------+---------------+
68+ /// | marker | version | # of files | file paths | # of env vars | env var pairs |
69+ /// +--------+---------+-------- ----+------------+---------------+---------------+
6770/// ```
6871///
6972/// Each field represents
7073///
74+ /// * _Marker_ --- A magic marker to ensure that older Cargoes, which only
75+ /// recognize format v0 (prior to checksum support in [`f4ca7390`]), do not
76+ /// proceed with parsing newer formats. Since [`EncodedDepInfo`] is merely
77+ /// an optimization, and to avoid adding complexity, Cargo recognizes only
78+ /// one version of [`CURRENT_ENCODED_DEP_INFO_VERSION`].
79+ /// The current layout looks like this
80+ /// ```text
81+ /// +----------------------------+
82+ /// | [0x01 0x00 0x00 0x00 0xff] |
83+ /// +----------------------------+
84+ /// ```
85+ /// These bytes will be interpreted as "one file tracked and an invalid
86+ /// [`DepInfoPathType`] variant with 255" by older Cargoes, causing them to
87+ /// stop parsing. This could prevent problematic parsing as noted in
88+ /// rust-lang/cargo#14712.
89+ /// * _Version_ --- The current format version.
7190/// * _Number of files/envs_ --- A `u32` representing the number of things.
7291/// * _File paths_ --- Zero or more paths of files the dep-info file depends on.
7392/// Each path is encoded as the following:
7493///
7594/// ```text
7695/// +-----------+-------------+------------+---------------+-----------+-------+
77- /// | Path type | len of path | path bytes | cksum exists? | file size | cksum |
96+ /// | path type | len of path | path bytes | cksum exists? | file size | cksum |
7897/// +-----------+-------------+------------+---------------+-----------+-------+
7998/// ```
8099/// * _Env var pairs_ --- Zero or more env vars the dep-info file depends on.
@@ -84,6 +103,8 @@ pub enum DepInfoPathType {
84103/// | len of key | key bytes | value exists? | len of value | value bytes |
85104/// +------------+-----------+---------------+--------------+-------------+
86105/// ```
106+ ///
107+ /// [`f4ca7390`]: https://github.com/rust-lang/cargo/commit/f4ca739073185ea5e1148ff100bb4a06d3bf721d
87108#[ derive( Default , Debug , PartialEq , Eq ) ]
88109pub struct EncodedDepInfo {
89110 pub files : Vec < ( DepInfoPathType , PathBuf , Option < ( u64 , String ) > ) > ,
@@ -93,6 +114,12 @@ pub struct EncodedDepInfo {
93114impl EncodedDepInfo {
94115 pub fn parse ( mut bytes : & [ u8 ] ) -> Option < EncodedDepInfo > {
95116 let bytes = & mut bytes;
117+ read_magic_marker ( bytes) ?;
118+ let version = read_u8 ( bytes) ?;
119+ if version != CURRENT_ENCODED_DEP_INFO_VERSION {
120+ return None ;
121+ }
122+
96123 let nfiles = read_usize ( bytes) ?;
97124 let mut files = Vec :: with_capacity ( nfiles) ;
98125 for _ in 0 ..nfiles {
@@ -129,6 +156,18 @@ impl EncodedDepInfo {
129156 }
130157 return Some ( EncodedDepInfo { files, env } ) ;
131158
159+ /// See [`EncodedDepInfo`] for why a magic marker exists.
160+ fn read_magic_marker ( bytes : & mut & [ u8 ] ) -> Option < ( ) > {
161+ let _size = read_usize ( bytes) ?;
162+ let path_type = read_u8 ( bytes) ?;
163+ if path_type != u8:: MAX {
164+ // Old depinfo. Give up parsing it.
165+ None
166+ } else {
167+ Some ( ( ) )
168+ }
169+ }
170+
132171 fn read_usize ( bytes : & mut & [ u8 ] ) -> Option < usize > {
133172 let ret = bytes. get ( ..4 ) ?;
134173 * bytes = & bytes[ 4 ..] ;
@@ -162,6 +201,10 @@ impl EncodedDepInfo {
162201 pub fn serialize ( & self ) -> CargoResult < Vec < u8 > > {
163202 let mut ret = Vec :: new ( ) ;
164203 let dst = & mut ret;
204+
205+ write_magic_marker ( dst) ;
206+ dst. push ( CURRENT_ENCODED_DEP_INFO_VERSION ) ;
207+
165208 write_usize ( dst, self . files . len ( ) ) ;
166209 for ( ty, file, checksum_info) in self . files . iter ( ) {
167210 match ty {
@@ -189,6 +232,14 @@ impl EncodedDepInfo {
189232 }
190233 return Ok ( ret) ;
191234
235+ /// See [`EncodedDepInfo`] for why a magic marker exists.
236+ ///
237+ /// There is an assumption that there is always at least a file.
238+ fn write_magic_marker ( dst : & mut Vec < u8 > ) {
239+ write_usize ( dst, 1 ) ;
240+ dst. push ( u8:: MAX ) ;
241+ }
242+
192243 fn write_bytes ( dst : & mut Vec < u8 > , val : impl AsRef < [ u8 ] > ) {
193244 let val = val. as_ref ( ) ;
194245 write_usize ( dst, val. len ( ) ) ;
@@ -673,7 +724,7 @@ mod encoded_dep_info {
673724 #[ rustfmt:: skip]
674725 let data = [
675726 0x01 , 0x00 , 0x00 , 0x00 , 0xff , // magic marker
676- 0x01 , // version
727+ CURRENT_ENCODED_DEP_INFO_VERSION , // version
677728 0x01 , 0x00 , 0x00 , 0x00 , // # of files
678729 0x00 , // path type
679730 0x04 , 0x00 , 0x00 , 0x00 , // len of path
@@ -682,7 +733,13 @@ mod encoded_dep_info {
682733 0x00 , 0x00 , 0x00 , 0x00 , // # of env vars
683734 ] ;
684735 // The current cargo doesn't recognize the magic marker.
685- assert ! ( EncodedDepInfo :: parse( & data) . is_none( ) ) ;
736+ assert_eq ! (
737+ EncodedDepInfo :: parse( & data) . unwrap( ) ,
738+ EncodedDepInfo {
739+ files: vec![ ( DepInfoPathType :: PackageRootRelative , "rust" . into( ) , None ) ] ,
740+ env: Vec :: new( ) ,
741+ }
742+ ) ;
686743 }
687744
688745 #[ test]
0 commit comments