Skip to content

Commit 40faf90

Browse files
Teppo JärvelinMirela Chirica
authored andcommitted
Cellular: fix ATHandler destructor possible crash on delete
In some multithread cases there is possibility that process_oob function was called after ATHandler was deleted. Fix is to wait if oob processing is ongoing.
1 parent 7e0fb8f commit 40faf90

File tree

16 files changed

+152
-19
lines changed

16 files changed

+152
-19
lines changed

UNITTESTS/features/cellular/framework/AT/at_cellularbase/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ set(unittest-test-sources
2525
stubs/ATHandler_stub.cpp
2626
stubs/EventQueue_stub.cpp
2727
stubs/FileHandle_stub.cpp
28+
stubs/ConditionVariable_stub.cpp
29+
stubs/Mutex_stub.cpp
2830
)

UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ set(unittest-test-sources
4242
stubs/CellularContext_stub.cpp
4343
stubs/CellularUtil_stub.cpp
4444
stubs/SocketAddress_stub.cpp
45+
stubs/ConditionVariable_stub.cpp
46+
stubs/Mutex_stub.cpp
4547
)

UNITTESTS/features/cellular/framework/AT/at_cellulardevice/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ set(unittest-test-sources
4343
stubs/SerialBase_stub.cpp
4444
stubs/CellularStateMachine_stub.cpp
4545
stubs/CellularContext_stub.cpp
46+
stubs/ConditionVariable_stub.cpp
47+
stubs/Mutex_stub.cpp
4648
)
4749

4850
# defines

UNITTESTS/features/cellular/framework/AT/at_cellularinformation/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ set(unittest-test-sources
2525
stubs/EventQueue_stub.cpp
2626
stubs/FileHandle_stub.cpp
2727
stubs/mbed_assert_stub.c
28+
stubs/ConditionVariable_stub.cpp
29+
stubs/Mutex_stub.cpp
2830
)

UNITTESTS/features/cellular/framework/AT/at_cellularnetwork/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@ set(unittest-test-sources
2828
stubs/mbed_assert_stub.c
2929
stubs/SocketAddress_stub.cpp
3030
stubs/randLIB_stub.cpp
31+
stubs/ConditionVariable_stub.cpp
32+
stubs/Mutex_stub.cpp
3133
)

UNITTESTS/features/cellular/framework/AT/at_cellularsms/unittest.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,7 @@ set(unittest-test-sources
2727
stubs/us_ticker_stub.cpp
2828
stubs/mbed_assert_stub.c
2929
stubs/ThisThread_stub.cpp
30+
stubs/mbed_wait_api_stub.cpp
31+
stubs/ConditionVariable_stub.cpp
32+
stubs/Mutex_stub.cpp
3033
)

UNITTESTS/features/cellular/framework/AT/at_cellularstack/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@ set(unittest-test-sources
2929
stubs/SocketAddress_stub.cpp
3030
stubs/mbed_assert_stub.c
3131
stubs/ThisThread_stub.cpp
32+
stubs/ConditionVariable_stub.cpp
33+
stubs/Mutex_stub.cpp
3234
)

UNITTESTS/features/cellular/framework/AT/athandler/unittest.cmake

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
# Add test specific include paths
77
set(unittest-includes ${unittest-includes}
8-
features/cellular/framework/common/util
8+
../platform
9+
../features/cellular/framework/common/util
910
../features/cellular/framework/common
1011
../features/cellular/framework/AT
1112
../features/frameworks/mbed-client-randlib/mbed-client-randlib
13+
1214
)
1315

1416
# Source files
@@ -31,6 +33,8 @@ set(unittest-test-sources
3133
stubs/ThisThread_stub.cpp
3234
stubs/randLIB_stub.cpp
3335
stubs/CellularUtil_stub.cpp
36+
stubs/ConditionVariable_stub.cpp
37+
stubs/Mutex_stub.cpp
3438
)
3539

3640
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_CELLULAR_DEBUG_AT=true -DOS_STACK_SIZE=2048")

UNITTESTS/features/cellular/framework/device/cellulardevice/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ set(unittest-test-sources
3333
stubs/NetworkInterface_stub.cpp
3434
stubs/NetworkInterfaceDefaults_stub.cpp
3535
stubs/CellularContext_stub.cpp
36+
stubs/ConditionVariable_stub.cpp
37+
stubs/Mutex_stub.cpp
3638
)
3739

3840
# defines

UNITTESTS/features/cellular/framework/device/cellularstatemachine/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ set(unittest-test-sources
3838
stubs/EventQueue_stub.cpp
3939
stubs/equeue_stub.c
4040
stubs/CellularContext_stub.cpp
41+
stubs/ConditionVariable_stub.cpp
42+
stubs/Mutex_stub.cpp
4143
)
4244

4345
# defines

UNITTESTS/stubs/ATHandler_stub.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ void ATHandler_stub::debug_call_count_clear()
8383

8484
ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, uint32_t timeout, const char *output_delimiter, uint16_t send_delay) :
8585
_nextATHandler(0),
86+
#ifdef AT_HANDLER_MUTEX
87+
_oobCv(_fileHandleMutex),
88+
#endif
8689
_fileHandle(fh),
8790
_queue(queue),
8891
_ref_count(1),
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2019, Arm Limited and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#ifndef MBED_OS_UNITTESTS_STUBS_CONDITIONVARIABLE_STUB_CPP_
18+
#define MBED_OS_UNITTESTS_STUBS_CONDITIONVARIABLE_STUB_CPP_
19+
20+
#include "ConditionVariable_stub.h"
21+
#include "mbed_error.h"
22+
#include "mbed_assert.h"
23+
24+
bool ConditionVariable_stub::time_out = false;
25+
using namespace rtos;
26+
27+
ConditionVariable::ConditionVariable(Mutex &mutex): _mutex(mutex), _wait_list(0)
28+
{
29+
// No initialization to do
30+
}
31+
32+
ConditionVariable::~ConditionVariable()
33+
{
34+
}
35+
36+
void ConditionVariable::notify_one()
37+
{
38+
39+
}
40+
41+
void ConditionVariable::wait()
42+
{
43+
}
44+
45+
bool ConditionVariable::wait_for(uint32_t millisec)
46+
{
47+
return ConditionVariable_stub::time_out;
48+
}
49+
50+
void ConditionVariable::notify_all()
51+
{
52+
}
53+
54+
#endif /* MBED_OS_UNITTESTS_STUBS_CONDITIONVARIABLE_STUB_CPP_ */
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2019, Arm Limited and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#ifndef MBED_OS_UNITTESTS_STUBS_CONDITIONVARIABLE_STUB_H_
18+
#define MBED_OS_UNITTESTS_STUBS_CONDITIONVARIABLE_STUB_H_
19+
20+
#include "rtos/ConditionVariable.h"
21+
22+
namespace ConditionVariable_stub {
23+
extern bool time_out;
24+
}
25+
26+
27+
#endif /* MBED_OS_UNITTESTS_STUBS_CONDITIONVARIABLE_STUB_H_ */

features/cellular/framework/AT/ATHandler.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "Kernel.h"
2727
#include "CellularUtil.h"
2828
#include "SingletonPtr.h"
29+
#include "ScopedLock.h"
2930

3031
using namespace mbed;
3132
using namespace events;
@@ -161,6 +162,9 @@ bool ATHandler::ok_to_proceed()
161162

162163
ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, uint32_t timeout, const char *output_delimiter, uint16_t send_delay) :
163164
_nextATHandler(0),
165+
#ifdef AT_HANDLER_MUTEX
166+
_oobCv(_fileHandleMutex),
167+
#endif
164168
_fileHandle(NULL), // filehandle is set by set_file_handle()
165169
_queue(queue),
166170
_last_err(NSAPI_ERROR_OK),
@@ -171,7 +175,6 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, uint32_t timeout, const
171175
_previous_at_timeout(timeout),
172176
_at_send_delay(send_delay),
173177
_last_response_stop(0),
174-
_oob_queued(false),
175178
_ref_count(1),
176179
_is_fh_usable(false),
177180
_stop_tag(NULL),
@@ -183,7 +186,8 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, uint32_t timeout, const
183186
_debug_on(MBED_CONF_CELLULAR_DEBUG_AT),
184187
_cmd_start(false),
185188
_use_delimiter(true),
186-
_start_time(0)
189+
_start_time(0),
190+
_event_id(-1)
187191
{
188192
clear_error();
189193

@@ -218,8 +222,17 @@ bool ATHandler::get_debug() const
218222

219223
ATHandler::~ATHandler()
220224
{
225+
ScopedLock <ATHandler> lock(*this);
221226
set_file_handle(NULL);
222227

228+
while (_event_id > 0) {
229+
#ifdef AT_HANDLER_MUTEX
230+
_oobCv.wait();
231+
#else
232+
ThisThread::sleep_for(PROCESS_URC_TIME);
233+
#endif // AT_HANDLER_MUTEX
234+
}
235+
223236
while (_oobs) {
224237
struct oob_t *oob = _oobs;
225238
_oobs = oob->next;
@@ -252,6 +265,7 @@ FileHandle *ATHandler::get_file_handle()
252265

253266
void ATHandler::set_file_handle(FileHandle *fh)
254267
{
268+
ScopedLock<ATHandler> lock(*this);
255269
if (_fileHandle) {
256270
set_is_filehandle_usable(false);
257271
}
@@ -263,6 +277,7 @@ void ATHandler::set_file_handle(FileHandle *fh)
263277

264278
void ATHandler::set_is_filehandle_usable(bool usable)
265279
{
280+
ScopedLock<ATHandler> lock(*this);
266281
if (_fileHandle) {
267282
if (usable) {
268283
_fileHandle->set_blocking(false);
@@ -337,9 +352,8 @@ bool ATHandler::find_urc_handler(const char *prefix)
337352

338353
void ATHandler::event()
339354
{
340-
if (!_oob_queued) {
341-
_oob_queued = true;
342-
(void) _queue.call(Callback<void(void)>(this, &ATHandler::process_oob));
355+
if (_event_id <= 0) {
356+
_event_id = _queue.call(Callback<void(void)>(this, &ATHandler::process_oob));
343357
}
344358
}
345359

@@ -354,12 +368,12 @@ void ATHandler::lock()
354368

355369
void ATHandler::unlock()
356370
{
371+
if (_is_fh_usable && (_fileHandle->readable() || (_recv_pos < _recv_len))) {
372+
_event_id = _queue.call(Callback<void(void)>(this, &ATHandler::process_oob));
373+
}
357374
#ifdef AT_HANDLER_MUTEX
358375
_fileHandleMutex.unlock();
359376
#endif
360-
if (_fileHandle->readable() || (_recv_pos < _recv_len)) {
361-
(void) _queue.call(Callback<void(void)>(this, &ATHandler::process_oob));
362-
}
363377
}
364378

365379
nsapi_error_t ATHandler::unlock_return_error()
@@ -393,12 +407,15 @@ void ATHandler::restore_at_timeout()
393407

394408
void ATHandler::process_oob()
395409
{
410+
ScopedLock<ATHandler> lock(*this);
396411
if (!_is_fh_usable) {
397412
tr_debug("process_oob, filehandle is not usable, return...");
413+
_event_id = -1;
414+
#ifdef AT_HANDLER_MUTEX
415+
_oobCv.notify_all();
416+
#endif
398417
return;
399418
}
400-
lock();
401-
_oob_queued = false;
402419
if (_fileHandle->readable() || (_recv_pos < _recv_len)) {
403420
tr_debug("AT OoB readable %d, len %u", _fileHandle->readable(), _recv_len - _recv_pos);
404421
_current_scope = NotSet;
@@ -424,7 +441,10 @@ void ATHandler::process_oob()
424441
_at_timeout = timeout;
425442
tr_debug("AT OoB done");
426443
}
427-
unlock();
444+
_event_id = -1;
445+
#ifdef AT_HANDLER_MUTEX
446+
_oobCv.notify_all();
447+
#endif
428448
}
429449

430450
void ATHandler::reset_buffer()

features/cellular/framework/AT/ATHandler.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,12 @@
2121
#include "platform/mbed_retarget.h"
2222

2323
#include "events/EventQueue.h"
24-
#include "PlatformMutex.h"
2524
#include "nsapi_types.h"
2625

2726
#include "Callback.h"
2827

2928
#include <cstdarg>
3029

31-
namespace mbed {
32-
33-
class FileHandle;
34-
3530
/**
3631
* If application calls associated FileHandle only from single thread context
3732
* then locking between AT command and response is not needed. However,
@@ -40,6 +35,14 @@ class FileHandle;
4035
*/
4136
#define AT_HANDLER_MUTEX
4237

38+
#ifdef AT_HANDLER_MUTEX
39+
#include "ConditionVariable.h"
40+
#endif
41+
42+
namespace mbed {
43+
44+
class FileHandle;
45+
4346
extern const char *OK;
4447
extern const char *CRLF;
4548

@@ -219,7 +222,8 @@ class ATHandler {
219222
protected:
220223
void event();
221224
#ifdef AT_HANDLER_MUTEX
222-
PlatformMutex _fileHandleMutex;
225+
rtos::Mutex _fileHandleMutex;
226+
rtos::ConditionVariable _oobCv;
223227
#endif
224228
FileHandle *_fileHandle;
225229
private:
@@ -251,7 +255,6 @@ class ATHandler {
251255
uint16_t _at_send_delay;
252256
uint64_t _last_response_stop;
253257

254-
bool _oob_queued;
255258
int32_t _ref_count;
256259
bool _is_fh_usable;
257260

@@ -550,6 +553,8 @@ class ATHandler {
550553

551554
// time when a command or an URC processing was started
552555
uint64_t _start_time;
556+
// eventqueue event id
557+
int _event_id;
553558

554559
char _cmd_buffer[BUFF_SIZE];
555560

features/cellular/framework/AT/AT_CellularStack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "AT_CellularBase.h"
2222
#include "NetworkStack.h"
23+
#include "PlatformMutex.h"
2324

2425
namespace mbed {
2526

0 commit comments

Comments
 (0)