diff --git a/CHANGELOG.md b/CHANGELOG.md index 11e6d985c..bf2e756ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ librdkafka v2.12.0 is a feature release: * Issues: #4878. Fix to ensure `rd_kafka_query_watermark_offsets` enforces the specified timeout and does not continue beyond timeout expiry. Happening since 2.3.0 (#5201). +* Issues: #4949: Prevent an FPE in rd_hdr_histogram_new. ### Telemetry fixes diff --git a/src/rdhdrhistogram.c b/src/rdhdrhistogram.c index 08240ac7a..ecb24f3a8 100644 --- a/src/rdhdrhistogram.c +++ b/src/rdhdrhistogram.c @@ -89,6 +89,7 @@ rd_hdr_histogram_t *rd_hdr_histogram_new(int64_t minValue, int64_t largestValueWithSingleUnitResolution; int32_t subBucketCountMagnitude; int32_t subBucketHalfCountMagnitude; + double potentialUnitMagnitude; int32_t unitMagnitude; int32_t subBucketCount; int32_t subBucketHalfCount; @@ -109,7 +110,8 @@ rd_hdr_histogram_t *rd_hdr_histogram_new(int64_t minValue, subBucketHalfCountMagnitude = RD_MAX(subBucketCountMagnitude, 1) - 1; - unitMagnitude = (int32_t)RD_MAX(floor(log2((double)minValue)), 0); + potentialUnitMagnitude = minValue == 0 ? 0 : log2((double)minValue); + unitMagnitude = (int32_t)RD_MAX(floor(potentialUnitMagnitude), 0); subBucketCount = (int32_t)pow(2, (double)subBucketHalfCountMagnitude + 1.0); diff --git a/tests/0154-rd_hdr_histogram_new-fpe.c b/tests/0154-rd_hdr_histogram_new-fpe.c new file mode 100644 index 000000000..003abc023 --- /dev/null +++ b/tests/0154-rd_hdr_histogram_new-fpe.c @@ -0,0 +1,44 @@ +/* + * librdkafka - Apache Kafka C library + * + * Copyright (c) 2025, Confluent Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" +#include "rdhdrhistogram.h" +#include + +void do_test_rd_hdr_histogram_new_fpe() { + rd_hdr_histogram_t *hist; + feclearexcept(FE_ALL_EXCEPT); + hist = rd_hdr_histogram_new(0, 10000, 2); + TEST_ASSERT(fetestexcept(FE_DIVBYZERO) == 0, "Division by zero occurred"); + rd_hdr_histogram_destroy(hist); +} + +int main_0154_rd_hdr_histogram_new_fpe(int argc, char **argv) { + do_test_rd_hdr_histogram_new_fpe(); + return 0; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 324281bd9..0d16c1829 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -144,6 +144,7 @@ set( 0151-purge-brokers.c 0152-rebootstrap.c 0153-memberid.c + 0154-rd_hdr_histogram_new-fpe.c 8000-idle.cpp 8001-fetch_from_follower_mock_manual.c test.c diff --git a/tests/test.c b/tests/test.c index 42e525a9c..e11b02f19 100644 --- a/tests/test.c +++ b/tests/test.c @@ -272,6 +272,7 @@ _TEST_DECL(0150_telemetry_mock); _TEST_DECL(0151_purge_brokers_mock); _TEST_DECL(0152_rebootstrap_local); _TEST_DECL(0153_memberid); +_TEST_DECL(0154_rd_hdr_histogram_new_fpe); /* Manual tests */ _TEST_DECL(8000_idle); @@ -540,6 +541,7 @@ struct test tests[] = { _TEST(0151_purge_brokers_mock, TEST_F_LOCAL), _TEST(0152_rebootstrap_local, TEST_F_LOCAL), _TEST(0153_memberid, 0, TEST_BRKVER(0, 4, 0, 0)), + _TEST(0154_rd_hdr_histogram_new_fpe, TEST_F_LOCAL), /* Manual tests */ _TEST(8000_idle, TEST_F_MANUAL), diff --git a/win32/tests/tests.vcxproj b/win32/tests/tests.vcxproj index 812a2674d..f226849e9 100644 --- a/win32/tests/tests.vcxproj +++ b/win32/tests/tests.vcxproj @@ -234,6 +234,7 @@ +