Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-15795

Stack exceeded if pthread_attr_setstacksize(&thr_attr,8196) succeeds

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open (View Workflow)
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 10.2
    • Fix Version/s: 10.2
    • Component/s: Server
    • Labels:
      None

      Description

      mysys/thr_timer.c contains this code:

       67 my_bool init_thr_timer(uint alloc_timers)
       68 {
       ...
       88   pthread_attr_setstacksize(&thr_attr,8196);
       ...
       90   if (mysql_thread_create(key_thread_timer, &timer_thread, &thr_attr,
       91                           timer_handler, NULL))
      

      On Linux the pthread_attr_setstacksize() call on line 88 fails due to `EINVAL The stack size is less than PTHREAD_STACK_MIN (16384) bytes.`, the error is being ignored by the code and so the fact that the thread actually uses more than 8196 bytes of stack remains unnoticed.

      On FreeBSD the call is accepted and the thread's stack size is indeed capped to 8196 bytes (btw, 2^13 is 8192, why 8196 is used!?). Then the stack is exceeded and a crash occurs during e.g. `mysqld --help --verbose`.

      Apply this patch to demonstrate the problem, either by printing the bytes that were overwritten beyond the 8196-th byte or by causing a segfault the moment the overflow occurs:

      diff --git i/mysys/thr_timer.c w/mysys/thr_timer.c
      index b8726617f44..551b0a7b381 100644
      --- i/mysys/thr_timer.c
      +++ w/mysys/thr_timer.c
      @@ -20,12 +20,13 @@
       */
       
       #include "mysys_priv.h"
       #include "thr_timer.h"
       #include <m_string.h>
       #include <queues.h>
      +#include <stdint.h>
       #ifdef HAVE_TIMER_CREATE
       #include <sys/syscall.h>
       #endif
       
       struct timespec next_timer_expire_time;
       
      @@ -61,12 +62,18 @@ static int compare_timespec(void *not_used __attribute__((unused)),
         @return 0 ok
         @return 1 error; Can't create thread
       */
       
       static thr_timer_t max_timer_data;
       
      +static void* buf;
      +const size_t malloc_size = 128*1024;
      +const size_t pre_size = 16*1024;
      +const size_t stack_size = 8196;
      +const int magic_byte = 0xf7;
      +
       my_bool init_thr_timer(uint alloc_timers)
       {
         pthread_attr_t thr_attr;
         my_bool res= 0;
         DBUG_ENTER("init_thr_timer");
       
      @@ -82,13 +89,22 @@ my_bool init_thr_timer(uint alloc_timers)
         queue_insert(&timer_queue, (uchar*) &max_timer_data);
         next_timer_expire_time= max_timer_data.expire_time;
       
         /* Create a thread to handle timers */
         pthread_attr_init(&thr_attr);
         pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
      -  pthread_attr_setstacksize(&thr_attr,8196);
      +
      +  buf = malloc(malloc_size);
      +  DBUG_ASSERT(buf != NULL);
      +  memset(buf, magic_byte, malloc_size);
      +  int ret;
      +  //ret = mprotect(buf, pre_size, PROT_NONE);
      +  //DBUG_ASSERT(ret == 0);
      +  ret = pthread_attr_setstack(&thr_attr, (char*)buf + pre_size, stack_size);
      +  DBUG_ASSERT(ret == 0);
      +
         thr_timer_inited= 1;
         if (mysql_thread_create(key_thread_timer, &timer_thread, &thr_attr,
                                 timer_handler, NULL))
         {
           thr_timer_inited= 0;
           res= 1;
      @@ -112,12 +128,25 @@ void end_thr_timer(void)
         mysql_mutex_lock(&LOCK_timer);
         thr_timer_inited= 0;                          /* Signal abort */
         mysql_cond_signal(&COND_timer);
         mysql_mutex_unlock(&LOCK_timer);
         pthread_join(timer_thread, NULL);
       
      +  for (size_t i = 0; i < pre_size; i++) {
      +    const unsigned char c = *((unsigned char*)buf + i);
      +    if (i > 0 && i % 16 == 0) {
      +      fprintf(stderr, "\n");
      +    }
      +    if (c == magic_byte) {
      +      fprintf(stderr, "__ ");
      +    } else {
      +      fprintf(stderr, "%02hhx ", c);
      +    }
      +  }
      +  fprintf(stderr, "\n");
      +
         mysql_mutex_destroy(&LOCK_timer);
         mysql_cond_destroy(&COND_timer);
         delete_queue(&timer_queue);
         DBUG_VOID_RETURN;
       }
       
      

        Attachments

          Activity

            People

            Assignee:
            serg Sergei Golubchik
            Reporter:
            Dimov Vasil
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated: