|
2 | 2 |
|
3 | 3 | - Priority: High |
4 | 4 | - Created: 2026-07-14 |
5 | | -- Completed: {YYYY-MM-DD} |
| 5 | +- Completed: 2026-07-27 |
6 | 6 | - Model: DeepSeek V4 Pro |
7 | 7 | - Branch: feature/fix-base-renderer-buffer-overflow-on-resize |
8 | 8 | - Polished: 2026-07-27 |
@@ -136,54 +136,19 @@ sumomo をローカルの SDK 実装と紐付けてデスクトップ向けに |
136 | 136 |
|
137 | 137 | ## 解決方法 |
138 | 138 |
|
139 | | -`BaseRenderer::RenderThread()` を次の順序へ変更する。 |
140 | | -`<vector>` と `<cstring>` は既に利用可能なため、追加の依存は不要である。 |
141 | | -以下は描画用バッファに関係する変更箇所だけを示し、フレームレート制御は省略する。 |
| 139 | +`BaseRenderer::RenderThread()` の描画用バッファを `std::vector<uint8_t>` に変更し、各描画イテレーションで現在のキャンバス寸法に合わせて `resize()` するようにした。 |
142 | 140 |
|
143 | | -```cpp |
144 | | -std::vector<uint8_t> image; |
| 141 | +キャンバス寸法のスナップショット、描画用バッファのサイズ変更とクリア、各 Sink の合成を同じ `sinks_lock_` の保持中に実行する。 |
| 142 | +これにより、`SetSize()` と描画処理が並行しても、バッファサイズ、Y offset、stride、Sink の outline が同じキャンバス寸法に基づくようにした。 |
| 143 | +`Render()` は従来どおりロック外で呼び出し、スナップショットした寸法と `resize()` 後のバッファを渡す。 |
145 | 144 |
|
146 | | -while (running_) { |
147 | | - std::vector<SinkInfo> sink_infos; |
148 | | - int canvas_width = 0; |
149 | | - int canvas_height = 0; |
150 | | - |
151 | | - { |
152 | | - webrtc::MutexLock lock(&sinks_lock_); |
153 | | - canvas_width = width_; |
154 | | - canvas_height = height_; |
155 | | - image.resize(static_cast<size_t>(canvas_width) * |
156 | | - static_cast<size_t>(canvas_height) * 4); |
157 | | - memset(image.data(), 0, image.size()); |
158 | | - |
159 | | - for (const VideoTrackSinkVector::value_type& sinks : sinks_) { |
160 | | - Sink* sink = sinks.second.get(); |
161 | | - webrtc::MutexLock frame_lock(sink->GetMutex()); |
162 | | - if (sink->GetOutlineChanged()) { |
163 | | - continue; |
164 | | - } |
165 | | - |
166 | | - int width = sink->GetFrameWidth(); |
167 | | - int height = sink->GetFrameHeight(); |
168 | | - if (width == 0 || height == 0) { |
169 | | - continue; |
170 | | - } |
171 | | - |
172 | | - libyuv::ARGBCopy(sink->GetImage(), width * 4, |
173 | | - image.data() + sink->GetOffsetX() * 4 + |
174 | | - sink->GetOffsetY() * canvas_width * 4, |
175 | | - canvas_width * 4, width, height); |
176 | | - |
177 | | - // SinkInfo の構築は現行どおり |
178 | | - } |
179 | | - } |
180 | | - |
181 | | - Render(image.data(), canvas_width, canvas_height, sink_infos); |
182 | | -} |
183 | | -``` |
| 145 | +SDL、ANSI、Sixel の各レンダラーが `Render()` の呼び出し中に画像を同期的に消費し、返却後にポインタを保持しないことも確認した。 |
184 | 146 |
|
185 | | -### 注意点 |
| 147 | +次の検証を実施した。 |
186 | 148 |
|
187 | | -- `resize()` より前に取得した `data()` は再確保によって無効になりうるため、必ず `resize()` の後で `image.data()` を使う |
188 | | -- Sink ごとの `image_` は `Sink::OnFrame()` 内で outline または入力解像度が変わったときに再確保されるため、本修正の対象外とする |
189 | | -- ロック順序は現行どおり `sinks_lock_` から Sink の mutex の順とし、逆順の取得を追加しない |
| 149 | +- SDK のテストを含む macOS ARM64 ビルド |
| 150 | +- ローカル SDK を使用した sumomo の macOS ARM64 ビルド |
| 151 | +- `test_sumomo_sendonly_recvonly[VP8]` の E2E |
| 152 | +- AddressSanitizer を有効にした SDK と sumomo のクリーンビルド |
| 153 | +- F キー処理と同じ SDL フルスクリーン切替を 3 往復、ウィンドウ拡大、`--fullscreen` 起動 |
| 154 | +- 各リサイズ後にクラッシュと `heap-buffer-overflow` が発生せず、fake 映像の描画が継続すること |
0 commit comments