According to the POSIX spec the value of the timeout parameter needs
not to be validated if the mutex/semaphore could be taken immediately.

While the implementation of the semaphore timedwait (sem_timedwait())
allowed an invalid timeout pthread_mutex_timedlock() was failing with
-EFAULT in case the mutex could be taken immediately.

Signed-off-by: Florian Bezdeka <florian.bezd...@siemens.com>
---
 kernel/cobalt/posix/mutex.c                |  5 ++
 testsuite/smokey/posix-mutex/posix-mutex.c | 60 ++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/kernel/cobalt/posix/mutex.c b/kernel/cobalt/posix/mutex.c
index 70fe7960a..01478978e 100644
--- a/kernel/cobalt/posix/mutex.c
+++ b/kernel/cobalt/posix/mutex.c
@@ -167,6 +167,11 @@ redo:
        xnthread_commit_ceiling(curr);
 
        if (xnsynch_owner_check(&mutex->synchbase, curr)) {
+               /* Check if we can take the mutex immediately */
+               ret = xnsynch_try_acquire(&mutex->synchbase);
+               if (ret != -EBUSY)
+                       goto out;
+
                if (fetch_timeout) {
                        xnlock_put_irqrestore(&nklock, s);
                        ret = fetch_timeout(&ts, u_ts);
diff --git a/testsuite/smokey/posix-mutex/posix-mutex.c 
b/testsuite/smokey/posix-mutex/posix-mutex.c
index e5793c42c..4aad24964 100644
--- a/testsuite/smokey/posix-mutex/posix-mutex.c
+++ b/testsuite/smokey/posix-mutex/posix-mutex.c
@@ -1002,6 +1002,65 @@ static int protect_handover(void)
        return 0;
 }
 
+static void *mutex_timed_locker_inv_timeout(void *arg)
+{
+       struct locker_context *p = arg;
+       int ret;
+
+       if (__F(ret, pthread_mutex_timedlock(p->mutex, (void *) 0xdeadbeef)) &&
+           __Tassert(ret == -EFAULT))
+               return (void *)1;
+
+       return NULL;
+}
+
+static int check_timedlock_abstime_validation(void)
+{
+       struct locker_context args;
+       pthread_mutex_t mutex;
+       pthread_t tid;
+       void *status;
+       int ret;
+
+       if (!__T(ret, pthread_mutex_init(&mutex, NULL)))
+               return ret;
+
+       /*
+        * We don't own the mutex yet, so no need to validate the timeout as
+        * the mutex can be locked immediately.
+        *
+        * The second parameter of phtread_mutex_timedlock() is flagged as
+        * __nonnull so we take an invalid address instead of NULL.
+        */
+       if (!__T(ret, pthread_mutex_timedlock(&mutex, (void *) 0xdeadbeef)))
+               return ret;
+
+       /*
+        * Create a second thread which will have to wait and therefore will
+        * validate the (invalid) timeout
+        */
+       args.mutex = &mutex;
+       ret = create_thread(&tid, SCHED_FIFO, THREAD_PRIO_LOW,
+                           mutex_timed_locker_inv_timeout, &args);
+
+       if (ret)
+               return ret;
+
+       if (!__T(ret, pthread_join(tid, &status)))
+               return ret;
+
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
+
+       if (!__T(ret, pthread_mutex_destroy(&mutex)))
+               return ret;
+
+       if (!__Fassert(status == NULL))
+               return -EINVAL;
+
+       return 0;
+}
+
 /* Detect obviously wrong execution times. */
 static int check_time_limit(const struct timespec *start,
                            xnticks_t limit_ns)
@@ -1065,6 +1124,7 @@ static int run_posix_mutex(struct smokey_test *t, int 
argc, char *const argv[])
        do_test(protect_dynamic, MAX_100_MS);
        do_test(protect_trylock, MAX_100_MS);
        do_test(protect_handover, MAX_100_MS);
+       do_test(check_timedlock_abstime_validation, MAX_100_MS);
 
        return 0;
 }
-- 
2.30.2


Reply via email to