kernel: sem: Ensure that initial count is lesser or equal than limit

Ensure this value during static initialization (with build assertions),
and dynamic initializations through system calls.

If initial count is larger than the limit, it's possible for the count
to wraparound, causing locking issues.

Expanding the BUILD_ASSERT() macros after declaring a k_sem struct in
K_SEM_DEFINE() is necessary to support cases where a semaphore is
defined statically.

Signed-off-by: Leandro Pereira <leandro.pereira@intel.com>
This commit is contained in:
Leandro Pereira 2018-04-06 15:55:11 -07:00 committed by Anas Nashif
commit f5f95ee3a9
2 changed files with 5 additions and 2 deletions

View file

@ -2695,7 +2695,9 @@ static inline unsigned int _impl_k_sem_count_get(struct k_sem *sem)
#define K_SEM_DEFINE(name, initial_count, count_limit) \
struct k_sem name \
__in_section(_k_sem, static, name) = \
_K_SEM_INITIALIZER(name, initial_count, count_limit)
_K_SEM_INITIALIZER(name, initial_count, count_limit); \
BUILD_ASSERT((count_limit) != 0); \
BUILD_ASSERT((initial_count) <= (count_limit));
/** @} */

View file

@ -58,6 +58,7 @@ void _impl_k_sem_init(struct k_sem *sem, unsigned int initial_count,
unsigned int limit)
{
__ASSERT(limit != 0, "limit cannot be zero");
__ASSERT(initial_count <= limit, "count cannot be greater than limit");
sem->count = initial_count;
sem->limit = limit;
@ -75,7 +76,7 @@ void _impl_k_sem_init(struct k_sem *sem, unsigned int initial_count,
_SYSCALL_HANDLER(k_sem_init, sem, initial_count, limit)
{
_SYSCALL_OBJ_INIT(sem, K_OBJ_SEM);
_SYSCALL_VERIFY(limit != 0);
_SYSCALL_VERIFY(limit != 0 && initial_count <= limit);
_impl_k_sem_init((struct k_sem *)sem, initial_count, limit);
return 0;
}