audeering / opensmile

The Munich Open-Source Large-Scale Multimedia Feature Extractor
https://audeering.github.io/opensmile/
Other
569 stars 75 forks source link

potential crash for android example app #12

Open toan-t-le opened 3 years ago

toan-t-le commented 3 years ago

I believe the current example app could randomly crash upon stopping recording audio depending on which line of code get executed first.

In child thread, we have OpenSmileAdapter running: https://github.com/audeering/opensmile/blob/master/progsrc/android-template/app/src/main/java/com/audeering/androidtemplate/OpenSmileExamples.kt#L112

In the main thread, we have https://github.com/audeering/opensmile/blob/master/progsrc/android-template/app/src/main/java/com/audeering/androidtemplate/OpenSmileExamples.kt#L194 which then call https://github.com/audeering/opensmile/blob/master/progsrc/android-template/app/src/main/java/com/audeering/androidtemplate/OpenSmileExamples.kt#L123

If line 122 ose.smile_abort() is executed, line 112 state = ose.smile_run() in child thread would finish executing, and then line 123 ose.smile_free() would run. This would be the ideal case. However, if the child thread runs slower and ose.smile_free() is executed first before ose.smile_run() finish properly, it would cause

A/libc: FORTIFY: pthread_mutex_lock called on a destroyed mutex (0x79cbf38144)
A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 21603 (AudioProcessing), pid 21308

This is quite a rare case, I could go for hundred runs without hitting it, however, there is a chance that it will crash (which has caused me some headache for days) when the condition is right.

I am not sure if my fix is the best but I moved ose.smile_free() to the child thread after ose.smile_run() to make sure the order of execution is properly maintained (if I understand the library correctly), and the crashes have stopped

chausner-audeering commented 3 years ago

Thanks a lot for reporting this issue. I think you are right, smile_abort performs an asynchronous abort and returns immediately but openSMILE may continue to run for a short while. So the proper way to handle this would be to do a thread join after smile_abort to wait for the child thread to have finished before calling smile_free.

Your fix of calling smile_free after smile_run probably also works, although freeing it from a different thread than where it was created on is a bit risky. I'd go with the thread join instead.