LINUX.ORG.RU

напрягшись, телепатически мне удалось прочитать пару невысказанных слов и предположить, что речь идёт о C/C++ и gcc...

дай плиз ссылочку на раздел справки gcc, где говорится про --stack, а?

man setrlimit
man pthread_attr_setstack

помогут...

jek_
()
Ответ на: комментарий от jek_

Может я чего не понимаю, но распределением памяти 
должен заниматься линковщик, по идее. Нет?
Но нашел только вот такое, на вид не то.
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

Кто-нибудь может объяснить, что это значит? Стека ну всяко достаточно.

anonymous
()
Ответ на: комментарий от anonymous

Понятно. Действительно, в ELF размер стека НЕ прописывается. Любая
программа должна сама себе выставлять кастомный размер стека, если
нужно.

> Стека ну всяко достаточно.

Дык как же достаточно, когда ты выставляешь его в 10000 вот здесь:

        rl.rlim_cur = 100000;
        setrlimit(RLIMIT_STACK, &rl);

и пытаешься выделить фрейм в 10000 байт:

        char a[10000];
 
Было 8388608, стало 10000 - слишком мало для такого массива. Что же
тут непонятного?

jek_
()
Ответ на: комментарий от jek_

100к не достаточно для выделения 10к? Сомневаюсь. В любом случае, даже если уставить значение по умолчанию 8М - ничего не меняется. Ощущение, что стек улетает в пустоту, нет проверки все замечательно(?), есть - стек не валиден...

anonymous
()
Ответ на: комментарий от anonymous

А, пардон, я пятый нолик не увидел... Можно посмотреть в gdb или сгенерированный код, в чём может быть причина такого поведения.

jek_
()
Ответ на: комментарий от cvv

Вы на код посмотрите!

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;
}

то все работает.

kosmonavt
()
Ответ на: комментарий от kosmonavt

>то все работает.

внимательней читай вопрос. смотри:

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$

cvv ★★★★★
()
Ответ на: комментарий от cvv

Гррр... я как-то смотрел этот момент. Мне казалось, что при -fstack-check gcc правильно инициализирует стек, чтобы не было выхода за границу стека. Сейчас проверил - ни без -fstack-check ни с оным, gcc не проверяет. Чудеса да и только ...

Murr ★★
()
Ответ на: комментарий от kosmonavt

Вроде в man про gcc сказано, что если использовать fstack-check, "это ключ фактически не делает проверку, проверку должна выполнять ОС"

А по ссылке https://bugzilla.redhat.com/beta/show_bug.cgi?id=98687 сказано, что "This is not allowed by the kernel (do_page_fault () in arch/i386/mm/fault.c)" и, что эту опцию надо выкинуть.

mky ★★★★★
()
Ответ на: комментарий от Murr

Интересно, что без fstack-check gcc генерирует правильный код в отличие от с fstack-check:

void aaa()
{
080483f4 <aaa> push ebp
080483f5 <aaa+0x1> mov ebp,esp
080483f7 <aaa+0x3> sub esp,0x30d48
char a[200000];
memset(a,0,sizeof(a));
080483fd <aaa+0x9> sub esp,0x4
08048400 <aaa+0xc> push 0x30d40
08048405 <aaa+0x11> push 0x0
08048407 <aaa+0x13> lea eax,[ebp-200008]
0804840d <aaa+0x19> push eax
0804840e <aaa+0x1a> call 0804832c <memset@plt>
08048413 <aaa+0x1f> add esp,0x10
}
08048416 <aaa+0x22> leave
08048417 <aaa+0x23> ret


Т.е. просто esp уменьшается на размер локальных переменных, что приводит к тому, что linux отлавливает все страничные исключения и расширяет stack VMA.

Если же сделать fstack-check, то попытается сделать commit всех страниц под локальные переменные, но esp уменьшит __после__ commit, что, естественно, при большом общем размере локальных переменных приведет к тому, что linux зафиксирует page fault не под esp и как следствие не поймет, куда обращались, и отправит SIGSEGV.

По-моему, когда-то это работало правильно, т.е. esp уменьшался перед commit.

Murr ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.