From e3c93cb7413934ae774a1e895b8c0e6529a5a42c Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Mon, 11 May 2026 21:40:28 +0300
Subject: [PATCH] updated dr_flac.h from mainstream.
(cherry picked from commit 7d97b0c21296ad8f5f266716a89daba5129a1230)
---
src/codecs/dr_libs/dr_flac.h | 89 ++++++++++++++++++++++++++++--------
1 file changed, 71 insertions(+), 18 deletions(-)
diff --git a/src/codecs/dr_libs/dr_flac.h b/src/codecs/dr_libs/dr_flac.h
index c95a78c3e..72bc6b762 100644
--- a/src/codecs/dr_libs/dr_flac.h
+++ b/src/codecs/dr_libs/dr_flac.h
@@ -1,6 +1,6 @@
/*
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
-dr_flac - v0.13.2 - 2025-12-02
+dr_flac - v0.13.4 - TBD
David Reid - mackron@gmail.com
@@ -126,7 +126,7 @@ extern "C" {
#define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 13
-#define DRFLAC_VERSION_REVISION 2
+#define DRFLAC_VERSION_REVISION 4
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
@@ -1547,6 +1547,8 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
#define DRFLAC_ZERO_OBJECT(p) DRFLAC_ZERO_MEMORY((p), sizeof(*(p)))
#endif
+#define DRFLAC_MIN(a, b) (((a) < (b)) ? (a) : (b))
+
#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */
/* Result Codes */
@@ -2716,9 +2718,17 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
#if defined(__GNUC__) || defined(__clang__)
#if defined(DRFLAC_X64)
{
+ /*
+ A note on lzcnt.
+
+ We check for the presence of the lzcnt instruction at runtime before calling this function, but we still generate this code. I have had
+ a report where the assembler does not recognize the lzcnt instruction. To work around this we are going to use `rep; bsr` instead which
+ has an identical byte encoding as lzcnt, and should hopefully improve compatibility with older assemblers.
+ */
drflac_uint64 r;
__asm__ __volatile__ (
- "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+ "rep; bsr{q %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+ /*"lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"*/
);
return (drflac_uint32)r;
@@ -2727,7 +2737,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
{
drflac_uint32 r;
__asm__ __volatile__ (
- "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+ "rep; bsr{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+ /*"lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"*/
);
return r;
@@ -5971,8 +5982,6 @@ static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* p
break; /* Failed to seek to FLAC frame. */
}
} else {
- const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f);
-
if (pcmRangeLo > pcmFrameIndex) {
/* We seeked too far forward. We need to move our target byte backward and try again. */
byteRangeHi = lastSuccessfulSeekOffset;
@@ -5995,12 +6004,14 @@ static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* p
break; /* Failed to seek to FLAC frame. */
}
} else {
+ const double approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0);
+
byteRangeLo = lastSuccessfulSeekOffset;
if (byteRangeHi < byteRangeLo) {
byteRangeHi = byteRangeLo;
}
- targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio);
+ targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0) * approxCompressionRatio);
if (targetByte > byteRangeHi) {
targetByte = byteRangeHi;
}
@@ -6393,7 +6404,7 @@ static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld,
}
if (p != NULL) {
- DRFLAC_COPY_MEMORY(p2, p, szOld);
+ DRFLAC_COPY_MEMORY(p2, p, DRFLAC_MIN(szNew, szOld));
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
@@ -6421,11 +6432,22 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
we'll be sitting on byte 42.
*/
- drflac_uint64 runningFilePos = 42;
- drflac_uint64 seektablePos = 0;
- drflac_uint32 seektableSize = 0;
+ drflac_uint64 runningFilePos = 42;
+ drflac_uint64 seektablePos = 0;
+ drflac_uint32 seektableSize = 0;
+ drflac_int64 fileSize = 0;
+ drflac_bool32 hasKnownFileSize = DRFLAC_FALSE;
- (void)onTell;
+ /* We'll be doing some memory allocations here against untrusted data. We'll do a basic validation check that they don't exceed the size of the file. */
+ if (onTell != NULL && onSeek != NULL) {
+ if (onSeek(pUserData, 0, DRFLAC_SEEK_END)) {
+ if (onTell(pUserData, &fileSize)) {
+ hasKnownFileSize = DRFLAC_TRUE;
+ }
+
+ onSeek(pUserData, runningFilePos, DRFLAC_SEEK_SET);
+ }
+ }
for (;;) {
drflac_metadata metadata;
@@ -6435,6 +6457,11 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
return DRFLAC_FALSE;
}
+
+ if (hasKnownFileSize && (blockSize > ((drflac_uint64)fileSize - runningFilePos))) {
+ return DRFLAC_FALSE; /* Block size exceeds the size of the file. */
+ }
+
runningFilePos += 4;
metadata.type = blockType;
@@ -6550,7 +6577,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
- metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
+ metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
/* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */
@@ -6738,13 +6765,18 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
blockSizeRemaining -= 4;
metadata.data.picture.mimeLength = drflac__be2host_32(metadata.data.picture.mimeLength);
+ if (blockSizeRemaining < metadata.data.picture.mimeLength) {
+ result = DRFLAC_FALSE;
+ goto done_flac;
+ }
+
pMime = (char*)drflac__malloc_from_callbacks(metadata.data.picture.mimeLength + 1, pAllocationCallbacks); /* +1 for null terminator. */
if (pMime == NULL) {
result = DRFLAC_FALSE;
goto done_flac;
}
- if (blockSizeRemaining < metadata.data.picture.mimeLength || onRead(pUserData, pMime, metadata.data.picture.mimeLength) != metadata.data.picture.mimeLength) {
+ if (onRead(pUserData, pMime, metadata.data.picture.mimeLength) != metadata.data.picture.mimeLength) {
result = DRFLAC_FALSE;
goto done_flac;
}
@@ -6760,13 +6792,18 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
blockSizeRemaining -= 4;
metadata.data.picture.descriptionLength = drflac__be2host_32(metadata.data.picture.descriptionLength);
+ if (blockSizeRemaining < metadata.data.picture.descriptionLength) {
+ result = DRFLAC_FALSE;
+ goto done_flac;
+ }
+
pDescription = (char*)drflac__malloc_from_callbacks(metadata.data.picture.descriptionLength + 1, pAllocationCallbacks); /* +1 for null terminator. */
if (pDescription == NULL) {
result = DRFLAC_FALSE;
goto done_flac;
}
- if (blockSizeRemaining < metadata.data.picture.descriptionLength || onRead(pUserData, pDescription, metadata.data.picture.descriptionLength) != metadata.data.picture.descriptionLength) {
+ if (onRead(pUserData, pDescription, metadata.data.picture.descriptionLength) != metadata.data.picture.descriptionLength) {
result = DRFLAC_FALSE;
goto done_flac;
}
@@ -6842,8 +6879,10 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
}
blockSizeRemaining -= metadata.data.picture.pictureDataSize;
- metadata.data.picture.pPictureData = (const drflac_uint8*)pPictureData;
+ (void)blockSizeRemaining;
+ metadata.data.picture.pPictureData = (const drflac_uint8*)pPictureData;
+
/* Only fire the callback if we actually have a way to read the image data. We must have either a valid offset, or a valid data pointer. */
if (metadata.data.picture.pictureDataOffset != 0 || metadata.data.picture.pPictureData != NULL) {
@@ -8083,11 +8122,17 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
return NULL;
}
+ if ((0xFFFFFFFF - (seekpointCount * sizeof(drflac_seekpoint))) < allocationSize) {
+ #ifndef DR_FLAC_NO_OGG
+ drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
+ #endif
+ return NULL;
+ }
+
allocationSize += seekpointCount * sizeof(drflac_seekpoint);
}
-
- pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
+ pFlac = (drflac*)drflac__malloc_from_callbacks((size_t)allocationSize, &allocationCallbacks);
if (pFlac == NULL) {
#ifndef DR_FLAC_NO_OGG
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
@@ -12158,6 +12203,14 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
/*
REVISION HISTORY
================
+v0.13.4 - TBD
+ - Add a bounds check when allocating memory during metadata processing.
+ - Fix a possible overflow error when parsing picture metadata.
+
+v0.13.3 - 2026-01-17
+ - Fix a compiler compatibility issue with some inlined assembly.
+ - Fix a compilation warning.
+
v0.13.2 - 2025-12-02
- Improve robustness of the parsing of picture metadata to improve support for memory constrained embedded devices.
- Fix a warning about an assigned by unused variable.