1From 9171c2495b1a05eabaeb0afeee629682cc6f5bac Mon Sep 17 00:00:00 2001 2From: Adhemerval Zanella <adhemerval.zanella@linaro.org> 3Date: Mon, 5 Oct 2020 17:30:05 -0300 4Subject: [PATCH 15/20] posix: Fix -Warray-bounds instances building 5 timer_create [BZ #26687] 6 7GCC 11 -Warray-bounds triggers invalid warnings when building 8Linux timer_create.c: 9 10../sysdeps/unix/sysv/linux/timer_create.c: In function '__timer_create_new': 11../sysdeps/unix/sysv/linux/timer_create.c:83:17: warning: array subscript 'struct timer[0]' is partly outside array bounds of 'unsigned char[8]' [-Warray-bounds] 12 83 | newp->sigev_notify = (evp != NULL 13 | ^~ 14../sysdeps/unix/sysv/linux/timer_create.c:59:47: note: referencing an object of size 8 allocated by 'malloc' 15 59 | struct timer *newp = (struct timer *) malloc (offsetof (struct timer, 16 | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 17 60 | thrfunc)); 18 | ~~~~~~~~~ 19 20The struct allocated for !SIGEV_THREAD timers only requires two 'int' 21fields (sigev_notify and ktimerid) and the offsetof trick tries minimize 22the memory usage by only allocation the required size. However, 23although the resulting size is suffice for !SIGEV_THREAD time, accessing 24the partially allocated object is error-prone and UB. 25 26This patch fixes both issues by embedding the information whether 27the timer if a SIGEV_THREAD in the returned 'timer_t'. For 28!SIGEV_THREAD, the resulting 'timer_t' is the returned kernel timer 29identifer (kernel_timer_t), while for SIGEV_THREAD it uses the fact 30malloc returns at least _Alignof (max_align_t) pointers plus that 31valid kernel_timer_t are always positive to set MSB bit of the returned 32'timer_t' to indicate the timer handles a SIGEV_THREAD. 33 34It allows to remove the memory allocation for !SIGEV_THREAD and also 35remove the 'sigev_notify' field from 'struct timer'. 36 37Checked on x86_64-linux-gnu and i686-linux-gnu. 38 39(cherry picked from commit 7a887dd537cd00fe3cdf42b788b3f0e3b430b0ed) 40Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 41--- 42 sysdeps/unix/sysv/linux/kernel-posix-timers.h | 52 ++++++++++--- 43 sysdeps/unix/sysv/linux/timer_create.c | 74 ++++++------------- 44 sysdeps/unix/sysv/linux/timer_delete.c | 15 ++-- 45 sysdeps/unix/sysv/linux/timer_getoverr.c | 8 +- 46 sysdeps/unix/sysv/linux/timer_gettime.c | 4 +- 47 sysdeps/unix/sysv/linux/timer_settime.c | 4 +- 48 6 files changed, 76 insertions(+), 81 deletions(-) 49 50diff --git a/sysdeps/unix/sysv/linux/kernel-posix-timers.h b/sysdeps/unix/sysv/linux/kernel-posix-timers.h 51index 31f51997..ad998235 100644 52--- a/sysdeps/unix/sysv/linux/kernel-posix-timers.h 53+++ b/sysdeps/unix/sysv/linux/kernel-posix-timers.h 54@@ -43,21 +43,11 @@ extern pthread_mutex_t __active_timer_sigev_thread_lock attribute_hidden; 55 /* Type of timers in the kernel. */ 56 typedef int kernel_timer_t; 57 58- 59-/* Internal representation of timer. */ 60+/* Internal representation of SIGEV_THREAD timer. */ 61 struct timer 62 { 63- /* Notification mechanism. */ 64- int sigev_notify; 65- 66- /* Timer ID returned by the kernel. */ 67 kernel_timer_t ktimerid; 68 69- /* All new elements must be added after ktimerid. And if the thrfunc 70- element is not the third element anymore the memory allocation in 71- timer_create needs to be changed. */ 72- 73- /* Parameters for the thread to be started for SIGEV_THREAD. */ 74 void (*thrfunc) (sigval_t); 75 sigval_t sival; 76 pthread_attr_t attr; 77@@ -65,3 +55,43 @@ struct timer 78 /* Next element in list of active SIGEV_THREAD timers. */ 79 struct timer *next; 80 }; 81+ 82+ 83+/* For !SIGEV_THREAD, the resulting 'timer_t' is the returned kernel timer 84+ identifer (kernel_timer_t), while for SIGEV_THREAD it uses the fact malloc 85+ returns at least _Alignof (max_align_t) pointers plus that valid 86+ kernel_timer_t are always positive to set the MSB bit of the returned 87+ 'timer_t' to indicate the timer handles a SIGEV_THREAD. */ 88+ 89+static inline timer_t 90+kernel_timer_to_timerid (kernel_timer_t ktimerid) 91+{ 92+ return (timer_t) ((intptr_t) ktimerid); 93+} 94+ 95+static inline timer_t 96+timer_to_timerid (struct timer *ptr) 97+{ 98+ return (timer_t) (INTPTR_MIN | (uintptr_t) ptr >> 1); 99+} 100+ 101+static inline bool 102+timer_is_sigev_thread (timer_t timerid) 103+{ 104+ return (intptr_t) timerid < 0; 105+} 106+ 107+static inline struct timer * 108+timerid_to_timer (timer_t timerid) 109+{ 110+ return (struct timer *)((uintptr_t) timerid << 1); 111+} 112+ 113+static inline kernel_timer_t 114+timerid_to_kernel_timer (timer_t timerid) 115+{ 116+ if (timer_is_sigev_thread (timerid)) 117+ return timerid_to_timer (timerid)->ktimerid; 118+ else 119+ return (kernel_timer_t) ((uintptr_t) timerid); 120+} 121diff --git a/sysdeps/unix/sysv/linux/timer_create.c b/sysdeps/unix/sysv/linux/timer_create.c 122index a49a546e..ad4b0d46 100644 123--- a/sysdeps/unix/sysv/linux/timer_create.c 124+++ b/sysdeps/unix/sysv/linux/timer_create.c 125@@ -52,16 +52,6 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) 126 { 127 struct sigevent local_evp; 128 129- /* We avoid allocating too much memory by basically 130- using struct timer as a derived class with the 131- first two elements being in the superclass. We only 132- need these two elements here. */ 133- struct timer *newp = (struct timer *) malloc (offsetof (struct timer, 134- thrfunc)); 135- if (newp == NULL) 136- /* No more memory. */ 137- return -1; 138- 139 if (evp == NULL) 140 { 141 /* The kernel has to pass up the timer ID which is a 142@@ -69,31 +59,17 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) 143 the kernel to determine it. */ 144 local_evp.sigev_notify = SIGEV_SIGNAL; 145 local_evp.sigev_signo = SIGALRM; 146- local_evp.sigev_value.sival_ptr = newp; 147+ local_evp.sigev_value.sival_ptr = NULL; 148 149 evp = &local_evp; 150 } 151 152 kernel_timer_t ktimerid; 153- int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp, 154- &ktimerid); 155- 156- if (retval != -1) 157- { 158- newp->sigev_notify = (evp != NULL 159- ? evp->sigev_notify : SIGEV_SIGNAL); 160- newp->ktimerid = ktimerid; 161- 162- *timerid = (timer_t) newp; 163- } 164- else 165- { 166- /* Cannot allocate the timer, fail. */ 167- free (newp); 168- retval = -1; 169- } 170+ if (INLINE_SYSCALL_CALL (timer_create, syscall_clockid, evp, 171+ &ktimerid) == -1) 172+ return -1; 173 174- return retval; 175+ *timerid = kernel_timer_to_timerid (ktimerid); 176 } 177 else 178 { 179@@ -106,20 +82,18 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) 180 return -1; 181 } 182 183- struct timer *newp; 184- newp = (struct timer *) malloc (sizeof (struct timer)); 185+ struct timer *newp = malloc (sizeof (struct timer)); 186 if (newp == NULL) 187 return -1; 188 189 /* Copy the thread parameters the user provided. */ 190 newp->sival = evp->sigev_value; 191 newp->thrfunc = evp->sigev_notify_function; 192- newp->sigev_notify = SIGEV_THREAD; 193 194 /* We cannot simply copy the thread attributes since the 195 implementation might keep internal information for 196 each instance. */ 197- (void) pthread_attr_init (&newp->attr); 198+ pthread_attr_init (&newp->attr); 199 if (evp->sigev_notify_attributes != NULL) 200 { 201 struct pthread_attr *nattr; 202@@ -137,8 +111,7 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) 203 } 204 205 /* In any case set the detach flag. */ 206- (void) pthread_attr_setdetachstate (&newp->attr, 207- PTHREAD_CREATE_DETACHED); 208+ pthread_attr_setdetachstate (&newp->attr, PTHREAD_CREATE_DETACHED); 209 210 /* Create the event structure for the kernel timer. */ 211 struct sigevent sev = 212@@ -150,27 +123,24 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) 213 /* Create the timer. */ 214 INTERNAL_SYSCALL_DECL (err); 215 int res; 216- res = INTERNAL_SYSCALL (timer_create, err, 3, 217- syscall_clockid, &sev, &newp->ktimerid); 218- if (! INTERNAL_SYSCALL_ERROR_P (res, err)) 219+ res = INTERNAL_SYSCALL_CALL (timer_create, syscall_clockid, &sev, 220+ &newp->ktimerid); 221+ if (INTERNAL_SYSCALL_ERROR_P (res, err)) 222 { 223- /* Add to the queue of active timers with thread 224- delivery. */ 225- pthread_mutex_lock (&__active_timer_sigev_thread_lock); 226- newp->next = __active_timer_sigev_thread; 227- __active_timer_sigev_thread = newp; 228- pthread_mutex_unlock (&__active_timer_sigev_thread_lock); 229- 230- *timerid = (timer_t) newp; 231- return 0; 232+ free (newp); 233+ __set_errno (INTERNAL_SYSCALL_ERRNO (res, err)); 234+ return -1; 235 } 236 237- /* Free the resources. */ 238- free (newp); 239- 240- __set_errno (INTERNAL_SYSCALL_ERRNO (res, err)); 241+ /* Add to the queue of active timers with thread delivery. */ 242+ pthread_mutex_lock (&__active_timer_sigev_thread_lock); 243+ newp->next = __active_timer_sigev_thread; 244+ __active_timer_sigev_thread = newp; 245+ pthread_mutex_unlock (&__active_timer_sigev_thread_lock); 246 247- return -1; 248+ *timerid = timer_to_timerid (newp); 249 } 250 } 251+ 252+ return 0; 253 } 254diff --git a/sysdeps/unix/sysv/linux/timer_delete.c b/sysdeps/unix/sysv/linux/timer_delete.c 255index e1eb1db5..be459dc3 100644 256--- a/sysdeps/unix/sysv/linux/timer_delete.c 257+++ b/sysdeps/unix/sysv/linux/timer_delete.c 258@@ -32,15 +32,15 @@ int 259 timer_delete (timer_t timerid) 260 { 261 #undef timer_delete 262- struct timer *kt = (struct timer *) timerid; 263- 264- /* Delete the kernel timer object. */ 265- int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid); 266+ kernel_timer_t ktimerid = timerid_to_kernel_timer (timerid); 267+ int res = INLINE_SYSCALL_CALL (timer_delete, ktimerid); 268 269 if (res == 0) 270 { 271- if (kt->sigev_notify == SIGEV_THREAD) 272+ if (timer_is_sigev_thread (timerid)) 273 { 274+ struct timer *kt = timerid_to_timer (timerid); 275+ 276 /* Remove the timer from the list. */ 277 pthread_mutex_lock (&__active_timer_sigev_thread_lock); 278 if (__active_timer_sigev_thread == kt) 279@@ -58,10 +58,9 @@ timer_delete (timer_t timerid) 280 prevp = prevp->next; 281 } 282 pthread_mutex_unlock (&__active_timer_sigev_thread_lock); 283- } 284 285- /* Free the memory. */ 286- (void) free (kt); 287+ free (kt); 288+ } 289 290 return 0; 291 } 292diff --git a/sysdeps/unix/sysv/linux/timer_getoverr.c b/sysdeps/unix/sysv/linux/timer_getoverr.c 293index 26f23e1d..0dfcbe81 100644 294--- a/sysdeps/unix/sysv/linux/timer_getoverr.c 295+++ b/sysdeps/unix/sysv/linux/timer_getoverr.c 296@@ -31,10 +31,6 @@ int 297 timer_getoverrun (timer_t timerid) 298 { 299 #undef timer_getoverrun 300- struct timer *kt = (struct timer *) timerid; 301- 302- /* Get the information from the kernel. */ 303- int res = INLINE_SYSCALL (timer_getoverrun, 1, kt->ktimerid); 304- 305- return res; 306+ kernel_timer_t ktimerid = timerid_to_kernel_timer (timerid); 307+ return INLINE_SYSCALL_CALL (timer_getoverrun, ktimerid); 308 } 309diff --git a/sysdeps/unix/sysv/linux/timer_gettime.c b/sysdeps/unix/sysv/linux/timer_gettime.c 310index 10a19d9e..a3e1981a 100644 311--- a/sysdeps/unix/sysv/linux/timer_gettime.c 312+++ b/sysdeps/unix/sysv/linux/timer_gettime.c 313@@ -32,10 +32,10 @@ int 314 timer_gettime (timer_t timerid, struct itimerspec *value) 315 { 316 #undef timer_gettime 317- struct timer *kt = (struct timer *) timerid; 318+ kernel_timer_t ktimerid = timerid_to_kernel_timer (timerid); 319 320 /* Delete the kernel timer object. */ 321- int res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value); 322+ int res = INLINE_SYSCALL (timer_gettime, 2, ktimerid, value); 323 324 return res; 325 } 326diff --git a/sysdeps/unix/sysv/linux/timer_settime.c b/sysdeps/unix/sysv/linux/timer_settime.c 327index 7c938bd4..7038e2a7 100644 328--- a/sysdeps/unix/sysv/linux/timer_settime.c 329+++ b/sysdeps/unix/sysv/linux/timer_settime.c 330@@ -33,10 +33,10 @@ timer_settime (timer_t timerid, int flags, const struct itimerspec *value, 331 struct itimerspec *ovalue) 332 { 333 #undef timer_settime 334- struct timer *kt = (struct timer *) timerid; 335+ kernel_timer_t ktimerid = timerid_to_kernel_timer (timerid); 336 337 /* Delete the kernel timer object. */ 338- int res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags, 339+ int res = INLINE_SYSCALL (timer_settime, 4, ktimerid, flags, 340 value, ovalue); 341 342 return res; 343-- 3442.20.1 345 346