Часть стека pthread, похоже, уже использована

#stack #pthreads

#стек #pthreads

Вопрос:

Я установил размер стека pthread в Linux равным 16 КБ. Если я затем добавлю в стек массив размером более 8 КБ, приложения остановятся из-за ошибки сегментации. Мне кажется, что я пытаюсь получить доступ к памяти ниже нижней части стека, которая, вероятно, является незамеченной памятью и, следовательно, ошибкой segfault.

Вот пример кода:

 #include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>

void *start_routine(void *arg)
{
  size_t size = 9*1024;
  unsigned char arr[size];

  memset(arr, 0, size);
}

int main()
{
  int err;
  pthread_attr_t threadAttr;
  size_t stacksize;
  void *stackAddr;
  pthread_t thread;

  pthread_attr_init(amp;threadAttr);
  pthread_attr_setstacksize(amp;threadAttr, 16*1024);
  pthread_attr_getstacksize(amp;threadAttr, amp;stacksize);
  printf("stacksize: %dn", stacksize);

  pthread_create(amp;thread, amp;threadAttr, start_routine, NULL );
  pthread_join(thread, NULL);

  return 0;
}  
  

Кажется странным, что я теряю около 8 КБ стека. Я пробовал также с немного большими размерами стека. Каким-то образом, кажется, зависит от того, какую часть стека я могу использовать.

Я знаю, что для современных систем (за исключением некоторых встроенных систем) эти несколько байтов на самом деле не важны, но мне просто любопытно, почему я не могу использовать большую часть определенного стека. Я не ожидаю, что смогу использовать весь стек, но потеря около 8 КБ кажется довольно большой.

Какая информация помещается в стек потока перед вызовом процедуры ввода?

Спасибо, Филипп

Комментарии:

1. Я без проблем компилирую и запускаю программу, используя gcc на macOS.

2. Единственное, о чем я могу подумать, это то, что вы можете проверить, что возвращаемое значение pthread_attr_setstacksize(…) == 0. На странице руководства указано, что она возвращает -1 и присваивает errno значение EINVAL, если вы пытаетесь установить размер стека выше некоторого установленного системой ограничения. Хотя это кажется маловероятным.

3. Взгляните на результат ulimit -s — вы, вероятно, не получаете целых 16 КБ на поток.

4. @Kevin Интересно знать, что вы можете запускать программу на macOS. Может быть, вы можете попробовать увеличить размер массива и посмотреть, как далеко вы сможете продвинуться?

5. @Kevin Функция pthread_attr_setstacksize возвращает 0. И дополнительно у меня есть запрос stacksize с помощью pthread_attr_getstacksize. Кажется, это нормально.

Ответ №1:

После некоторого изучения исходного кода glibc nptl я прихожу к выводу, что в нижней части стека находится pthread-struct потока, которому принадлежит стек, и, вероятно, некоторые другие переменные, зависящие от конфигурации glibc. Они используют вместе около 3 Тыс. Верхняя часть стека заполнена защитной страницей, которая обычно имеет размер 4K. Таким образом, уже используется около 7-8 Тыс. Я немного удивлен, что, по крайней мере, память для страницы guard не выделяется отдельно. В верхней части моей головы я думал вспомнить, что это было бы так, но это не так.