Skip to content

Commit cbfe50e

Browse files
authored
Add FLAC__stream_decoder_get_link_lengths (#793)
1 parent 3542ae8 commit cbfe50e

File tree

5 files changed

+143
-0
lines changed

5 files changed

+143
-0
lines changed

include/FLAC/stream_decoder.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,43 @@ FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamD
11121112
*/
11131113
FLAC_API const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder);
11141114

1115+
#define FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID -1
1116+
#define FLAC__STREAM_DECODER_GET_LINK_LENGTHS_NOT_INDEXED -2
1117+
#define FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR -3
1118+
1119+
/** Get the link lengths in samples in a chained stream
1120+
*
1121+
* After either processing the whole file or using
1122+
* FLAC__stream_decoder_find_total_samples, this function
1123+
* returns an array with link lengths in samples. If it fails,
1124+
* it returns a negative number as error code, currently either
1125+
* FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID if the current
1126+
* decoder is not in a valid state or not processing a chained
1127+
* stream, FLAC__STREAM_DECODER_GET_LINK_LENGTHS_NOT_INDEXED if
1128+
* the stream hasn't been indexed yet, and
1129+
* FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR
1130+
* if allocating memory failed.
1131+
*
1132+
* If the function succeeds, the return value is the number of
1133+
* links. The link_lengths parameter is a FLAC__uint64 pointer
1134+
* which is allocated by the call, and must be freed by the user.
1135+
* If a null pointer is passed, the function only returns the
1136+
* number of links, not their lengths. The length of the returned
1137+
* array is equal to the number of links and thus to the return
1138+
* value of the function.
1139+
*
1140+
* \param decoder A decoder instance to query.
1141+
* \param link_lengths Address at which to return the link lengths
1142+
* array.
1143+
* \assert
1144+
* \code decoder != NULL \endcode
1145+
* \retval int32_t
1146+
* \c the number of links if successful, zero or a negative
1147+
* number if unsuccessful
1148+
*/
1149+
1150+
FLAC_API int32_t FLAC__stream_decoder_get_link_lengths(FLAC__StreamDecoder *decoder, FLAC__uint64 **link_lengths);
1151+
11151152
/** Initialize the decoder instance to decode native FLAC streams.
11161153
*
11171154
* This flavor of initialization sets up the decoder to decode from a

oss-fuzz/seek.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
#include "FLAC/stream_decoder.h"
3535
#include "common.h"
3636

37+
#if MSAN == 1
38+
extern "C" void __msan_check_mem_is_initialized(const volatile void *x, size_t size);
39+
#endif
40+
3741
int write_abort_check_counter = -1;
3842
int written_uncompressed_bytes = 0;
3943
int errors_received_counter = 0;
@@ -226,6 +230,26 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
226230
decoder_valid = false;
227231
}
228232
break;
233+
case 13:
234+
int32_t retval;
235+
FLAC__uint64 *link_lengths;
236+
FPRINTF_DEBUG_ONLY(stderr,"get_link_lengths\n");
237+
retval = FLAC__stream_decoder_get_link_lengths(decoder, &link_lengths);
238+
if(retval == FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR) {
239+
decoder_valid = false;
240+
}
241+
if(retval > 0) {
242+
for(int32_t j = 0; j < retval; j++) {
243+
#if MSAN == 1
244+
__msan_check_mem_is_initialized(&link_lengths[j],sizeof(link_lengths[j]));
245+
#else
246+
;
247+
#endif
248+
}
249+
free(link_lengths);
250+
}
251+
break;
252+
/* case 14 is already used above */
229253
}
230254
if(!decoder_valid) {
231255
/* Try again if possible */

src/libFLAC/ogg_decoder_aspect.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,10 @@ FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_skip_link(FLAC__OggDec
696696
else if(aspect->end_of_stream) {
697697
if(aspect->beginning_of_link && !aspect->bos_flag_seen) {
698698
/* We were looking for the next link, but found end of stream instead */
699+
if(aspect->current_linknumber == 0)
700+
return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
701+
aspect->current_linknumber--;
702+
aspect->linkdetails[aspect->current_linknumber].is_last = true;
699703
return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
700704
}
701705
else if(did_a_seek) {

src/libFLAC/stream_decoder.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,43 @@ FLAC_API FLAC__uint64 FLAC__stream_decoder_find_total_samples(FLAC__StreamDecode
14711471
return 0;
14721472
}
14731473

1474+
FLAC_API int32_t FLAC__stream_decoder_get_link_lengths(FLAC__StreamDecoder *decoder, FLAC__uint64 **link_lengths)
1475+
{
1476+
/* If we don't have Ogg, this is (for now) useless, fail */
1477+
#if FLAC__HAS_OGG
1478+
uint32_t i;
1479+
1480+
/* Check whether we're decoding chaines ogg, and decoder is somewhat valid */
1481+
if(!decoder->private_->is_ogg ||
1482+
!FLAC__stream_decoder_get_decode_chained_stream(decoder) ||
1483+
decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED ||
1484+
decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR ||
1485+
decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
1486+
return FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID;
1487+
1488+
/* Check whether link details are known. If not, fail */
1489+
if(decoder->protected_->ogg_decoder_aspect.number_of_links_indexed == 0 ||
1490+
!decoder->protected_->ogg_decoder_aspect.linkdetails[decoder->protected_->ogg_decoder_aspect.number_of_links_indexed - 1].is_last)
1491+
return FLAC__STREAM_DECODER_GET_LINK_LENGTHS_NOT_INDEXED;
1492+
1493+
if(link_lengths != NULL) {
1494+
*link_lengths = safe_malloc_mul_2op_p(sizeof(FLAC__uint64), decoder->protected_->ogg_decoder_aspect.number_of_links_indexed);
1495+
if(*link_lengths == NULL)
1496+
return FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR;
1497+
1498+
for(i = 0; i < decoder->protected_->ogg_decoder_aspect.number_of_links_indexed; i++)
1499+
(*link_lengths)[i] = decoder->protected_->ogg_decoder_aspect.linkdetails[i].samples;
1500+
}
1501+
1502+
return decoder->protected_->ogg_decoder_aspect.number_of_links_indexed;
1503+
#else
1504+
(void)decoder;
1505+
(void)link_lengths;
1506+
return FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID;
1507+
#endif
1508+
}
1509+
1510+
14741511
/***********************************************************************
14751512
*
14761513
* Protected class methods

src/test_libFLAC/decoders.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,17 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg, FLAC__bool
560560
return die_s_(0, decoder);
561561
printf("OK\n");
562562

563+
printf("testing FLAC__stream_decoder_get_link_lengths()... ");
564+
if(is_chained_ogg) {
565+
if(FLAC__stream_decoder_get_link_lengths(decoder, NULL) != FLAC__STREAM_DECODER_GET_LINK_LENGTHS_NOT_INDEXED)
566+
return die_s_("returned incorrectly", decoder);
567+
}
568+
else{ /* not chained ogg */
569+
if(FLAC__stream_decoder_get_link_lengths(decoder, NULL) != FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID)
570+
return die_s_("returned incorrectly", decoder);
571+
}
572+
printf("OK\n");
573+
563574
printf("testing FLAC__stream_decoder_find_total_samples... ");
564575
total_samples = FLAC__stream_decoder_find_total_samples(decoder);
565576
printf("Number of samples returned is %" PRIu64 "... ",total_samples);
@@ -569,6 +580,22 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg, FLAC__bool
569580
return die_s_("returned wrong number of samples", decoder);
570581
printf("OK\n");
571582

583+
if(is_chained_ogg) {
584+
printf("testing FLAC__stream_decoder_get_link_lengths()... ");
585+
if(layer == LAYER_STREAM) {
586+
if(FLAC__stream_decoder_get_link_lengths(decoder, NULL) != FLAC__STREAM_DECODER_GET_LINK_LENGTHS_NOT_INDEXED)
587+
return die_s_("returned incorrectly", decoder);
588+
}
589+
else {
590+
int32_t retval = FLAC__stream_decoder_get_link_lengths(decoder, NULL);
591+
printf("Number of links returned is %d\n",retval);
592+
if(retval != 2)
593+
return die_s_("returned incorrectly", decoder);
594+
595+
}
596+
printf("OK\n");
597+
}
598+
572599
if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
573600
fclose(decoder_client_data.file);
574601

@@ -722,6 +749,20 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg, FLAC__bool
722749
}
723750
printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
724751

752+
printf("testing FLAC__stream_decoder_get_link_lengths()... ");
753+
{
754+
FLAC__uint64 *link_lengths;
755+
int32_t retval = FLAC__stream_decoder_get_link_lengths(decoder, &link_lengths);
756+
printf("Number of links returned is %d\n",retval);
757+
printf("Number of samples is %" PRIu64 " and %" PRIu64 "\n",link_lengths[0],link_lengths[1]);
758+
if(retval != 2)
759+
return die_s_("returned incorrectly", decoder);
760+
free(link_lengths);
761+
762+
}
763+
printf("OK\n");
764+
765+
725766
printf("testing FLAC__stream_decoder_reset()... ");
726767
if(!FLAC__stream_decoder_reset(decoder)) {
727768
state = FLAC__stream_decoder_get_state(decoder);

0 commit comments

Comments
 (0)