diff --git a/Source/UnitTest/test_encode.cpp b/Source/UnitTest/test_encode.cpp index 069f6441..cc9be93c 100644 --- a/Source/UnitTest/test_encode.cpp +++ b/Source/UnitTest/test_encode.cpp @@ -96,6 +96,41 @@ TEST(compress, overflow_in_16) astcenc_context_free(context); } +/** @brief Input test for an out-of-range alpha-scale radius. */ +TEST(compress, ascale_radius_clamped) +{ + astcenc_error status; + astcenc_config config; + astcenc_context* context; + + static const astcenc_swizzle swizzle { + ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A + }; + + astcenc_config_init(ASTCENC_PRF_LDR, 4, 4, 1, ASTCENC_PRE_MEDIUM, 0, &config); + + // Set to largest possible value to check input validation + config.a_scale_radius = 0xFFFFFFFFu; + status = astcenc_context_alloc(&config, 1, &context, nullptr); + EXPECT_EQ(status, ASTCENC_SUCCESS); + + uint8_t data[16]; + uint8_t input[4 * 4 * 4]; + + astcenc_image image; + image.dim_x = 4; + image.dim_y = 4; + image.dim_z = 1; + image.data_type = ASTCENC_TYPE_U8; + uint8_t* slices = input; + image.data = reinterpret_cast(&slices); + + // Compression should succeed without bad_alloc or ASAN failure + status = astcenc_compress_image(context, &image, &swizzle, data, sizeof(data), 0); + EXPECT_EQ(status, ASTCENC_SUCCESS); + + astcenc_context_free(context); +} /** @brief Input data buffer overrun tests. */ TEST(compress, data_buffer_exceeded) diff --git a/Source/astcenc_entry.cpp b/Source/astcenc_entry.cpp index 79c65a0c..3e7dddf1 100644 --- a/Source/astcenc_entry.cpp +++ b/Source/astcenc_entry.cpp @@ -464,6 +464,9 @@ static astcenc_error validate_config( config.rgbm_m_scale = astc::max(config.rgbm_m_scale, 1.0f); + // Clamp alpha-scale kernel radius to put an upper bound on memory use + config.a_scale_radius = astc::min(config.a_scale_radius, ALPHASCALE_MAX_RADIUS); + config.tune_partition_count_limit = astc::clamp(config.tune_partition_count_limit, 1u, 4u); config.tune_2partition_index_limit = astc::clamp(config.tune_2partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS); config.tune_3partition_index_limit = astc::clamp(config.tune_3partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS); diff --git a/Source/astcenc_internal.h b/Source/astcenc_internal.h index 46942171..ea3c1a42 100644 --- a/Source/astcenc_internal.h +++ b/Source/astcenc_internal.h @@ -120,6 +120,9 @@ static constexpr unsigned int WEIGHTS_MAX_DECIMATION_MODES { 87 }; /** @brief The high default error used to initialize error trackers. */ static constexpr float ERROR_CALC_DEFAULT { 1e30f }; +/** @brief The maximum alpha-scale kernel radius. */ +static constexpr unsigned int ALPHASCALE_MAX_RADIUS { 64 }; + /** * @brief The minimum tuning setting threshold for the one partition fast path. */