Skip to content

Commit 4eb3665

Browse files
author
Teppo Järvelin
committed
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 cancel eventqueue if it's holding an event and wait if oob processing is ongoing.
1 parent b2abfc3 commit 4eb3665

File tree

16 files changed

+149
-17
lines changed

16 files changed

+149
-17
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
@@ -26,4 +26,6 @@ set(unittest-test-sources
2626
stubs/ATHandler_stub.cpp
2727
stubs/EventQueue_stub.cpp
2828
stubs/FileHandle_stub.cpp
29+
stubs/ConditionVariable_stub.cpp
30+
stubs/Mutex_stub.cpp
2931
)

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/UARTSerial_stub.cpp
4343
stubs/SerialBase_stub.cpp
4444
stubs/CellularContext_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
@@ -44,6 +44,8 @@ set(unittest-test-sources
4444
stubs/SerialBase_stub.cpp
4545
stubs/CellularStateMachine_stub.cpp
4646
stubs/CellularContext_stub.cpp
47+
stubs/ConditionVariable_stub.cpp
48+
stubs/Mutex_stub.cpp
4749
)
4850

4951
# 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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ set(unittest-test-sources
2727
stubs/us_ticker_stub.cpp
2828
stubs/mbed_assert_stub.c
2929
stubs/mbed_wait_api_stub.cpp
30+
stubs/ConditionVariable_stub.cpp
31+
stubs/Mutex_stub.cpp
3032
)

UNITTESTS/features/cellular/framework/AT/at_cellularstack/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/NetworkStack_stub.cpp
2929
stubs/SocketAddress_stub.cpp
3030
stubs/mbed_assert_stub.c
31+
stubs/ConditionVariable_stub.cpp
32+
stubs/Mutex_stub.cpp
3133
)

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
@@ -33,6 +35,8 @@ set(unittest-test-sources
3335
stubs/Kernel_stub.cpp
3436
stubs/ThisThread_stub.cpp
3537
stubs/randLIB_stub.cpp
38+
stubs/ConditionVariable_stub.cpp
39+
stubs/Mutex_stub.cpp
3640
)
3741

3842
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
@@ -39,6 +39,8 @@ set(unittest-test-sources
3939
stubs/EventQueue_stub.cpp
4040
stubs/equeue_stub.c
4141
stubs/CellularContext_stub.cpp
42+
stubs/ConditionVariable_stub.cpp
43+
stubs/Mutex_stub.cpp
4244
)
4345

4446
# defines

UNITTESTS/stubs/ATHandler_stub.cpp

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

8282
ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, uint32_t timeout, const char *output_delimiter, uint16_t send_delay) :
8383
_nextATHandler(0),
84+
#ifdef AT_HANDLER_MUTEX
85+
_oobCv(_fileHandleMutex),
86+
#endif
8487
_fileHandle(fh),
8588
_queue(queue),
8689
_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: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "rtos/ThisThread.h"
2727
#include "Kernel.h"
2828
#include "CellularUtil.h"
29+
#include "ScopedLock.h"
2930

3031
using namespace mbed;
3132
using namespace events;
@@ -63,6 +64,9 @@ static const uint8_t map_3gpp_errors[][2] = {
6364

6465
ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, uint32_t timeout, const char *output_delimiter, uint16_t send_delay) :
6566
_nextATHandler(0),
67+
#ifdef AT_HANDLER_MUTEX
68+
_oobCv(_fileHandleMutex),
69+
#endif
6670
_fileHandle(NULL), // filehandle is set by set_file_handle()
6771
_queue(queue),
6872
_last_err(NSAPI_ERROR_OK),
@@ -85,7 +89,9 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, uint32_t timeout, const
8589
_debug_on(MBED_CONF_CELLULAR_DEBUG_AT),
8690
_cmd_start(false),
8791
_use_delimiter(true),
88-
_start_time(0)
92+
_start_time(0),
93+
_event_id(-1),
94+
_oob_pending(false)
8995
{
9096
clear_error();
9197

@@ -120,8 +126,15 @@ bool ATHandler::get_debug() const
120126

121127
ATHandler::~ATHandler()
122128
{
129+
ScopedLock <ATHandler> lock(*this);
123130
set_file_handle(NULL);
124131

132+
// cancel possible oob event from queue and wait if oob is ongoing
133+
_queue.cancel(_event_id);
134+
while (_oob_pending) {
135+
_oobCv.wait();
136+
}
137+
125138
while (_oobs) {
126139
struct oob_t *oob = _oobs;
127140
_oobs = oob->next;
@@ -154,6 +167,7 @@ FileHandle *ATHandler::get_file_handle()
154167

155168
void ATHandler::set_file_handle(FileHandle *fh)
156169
{
170+
ScopedLock<ATHandler> lock(*this);
157171
if (_fileHandle) {
158172
set_is_filehandle_usable(false);
159173
}
@@ -165,6 +179,7 @@ void ATHandler::set_file_handle(FileHandle *fh)
165179

166180
void ATHandler::set_is_filehandle_usable(bool usable)
167181
{
182+
ScopedLock<ATHandler> lock(*this);
168183
if (_fileHandle) {
169184
if (usable) {
170185
_fileHandle->set_blocking(false);
@@ -241,7 +256,7 @@ void ATHandler::event()
241256
{
242257
if (!_oob_queued) {
243258
_oob_queued = true;
244-
(void) _queue.call(Callback<void(void)>(this, &ATHandler::process_oob));
259+
_event_id = _queue.call(Callback<void(void)>(this, &ATHandler::process_oob));
245260
}
246261
}
247262

@@ -256,12 +271,12 @@ void ATHandler::lock()
256271

257272
void ATHandler::unlock()
258273
{
274+
if (_is_fh_usable && (_fileHandle->readable() || (_recv_pos < _recv_len))) {
275+
_event_id = _queue.call(Callback<void(void)>(this, &ATHandler::process_oob));
276+
}
259277
#ifdef AT_HANDLER_MUTEX
260278
_fileHandleMutex.unlock();
261279
#endif
262-
if (_fileHandle->readable() || (_recv_pos < _recv_len)) {
263-
(void) _queue.call(Callback<void(void)>(this, &ATHandler::process_oob));
264-
}
265280
}
266281

267282
nsapi_error_t ATHandler::unlock_return_error()
@@ -295,12 +310,15 @@ void ATHandler::restore_at_timeout()
295310

296311
void ATHandler::process_oob()
297312
{
313+
ScopedLock<ATHandler> lock(*this);
314+
_oob_pending = true;
315+
_oob_queued = false;
298316
if (!_is_fh_usable) {
299317
tr_debug("process_oob, filehandle is not usable, return...");
318+
_oob_pending = false;
319+
_oobCv.notify_all();
300320
return;
301321
}
302-
lock();
303-
_oob_queued = false;
304322
if (_fileHandle->readable() || (_recv_pos < _recv_len)) {
305323
tr_debug("AT OoB readable %d, len %u", _fileHandle->readable(), _recv_len - _recv_pos);
306324
_current_scope = NotSet;
@@ -326,7 +344,8 @@ void ATHandler::process_oob()
326344
_at_timeout = timeout;
327345
tr_debug("AT OoB done");
328346
}
329-
unlock();
347+
_oob_pending = false;
348+
_oobCv.notify_all();
330349
}
331350

332351
void ATHandler::reset_buffer()

features/cellular/framework/AT/ATHandler.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,9 @@
2121
#include "platform/mbed_retarget.h"
2222

2323
#include "events/EventQueue.h"
24-
#include "PlatformMutex.h"
2524
#include "nsapi_types.h"
26-
27-
#include "PlatformMutex.h"
2825
#include "Callback.h"
2926

30-
namespace mbed {
31-
32-
class FileHandle;
33-
3427
/**
3528
* If application calls associated FileHandle only from single thread context
3629
* then locking between AT command and response is not needed. However,
@@ -39,6 +32,14 @@ class FileHandle;
3932
*/
4033
#define AT_HANDLER_MUTEX
4134

35+
#ifdef AT_HANDLER_MUTEX
36+
#include "ConditionVariable.h"
37+
#endif
38+
39+
namespace mbed {
40+
41+
class FileHandle;
42+
4243
extern const char *OK;
4344
extern const char *CRLF;
4445

@@ -212,7 +213,8 @@ class ATHandler {
212213
protected:
213214
void event();
214215
#ifdef AT_HANDLER_MUTEX
215-
PlatformMutex _fileHandleMutex;
216+
rtos::Mutex _fileHandleMutex;
217+
rtos::ConditionVariable _oobCv;
216218
#endif
217219
FileHandle *_fileHandle;
218220
private:
@@ -496,6 +498,10 @@ class ATHandler {
496498

497499
// time when a command or an URC processing was started
498500
uint64_t _start_time;
501+
// eventqueue event id
502+
int _event_id;
503+
// used to check if oob processing is ongoing
504+
bool _oob_pending;
499505

500506
// Gets char from receiving buffer.
501507
// Resets and fills the buffer if all are already read (receiving position equals receiving length).

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)