Commit 18cb9b53f5 for aom
commit 18cb9b53f59290810828a72d89730d932cc301bc
Author: Cheng Chen <chengchen@google.com>
Date: Mon Sep 28 16:08:46 2026 -0700
Correctly allocate restoration buffer size
Adjust the condition when to allocate the restoration buffer size,
such that is could reallocate when the frame size is changed.
Bug:565488030
Change-Id: I319cb6e8bf8a285c349a431c4caa4f38e35305b5
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 9b73008698..5cc887bee5 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1036,6 +1036,8 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf,
}
}
+ cm->tiles.large_scale = oxcf->tile_cfg.enable_large_scale_tile;
+ cm->tiles.single_tile_decoding = oxcf->tile_cfg.enable_single_tile_decoding;
features->interp_filter =
oxcf->tile_cfg.enable_large_scale_tile ? EIGHTTAP_REGULAR : SWITCHABLE;
features->switchable_motion_mode = is_switchable_motion_mode_allowed(
@@ -1053,6 +1055,8 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf,
int last_height = cm->height;
cm->width = frm_dim_cfg->width;
cm->height = frm_dim_cfg->height;
+ cm->superres_upscaled_width = frm_dim_cfg->width;
+ cm->superres_upscaled_height = frm_dim_cfg->height;
if (cm->width > cpi->data_alloc_width ||
cm->height > cpi->data_alloc_height || is_sb_size_changed) {
@@ -2720,7 +2724,7 @@ void av1_set_frame_size(AV1_COMP *cpi, int width, int height) {
if (!is_stat_generation_stage(cpi)) av1_init_cdef_worker(cpi);
#if !CONFIG_REALTIME_ONLY
- if (is_restoration_used(cm)) {
+ if (cm->seq_params->enable_restoration) {
for (int i = 0; i < num_planes; ++i)
cm->rst_info[i].frame_restoration_type = RESTORE_NONE;
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index 581294c01c..dcbc744cb8 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -912,7 +912,7 @@ void av1_init_mt_sync(AV1_COMP *cpi, int is_first_pass) {
}
#if !CONFIG_REALTIME_ONLY
- if (is_restoration_used(cm)) {
+ if (cm->seq_params->enable_restoration) {
// Initialize loop restoration MT object.
AV1LrSync *lr_sync = &mt_info->lr_row_sync;
int rst_unit_size = cpi->sf.lpf_sf.min_lr_unit_size;
@@ -1333,7 +1333,7 @@ static inline void prepare_fpmt_workers(AV1_PRIMARY *ppi,
mt_info->cdef_worker->colbuf[plane];
}
#if !CONFIG_REALTIME_ONLY
- if (is_restoration_used(cm)) {
+ if (cm->seq_params->enable_restoration) {
// Back up the original LR buffers before update.
int idx = i + mt_info->num_workers - 1;
assert(idx < mt_info->lr_row_sync.num_workers);
@@ -1407,7 +1407,7 @@ static inline void restore_workers_after_fpmt(AV1_PRIMARY *ppi,
mt_info->restore_state_buf.cdef_colbuf[plane];
}
#if !CONFIG_REALTIME_ONLY
- if (is_restoration_used(cm)) {
+ if (cm->seq_params->enable_restoration) {
// Restore the original LR buffers.
int idx = i + mt_info->num_workers - 1;
assert(idx < mt_info->lr_row_sync.num_workers);
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index 7ac5498719..387e753fb6 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -3292,6 +3292,79 @@ TEST(EncodeAPI, Buganizer558417547) {
aom_free(cpi_test->mb_weber_stats);
#endif // !CONFIG_SHARED
}
+
+// Regression test for b/565488030: Heap-buffer-overflow in
+// save_deblock_boundary_lines when Frame 0 is coded losslessly (q = 0, setting
+// cm->features.all_lossless = 1) or with large_scale_tile = 1 at a small
+// resolution and Frame 1 increases the resolution via
+// aom_codec_enc_config_set() with large_scale_tile = 0 and lossy coding (q > 0,
+// cm->features.all_lossless = 0) with loop restoration enabled.
+TEST(EncodeAPI, Buganizer565488030) {
+ for (unsigned int threads : { 1u, 4u }) {
+ for (unsigned int large_scale_tile : { 0u, 1u }) {
+ aom_codec_iface_t *const iface = aom_codec_av1_cx();
+ aom_codec_enc_cfg_t cfg;
+ ASSERT_EQ(
+ aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY),
+ AOM_CODEC_OK);
+
+ cfg.g_w = 4;
+ cfg.g_h = 4;
+ cfg.g_forced_max_frame_width = 256;
+ cfg.g_forced_max_frame_height = 256;
+ cfg.g_threads = threads;
+ cfg.g_lag_in_frames = 0;
+ cfg.large_scale_tile = large_scale_tile;
+ cfg.rc_end_usage = AOM_CBR;
+ cfg.rc_target_bitrate = 3999;
+ cfg.rc_min_quantizer = 0;
+ cfg.rc_max_quantizer = 63;
+
+ aom_codec_ctx_t enc;
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 4), AOM_CODEC_OK);
+ // large_scale_tile = 1 implicitly disables global motion, so switching
+ // it to 0 below would turn global motion on mid-stream. The reference
+ // frames coded before that have no image pyramid, which trips
+ // assert(buf->buf.y_pyramid) in av1_encode_frame(). That is a separate
+ // issue, so keep global motion off to focus on loop restoration.
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_GLOBAL_MOTION, 0),
+ AOM_CODEC_OK);
+
+ aom_image_t *img_small =
+ aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 4, 4, 16);
+ ASSERT_NE(img_small, nullptr);
+ FillImage(img_small, 128);
+
+ // Frame 0: 4x4 at high CBR bitrate picks q = 0 (all_lossless = 1).
+ EncodeOne(&enc, img_small, 0);
+ aom_img_free(img_small);
+
+ // Frame 1: Reconfigure to 256x256 with large_scale_tile = 0 (picks q > 0,
+ // all_lossless = 0).
+ cfg.g_w = 256;
+ cfg.g_h = 256;
+ cfg.large_scale_tile = 0;
+ ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK);
+
+ aom_image_t *img_large =
+ aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 256, 256, 16);
+ ASSERT_NE(img_large, nullptr);
+ FillImage(img_large, 128);
+
+ EncodeOne(&enc, img_large, 1);
+ aom_img_free(img_large);
+
+ // Flush encoder.
+ ASSERT_EQ(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK);
+ aom_codec_iter_t iter = nullptr;
+ while (aom_codec_get_cx_data(&enc, &iter) != nullptr) {
+ }
+
+ ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
+ }
+ }
+}
#endif // !CONFIG_REALTIME_ONLY
} // namespace