Updater::begin picks the 4 KB buffer by total free heap, and does not fall back to 256 B when the allocation fails

Ouverte Adaptée aux débutants
#9,342 2 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Personne n'a encore pris cette issue.

Évaluation

Difficulté
2/5
Temps estimé
1-3 heures
Accessibilité débutants
76/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
cpp
Domaine
embedded-iot

Piste de recherche

Lisez cores/esp8266/Updater.cpp autour de UpdaterClass::begin() et _writeBuffer(), puis vérifiez le modèle de flux de Updater.h pour comprendre comment la taille du tampon est utilisée. Vérifiez qu’un tampon plus petit peut être sélectionné lorsqu’une allocation de 4 Ko échoue et que l’effacement des secteurs fonctionne toujours avec des écritures de 256 octets. Le travail est terminé lorsque begin() peut se rabattre sur le tampon plus petit en cas de fragmentation du tas, sans modifier le comportement de la mise à jour.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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.

Langage dominant
C++
Étoiles
16.7k
Forks
13k
Merge moyen
1 j 2 h
PR mergées (30 j)
7

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de esp8266/Arduino

Toutes les issues de esp8266/Arduino

Issues similaires

Plus d'issues C++

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.