Czy funkcja zwracająca wartość musi ją przypisać do zmiennej?

1

Mam taki czeski błąd w programie, który przechodzi przez kompilator adruino, a wywalał się dopiero na etapie platformy esp32.

Otóż dziwnym zbiegiem okoliczności kiedy w programie użyłem takiej konstrukcji funkcji:

String blabla(){

Serial.println("blabla..");

return "ok";
}
  
 blabla();

otrzymywałem błąd i urządzenie robiło restart.

guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x4012b31e  PS      : 0x00060433  A0      : 0x8012b450  A1      : 0x3ffb1e10  
A2      : 0x00be7372  A3      : 0x00000003  A4      : 0x3ffbbd0c  A5      : 0x00000003  
A6      : 0x3ffbbcbc  A7      : 0x00000000  A8      : 0x00be7372  A9      : 0x3ffb1de0  
A10     : 0x00000001  A11     : 0x3ffb8058  A12     : 0x00000001  A13     : 0x00000001  
A14     : 0x00060420  A15     : 0x00000000  SAR     : 0x00000018  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00be7372  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  

Długo szukałem zanim przypadkiem odkryłem o co chodzi. Stwierdziłem, że w zasadzie skoro ta funkcja coś zwraca to powinienem swoją drogą przypisać wynik to jakieś zmiennej.
Wystarczyło dopisać kod w następujący sposób i procesor się już nie zawieszał.

String blavalue = blabla();

Ktoś mi to wyjaśni? Czy nie przypisując wyniku popełniłem błąd?

Cały kod wygląda tak:

#include <WiFi.h>
#include <WiFiClient.h>
#include <ESP32WebServer.h>
#include <ESPmDNS.h>



#define SDA1 23
#define SCL1 22
#include <Wire.h>
#include <I2C_EEPROM.h>
AT24C32<0x57> eep; // Das EEProm auf der china üblichen RTC3231 



const char *ssid = "smartyAPek";
const char *password = "sdfasdfsdf";


ESP32WebServer server(80);  


int app = 0; 
String wynik;

struct MySetingsTab {
  char struct_start[10];
  char wifi_ssid[64]; 
  char wifi_password[64];
  int svrport; 
  int dhcp;
  int ip_0;
  int ip_1;
  int ip_2;
  int ip_3;
  int nm_0;
  int nm_1;
  int nm_2;
  int nm_3;
  int gw_0;
  int gw_1;
  int gw_2;
  int gw_3;
  int dns_p0;
  int dns_p1;
  int dns_p2;
  int dns_p3;
  int dns_s0;
  int dns_s1;
  int dns_s2;
  int dns_s3;
  char  system_login[64];
  char  system_password[64];
  // setings  for sleep mode option - work if this option is active
  int  active_time;
  int  sleep_time;
  // setings for remote raporting sensor values
  int  remote_raporting;
  int  frequency_sec;
  char remote_url[64];

  
  char struct_end[10];
  
} mysetingstab, setingsfromdb;




//test funkcji string
String blabla(){

Serial.println("blabla..");

return "ok";
}
  



void handleRoot() {
  
  server.send(200, "text/plain", "hello from ESP32!");
  
}



void handleNotFound(){
 
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);

}

String WifiClientMode(char wfssid[], char wfpassword[]) {

    
     Serial.println("try connect to wifi network");
     Serial.print("wifi network ssid: ");
     Serial.print("'");
     Serial.print(wfssid);
     Serial.println("'");
     Serial.print("wifi network  pass: ");
     Serial.print("'");
     Serial.print(wfpassword);
     Serial.println("'");
     WiFi.begin( wfssid, wfpassword);

     // Wait for connection
     int wait_time = 0;
     while (WiFi.status() != WL_CONNECTED) {
       
        delay(500);
        Serial.print(".");
 
     }
     
     Serial.println("");
     Serial.print("Connected to ");
     Serial.println( wfssid);
     Serial.println( wfpassword);
     Serial.print("IP address: ");
     Serial.println(WiFi.localIP());
     delay(10000);
     Serial.println("end wifi procedure starting");
}


void setup(void){

  Serial.begin(9600);
  delay(1000);
  
  Serial.println("esp starts ");
  delay(1000);
  Serial.println("wire begin");

// wire begin mode sda pin / scl pin // speed
  Wire.begin(SDA1,SCL1,100000); // piny dla esp32
  
  delay(2000);

  Serial.println("check db ");
  //GetSetingsfromdb();

   if(eep.ready()){
    Serial.println("Epprom ready...");
   }

  delay(2000);

 String blavalue = blabla();
   //  Serial.println(dupa);


  strcpy(mysetingstab.wifi_ssid ,"privnet"); 
  strcpy(mysetingstab.wifi_password ,"987sdfsd");
    

      
 if (strcmp(mysetingstab.wifi_ssid, ssid) != 0) {
    Serial.println("Try run Network run in WIFI_CLIENT_STA mode: ");
    WifiClientMode(mysetingstab.wifi_ssid, mysetingstab.wifi_password);
    Serial.println("Network run in WIFI_CLIENT_STA mode: ");
    //WiFi.printDiag(Serial);
    delay(5000);
 }



      if (MDNS.begin("esp32")) {
      Serial.println("MDNS responder started");
      }


 

        server.on("/", handleRoot);
      
        server.on("/inline", [](){
          server.send(200, "text/plain", "this works as well");
        });
      
        server.onNotFound(handleNotFound);


      
      server.begin();

     
      Serial.println("HTTP server started");

  

}


void loop(void){
  server.handleClient();
}
1

Albo gdzieś masz szalone UB, albo kompilujesz jakąś zbugowaną wersją kompilatora.

0

Dokleiłem cały kod zerknij. biblioteki dopiero ściągnąłem z GITHUB.

0

Nic oczywistego mi się nie rzuca w oczy. Klasa String jest twoja, czy z frameworka?

0

Jest wbudowana w Arduino. Co dziwne jak wyłączę poniższy fragment odwołujący się do pomięci eeprom

 if(eep.ready()){
    Serial.println("Epprom ready...");
   }

to błąd również znika. Tak jakby coś gdzieś się gryzło.

Kod mam znacznie bardziej rozbudowany. Starałem się metodą prób i błędów usuwać kolejne fragmenty, które mogą tu coś kolidować do chodząc do tego etapu. Dane ze struktury eeprom normalnie odczytuję i łączę się z wifi. Dopiero na etapie startu tego serwera www wszystko pada.

0

Szczerze mówiąc, strzelałbym, że tu masz tylko objaw problemu, a faktyczny problem - np. jakiś heap corruption czy stack smashing - jest gdzieś indziej. Czy możesz to jakoś sensownie emulować na kompie, żeby przepuścić pod valgrindem albo address sanitizerem?

1

Funkcje C++ zwracając wartość de facto wpisują go do rejestru RAX/EAX, więc jeśli rejestr ów jest używany w adruino to może powodować problemy - acz byłoby to w Peruna dziwne.

1

To mi raczej wygląda na niezresocjalizowany wskaźnik.

EXCCAUSE: 0x0000001c

https://links2004.github.io/Arduino/dc/deb/md_esp8266_doc_exception_causes.html

EXC-CAUSE Code Cause Name Cause Description Required Option EXC-VADDR Loaded
28 LoadProhibitedCause A load referenced a page mapped with an attribute that does not permit loads Region Protection or MMU Yes

Czyli odczyt strony, której nie da się odczytać.

Zacząłbym od ustalenia jaki kod jest pod adresem: PC : 0x4012b31e (powinieneś mieć plik z symbolami, żeby zdekodować ten adres na linię kodu).
Nie wiem, czy na tym sprzęcie crash log wypisuje call stack (raczej powinien), warto go zdekodować.

Wygooglałem coś takiego: https://esp32.com/viewtopic.php?t=5579, nie czytałem, ale widzę słowa kluczowe, które powinny pomóc, szczególnie ta linia powinna być pomocna w dekodowaniu call stack:

xtensa-esp32-elf-addr2line -pfiaC -e build/<MYAPP>.elf 0x<ADDRESS>


<hr>
Znalazłem jeszcze coś takiego: [instrukcja krok po kroku jak analizować crash log na Arduino](https://arduino-esp8266.readthedocs.io/en/latest/faq/a02-my-esp-crashes.html).
To powinno ci pomóc ustalić co jest nie tak.
0

Zainstalowałem sobie Exception Decoder:

taki wynik:

PC: 0x40130e22: find_key at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/pthread/pthread_local_storage.c line 83
EXCVADDR: 0x8ffa0771

Decoding stack results
0x40130e22: find_key at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/pthread/pthread_local_storage.c line 83
0x40130f51: pthread_setspecific at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/pthread/pthread_local_storage.c line 215
0x40111e2d: sys_thread_sem_init at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/lwip/port/esp32/freertos/sys_arch.c line 548
0x40111e43: sys_thread_sem_get at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/lwip/port/esp32/freertos/sys_arch.c line 511
0x400ffdf1: tcpip_api_call at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/lwip/lwip/src/api/tcpip.c line 423
0x400e4e7f: _mdns_pcb_init at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/mdns/mdns_networking.c line 271
0x400e4133: _mdns_enable_pcb at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/mdns/mdns.c line 2947
0x400e4735: mdns_init at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/mdns/mdns.c line 4027
0x400d8d53: MDNSResponder::begin(char const*) at C:\Users\dom\Documents\Arduino\hardware\espressif\esp32\libraries\ESPmDNS\src\ESPmDNS.cpp line 56
0x400d3a31: setup() at C:\Users\dom\Documents\Arduino\web_serwer_auth_v4_test_esp32/web_serwer_auth_v4_test_esp32.ino line 556
0x40132177: loopTask(void*) at C:\Users\dom\Documents\Arduino\hardware\espressif\esp32\cores\esp32\main.cpp line 15
0x4008c23d: vPortTaskWrapper at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/port.c line 141
0

Zgłosiłem błąd na grupie dyskusyjnej projektu arduino dla Esp32. Jedank tam starsi koledzy wylali na mój kod kubeł zimnej wody wskazując np. że korzystanie z typów zmiennych jako String jest ryzkowne z uwagi na to, że mamy do czynienia z dynamicznym alokowaniem pamięci, ktorej i tak jest bardzo mało. Każda taka zmienna lub typ fukcji wymusza podział pamięc w stosie i przez co program staje się mało stabilny.

No i szeczerze mówiąc nie bardzo mi się taka interpretacja problemu podoba, aczkolwiek poniekąt wydaje się być przekonywująca. Z drugiej steony ten sam kod działa bez problemu na esp8266. Problemy są tylko z Esp32.

https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/

Kolejną wskazówką, było stwierdzenie żeby nie używać lambda for callback oraz stosować IRAM_ATTR.

I tej wskazówki nie do końca rozumiem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1