Skip to content

Commit 64afbf0

Browse files
authored
[rtsan][compiler-rt] Prevent UB hang in rtsan lock unit tests (#104733)
It is undefined behavior to lock or unlock an uninitialized lock, and unlock a lock which isn't locked. Introduce a fixture to set up and tear down the locks where appropriate, and separates them into two tests (realtime death and non realtime survival) so each test is guaranteed a fresh lock.
1 parent d7073c5 commit 64afbf0

File tree

1 file changed

+107
-23
lines changed

1 file changed

+107
-23
lines changed

compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp

+107-23
Original file line numberDiff line numberDiff line change
@@ -328,26 +328,64 @@ TEST(TestRtsanInterceptors, PthreadCreateDiesWhenRealtime) {
328328
ExpectNonRealtimeSurvival(Func);
329329
}
330330

331-
TEST(TestRtsanInterceptors, PthreadMutexLockDiesWhenRealtime) {
332-
auto Func = []() {
333-
pthread_mutex_t mutex{};
331+
class PthreadMutexLockTest : public ::testing::Test {
332+
protected:
333+
void SetUp() override {
334+
pthread_mutex_init(&mutex, nullptr);
335+
is_locked = false;
336+
}
337+
338+
void TearDown() override {
339+
if (is_locked)
340+
Unlock();
341+
342+
pthread_mutex_destroy(&mutex);
343+
}
344+
345+
void Lock() {
346+
ASSERT_TRUE(!is_locked);
334347
pthread_mutex_lock(&mutex);
335-
};
348+
is_locked = true;
349+
}
350+
351+
void Unlock() {
352+
ASSERT_TRUE(is_locked);
353+
pthread_mutex_unlock(&mutex);
354+
is_locked = false;
355+
}
356+
357+
private:
358+
pthread_mutex_t mutex;
359+
bool is_locked;
360+
};
361+
362+
TEST_F(PthreadMutexLockTest, PthreadMutexLockDiesWhenRealtime) {
363+
auto Func = [this]() { Lock(); };
336364

337365
ExpectRealtimeDeath(Func, "pthread_mutex_lock");
366+
}
367+
368+
TEST_F(PthreadMutexLockTest, PthreadMutexLockSurvivesWhenNotRealtime) {
369+
auto Func = [this]() { Lock(); };
370+
338371
ExpectNonRealtimeSurvival(Func);
339372
}
340373

341-
TEST(TestRtsanInterceptors, PthreadMutexUnlockDiesWhenRealtime) {
342-
auto Func = []() {
343-
pthread_mutex_t mutex{};
344-
pthread_mutex_unlock(&mutex);
345-
};
374+
TEST_F(PthreadMutexLockTest, PthreadMutexUnlockDiesWhenRealtime) {
375+
Lock();
376+
auto Func = [this]() { Unlock(); };
346377

347378
ExpectRealtimeDeath(Func, "pthread_mutex_unlock");
348379
ExpectNonRealtimeSurvival(Func);
349380
}
350381

382+
TEST_F(PthreadMutexLockTest, PthreadMutexUnlockSurvivesWhenNotRealtime) {
383+
Lock();
384+
auto Func = [this]() { Unlock(); };
385+
386+
ExpectNonRealtimeSurvival(Func);
387+
}
388+
351389
TEST(TestRtsanInterceptors, PthreadMutexJoinDiesWhenRealtime) {
352390
auto Func = []() {
353391
pthread_t thread{};
@@ -431,30 +469,76 @@ TEST(TestRtsanInterceptors, PthreadCondWaitDiesWhenRealtime) {
431469
pthread_mutex_destroy(&mutex);
432470
}
433471

434-
TEST(TestRtsanInterceptors, PthreadRwlockRdlockDiesWhenRealtime) {
435-
auto Func = []() {
436-
pthread_rwlock_t rw_lock;
472+
class PthreadRwlockTest : public ::testing::Test {
473+
protected:
474+
void SetUp() override {
475+
pthread_rwlock_init(&rw_lock, nullptr);
476+
is_locked = false;
477+
}
478+
479+
void TearDown() override {
480+
if (is_locked)
481+
Unlock();
482+
483+
pthread_rwlock_destroy(&rw_lock);
484+
}
485+
486+
void RdLock() {
487+
ASSERT_TRUE(!is_locked);
437488
pthread_rwlock_rdlock(&rw_lock);
438-
};
489+
is_locked = true;
490+
}
491+
492+
void WrLock() {
493+
ASSERT_TRUE(!is_locked);
494+
pthread_rwlock_wrlock(&rw_lock);
495+
is_locked = true;
496+
}
497+
498+
void Unlock() {
499+
ASSERT_TRUE(is_locked);
500+
pthread_rwlock_unlock(&rw_lock);
501+
is_locked = false;
502+
}
503+
504+
private:
505+
pthread_rwlock_t rw_lock;
506+
bool is_locked;
507+
};
508+
509+
TEST_F(PthreadRwlockTest, PthreadRwlockRdlockDiesWhenRealtime) {
510+
auto Func = [this]() { RdLock(); };
439511
ExpectRealtimeDeath(Func, "pthread_rwlock_rdlock");
512+
}
513+
514+
TEST_F(PthreadRwlockTest, PthreadRwlockRdlockSurvivesWhenNonRealtime) {
515+
auto Func = [this]() { RdLock(); };
440516
ExpectNonRealtimeSurvival(Func);
441517
}
442518

443-
TEST(TestRtsanInterceptors, PthreadRwlockUnlockDiesWhenRealtime) {
444-
auto Func = []() {
445-
pthread_rwlock_t rw_lock;
446-
pthread_rwlock_unlock(&rw_lock);
447-
};
519+
TEST_F(PthreadRwlockTest, PthreadRwlockUnlockDiesWhenRealtime) {
520+
RdLock();
521+
522+
auto Func = [this]() { Unlock(); };
448523
ExpectRealtimeDeath(Func, "pthread_rwlock_unlock");
524+
}
525+
526+
TEST_F(PthreadRwlockTest, PthreadRwlockUnlockSurvivesWhenNonRealtime) {
527+
RdLock();
528+
529+
auto Func = [this]() { Unlock(); };
449530
ExpectNonRealtimeSurvival(Func);
450531
}
451532

452-
TEST(TestRtsanInterceptors, PthreadRwlockWrlockDiesWhenRealtime) {
453-
auto Func = []() {
454-
pthread_rwlock_t rw_lock;
455-
pthread_rwlock_wrlock(&rw_lock);
456-
};
533+
TEST_F(PthreadRwlockTest, PthreadRwlockWrlockDiesWhenRealtime) {
534+
auto Func = [this]() { WrLock(); };
535+
457536
ExpectRealtimeDeath(Func, "pthread_rwlock_wrlock");
537+
}
538+
539+
TEST_F(PthreadRwlockTest, PthreadRwlockWrlockSurvivesWhenNonRealtime) {
540+
auto Func = [this]() { WrLock(); };
541+
458542
ExpectNonRealtimeSurvival(Func);
459543
}
460544

0 commit comments

Comments
 (0)