homie-esp8266 icon indicating copy to clipboard operation
homie-esp8266 copied to clipboard

Homie.cpp setup() fails with pagefault in line 108

Open msandres13 opened this issue 6 years ago • 7 comments

HomieBootMode _nextHomieBootMode = Interface::get().getConfig().getHomieBootModeOnNextBoot();

getConfig return nullptr so next call to getHomieBootModeOnNextBoot() pagefaults.

I am compiling with Sloeber, anyways I am using the Example code or Homie.

I am assuming the is a problem with unitialized valiables which can work on some IDE and other not. I am using develop branch of Homie. I will try a tagged branch to see if problem is gone. Anyways I though I report this.

msandres13 avatar Nov 02 '19 17:11 msandres13

Looks like it has something to do with the missing SPIFFS in sloeber. Still trying to understand why Homie dies with a pagefault instead clean error message.

msandres13 avatar Nov 02 '19 18:11 msandres13

Hmm, the toolchain should be the same, regardless of the IDE... Or shouldn't it? Could you post the stacktrace? https://github.com/me-no-dev/EspExceptionDecoder

MajorTwip avatar Nov 02 '19 18:11 MajorTwip

Struggeling with Code setup. In Sloeber I think this Decoder is not supported. Still trying...

msandres13 avatar Nov 02 '19 18:11 msandres13

Looked at the problem again in Sloeber with serial line debug.

// boot mode set before resetting the device. If application has defined a boot mode, this will be ignored
 HomieBootMode _nextHomieBootMode = Interface::get().getConfig().getHomieBootModeOnNextBoot();

Added the following Config& getConfig() { if(_config==nullptr) { Serial.println("Config is NULL"); }; return *_config; }

And see this Compiled at Sat Nov 2 17:29:36 2019 Setup start Set Firmware Set advertise Homie setup HomieClass::setup() 1 HomieClass::setup() 2 HomieClass::setup() 2.1 Config is NULL HomieBootMode Config::getHomieBootModeOnNextBoot() 1

Produced by this: HomieBootMode Config::getHomieBootModeOnNextBoot() { Serial.println("HomieBootMode Config::getHomieBootModeOnNextBoot() 1"); if (!_spiffsBegin()) { return HomieBootMode::UNDEFINED; } Serial.println("HomieBootMode Config::getHomieBootModeOnNextBoot() 2");

Failing here: bool Config::_spiffsBegin() { Serial.print("bool Config::_spiffsBegin()"); Serial.print(_spiffsBegan); Serial.println(" is true or false"); Serial.flush(); delay(100); if (!_spiffsBegan) { Serial.println("bool Config::_spiffsBegin() 1"); Serial.flush(); delay(100);

This tells me that the object Config it self is NULL and basicaly mapped to addr 0x0 and finaly access its member _spiffsBegan causes a fail since I guess there is no memory.

Complete output:

`
SDK:2.2.1(cfd48f3)/Core:2.5.2=20502000/lwIP:STABLE-2_1_2_RELEASE/glue:1.1-7-g82abda3/BearSSL:a143020
Compiled at Sat Nov  2 17:29:36 2019
Setup start
Set Firmware
Set advertise
Homie setup
HomieClass::setup() 1
HomieClass::setup() 2
HomieClass::setup() 2.1
Config is NULL
HomieBootMode Config::getHomieBootModeOnNextBoot() 1
bool Config::_spiffsBegin()Fatal exception 28(LoadProhibitedCause):
epc1=0x4020865b, epc2=0x00000000, epc3=0x00000000, excvaddr=0x000002a8, depc=0x00000000

Exception (28):
epc1=0x4020865b epc2=0x00000000 epc3=0x00000000 excvaddr=0x000002a8 depc=0x00000000

>>>stack>>>

ctx: cont
sp: 3fff18a0 end: 3fff1b00 offset: 01a0
3fff1a40:  00000001 00000000 3fff09c8 40208cdf  
3fff1a50:  3ffe86ee 00000000 3fff09c8 4021d7bc  
3fff1a60:  3ffe8c88 00000000 3fff09c8 4021d808  
3fff1a70:  3fffdad0 3fff09c8 3fff0128 4020b105  
3fff1a80:  3fffdad0 3fff09c8 3fff0188 4020b43e  
3fff1a90:  3ffe8f9a 00000001 3fff09c8 4021d5a1  
3fff1aa0:  00000000 432f2933 3fff09c8 4021d7bc  
3fff1ab0:  40201070 00000000 3fff09c8 3fff1b38  
3fff1ac0:  3fffdad0 3fff0188 3fff09c8 402011b8  
3fff1ad0:  40201070 feefeffe 40226ec0 40226ea8  
3fff1ae0:  feefeffe 00000000 3fff1b08 4021fb38  
3fff1af0:  feefeffe feefeffe 3ffe859c 40100741  
<<<stack<<<
`

So the fault is just a symptom, For some reason the _config variable in Interface.hpp is never initialized after it got set to nullptr in the constructor.

Any idea how it normally gets initalized? The code is written like it NEVER can be NULL.

Thanks for all your help.
Michael

msandres13 avatar Nov 02 '19 19:11 msandres13

https://github.com/homieiot/homie-esp8266/pull/696 have a nice day.

WLimin avatar Dec 21 '20 22:12 WLimin

The order in which we expect to initialize global class instances is as follows:

  1. InterfaceData Interface::_ interface; ---it's in the Interface.cpp: _config=nullptr
  2. HomieClass Homie; ---in the Homie.cpp, constructor: Interface::get()._ config = &_ config;

So, on line 113 of Homie.cpp: HomieBootMode _ nextHomieBootMode = Interface::get().getConfig().getHomieBootModeOnNextBoot(); The 'Interface:: get().getConfig()' gets the correct address of member variable Homie._config.

However, according to the C++ standard, the initialization order of global class instances in different files is random. If Homie is earlier than 'Interface::_interface' initialization, the value of 'InterfaceData._config'(in Interface::_interface) will be overrode by 'nullptr', and 'Interface:: get().getConfig()==nullptr' is always true, so esp8266 will crash on line 113.

The LINK order is different between Sloeber and Arduino IDE, which results in different order of initialization variables.

Solution 1 Move the 'InterfaceData Interface::_interface;" line from Interface.cpp to Homie.cpp before "Homieclass homie;" line. Not tested. Solution 2 using the variable in function

WLimin avatar Dec 23 '20 03:12 WLimin

@WLimin Thanks for the explanation. This is beyond my C++ knowledge, so I asked for reviews. Could you please fix the compile and lint failures? I see no chance of merging your PR if the CI build fails.

luebbe avatar Dec 23 '20 08:12 luebbe