Skip to content

Commit c1f35d6

Browse files
committed
Release 1.22.1
2 parents 36f20e7 + b2a06e3 commit c1f35d6

21 files changed

+138
-41
lines changed

.cirrus.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ gcc_task:
7676
- environment:
7777
USE_CONFIG: yes
7878
# ubsan is incompatible with some -Wformat opts so we do that on clang.
79-
CFLAGS: -g -O3 -fsanitize=address,undefined -DHTS_ALLOW_UNALIGNED=0 -Wno-format-truncation -Wno-format-overflow
79+
CFLAGS: -g -Og -fsanitize=address,undefined -DHTS_ALLOW_UNALIGNED=0 -Wno-format-truncation -Wno-format-overflow
8080
LDFLAGS: -fsanitize=address,undefined
8181
USE_LIBDEFLATE: yes
8282
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1

NEWS

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,46 @@
1+
Noteworthy changes in release 1.22.1 (14th July 2025)
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
Bug Fixes
5+
---------
6+
7+
* SECURITY fix: Prevent CRAM byte_array decoder from overflowing its output
8+
buffer. This could be triggered by certain malformed CRAM inputs.
9+
(PR #1934)
10+
11+
* Two fixes for crashes reported when trying to save data with very long
12+
alignment records with sequence '*' as CRAM 3.1:
13+
14+
- The htscodecs submodule is updated to v1.6.4.
15+
This includes a fix to the rANS encoder to prevent it from failing on
16+
these inputs.
17+
(PR #1935. Reported by Martin Pollard)
18+
19+
- Improved error handling in cram_compress_block2(). If the previously-chosen
20+
CRAM compression method starts to fail, it will now try other methods
21+
instead of giving up immediately.
22+
(PR #1931. Reported by Martin Pollard)
23+
24+
25+
* Fix warnings due to the wrong datatype being passed to curl_easy_setopt()
26+
(PR #1925. Thanks to John Marshall)
27+
28+
* Prevent instances of `memcpy(out, NULL, 0)`, which is strictly undefined
29+
behaviour.
30+
(PR #1930. Thanks to Ben Lawrence).
31+
32+
Build Changes
33+
-------------
34+
35+
* Fixed compilation against older glibc / macOS SDKs that incorrectly
36+
suppressed some symbols if _XOPEN_SOURCE was defined.
37+
(PR #1928. Reported by John Marshall)
38+
39+
* Fixed ref-cache configure check for libcurl, so that if libcurl is
40+
not available, or turned off by `./configure --disable-libcurl`,
41+
the `ref-cache` build will be automatically disabled as well.
42+
(PR #1929, fixes #1926. Reported by biounix)
43+
144
Noteworthy changes in release 1.22 (30th May 2025)
245
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
346

annot-tsv.1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'\" t
2-
.TH annot-tsv 1 "30 May 2025" "htslib-1.22" "Bioinformatics tools"
2+
.TH annot-tsv 1 "14 July 2025" "htslib-1.22.1" "Bioinformatics tools"
33
.\"
44
.\" Copyright (C) 2015, 2017-2018, 2023-2024 Genome Research Ltd.
55
.\"

bgzip.1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.TH bgzip 1 "30 May 2025" "htslib-1.22" "Bioinformatics tools"
1+
.TH bgzip 1 "14 July 2025" "htslib-1.22.1" "Bioinformatics tools"
22
.SH NAME
33
.PP
44
bgzip \- Block compression/decompression utility

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ AS_IF([test "x$enable_ref_cache" != xno],
645645
[AS_CASE([$PLATFORM],
646646
[Darwin | default],[
647647
AS_IF([test "x$libcurl" = xenabled], [ref_cache="enabled"], [
648-
AS_IF([test "x$enable_ref_cache" = check], [
648+
AS_IF([test "x$enable_ref_cache" = xcheck], [
649649
AC_MSG_WARN([ref-cache not enabled: requires libcurl])
650650
],[
651651
MSG_ERROR([ref-cache not enabled

cram/cram_codecs.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3575,12 +3575,18 @@ static int cram_byte_array_stop_decode_char(cram_slice *slice, cram_codec *c,
35753575

35763576
cp = (char *)b->data + b->idx;
35773577
if (out) {
3578+
// memccpy equivalent but without copying the terminating byte
3579+
ssize_t term = MIN(*out_size, b->uncomp_size - b->idx);
35783580
while ((ch = *cp) != (char)c->u.byte_array_stop.stop) {
3579-
if (cp - (char *)b->data >= b->uncomp_size)
3580-
return -1;
3581+
if (term-- < 0)
3582+
break;
35813583
*out++ = ch;
35823584
cp++;
35833585
}
3586+
3587+
// Attempted overrun on input or output
3588+
if (ch != (char)c->u.byte_array_stop.stop)
3589+
return -1;
35843590
} else {
35853591
// Consume input, but produce no output
35863592
while ((ch = *cp) != (char)c->u.byte_array_stop.stop) {

cram/cram_decode.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,7 @@ static int cram_decode_seq(cram_fd *fd, cram_container *c, cram_slice *s,
12751275

12761276
switch(op) {
12771277
case 'S': { // soft clip: IN
1278-
int32_t out_sz2 = 1;
1278+
int32_t out_sz2 = cr->len ? cr->len-(pos-1) : 1;
12791279
int have_sc = 0;
12801280

12811281
if (cig_len) {
@@ -1431,7 +1431,7 @@ static int cram_decode_seq(cram_fd *fd, cram_container *c, cram_slice *s,
14311431
}
14321432

14331433
case 'I': { // Insertion (several bases); IN
1434-
int32_t out_sz2 = 1;
1434+
int32_t out_sz2 = cr->len ? cr->len-(pos-1) : 1;
14351435

14361436
if (cig_len && cig_op != BAM_CINS) {
14371437
cigar[ncigar++] = (cig_len<<4) + cig_op;
@@ -1473,7 +1473,7 @@ static int cram_decode_seq(cram_fd *fd, cram_container *c, cram_slice *s,
14731473
}
14741474

14751475
case 'b': { // Several bases
1476-
int32_t len = 1;
1476+
int32_t len = cr->len ? cr->len-(pos-1) : 1;
14771477

14781478
if (cig_len && cig_op != BAM_CMATCH) {
14791479
cigar[ncigar++] = (cig_len<<4) + cig_op;
@@ -1523,7 +1523,7 @@ static int cram_decode_seq(cram_fd *fd, cram_container *c, cram_slice *s,
15231523
}
15241524

15251525
case 'q': { // Several quality values
1526-
int32_t len = 1;
1526+
int32_t len = cr->len ? cr->len - (pos-1) : 1;
15271527

15281528
if (cig_len && cig_op != BAM_CMATCH) {
15291529
cigar[ncigar++] = (cig_len<<4) + cig_op;
@@ -2298,9 +2298,13 @@ int cram_decode_slice(cram_fd *fd, cram_container *c, cram_slice *s,
22982298
// However it's likely that this also saves memory as own growth
22992299
// factor (*=1.5) is never applied.
23002300
{
2301+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2302+
int qsize=0, nsize=0, q_id=0;
2303+
#else
23012304
int qsize, nsize, q_id;
23022305
cram_decode_estimate_sizes(c->comp_hdr, s, &qsize, &nsize, &q_id);
23032306
//fprintf(stderr, "qsize=%d nsize=%d\n", qsize, nsize);
2307+
#endif
23042308

23052309
if (qsize && (ds & CRAM_RL)) BLOCK_RESIZE_EXACT(s->seqs_blk, qsize+1);
23062310
if (qsize && (ds & CRAM_RL)) BLOCK_RESIZE_EXACT(s->qual_blk, qsize+1);
@@ -2639,7 +2643,7 @@ int cram_decode_slice(cram_fd *fd, cram_container *c, cram_slice *s,
26392643
cr->name_len = 0;
26402644

26412645
if (c->comp_hdr->read_names_included) {
2642-
int32_t out_sz2 = 1;
2646+
int32_t out_sz2 = 1; // block auto grows in decode()
26432647

26442648
// Read directly into name cram_block
26452649
cr->name = BLOCK_SIZE(s->name_blk);
@@ -2800,15 +2804,15 @@ int cram_decode_slice(cram_fd *fd, cram_container *c, cram_slice *s,
28002804
/* Fake up dynamic string growth and appending */
28012805
if (ds & CRAM_RL) {
28022806
cr->seq = BLOCK_SIZE(s->seqs_blk);
2803-
BLOCK_GROW(s->seqs_blk, cr->len);
2807+
BLOCK_RESIZE(s->seqs_blk, cr->seq + cr->len);
28042808
seq = (char *)BLOCK_END(s->seqs_blk);
28052809
BLOCK_SIZE(s->seqs_blk) += cr->len;
28062810

28072811
if (!seq)
28082812
goto block_err;
28092813

28102814
cr->qual = BLOCK_SIZE(s->qual_blk);
2811-
BLOCK_GROW(s->qual_blk, cr->len);
2815+
BLOCK_RESIZE(s->qual_blk, cr->qual + cr->len);
28122816
qual = (char *)BLOCK_END(s->qual_blk);
28132817
BLOCK_SIZE(s->qual_blk) += cr->len;
28142818

cram/cram_io.c

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,24 +1899,21 @@ static char *cram_compress_by_method(cram_slice *s, char *in, size_t in_size,
18991899
return NULL;
19001900
}
19011901

1902-
19031902
/*
1904-
* Compresses a block using one of two different zlib strategies. If we only
1905-
* want one choice set strat2 to be -1.
1906-
*
1907-
* The logic here is that sometimes Z_RLE does a better job than Z_FILTERED
1908-
* or Z_DEFAULT_STRATEGY on quality data. If so, we'd rather use it as it is
1909-
* significantly faster.
1910-
*
1911-
* Method and level -1 implies defaults, as specified in cram_fd.
1903+
* A copy of cram_compress_block2 with added recursion detection.
1904+
* This is only called for error handling where the auto-tuning has failed.
1905+
* The simplest way of doing this is recusion + an additional argument, but
1906+
* we didn't want to complicate the existing code hence this is static.
19121907
*/
1913-
int cram_compress_block2(cram_fd *fd, cram_slice *s,
1914-
cram_block *b, cram_metrics *metrics,
1915-
int method, int level) {
1908+
static int cram_compress_block3(cram_fd *fd, cram_slice *s,
1909+
cram_block *b, cram_metrics *metrics,
1910+
int method, int level,
1911+
int recurse) {
19161912

19171913
if (!b)
19181914
return 0;
19191915

1916+
int orig_method = method;
19201917
char *comp = NULL;
19211918
size_t comp_size = 0;
19221919
int strat;
@@ -2249,8 +2246,23 @@ int cram_compress_block2(cram_fd *fd, cram_slice *s,
22492246
b->content_id, &comp_size, method,
22502247
method == GZIP_1 ? 1 : level,
22512248
strat);
2252-
if (!comp)
2249+
if (!comp) {
2250+
// Our cached best method failed, but maybe another works?
2251+
// Rerun with trial mode engaged again.
2252+
if (!recurse) {
2253+
hts_log_warning("Compressed block ID %d method %s failed, "
2254+
"redoing trial", b->content_id,
2255+
cram_block_method2str(method));
2256+
pthread_mutex_lock(&fd->metrics_lock);
2257+
metrics->trial = NTRIALS;
2258+
metrics->next_trial = TRIAL_SPAN;
2259+
metrics->revised_method = orig_method;
2260+
pthread_mutex_unlock(&fd->metrics_lock);
2261+
return cram_compress_block3(fd, s, b, metrics, method,
2262+
level, 1);
2263+
}
22532264
return -1;
2265+
}
22542266

22552267
if (comp_size < b->uncomp_size) {
22562268
free(b->data);
@@ -2290,6 +2302,19 @@ int cram_compress_block2(cram_fd *fd, cram_slice *s,
22902302

22912303
return 0;
22922304
}
2305+
2306+
/*
2307+
* Compresses a block using a selection of compression codecs and options.
2308+
* The best is learnt and used for subsequent slices, periodically resampling.
2309+
*
2310+
* Method and level -1 implies defaults, as specified in cram_fd.
2311+
*/
2312+
int cram_compress_block2(cram_fd *fd, cram_slice *s,
2313+
cram_block *b, cram_metrics *metrics,
2314+
int method, int level) {
2315+
return cram_compress_block3(fd, s, b, metrics, method, level, 0);
2316+
}
2317+
22932318
int cram_compress_block(cram_fd *fd, cram_block *b, cram_metrics *metrics,
22942319
int method, int level) {
22952320
return cram_compress_block2(fd, NULL, b, metrics, method, level);

cram/cram_io.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,12 @@ static inline int block_resize(cram_block *b, size_t len) {
227227
if (b->alloc > len)
228228
return 0;
229229

230+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
231+
// Removal of extra padding causes many more reallocs, but detects
232+
// more buffer overruns.
233+
return block_resize_exact(b, len?len:1);
234+
#endif
235+
230236
size_t alloc = b->alloc+800;
231237
alloc = MAX(alloc + (alloc>>2), len);
232238
return block_resize_exact(b, alloc);

hfile_libcurl.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1222,7 +1222,8 @@ libcurl_open(const char *url, const char *modes, http_headers *headers)
12221222

12231223
// Avoid many repeated CWD calls with FTP, instead requesting the filename
12241224
// by full path (but not strictly compliant with RFC1738).
1225-
err |= curl_easy_setopt(fp->easy, CURLOPT_FTP_FILEMETHOD, CURLFTPMETHOD_NOCWD);
1225+
err |= curl_easy_setopt(fp->easy, CURLOPT_FTP_FILEMETHOD,
1226+
(long) CURLFTPMETHOD_NOCWD);
12261227

12271228
if (mode == 'r') {
12281229
err |= curl_easy_setopt(fp->easy, CURLOPT_WRITEFUNCTION, recv_callback);

0 commit comments

Comments
 (0)