Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uploading multiple files raises HEAP and AsyncTCP errors #1381

Open
tobiasfaust opened this issue Feb 22, 2024 · 4 comments
Open

uploading multiple files raises HEAP and AsyncTCP errors #1381

tobiasfaust opened this issue Feb 22, 2024 · 4 comments

Comments

@tobiasfaust
Copy link

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\toolchain-xtensa-esp32@8.4.0+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\toolchain-xtensa-esp32@8.4.0+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?

@Belleson
Copy link

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.

@tobiasfaust
Copy link
Author

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…..

@Belleson
Copy link

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.

@tobiasfaust
Copy link
Author

tobiasfaust commented Apr 20, 2024

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));
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants