homie-esp8266
homie-esp8266 copied to clipboard
Homie.cpp setup() fails with pagefault in line 108
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.
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.
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
Struggeling with Code setup. In Sloeber I think this Decoder is not supported. Still trying...
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
https://github.com/homieiot/homie-esp8266/pull/696 have a nice day.
The order in which we expect to initialize global class instances is as follows:
- InterfaceData Interface::_ interface; ---it's in the Interface.cpp: _config=nullptr
- 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 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.