I hope this isn't an ESP8266 issue: I will post it there too just in case.
Symptom is that working code fails (panic + stack dump) if definition of static std::function is moved to .cpp file. Most of the rest is beyond my pay grade but it seems maybe the variable has been "optimised away"
Arduino IDE 1.8.9 + ESP8266 core 2.4.0 (I know it's not the latest but 2.50. adds 35k+ of additional bloat that breaks OTA on my big projects... :( )
The Code:
Its MVCE, cut out of a 5000+ line project. The workaround "solution" of having the code in the same file where its called is just not viable.
Class .h file
#ifndef FUNCSPOOL_H
#define FUNCSPOOL_H
#include<Arduino.h>
#include <string>
#include <functional>
using namespace std;
class funcSpool{
function<void(string)> fail;
protected:
static function<void(string)> staticFail;
public:
funcSpool(function<void(string)> f=staticFail): fail(f){}
virtual ~funcSpool(){}
void run(const string s){ fail(s); }
};
class fsPassthru: public funcSpool{};
#endif // funcspool_H
the external .cpp file
#include "funcSpool.h"
//When uncommented and thus declared in .cpp file, panic results
function<void(string)> funcSpool::staticFail =[](string s){ Serial.printf("STATIC FUNCTOR %s\n",s.c_str()); };
The main .ino:
#include "funcSpool.h"
//When uncommented and thus declared HERE, all is correct
//function<void(string)> funcSpool::staticFail =[](string s){ Serial.printf("STATIC FUNCTOR %s\n",s.c_str()); };
funcSpool* gsp=new fsPassthru;
void setup() {
Serial.begin(74880);
string test="always works locally both ways";
funcSpool* lsp=new fsPassthru;
Serial.printf("LOCAL POINTER %08x\n",(void*)lsp);
lsp->run(test);
Serial.printf("GLOBAL POINTER %08x\n",(void*)gsp);
gsp->run(test);
Serial.printf("EVERYTHING OK\n");
}
void loop(){}
The working output:
From the "correct" run where funcSpool::staticFail is declared within the .ino by uncommenting
Includes portions of the .map file
LOCAL POINTER 3ffef5c4
STATIC FUNCTOR always works locally both ways
GLOBAL POINTER 3ffef434
STATIC FUNCTOR always works locally both ways
EVERYTHING OK
Map
.literal.setup
0x00000000 0x0 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcspool3.ino.cpp.o
.literal.startup._GLOBAL__sub_I__ZN9funcSpool10staticFailE
0x00000000 0x0 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcspool3.ino.cpp.o
.literal.exit._GLOBAL__sub_D__ZN9funcSpool10staticFailE
0x00000000 0x0 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcspool3.ino.cpp.o
...
.text.startup._GLOBAL__sub_I__ZN9funcSpool10staticFailE
0x40202698 0x40 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcspool3.ino.cpp.o
0x5c (size before relaxing)
.text.exit._GLOBAL__sub_D__ZN9funcSpool10staticFailE
0x402026d8 0x15 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcspool3.ino.cpp.o
0x1d (size before relaxing)
*fill* 0x402026ed 0x3
...
.bss._ZN9funcSpool10staticFailE
0x3ffee84c 0x10 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcspool3.ino.cpp.o
0x3ffee84c funcSpool::staticFail
The Failing Output:
The .ino declaration is commented out and the .cpp declaration is uncommented:
LOCAL POINTER 3ffef5b4
STATIC FUNCTOR always works locally both ways
GLOBAL POINTER 3ffef42c
Panic C:\Users\phil\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.2\cores\esp8266\abi.cpp:106 __throw_bad_function_call
ctx: cont
sp: 3ffffd50 end: 3fffffd0 offset: 01b0
>>>stack>>>
3fffff00: 424f4c47 50204c41 544e494f 33205245
3fffff10: 66656666 0a633234 3ffef500 00000017
3fffff20: 6000001c 00000017 000000f3 4010020c
3fffff30: 3ffe8860 3ffef5b4 3fffff10 40208f8e
3fffff40: 3fffff80 3fffff50 00000008 3ffee89c
3fffff50: 3fffdad0 3ffef5b4 3ffef42c 40209028
3fffff60: 6000001c 0000002e 3ffef5b4 40202a89
3fffff70: 3ffe88a8 00000000 3ffef42c 402025ea
3fffff80: 3ffeece4 3ffef590 402024d0 3ffee89c
3fffff90: 3fffdad0 3ffee858 3ffee878 402026c7
3fffffa0: 3ffef590 3ffef590 feefeffe feefeffe
3fffffb0: feefeffe 00000000 3ffee894 40202bc0
3fffffc0: feefeffe feefeffe 3ffe84fc 40100739
<<<stack<<<
Decoding 9 results
0x4010020c: _umm_free at C:\Users\phil\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.2\cores\esp8266\umm_malloc/umm_malloc.c line 1295
0x40208f8e: std::basic_string , std::allocator >::~basic_string() at /Users/igrokhotkov/e/ESPTools/crosstool-NG/.build/xtensa-lx106-elf/build/build-cc-gcc-final/xtensa-lx106-elf/libstdc++-v3/include/bits/basic_string.h line 2208
0x40209028: std::basic_string , std::allocator >::basic_string(std::string const&) at /Users/igrokhotkov/e/ESPTools/crosstool-NG/.build/xtensa-lx106-elf/build/build-cc-gcc-final/xtensa-lx106-elf/libstdc++-v3/include/bits/basic_string.h line 2208
0x40202a89: std::__throw_bad_function_call() at ?? line ?
0x402025ea: _Alloc_hider at c:\users\phil\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2\xtensa-lx106-elf\include\c++\4.8.2\bits/basic_string.h line 272
: (inlined by) basic_string at c:\users\phil\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2\xtensa-lx106-elf\include\c++\4.8.2\bits/basic_string.h line 508
: (inlined by) std::function ::operator()(std::string) const at c:\users\phil\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2\xtensa-lx106-elf\include\c++\4.8.2/functional line 2464
: (inlined by) funcSpool::run(std::string) at C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch/funcSpool.h line 17
0x402024d0: _M_manager at c:\users\phil\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2\xtensa-lx106-elf\include\c++\4.8.2/functional line 1931
0x402026c7: setup at C:\Users\phil\Desktop\funcspool 3\funcspool3/funcspool3.ino line 16
0x40202bc0: loop_wrapper at C:\Users\phil\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.2\cores\esp8266/core_esp8266_main.cpp line 122
0x40100739: cont_wrapper at C:\Users\phil\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.2\cores\esp8266/cont.S line 81
Discarded input sections
.group 0x00000000 0x10 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcSpool.cpp.o
.literal._ZNSt17_Function_handlerIFvSsEN9funcSpoolUlSsE_EE9_M_invokeERKSt9_Any_dataSs
0x00000000 0x0 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcSpool.cpp.o
.literal._ZNSt14_Function_base13_Base_managerIN9funcSpoolUlSsE_EE10_M_managerERSt9_Any_dataRKS4_St18_Manager_operation
0x00000000 0x0 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcSpool.cpp.o
.literal.startup._GLOBAL__sub_I__ZN9funcSpool10staticFailE
0x00000000 0x0 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcSpool.cpp.o
.literal.exit._GLOBAL__sub_D__ZN9funcSpool10staticFailE
0x00000000 0x0 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcSpool.cpp.o
...
.text.startup._GLOBAL__sub_I__ZN9funcSpool10staticFailE
0x40202508 0x37 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcSpool.cpp.o
0x3b (size before relaxing)
*fill* 0x4020253f 0x1
.text.exit._GLOBAL__sub_D__ZN9funcSpool10staticFailE
0x40202540 0x15 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcSpool.cpp.o
0x1d (size before relaxing)
*fill* 0x40202555 0x3
...
.bss._ZN9funcSpool10staticFailE
0x3ffee848 0x10 C:\Users\phil\AppData\Local\Temp\arduino_build_321602\sketch\funcSpool.cpp.o
0x3ffee848 funcSpool::staticFail
I hope this isn't an ESP8266 issue: I will post it there too just in case.
Symptom is that working code fails (panic + stack dump) if definition of static std::function is moved to .cpp file. Most of the rest is beyond my pay grade but it seems maybe the variable has been "optimised away"
Arduino IDE 1.8.9 + ESP8266 core 2.4.0 (I know it's not the latest but 2.50. adds 35k+ of additional bloat that breaks OTA on my big projects... :( )
The Code:
Its MVCE, cut out of a 5000+ line project. The workaround "solution" of having the code in the same file where its called is just not viable. Class .h file
the external .cpp file
The main .ino:
The working output:
From the "correct" run where funcSpool::staticFail is declared within the .ino by uncommenting Includes portions of the .map file
The Failing Output:
The .ino declaration is commented out and the .cpp declaration is uncommented: