Skip to content

Commit 309ab70

Browse files
author
Lance Hepler
authored
fix leaked header mutability (#181)
htslib may modify `cigar_tab` in header as records are parsed, also fix misc warnings from compiler
1 parent 94a7f57 commit 309ab70

File tree

3 files changed

+33
-17
lines changed

3 files changed

+33
-17
lines changed

src/bam/mod.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ pub trait Read: Sized {
9292
/// Return the header.
9393
fn header(&self) -> &HeaderView;
9494

95+
/// Return the header, mutable.
96+
fn header_mut(&mut self) -> &mut HeaderView;
97+
9598
/// Seek to the given virtual offset in the file
9699
fn seek(&mut self, offset: i64) -> Result<()> {
97100
let htsfile = unsafe { self.htsfile().as_ref() }.expect("bug: null pointer to htsFile");
@@ -198,8 +201,8 @@ impl Reader {
198201
data: *mut ::std::os::raw::c_void,
199202
record: *mut htslib::bam1_t,
200203
) -> i32 {
201-
let _self = unsafe { &*(data as *mut Self) };
202-
unsafe { htslib::sam_read1(_self.htsfile(), &mut _self.header().inner(), record) }
204+
let mut _self = unsafe { (data as *mut Self).as_mut().unwrap() };
205+
unsafe { htslib::sam_read1(_self.htsfile(), _self.header_mut().inner_mut(), record) }
203206
}
204207

205208
/// Iterator over the records between the (optional) virtual offsets `start` and `end`
@@ -258,7 +261,7 @@ impl Read for Reader {
258261
match unsafe {
259262
htslib::sam_read1(
260263
self.htsfile,
261-
&mut self.header.inner(),
264+
self.header.inner_mut(),
262265
record.inner_ptr_mut(),
263266
)
264267
} {
@@ -295,6 +298,10 @@ impl Read for Reader {
295298
fn header(&self) -> &HeaderView {
296299
&self.header
297300
}
301+
302+
fn header_mut(&mut self) -> &mut HeaderView {
303+
&mut self.header
304+
}
298305
}
299306

300307
impl Drop for Reader {
@@ -412,7 +419,7 @@ impl IndexedReader {
412419
}
413420
let rstr = ffi::CString::new(region).unwrap();
414421
let rptr = rstr.as_ptr();
415-
let itr = unsafe { htslib::sam_itr_querys(self.idx, &mut self.header.inner(), rptr) };
422+
let itr = unsafe { htslib::sam_itr_querys(self.idx, self.header.inner_mut(), rptr) };
416423
if itr.is_null() {
417424
self.itr = None;
418425
Err(Error::Fetch)
@@ -426,10 +433,10 @@ impl IndexedReader {
426433
data: *mut ::std::os::raw::c_void,
427434
record: *mut htslib::bam1_t,
428435
) -> i32 {
429-
let _self = unsafe { &*(data as *mut Self) };
436+
let _self = unsafe { (data as *mut Self).as_mut().unwrap() };
430437
match _self.itr {
431438
Some(itr) => itr_next(_self.htsfile, itr, record), // read fetched region
432-
None => unsafe { htslib::sam_read1(_self.htsfile, &mut _self.header.inner(), record) }, // ordinary reading
439+
None => unsafe { htslib::sam_read1(_self.htsfile, _self.header.inner_mut(), record) }, // ordinary reading
433440
}
434441
}
435442

@@ -484,6 +491,10 @@ impl Read for IndexedReader {
484491
fn header(&self) -> &HeaderView {
485492
&self.header
486493
}
494+
495+
fn header_mut(&mut self) -> &mut HeaderView {
496+
&mut self.header
497+
}
487498
}
488499

489500
impl Drop for IndexedReader {
@@ -612,7 +623,7 @@ impl Writer {
612623
///
613624
/// * `record` - the record to write
614625
pub fn write(&mut self, record: &record::Record) -> Result<()> {
615-
if unsafe { htslib::sam_write1(self.f, &self.header.inner(), record.inner_ptr()) } == -1 {
626+
if unsafe { htslib::sam_write1(self.f, self.header.inner(), record.inner_ptr()) } == -1 {
616627
Err(Error::Write)
617628
} else {
618629
Ok(())
@@ -819,8 +830,8 @@ impl HeaderView {
819830
}
820831

821832
#[inline]
822-
pub fn inner(&self) -> htslib::bam_hdr_t {
823-
unsafe { (*self.inner) }
833+
pub fn inner(&self) -> &htslib::bam_hdr_t {
834+
unsafe { self.inner.as_ref().unwrap() }
824835
}
825836

826837
#[inline]
@@ -829,9 +840,14 @@ impl HeaderView {
829840
self.inner
830841
}
831842

843+
#[inline]
844+
pub fn inner_mut(&mut self) -> &mut htslib::bam_hdr_t {
845+
unsafe { self.inner.as_mut().unwrap() }
846+
}
847+
832848
#[inline]
833849
// Mutable pointer to bam_hdr_t struct
834-
pub fn inner_ptr_mut(&self) -> *mut htslib::bam_hdr_t {
850+
pub fn inner_ptr_mut(&mut self) -> *mut htslib::bam_hdr_t {
835851
self.inner
836852
}
837853

@@ -1249,12 +1265,12 @@ CCCCCCCCCCCCCCCCCCC"[..],
12491265
.push_tag(b"SN", &"1")
12501266
.push_tag(b"LN", &10000000),
12511267
);
1252-
let header = HeaderView::from_header(&_header);
1268+
let mut header = HeaderView::from_header(&_header);
12531269

12541270
let line =
12551271
b"blah1 0 1 1 255 1M * 0 0 A F CB:Z:AAAA-1 UR:Z:AAAA UB:Z:AAAA GX:Z:G1 xf:i:1 fx:Z:G1\tli:i:0\ttf:Z:cC";
12561272

1257-
let mut rec = Record::from_sam(&header, line).unwrap();
1273+
let mut rec = Record::from_sam(&mut header, line).unwrap();
12581274
assert_eq!(rec.qname(), b"blah1");
12591275
rec.set_qname(b"r0");
12601276
assert_eq!(rec.qname(), b"r0");
@@ -1492,7 +1508,7 @@ CCCCCCCCCCCCCCCCCCC"[..],
14921508
let sam_recs: Vec<Record> = sam
14931509
.split(|x| *x == b'\n')
14941510
.filter(|x| x.len() > 0 && x[0] != b'@')
1495-
.map(|line| Record::from_sam(rdr.header(), line).unwrap())
1511+
.map(|line| Record::from_sam(rdr.header_mut(), line).unwrap())
14961512
.collect();
14971513

14981514
for (b1, s1) in bam_recs.iter().zip(sam_recs.iter()) {

src/bam/record.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl Record {
131131
}
132132

133133
// Create a BAM record from a line SAM text. SAM slice need not be 0-terminated.
134-
pub fn from_sam(header_view: &HeaderView, sam: &[u8]) -> Result<Record> {
134+
pub fn from_sam(header_view: &mut HeaderView, sam: &[u8]) -> Result<Record> {
135135
let mut record = Self::new();
136136

137137
let mut sam_copy = Vec::with_capacity(sam.len() + 1);

src/bcf/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ mod tests {
953953
.ok()
954954
.expect("Error opening file.");
955955
let expected = ["./1", "1|1", "0/1", "0|1", "1|.", "1/1"];
956-
for (rec, exp_gt) in vcf.records().zip(expected.into_iter()) {
956+
for (rec, exp_gt) in vcf.records().zip(expected.iter()) {
957957
let mut rec = rec.expect("Error reading record.");
958958
let genotypes = rec.genotypes().expect("Error reading genotypes");
959959
assert_eq!(&format!("{}", genotypes.get(0)), exp_gt);
@@ -1327,7 +1327,7 @@ mod tests {
13271327
fn test_multi_string_info_tag() {
13281328
let mut reader = Reader::from_path("test/test-info-multi-string.vcf").unwrap();
13291329
let mut rec = reader.empty_record();
1330-
reader.read(&mut rec);
1330+
let _ = reader.read(&mut rec);
13311331

13321332
assert_eq!(rec.info(b"ANN").string().unwrap().unwrap().len(), 14);
13331333
}
@@ -1336,7 +1336,7 @@ mod tests {
13361336
fn test_multi_string_info_tag_number_a() {
13371337
let mut reader = Reader::from_path("test/test-info-multi-string-number=A.vcf").unwrap();
13381338
let mut rec = reader.empty_record();
1339-
reader.read(&mut rec);
1339+
let _ = reader.read(&mut rec);
13401340

13411341
assert_eq!(rec.info(b"X").string().unwrap().unwrap().len(), 2);
13421342
}

0 commit comments

Comments
 (0)