From 322e14322403a65066c3a1d80a77b81f00cc3f01 Mon Sep 17 00:00:00 2001 From: Martijn van Beurden Date: Thu, 29 Aug 2024 13:18:40 +0200 Subject: [PATCH] Reduce chance of ogg serial number collision When two ogg streams were made with two different calls to `flac` within the same second, their serial numbers would be the same. This caused problems with seeking in the test suite. While in theory, libFLAC should be able to seek in a chained stream with two equal serial numbers without fail, in practice seeking in chained streams is hard enough. So, this commit makes sure the chained test files have links with unequal serial numbers. --- config.cmake.h.in | 3 +++ configure.ac | 2 +- src/flac/CMakeLists.txt | 1 + src/flac/main.c | 34 ++++++++++++++++++++++++++++++++-- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/config.cmake.h.in b/config.cmake.h.in index 1aeaffc804..7fca78e2ef 100644 --- a/config.cmake.h.in +++ b/config.cmake.h.in @@ -109,6 +109,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H diff --git a/configure.ac b/configure.ac index 6391501bdb..f1f05c5fd8 100644 --- a/configure.ac +++ b/configure.ac @@ -53,7 +53,7 @@ AM_PROG_CC_C_O AC_C_INLINE AC_C_TYPEOF -AC_CHECK_HEADERS([stdint.h stdbool.h inttypes.h byteswap.h sys/auxv.h sys/param.h sys/ioctl.h termios.h x86intrin.h cpuid.h arm_neon.h]) +AC_CHECK_HEADERS([stdint.h stdbool.h inttypes.h byteswap.h sys/auxv.h sys/param.h sys/ioctl.h sys/time.h termios.h x86intrin.h cpuid.h arm_neon.h]) if test "x$ac_cv_header_stdint_h" != xyes -o "x$ac_cv_header_stdbool_h" != xyes; then AC_MSG_ERROR("Header stdint.h and/or stdbool.h not found") diff --git a/src/flac/CMakeLists.txt b/src/flac/CMakeLists.txt index da7ce8de9c..8b4e52a131 100644 --- a/src/flac/CMakeLists.txt +++ b/src/flac/CMakeLists.txt @@ -1,4 +1,5 @@ check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H) +check_include_file("sys/time.h" HAVE_SYS_TIME_H) check_include_file("termios.h" HAVE_TERMIOS_H) add_executable(flacapp diff --git a/src/flac/main.c b/src/flac/main.c index 6087371528..dc8c23cb06 100644 --- a/src/flac/main.c +++ b/src/flac/main.c @@ -30,6 +30,10 @@ #include #include +#ifdef HAVE_SYS_TIME_H +#include +#endif + #if !defined _MSC_VER && !defined __MINGW32__ /* unlink is in stdio.h in VC++ */ #include /* for unlink() */ @@ -322,7 +326,30 @@ static int main_to_fuzz(int argc, char *argv[]) _setmode(fileno(stderr),_O_U8TEXT); #endif - srand((uint32_t)time(0)); +#ifdef HAVE_SYS_TIME_H + { + struct timeval tv; + + if (gettimeofday(&tv, 0) < 0) { + srand(((uint32_t)time(0) << 8) + (uint32_t)clock()); + } + else { + /* fall back when gettimeofday fails */ + srand((uint32_t)(tv.tv_sec) * 1e6 + (uint32_t)tv.tv_usec); + } + } +#else + /* time(0) does not have sufficient resolution when flac is invoked more than + * once in quick succession (for example in the test suite). As far as I know, + * clock() is the only sub-second portable alternative, but measures + * execution time, which is often quite similar between runs. From limited + * testing, it seems the value varies by about 100, so that would make + * collision 100 times less likely than without. Therefore, use + * both together to generate a random number seed. + */ + srand(((uint32_t)time(0) << 8) + (uint32_t)clock()); +#endif + #ifdef _WIN32 { const char *var; @@ -1640,7 +1667,10 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ encode_options.use_ogg = option_values.use_ogg; /* set a random serial number if one has not yet been specified */ if(!option_values.has_serial_number) { - option_values.serial_number = rand(); + if (RAND_MAX < 0x7fffffff) + option_values.serial_number = (uint32_t)(rand() & 0x7fff) << 16 | (uint32_t)(rand()); + else + option_values.serial_number = rand(); option_values.has_serial_number = true; } encode_options.serial_number = option_values.serial_number++;