nixp.ru v3.0

25 мая 2017,
четверг,
19:20:36 MSK

DevOps с компанией «Флант»
Аватар пользователя metal
metal написал 8 мая 2008 года в 23:43 (395 просмотров) Ведет себя как мужчина; открыл 31 тему в форуме, оставил 1547 комментариев на сайте.

Вот задумался я, а что будет если исчерпается размер стека, написал маленькую программку:

#include
void f(unsigned long long count)
{
      try
      {
        char buffer[1024 *1024];
      std::cout << "count=" << count << 'M' << std::endl;
      //sleep(1);
      f( count + 1);
      }
      catch(...)
      {
            std::cout << "catch exception" << std::endl;
      }
}
int main(int argc,char* argv[])
{
      f(1);
      return 0;
}

Собираю: g++ main.cpp -o pkillself

Результат:

count=1M

count=2M

count=3M

count=4M

count=5M

count=6M

count=7M

Ошибка сегментирования (core dumped)

Собираю: g++ main.cpp -O2 -o pkillself

Результат:

count=24945M

count=24946M

count=24947M

count=24948M

count=24949M

count=24950M

count=24951M

Ошибка сегментирования (core dumped)

Вот у меня возникло 2 вопроса:

1) Как недопустить ошибки сегментирования?

2) Откуда такие не реальные объемы памяти?

sas

На Юникс подобных системах ulimit определяет размер стека (стандартно насколько я знаю это 8Мб). Можно попробывать:

ulimit -s unlimited

IMHO не существует стандартного пути для предотвращения seg fault в случае переполнения стека для C/C++. Библиотеки для контроля за переполнением буферов насколько я знаю этим тоже не занимаются.

Вообще лучше всего не использовать рекурсию и большие обьекты в стеке (да Вы и сами это знаете).

Код:

static const int MB = 1024 * 1024;
void f(unsigned long long count)
{
      try {
        char buffer[ MB ];
        std::fill( buffer, buffer + MB, '\0' );
        std::cout << "count=" << count << 'M' << std::endl;
        f( ++count );
      }
      catch(...) {
            std::cout << "catch exception" << std::endl;
      }
}

Даст ответ на 2–й вопрос.

Удачи

––– sas

rgo
metal
Вот у меня возникло 2 вопроса:

1) Как недопустить ошибки сегментирования?

RedZone? Или как там это называется? Посмотри что это такое, потом расскажешь ;)

metal
2) Откуда такие не реальные объемы памяти?

Функции f

_Z1fy:
.LFB1435:
      pushq      %rbx      #
.LCFI1:
      movl      $.LC0, %esi      #,
      movq      %rdi, %rbx      # count, count
      movl      $_ZSt4cout, %edi      #,
.LEHB0:
      call      _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc      #
      movq      %rax, %rdi      #, D.30670
      movq      %rbx, %rsi      # count, count
      call      _ZNSolsEy      #
      movq      %rax, %rdi      #, D.30671
      movl      $77, %esi      #,
      call      _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c      #
      movq      %rax, %rdi      #, this
      call      _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_      #
      leaq      1(%rbx), %rdi      #, tmp67
      call      _Z1fy      #
.LEHE0:
      popq      %rbx      #
      ret

Этот код не резервирует место под buffer. По ходу дела, g++ замечательно этот buffer соптимизировал. Каждый рекурсивный вызов откушивает от стека sizeof(long long) байт под аргумент вызова count.

metal

Всем спасибо!

1) По stack redzone, мало что нашел, но в общем идея понятна. Странно что с++ не генерирует ошибку в случае переполнения стека, это было бы логично. Вероятно из соображений проиводительности.

2) Да, что-то я не учел подлянки оптимизации:)

newcomer
metal
Странно что с++ не генерирует ошибку в случае переполнения стека

Может ещё C++ будет сборкой мусора заниматься… ;-)

metal
newcomer
Может ещё C++ будет сборкой мусора заниматься… ;-)

Да вообще занимается если надо.

newcomer
metal
Да вообще занимается если надо.

Во и со стеком точно также. Если надо…

С++ как и С ничего не делает за программера, он тоже расчитан быть использован в системном программировании.