uploading multiple files raises HEAP and AsyncTCP errors
Hi, I'm using a simple fileupload to littleFS partition.
input type="file" name='filesystem' webkitdirectory mozdirectory
server->on("/doUpload", HTTP_POST, [](AsyncWebServerRequest *request) {},
std::bind(&handleFiles::handleUpload, this, std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4,
std::placeholders::_5,
std::placeholders::_6));
void handleFiles::handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
AsyncResponseStream *response = request->beginResponseStream("text/json");
response->addHeader("Server","ESP Async Web Server");
rtc_wdt_feed();
String logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url();
Serial.println(logmessage);
if (!index) {
// open the file on first call and store the file handle in the request object
request->_tempFile = LittleFS.open("/" + filename, "w");
Serial.printf("Upload Start: %s\n", filename.c_str());
}
if (len) {
// stream the incoming chunk to the opened file
request->_tempFile.write(data, len);
rtc_wdt_feed();
Serial.printf("Writing file: %s ,index=%d len=%d bytes\n", filename.c_str(), index, len);
}
if (final) {
// close the file handle as the upload is now done
request->_tempFile.close();
Serial.printf("Upload Complete: %s ,size: %d Bytes\n", filename.c_str(), (index + len));
}
}
With only one file it works perfectly, but if i want to upload multiple files by selectiong a directory, the esp crashes after uploadfing 1-2 files
Upload Complete: /regs/Deye_SUN_SG04LP3.json ,size: 41580 Bytes
Upload Complete: /regs/Growatt-SPH.json ,size: 6992 Bytes
CORRUPT HEAP: Bad tail at 0x3ffd1602. Expected 0xbaad5678 got 0xbaad0000
assert failed: multi_heap_free multi_heap_poisoning.c:253 (head != NULL)
Backtrace:0x40083735:0x3ffdc4a00x4008d0c1:0x3ffdc4c0 0x400924c9:0x3ffdc4e0 0x4009210f:0x3ffdc610 0x40083bc9:0x3ffdc630 0x400924f9:0x3ffdc650 0x40188eaa:0x3ffdc670 0x400ea561:0x3ffdc690 0x400ecf86:0x3ffdc6c0 0x400ef3f1:0x3ffdc6e0 0x400ea763:0x3ffdc700 0x400ea771:0x3ffdc720 0x400e9aba:0x3ffdc740 0x400e9cc9:0x3ffdc770 0x400e9f7b:0x3ffdc7a0
#0 0x40083735:0x3ffdc4a0 in panic_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/panic.c:402
#1 0x4008d0c1:0x3ffdc4c0 in esp_system_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:128
#2 0x400924c9:0x3ffdc4e0 in __assert_func at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/assert.c:85
#3 0x4009210f:0x3ffdc610 in multi_heap_free at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/multi_heap_poisoning.c:253
(inlined by) multi_heap_free at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/multi_heap_poisoning.c:245
#4 0x40083bc9:0x3ffdc630 in heap_caps_free at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_caps.c:340
#5 0x400924f9:0x3ffdc650 in free at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/heap.c:39
#6 0x40188eaa:0x3ffdc670 in VFSFileImpl::close() at C:/Users/Tobias/.platformio/packages/framework-arduinoespressif32/libraries/FS/src/vfs_api.cpp:333
#7 0x400ea561:0x3ffdc690 in fs::File::close() at C:/Users/Tobias/.platformio/packages/framework-arduinoespressif32/libraries/FS/src/FS.cpp:145
#8 0x400ecf86:0x3ffdc6c0 in AsyncWebServerRequest::~AsyncWebServerRequest() at .pio/libdeps/firmware_ESP32/ESP Async WebServer/src/WebRequest.cpp:97
#9 0x400ef3f1:0x3ffdc6e0 in AsyncWebServer::_handleDisconnect(AsyncWebServerRequest*) at .pio/libdeps/firmware_ESP32/ESP Async WebServer/src/WebServer.cpp:102 (discriminator 1)
#10 0x400ea763:0x3ffdc700 in AsyncWebServerRequest::_onDisconnect() at .pio/libdeps/firmware_ESP32/ESP Async WebServer/src/WebRequest.cpp:229
#11 0x400ea771:0x3ffdc720 in std::_Function_handler::_M_invoke(std::_Any_data const&, void*&&, AsyncClient*&&) at .pio/libdeps/firmware_ESP32/ESP Async WebServer/src/WebRequest.cpp:74
(inlined by) _M_invoke at c:\users\tobias\.platformio\packages\[email protected]+2021r2-patch3\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h:297
#12 0x400e9aba:0x3ffdc740 in std::function::operator()(void*, AsyncClient*) const at c:\users\tobias\.platformio\packages\[email protected]+2021r2-patch3\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h:687
#13 0x400e9cc9:0x3ffdc770 in AsyncClient::_error(signed char) at .pio/libdeps/firmware_ESP32/AsyncTCP/src/AsyncTCP.cpp:860
#14 0x400e9f7b:0x3ffdc7a0 in AsyncClient::_s_error(void*, signed char) at .pio/libdeps/firmware_ESP32/AsyncTCP/src/AsyncTCP.cpp:1207
(inlined by) _handle_async_event at .pio/libdeps/firmware_ESP32/AsyncTCP/src/AsyncTCP.cpp:171
(inlined by) _async_service_task at .pio/libdeps/firmware_ESP32/AsyncTCP/src/AsyncTCP.cpp:194
ELF file SHA256: 0000000000000000
Rebooting...
Upload Complete: /regs/Growatt-SPH.json ,size: 6992 Bytes
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x4011ff6c PS : 0x00060b30 A0 : 0x8011c01c A1 : 0x3ffb3950
A2 : 0x3ffd4be4 A3 : 0x00000018 A4 : 0x3ffd4bfc A5 : 0x3ffc452c
A6 : 0x3ffef474 A7 : 0x00000080 A8 : 0x00007174 A9 : 0x3f40712c
A10 : 0x00000001 A11 : 0x3ffd4be4 A12 : 0x3ffd4bfc A13 : 0x00000b38
A14 : 0x3ffdc670 A15 : 0x00000000 SAR : 0x00000009 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000085 LBEG : 0x4008950c LEND : 0x40089522 LCOUNT : 0xffffffff
Backtrace:0x4011ff69:0x3ffb39500x4011c019:0x3ffb3990 0x400e915a:0x3ffb39b0 0x40118d48:0x3ffb39d0
#0 0x4011ff69:0x3ffb3950 in tcp_output at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/lwip/lwip/src/core/tcp_out.c:1305 (discriminator 4)
#1 0x4011c019:0x3ffb3990 in tcp_recved at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/lwip/lwip/src/core/tcp.c:999
#2 0x400e915a:0x3ffb39b0 in _tcp_recved_api(tcpip_api_call_data*) at .pio/libdeps/firmware_ESP32/AsyncTCP/src/AsyncTCP.cpp:419 #3 0x40118d48:0x3ffb39d0 in tcpip_thread_handle_msg at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/lwip/lwip/src/api/tcpip.c:172
(inlined by) tcpip_thread at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/lwip/lwip/src/api/tcpip.c:154
ELF file SHA256: 0000000000000000
Rebooting...
@me-no-dev do you have any suggestions?
Maybe it's a watchdog time-out because server->on(...) wants a fast return. Make a separate thread to upload files, and trigger it from handleFiles::handleUpload, passing the parameters. For example, put request data in a struct and pass it (as reference) to a Ticker (separate library) callback.
Hi,
Thanks for your answer. Are you sure of a watchdog Issue? To prevent that I inserted the rtc_wdt_feed();
The HEAP Issue seems like a buffer overflow…..
Hi Tobias,
I agree it shows a heap error and I'm not sure it's a watchdog timer issue. I only know there are limits on how much can be done in a call back.
I make the suggestion because it solved a similar problem for my application. And it gives flexibility to process the uploads individually to reduce heap usage. Maybe also take a look at chunked response in the readme.
This great library has not been updated in a long time so you may have to find your own work around.
solved my myself ;)
i opened permanently AsyncResponseStream *response = request->beginResponseStream("text/json"); without using that. Solution is to move that code-fragment into final if-case.
That shows the problem, this call allocates memory without give free if it not used
final solution function:
void handleFiles::handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
String logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url();
Serial.println(logmessage);
if (!index) {
// open the file on first call and store the file handle in the request object
request->_tempFile = LittleFS.open("/" + filename, "w");
Serial.printf("Upload Start: %s\n", filename.c_str());
}
if (len) {
// stream the incoming chunk to the opened file
request->_tempFile.write(data, len);
rtc_wdt_feed();
Serial.printf("Writing file: %s ,index=%d len=%d bytes\n", filename.c_str(), index, len);
}
if (final) {
AsyncResponseStream *response = request->beginResponseStream("text/json");
response->addHeader("Server","ESP Async Web Server");
// close the file handle as the upload is now done
request->_tempFile.close();
Serial.printf("Upload Complete: %s ,size: %d Bytes\n", filename.c_str(), (index + len));
}
}