LINUX.ORG.RU

Размер стека для exec.... Какой правильный?


0

0

У меня неожиданно возникла проблема: программа в main, сразу после
начала выполнения, выполняет fork-exec, предварительно установив
для себя размер стека 900'000 байт. Все прекрасно работало на многих
системах - RH8,9, Mandrake8,9.2,10, Fedora2. Но вдруг обнаружилось,
что на Fedora1 происходит SIGSEGV сразу после exec. Backtrace в
отладчике отсутствовал, текущая функция - _dl_sysinfo_int80.
Запускаемая программа даже не начинала исполняться (во
всяком случае, до ее main-а управление не доходило). Ничего не
помогало, пока я не догадался подкрутить rlimit для стека. Стоило
сделать его 2'000'000 байт, и все стало замечательно работать.
Повторюсь - это только на Fedora2. Вот и вопрос: в чему тут может
быть дело? Я хочу поковырять сорцы glibc от FC2, но вопрос несколько
более принципиальный - как управлять стеком? Какой остаток его будет
достаточен для fork-exec?

> Я хочу поковырять сорцы glibc от FC2,

возможно, вам нужно смотреть исходники kernel. никто
не знает, что там меняет readhat. 900K, разумеется
более чем достаточно для fork()+exec().

вообще-то, аргументы программы, environment также
кладутся в стек, но макс размер 32 страницы, что меньше
900K.

много аргументов передаете? чему равно MAX_ARG_PAGES
в include/linux/binfmts.h. только смотрите этот файл
в исходниках ядра, на котором это происходит.

хотя вряд ли в этом дело...

idle ★★★★★
()

>Все прекрасно работало на многих системах - RH8,9, Mandrake8,9.2,10, Fedora2.

Там опечатка? Подразумевается Fedora1?

А какое значение по умолчанию (getrlimit) в этой самой Fedora2? 900к должно хватать, где то ошибка, может и в glibc...

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

2mky: ээ, опечатка, да. Не работает на FC_1_, на второй (Fedora Core 2) - все прекрасно.

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

Значение по умолчанию - 10 мегабайт.

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

2idle. Посмотрел, MAX_ARG_PAGES=32.

Аргументов вообще никаких не передаю. Вот программа:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <limits.h>
#include <values.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

int main() {
    const char* curdir;
    pid_t pid;
    int status, res;

    struct rlimit lim;
    getrlimit(RLIMIT_STACK, &lim);
    printf("Stack size: %d\n", lim.rlim_cur);
    lim.rlim_cur = 900000;
    setrlimit(RLIMIT_STACK, &lim);
    printf("New stack size: %d\n", lim.rlim_cur);

    curdir = ".";

    fprintf(stderr, "[exec] curdir  : %s\n", curdir);

    if((pid = fork()) < 0) {
        fprintf(stderr, "[exec] fork failed: %s\n", strerror(errno));
        fflush(stderr);
        assert(0);
    }

    if(pid == 0) {

        //
        // child
        //

        char *shell[] = {"./hello", NULL};

        // change current directory
        if(curdir && chdir(curdir) < 0) {
            fprintf(stderr, "[exec] chdir failed: %s\n", strerror(errno));
            fflush(stderr);
            _exit(253);
        }

        execvp(shell[0], shell);

        // return of execvp() means an error
        fprintf(stderr, "[exec] exec (%s) failed: %s\n", shell[0], strerror(errno));
        fflush(stderr);

        _exit(251);
    }

    //
    // parent
    //

    if((res = waitpid(pid, &status, 0)) < 0) {
        fprintf(stderr, "[exec] waitpid failed: %s\n", strerror(errno));
        fflush(stderr);
        return -1;
    }

    if(res != 0) {
        // child has exited
        if(!WIFEXITED(status)) {
            fprintf(stderr, "[exec] Child has been terminated. Status: %d\n", status);
            fflush(stderr);
            return -1;
        }

        if(WEXITSTATUS(status) != 0) {
            fprintf(stderr, "[exec] Child has exited, exitcode == %d\n", WEXITSTATUS(status));
            fflush(stderr);
            return -1;
        }
    }

    return 0;
}

hello - крохотная программа, печатающая "Hello world" в терминал.
В половине случаев случается segmentation fault в ветке pid==0...
В другой половине - все хорошо.

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

да вроде все правильно, на первый взгляд...

какое ядро?

все таки, после setrlimit() сделайте еще раз getrlimit,
и распечатайте и cur и max, вдруг что-то странное.

посмотрите core, какой размер использованного стэка?

> Backtrace в отладчике отсутствовал, текущая функция
> - _dl_sysinfo_int80.

это просто вызов int 80, нужна для переключения между
sysenter и int способами входа ядро. что в регистре eax?

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

кстати, почему бы вам не упростить программу,
выкинуть chdir, fork. или перестает ломаться?

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