Updater::begin picks the 4 KB buffer by total free heap, and does not fall back to 256 B when the allocation fails
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 76/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- cpp
- 領域
- embedded-iot
調査の方向性
cores/esp8266/Updater.cppのUpdaterClass::begin()と_writeBuffer()の周辺を読み、次にUpdater.hのストリームテンプレートを確認して、バッファサイズの使われ方を把握してください。4 KBの割り当てに失敗したときにより小さいバッファを選択でき、256バイトの書き込みでもセクター消去が引き続き機能することを確認してください。begin()が断片化したヒープでより小さいバッファにフォールバックでき、更新動作を変えないことが完了の条件です。
索引モデルが issue の本文から書いたものです。
説明
What happens
UpdaterClass::begin() chooses its write buffer size from the total free heap:
// cores/esp8266/Updater.cpp, 3.1.2 lines 172-181 (same on master, lines 174-183)
if (ESP.getFreeHeap() > 2 * FLASH_SECTOR_SIZE) {
_bufferSize = FLASH_SECTOR_SIZE;
} else {
_bufferSize = 256;
}
_buffer = new (std::nothrow) uint8_t[_bufferSize];
if (!_buffer) {
_setError(UPDATE_ERROR_OOM);
_reset(false);
return false;
}
Total free heap says nothing about the largest free block. On a fragmented heap the check can pass while a 4096 byte block does not exist. Then new fails and begin() returns false with UPDATE_ERROR_OOM. The 256 byte buffer is never tried.
What I measured
- Core 3.1.2, ESP8266 (GeekMagic SmallTV-Ultra).
ESP.getFreeHeap()= 19.6 KB.ESP.getMaxFreeBlockSize()= 3,888 bytes.
What I did not measure
I did not run the upload in this state. I restarted the device first. That the upload would be refused with UPDATE_ERROR_OOM comes from reading the code above. 19.6 KB is more than 8192, so the 4 KB branch is taken. A 4096 byte allocation cannot fit in a 3,888 byte block.
Why a smaller buffer should be safe
_bufferSize is private and is only used inside Updater.cpp and the Updater.h stream template. The 256 byte case already exists for low free heap (commit 01e1c586, "Updater: if low on heap memory, use smaller write buffer"). _writeBuffer() erases a sector when _currentAddress % FLASH_SECTOR_SIZE == 0, which still works with 256 byte writes.
Proposed small change (sketch, untested)
- if (ESP.getFreeHeap() > 2 * FLASH_SECTOR_SIZE) {
+ if (ESP.getMaxFreeBlockSize() >= 2 * FLASH_SECTOR_SIZE) {
_bufferSize = FLASH_SECTOR_SIZE;
} else {
_bufferSize = 256;
}
_buffer = new (std::nothrow) uint8_t[_bufferSize];
+ if (!_buffer && _bufferSize > 256) {
+ _bufferSize = 256;
+ _buffer = new (std::nothrow) uint8_t[_bufferSize];
+ }
if (!_buffer) {
The first part picks by largest block. The second part is a safety net if the allocation still fails. Either part alone would already fix the case above. I can prepare a PR if this direction is fine.
- 主要言語
- C++
- スター
- 16.7k
- フォーク
- 13k
- 平均マージ
- 1日 2時間
- マージ済み PR(30日)
- 7
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
esp8266/Arduino のほかの issue
-
Typo in Scan Class Documentation対応中かも @MukundaKatta が 207 日前に担当しました。 オープン
難易度 1/5 1時間未満 初心者へのやさしさ 70/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
esp8266/Arduino#9203 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 52/100
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 65/100
esp8266/Arduino#9324 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 42/100
メンテナーはふだん 1 日以内に返信
esp8266/Arduino の issue をすべて見る
似ている issue
-
status:needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
PX4/PX4-Autopilot#29698 ·
メンテナーはふだん 1 日以内に返信
-
go perft exits when EvalFile is unavailable対応中かも @Muawiya-contact が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
official-stockfish/Stockfish#7292 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
arvidn/libtorrent#9149 ·
メンテナーはふだん 1 日以内に返信
-
Upstream report: MSVC rejects a designated initializer in a dependent template argument (C2131)オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
rhalbersma/tabula#72 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信