Может я чего не понимаю, но распределением памяти
должен заниматься линковщик, по идее. Нет?
Но нашел только вот такое, на вид не то.
man ld
--stack reserve
--stack reserve,commit
Specify the amount of memory to reserve
(and optionally commit) to be used as stack for this
program. The default is 2Mb reserved, 4K committed.
[This option is specific to the i386 PE targeted port
of the linker]
setrlimit и ко не помоголи. :-O
Вообще проблема какая-то странная.
#include <iostream>
#include <sys/resource.h>
int main()
{
rlimit rl;
getrlimit(RLIMIT_STACK, &rl);
std::cout << rl.rlim_cur << std::endl;
rl.rlim_cur = 100000;
setrlimit(RLIMIT_STACK, &rl);
char a[10000];
return 0;
}
g++ -o test -fstack-check test.cpp
./test
8388608
Segmentation fault
g++ -o test test.cpp
./test
8388608
Кто-нибудь может объяснить, что это значит? Стека ну всяко достаточно.
Понятно. Действительно, в ELF размер стека НЕ прописывается. Любая
программа должна сама себе выставлять кастомный размер стека, если
нужно.
> Стека ну всяко достаточно.
Дык как же достаточно, когда ты выставляешь его в 10000 вот здесь:
rl.rlim_cur = 100000;
setrlimit(RLIMIT_STACK, &rl);
и пытаешься выделить фрейм в 10000 байт:
char a[10000];
Было 8388608, стало 10000 - слишком мало для такого массива. Что же
тут непонятного?
100к не достаточно для выделения 10к? Сомневаюсь. В любом случае, даже если уставить значение по умолчанию 8М - ничего не меняется.
Ощущение, что стек улетает в пустоту, нет проверки все замечательно(?), есть - стек не валиден...
Вы на код посмотрите!
char a[] объявлен после вызова setrlimit, но g++ стек под переменные выделяет, до вызова setrlimit.
Если сделать так:
#include <iostream>
#include <sys/resource.h>
void aaa()
{
char a[10000];
memset(a,0,sizeof(a));
}
int main()
{
rlimit rl;
getrlimit(RLIMIT_STACK, &rl);
std::cout << rl.rlim_cur << std::endl;
rl.rlim_cur = 100000;
setrlimit(RLIMIT_STACK, &rl);
aaa();
std::cout << "Ok\n";
return 0;
}
то все работает.
>то все работает.
внимательней читай вопрос. смотри:
bash-2.05b$ cat test2.cc
#include <iostream>
#include <sys/resource.h>
void aaa()
{
char a[10000];
memset(a,0,sizeof(a));
}
int main()
{
rlimit rl;
getrlimit(RLIMIT_STACK, &rl);
std::cout << rl.rlim_cur << std::endl;
rl.rlim_cur = 100000;
setrlimit(RLIMIT_STACK, &rl);
aaa();
std::cout << "Ok\n";
return 0;
}
bash-2.05b$ g++ -g -o test2 -fstack-check test2.cc
bash-2.05b$ gdb ./test2
GNU gdb 6.1.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i486-slackware-linux"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) run
Starting program: /opt/home/cvv/tmp/cc/test2
8388608
Program received signal SIGSEGV, Segmentation fault.
0x08048831 in aaa () at test2.cc:6
6 char a[10000];
(gdb) The program is running. Exit anyway? (y or n) y
bash-2.05b$
Гррр... я как-то смотрел этот момент. Мне казалось, что при -fstack-check gcc правильно инициализирует стек, чтобы не было выхода за границу стека. Сейчас проверил - ни без -fstack-check ни с оным, gcc не проверяет. Чудеса да и только ...
Т.е. просто esp уменьшается на размер локальных переменных, что приводит к тому, что linux отлавливает все страничные исключения и расширяет stack VMA.
Если же сделать fstack-check, то попытается сделать commit всех страниц под локальные переменные, но esp уменьшит __после__ commit, что, естественно, при большом общем размере локальных переменных приведет к тому, что linux зафиксирует page fault не под esp и как следствие не поймет, куда обращались, и отправит SIGSEGV.
По-моему, когда-то это работало правильно, т.е. esp уменьшался перед commit.