Skip to content

atexit() called after setup() #1919

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

Closed
cider101 opened this issue Mar 9, 2014 · 8 comments
Closed

atexit() called after setup() #1919

cider101 opened this issue Mar 9, 2014 · 8 comments

Comments

@cider101
Copy link

cider101 commented Mar 9, 2014

First of all, there is no atexit() definition provieded by the runtime-environment which gives you, in case of "stack-based" singleton implementation - undefined references while linking.
class Singleton {
static Signleton& instance() { static Signleton theInstance; return theInstance; }
};
Secondly, the atexit is called after leaving setup() - which if implemented correctly - will just delete the instance and leave you with invalid memory!

@matthijskooijman
Copy link
Collaborator

I'm not sure what you mean here. I don't see any atexit function call in your code. Normally, atexit can be called to register function that should be called before the program terminates. In Arduino, the main function never returns, so this will never happen.

You also mention undefined references while linking and invalid memory, which are two completely separate issues. I suspect you just have a problem in your code that you're misinterpreting as an Arduino bug.

Could you paste a complete (but as small as possible) sketch that displays the problem and describe what happens and what you had expected to happen?

@cider101
Copy link
Author

ok...as i promised a more verbose explanation ;)

if a singleton is definded in the follwoing way:

class Singleton {
    static Signleton& instance() { 
         static Signleton theInstance;
         return theInstance; 
         }

     void sayHello() {  Serial.println("Hello World"); }
};

void setup() {
    Singleton::instance().sayHello();
}
void loop() {
    Singleton::instance().sayHello();
}

the linker will complain about an undefined/unresolved symbol for atexit(). If a correct implementation of atexit is provided in the user code (to fix the unresovled symbol)

int atexit(void (*func)()) {
    func();
    return 0;
}

the code will link, but at atexit is beeing called after the completion of the setup method. If func() is executed, it will invoke the destructor of the singleton-class and leaving you behind with an invalid reference in the loop() or on the next invovaction of instance().

@matthijskooijman
Copy link
Collaborator

Right. Your implementation of atexit is wrong: the function pointer passed to atexit should be called just before program termination, but you call it right away, which explains why things get broken.

I'm surpised that the compiler actually inserts calls to atexit - you'd expect that it can more efficiently call the destructors without using a function pointer and (thus) an indirect function call. However, thinking about this more, I think that the static variable you declared will not be initialized at startup, but only when the instance function is first called. Since it is not guaranteed this ever happens, the compiler can't call the destructor unconditionally at shutdown, so I suspect this is why it uses the atexit function. I'm just guessing here, though.

In any case, if you supply an empty atexit function, I think that would be more correct (since the main loop never terminates, so it's ok to never call the functions passed to atexit) and I think it would solve your problem. Now I wonder if the Arduino environment should be providing this dummy atexit...

@matthijskooijman
Copy link
Collaborator

Oh, one more thing: If you paste code, make sure to indent it at least 4 spaces or a tab, or put triple backticks (```) before and after the block of code, to get a fixed-width font.

@cider101
Copy link
Author

i just checked the c/c++ reference again... oops...you are right about the wrong implementation - sorry, my bad - seems i forgot to many thing within the last 5years i didn't use c++ ;)

yes, the static variable won't be initialized until the first call of instance(). One could provide an different, pointer based implementation - but this would produce more overhead

instance() {
    if(_ptr == NULL) {
         _ptr = new Singleton();
    }
    return *_ptr;
}

I "solved" the problem as you said with an empty implementation of atexit since atexit() doesn't make sense in the Arduino-Environment anyway. But as you suggested, an empty default implementation would be nice - maybe with an attribute weak, so in the unlikely case it's needed one can provide a different implementation

@cider101
Copy link
Author

thanks for the hint with the 4 spaces !

@matthijskooijman
Copy link
Collaborator

Perhaps you could supply a pullrequest that adds a weak and empty atexit() function? Perhaps proposing this on the developers mailing list (see the contact us page on arduino.cc) first is a good idea, though.

cmaglie pushed a commit that referenced this issue Aug 8, 2014
This is an empty stub to simply allow use of complex types with a
non global static lifetime. For more complex handling the function
'atexit' can be redefined in user code.

For more information see:

#2229
#1919
@cmaglie
Copy link
Member

cmaglie commented Aug 8, 2014

Fixed with 1bbcb2f
To be released in Arduino IDE 1.5.8

@cmaglie cmaglie closed this as completed Aug 8, 2014
klightspeed pushed a commit to klightspeed/EthertenMP3Player that referenced this issue Aug 30, 2015
This is an empty stub to simply allow use of complex types with a
non global static lifetime. For more complex handling the function
'atexit' can be redefined in user code.

For more information see:

arduino/Arduino#2229
arduino/Arduino#1919
klightspeed pushed a commit to klightspeed/Arduino-Libraries that referenced this issue Sep 6, 2015
This is an empty stub to simply allow use of complex types with a
non global static lifetime. For more complex handling the function
'atexit' can be redefined in user code.

For more information see:

arduino/Arduino#2229
arduino/Arduino#1919

(Filtered from arduino/Arduino@1bbcb2f)
facchinm pushed a commit to arduino/ArduinoCore-avr that referenced this issue Sep 20, 2017
This is an empty stub to simply allow use of complex types with a
non global static lifetime. For more complex handling the function
'atexit' can be redefined in user code.

For more information see:

arduino/Arduino#2229
arduino/Arduino#1919
facchinm pushed a commit to arduino/ArduinoCore-avr that referenced this issue Sep 20, 2017
This is an empty stub to simply allow use of complex types with a
non global static lifetime. For more complex handling the function
'atexit' can be redefined in user code.

For more information see:

arduino/Arduino#2229
arduino/Arduino#1919
facchinm pushed a commit to arduino/ArduinoCore-avr that referenced this issue Sep 20, 2017
This is an empty stub to simply allow use of complex types with a
non global static lifetime. For more complex handling the function
'atexit' can be redefined in user code.

For more information see:

arduino/Arduino#2229
arduino/Arduino#1919
facchinm pushed a commit to arduino/ArduinoCore-avr that referenced this issue Sep 20, 2017
This is an empty stub to simply allow use of complex types with a
non global static lifetime. For more complex handling the function
'atexit' can be redefined in user code.

For more information see:

arduino/Arduino#2229
arduino/Arduino#1919
rickyrockrat pushed a commit to rickyrockrat/Arduino.hardware that referenced this issue Apr 10, 2018
This is an empty stub to simply allow use of complex types with a
non global static lifetime. For more complex handling the function
'atexit' can be redefined in user code.

For more information see:

arduino/Arduino#2229
arduino/Arduino#1919
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

Successfully merging a pull request may close this issue.

3 participants