Skip to content

Commit d256bed

Browse files
daviesrobvaleriuo
authored andcommitted
Catch possible integer overflow in bam_write1()
When writing BAM, alignments with many CIGAR operations add a stub CIGAR record to say how long the alignment actually is. This could overflow the maximum length of a single CIGAR operation. For now, catch the problem and suggest using SAM or CRAM instead.
1 parent d58f21e commit d256bed

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

sam.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,10 +669,19 @@ int bam_write1(BGZF *fp, const bam1_t *b)
669669
} else { // with long CIGAR, insert a fake CIGAR record and move the real CIGAR to the CG:B,I tag
670670
uint8_t buf[8];
671671
uint32_t cigar_st, cigar_en, cigar[2];
672+
hts_pos_t cigreflen = bam_cigar2rlen(c->n_cigar, bam_get_cigar(b));
673+
if (cigreflen >= (1<<28)) {
674+
// Length of reference covered is greater than the biggest
675+
// CIGAR operation currently allowed.
676+
hts_log_error("Record %s with %d CIGAR ops and ref length %"PRIhts_pos
677+
" cannot be written in BAM. Try writing SAM or CRAM instead.\n",
678+
bam_get_qname(b), c->n_cigar, cigreflen);
679+
return -1;
680+
}
672681
cigar_st = (uint8_t*)bam_get_cigar(b) - b->data;
673682
cigar_en = cigar_st + c->n_cigar * 4;
674683
cigar[0] = (uint32_t)c->l_qseq << 4 | BAM_CSOFT_CLIP;
675-
cigar[1] = (uint32_t)bam_cigar2rlen(c->n_cigar, bam_get_cigar(b)) << 4 | BAM_CREF_SKIP;
684+
cigar[1] = (uint32_t)cigreflen << 4 | BAM_CREF_SKIP;
676685
u32_to_le(cigar[0], buf);
677686
u32_to_le(cigar[1], buf + 4);
678687
if (ok) ok = (bgzf_write(fp, buf, 8) >= 0); // write cigar: <read_length>S<ref_length>N

0 commit comments

Comments
 (0)