compat: libc: Bring libc hax inline with the latest sources
-> [1] added tests to ensure nano timespecs are below 1000000000 -> Legacy blobs before N were able to use tv_nsec > 100000000 -> One such example would be our libmmcamera2_sensor_modules.so, which have instances of timeouts of 5000000000 nsecs. -> The previous workaround was to shim the old libc functions to skip these tests, but that was really ugly since we leave out bug fixes and security patches introduced from MM up till Oreo. -> Current workaround is applied on the latest bionic code by correcting the invalid timespecs, taking out each second from tv_nsec, and then adding them to tv_sec, until tv_nsec goes below 1 second. -> Due to bionic's tight security, we've got no choice but to copy-paste its functions here. [1]: https://android.googlesource.com/platform/bionic/+/c9a659c Change-Id: I271f2899db54a252d0d2a018cf4eb7877b97a02a
This commit is contained in:
parent
3825e72a3c
commit
33327b651f
5 changed files with 201 additions and 52 deletions
|
@ -1,22 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "private/bionic_time_conversions.h"
|
||||
|
||||
#define NS_PER_S 1000000000
|
||||
#include "private/bionic_constants.h"
|
||||
|
||||
bool timespec_from_timeval(timespec& ts, const timeval& tv) {
|
||||
// Whole seconds can just be copied.
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
|
||||
// But we might overflow when converting microseconds to nanoseconds.
|
||||
if (tv.tv_usec >= 1000000 || tv.tv_usec < 0) {
|
||||
return false;
|
||||
}
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
return true;
|
||||
}
|
||||
|
||||
void timespec_from_ms(timespec& ts, const int ms) {
|
||||
ts.tv_sec = ms / 1000;
|
||||
ts.tv_nsec = (ms % 1000) * 1000000;
|
||||
}
|
||||
|
||||
bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock) {
|
||||
clock_gettime(clock, &ts);
|
||||
ts.tv_sec = abs_ts.tv_sec - ts.tv_sec;
|
||||
ts.tv_nsec = abs_ts.tv_nsec - ts.tv_nsec;
|
||||
if (ts.tv_nsec < 0) {
|
||||
ts.tv_sec--;
|
||||
ts.tv_nsec += NS_PER_S;
|
||||
}
|
||||
if (ts.tv_nsec < 0 || ts.tv_sec < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
void timeval_from_timespec(timeval& tv, const timespec& ts) {
|
||||
tv.tv_sec = ts.tv_sec;
|
||||
tv.tv_usec = ts.tv_nsec / 1000;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <pthread.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdatomic.h>
|
||||
|
@ -18,10 +17,10 @@
|
|||
// XXX then the signal will be lost.
|
||||
|
||||
// We use one bit in pthread_condattr_t (long) values as the 'shared' flag
|
||||
// and one bit for the clock type (CLOCK_REALTIME is ((clockid_t) 1), and
|
||||
// CLOCK_MONOTONIC is ((clockid_t) 0).). The rest of the bits are a counter.
|
||||
// and one bit for the clock type (CLOCK_REALTIME is 0 and
|
||||
// CLOCK_MONOTONIC is 1). The rest of the bits are a counter.
|
||||
//
|
||||
// The 'value' field pthread_cond_t has the same layout.
|
||||
// The 'value' field in pthread_cond_t has the same layout.
|
||||
|
||||
#define COND_SHARED_MASK 0x0001
|
||||
#define COND_CLOCK_MASK 0x0002
|
||||
|
@ -80,8 +79,8 @@ struct pthread_cond_internal_t {
|
|||
return COND_IS_SHARED(atomic_load_explicit(&state, memory_order_relaxed));
|
||||
}
|
||||
|
||||
int get_clock() {
|
||||
return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed));
|
||||
bool use_realtime_clock() {
|
||||
return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed)) == CLOCK_REALTIME;
|
||||
}
|
||||
|
||||
#if defined(__LP64__)
|
||||
|
@ -139,12 +138,17 @@ static int __pthread_cond_pulse(pthread_cond_internal_t* cond, int thread_count)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __pthread_cond_timedwait_relative(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
|
||||
const timespec* rel_timeout_or_null) {
|
||||
unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
|
||||
static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
|
||||
bool use_realtime_clock, const timespec* abs_timeout_or_null) {
|
||||
int result = check_timespec(abs_timeout_or_null, true);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
|
||||
pthread_mutex_unlock(mutex);
|
||||
int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state, rel_timeout_or_null);
|
||||
int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state,
|
||||
use_realtime_clock, abs_timeout_or_null);
|
||||
pthread_mutex_lock(mutex);
|
||||
|
||||
if (status == -ETIMEDOUT) {
|
||||
|
@ -153,21 +157,6 @@ static int __pthread_cond_timedwait_relative(pthread_cond_internal_t* cond, pthr
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
|
||||
const timespec* abs_timeout_or_null, clockid_t clock) {
|
||||
timespec ts;
|
||||
timespec* rel_timeout = NULL;
|
||||
|
||||
if (abs_timeout_or_null != NULL) {
|
||||
rel_timeout = &ts;
|
||||
if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return __pthread_cond_timedwait_relative(cond, mutex, rel_timeout);
|
||||
}
|
||||
|
||||
int pthread_cond_broadcast(pthread_cond_t* cond_interface) {
|
||||
return __pthread_cond_pulse(__get_internal_cond(cond_interface), INT_MAX);
|
||||
}
|
||||
|
@ -178,14 +167,14 @@ int pthread_cond_signal(pthread_cond_t* cond_interface) {
|
|||
|
||||
int pthread_cond_wait(pthread_cond_t* cond_interface, pthread_mutex_t* mutex) {
|
||||
pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
|
||||
return __pthread_cond_timedwait(cond, mutex, NULL, cond->get_clock());
|
||||
return __pthread_cond_timedwait(cond, mutex, false, nullptr);
|
||||
}
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond_interface, pthread_mutex_t * mutex,
|
||||
const timespec *abstime) {
|
||||
|
||||
pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
|
||||
return __pthread_cond_timedwait(cond, mutex, abstime, cond->get_clock());
|
||||
return __pthread_cond_timedwait(cond, mutex, cond->use_realtime_clock(), abstime);
|
||||
}
|
||||
|
||||
#if !defined(__LP64__)
|
||||
|
@ -194,8 +183,7 @@ extern "C" int pthread_cond_timedwait_monotonic(pthread_cond_t* cond_interface,
|
|||
pthread_mutex_t* mutex,
|
||||
const timespec* abs_timeout) {
|
||||
|
||||
return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, abs_timeout,
|
||||
CLOCK_MONOTONIC);
|
||||
return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
|
||||
}
|
||||
|
||||
extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface,
|
||||
|
@ -204,11 +192,18 @@ extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interfac
|
|||
return pthread_cond_timedwait_monotonic(cond_interface, mutex, abs_timeout);
|
||||
}
|
||||
|
||||
// Force this function using CLOCK_MONOTONIC because it was always using
|
||||
// CLOCK_MONOTONIC in history.
|
||||
extern "C" int pthread_cond_timedwait_relative_np(pthread_cond_t* cond_interface,
|
||||
pthread_mutex_t* mutex,
|
||||
const timespec* rel_timeout) {
|
||||
|
||||
return __pthread_cond_timedwait_relative(__get_internal_cond(cond_interface), mutex, rel_timeout);
|
||||
timespec ts;
|
||||
timespec* abs_timeout = nullptr;
|
||||
if (rel_timeout != nullptr) {
|
||||
absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_MONOTONIC);
|
||||
abs_timeout = &ts;
|
||||
}
|
||||
return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
|
||||
}
|
||||
|
||||
extern "C" int pthread_cond_timeout_np(pthread_cond_t* cond_interface,
|
||||
|
|
22
libc/private/bionic_constants.h
Normal file
22
libc/private/bionic_constants.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _BIONIC_CONSTANTS_H_
|
||||
#define _BIONIC_CONSTANTS_H_
|
||||
|
||||
#define NS_PER_S 1000000000
|
||||
|
||||
#endif // _BIONIC_CONSTANTS_H_
|
|
@ -1,3 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _BIONIC_FUTEX_H
|
||||
#define _BIONIC_FUTEX_H
|
||||
|
||||
|
@ -13,10 +40,12 @@ __BEGIN_DECLS
|
|||
|
||||
struct timespec;
|
||||
|
||||
static inline __always_inline int __futex(volatile void* ftx, int op, int value, const struct timespec* timeout) {
|
||||
static inline __always_inline int __futex(volatile void* ftx, int op, int value,
|
||||
const struct timespec* timeout,
|
||||
int bitset) {
|
||||
// Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
|
||||
int saved_errno = errno;
|
||||
int result = syscall(__NR_futex, ftx, op, value, timeout);
|
||||
int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
|
||||
if (__predict_false(result == -1)) {
|
||||
result = -errno;
|
||||
errno = saved_errno;
|
||||
|
@ -25,19 +54,22 @@ static inline __always_inline int __futex(volatile void* ftx, int op, int value,
|
|||
}
|
||||
|
||||
static inline int __futex_wake(volatile void* ftx, int count) {
|
||||
return __futex(ftx, FUTEX_WAKE, count, NULL);
|
||||
return __futex(ftx, FUTEX_WAKE, count, NULL, 0);
|
||||
}
|
||||
|
||||
static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
|
||||
return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL);
|
||||
return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
|
||||
}
|
||||
|
||||
static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
|
||||
return __futex(ftx, FUTEX_WAIT, value, timeout);
|
||||
return __futex(ftx, FUTEX_WAIT, value, timeout, 0);
|
||||
}
|
||||
|
||||
static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value, const struct timespec* timeout) {
|
||||
return __futex(ftx, shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE, value, timeout);
|
||||
static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
|
||||
bool use_realtime_clock, const struct timespec* abs_timeout) {
|
||||
return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
|
||||
(use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
|
||||
FUTEX_BITSET_MATCH_ANY);
|
||||
}
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -1,14 +1,83 @@
|
|||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _BIONIC_TIME_CONVERSIONS_H
|
||||
#define _BIONIC_TIME_CONVERSIONS_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "private/bionic_constants.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
__LIBC_HIDDEN__ bool timespec_from_timeval(timespec& ts, const timeval& tv);
|
||||
__LIBC_HIDDEN__ void timespec_from_ms(timespec& ts, const int ms);
|
||||
__LIBC_HIDDEN__ bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock);
|
||||
|
||||
__LIBC_HIDDEN__ void timeval_from_timespec(timeval& tv, const timespec& ts);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
static inline int check_timespec(const timespec* ts, bool null_allowed) {
|
||||
if (null_allowed && ts == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
#if 1
|
||||
// HAX: Timespec checks are failing if tv_nsec < 1000000000L (aka 1 sec).
|
||||
// Take out each second from tv_nsec and add them to tv_sec till tv_nsec is
|
||||
// < 1000000000L such that tv_nsec doesn't overflow and passes check_timespec().
|
||||
while (ts->tv_nsec >= NS_PER_S) {
|
||||
const_cast<timespec*>(ts)->tv_nsec -= NS_PER_S;
|
||||
const_cast<timespec*>(ts)->tv_sec += 1;
|
||||
}
|
||||
#endif
|
||||
// glibc just segfaults if you pass a null timespec.
|
||||
// That seems a lot more likely to catch bad code than returning EINVAL.
|
||||
if (ts->tv_nsec < 0 || ts->tv_nsec >= NS_PER_S) {
|
||||
return EINVAL;
|
||||
}
|
||||
if (ts->tv_sec < 0) {
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(__LP64__)
|
||||
static inline void absolute_timespec_from_timespec(timespec& abs_ts, const timespec& ts, clockid_t clock) {
|
||||
clock_gettime(clock, &abs_ts);
|
||||
abs_ts.tv_sec += ts.tv_sec;
|
||||
abs_ts.tv_nsec += ts.tv_nsec;
|
||||
if (abs_ts.tv_nsec >= NS_PER_S) {
|
||||
abs_ts.tv_nsec -= NS_PER_S;
|
||||
abs_ts.tv_sec++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue