Перегрузочная вилка( )

Я перегрузил системный вызов fork() и создал собственную версию fork(), используя RTLD_NEXT. То есть dlsym(RTLD_NEXT, fork). Это ударит по моей версии форка. После этого я хочу воспроизвести задачу реального системного вызова fork(), то есть создать дочерний процесс и вернуть pid, а также еще некоторые дополнительные функции.

Я не могу понять, как это сделать. Я проверил исходный код ядра для fork() (fork.c) и не смог многого понять.

Делая это:

dlsym(RTLD_NEXT,fork);  
int fork(void) {
    int pid=_fork(); // Trying to call actual fork does not work
    return pid;
}

Как я могу это сделать? Вот ссылка на исходный код ядра для форка: http://lxr.linux.no/linux+v2.6.32/kernel/fork.c#L10

Изменить (извлечено из комментариев):

Я работаю над инструментом обнаружения утечек, и этот инструмент обнаруживает двойное освобождение, когда дочерний процесс удаляет память, выделенную родителем. Чтобы преодолеть это, я переопределю fork(), и всякий раз, когда есть fork(), родительская таблица распределения памяти будет дублироваться дочерней.


person RajSanpui    schedule 02.02.2011    source источник
comment
Что вы имеете в виду под не работает? Ошибки во время выполнения? Ошибки компилятора?   -  person Simone    schedule 02.02.2011
comment
@Simone: _fork(); // Ошибка: _fork не был объявлен. Моя идея заключалась в том, чтобы сделать так, чтобы он попадал в настоящую версию ядра форка, а не в мою. Надеюсь теперь понятно.   -  person RajSanpui    schedule 02.02.2011
comment
Чего именно вы хотите добиться, делая это? Какова ваша конечная цель?   -  person Omnifarious    schedule 02.02.2011
comment
@Omnifarious: я хочу добавить некоторые функции к существующему вызову fork(), который будет использоваться одним из моих инструментов.   -  person RajSanpui    schedule 02.02.2011
comment
Почему бы не использовать макрос? В файле .c: int my_fork(void) { /* do stuff */; return fork(); } А в шапке: extern int my_fork(void); #define fork my_fork.   -  person Chris Lutz    schedule 02.02.2011
comment
the parent's memory allocation table will be duplicated to the child. Уже так работает fork(): у родителя и потомка одинаковые копии карты памяти, но в разных аренах. Если ребенок свободен (s), родитель этого не заметит, и наоборот.   -  person wildplasser    schedule 02.03.2015


Ответы (3)


Вы должны иметь возможность вызывать фактический fork с syscall(SYS_fork) после включения <sys/syscall.h>. См. syscall(2).

person Fred Foo    schedule 02.02.2011
comment
Я не был уверен, что действительно существует системный вызов fork. Я думал, что это было переведено в вызов clone с определенным набором параметров. - person Omnifarious; 02.02.2011
comment
@larsmans: Это дает хорошую идею!! Здорово. Позвольте мне попробовать это сейчас и посмотреть, работает ли это. - person RajSanpui; 02.02.2011
comment
@kingsmasher1 - Это работает... Наверное, это хорошо, но я бы так не делал. Я бы нашел способ вызвать исходную функцию fork из libc. Я думаю, что это решение более надежно с течением времени. - person Omnifarious; 02.02.2011
comment
@Omnifarious, в принципе, ты прав. Оба они являются системными вызовами и оба вызывают do_fork(). Clone передает свои параметры, fork устанавливает значения по умолчанию. См. lxr.linux.no/#linux +v2.6.37/arch/x86/kernel/process.c#L233 например. - person ; 02.02.2011
comment
Выполнение системного вызова напрямую - плохая идея. fork требуется для вызова функций pthread_atfork, а также для выполнения некоторой внутренней синхронизации, чтобы предотвратить повреждение состояния stdio/malloc в дочернем элементе с многопоточными родителями, обновить надежный указатель списка мьютексов и т. д. - person R.. GitHub STOP HELPING ICE; 22.09.2011

Вы не получите ничего полезного из исходного кода ядра для fork. Вашему коду не будет позволено делать то, что делает ядро, независимо от того, какими библиотечными трюками вы управляете. Это жесткая граница, которую нельзя нарушить, не написав модуль ядра.

Все, что делает библиотечный код для fork, это настройка и выполнение специальной инструкции, которая переключается в режим ядра, где выполняется код ядра fork. Есть своего рода способ поместить эту специальную инструкцию в ваш собственный код. Это функция syscall. Поскольку fork не принимает аргументов, использование этой функции для выполнения системного вызова должно быть относительно простым.

Но это не то, что я рекомендую вам делать. Я рекомендую вам сделать это вместо этого:

typedef int (*forkfunc_t)(void);

int fork(void)
{
     forkfunc_t sysfork = (forkfunc_t)dlsym(RTLD_DEFAULT, "fork");
     return sysfork();
}

По сути, какие бы хакерские операции с разделяемой библиотекой вы ни делали, вы должны найти какой-то способ получить предыдущее значение функции fork, прежде чем заменять его своим собственным.

person Omnifarious    schedule 02.02.2011
comment
Я работаю над инструментом обнаружения утечек, и этот инструмент обнаруживает двойное освобождение, когда дочерний процесс удаляет память, выделенную родителем. Чтобы преодолеть это, я переопределю fork(), и всякий раз, когда есть fork(), родительская таблица распределения памяти будет продублирована дочерней. - person RajSanpui; 02.02.2011
comment
@kingsmasher1: Ааа, так что вам не нужно изменять то, что ядро ​​​​делает с fork, вам просто нужно убедиться, что вы его перехватываете и обертываете соответствующим образом. Это очень выполнимо, и ваша техника с общей библиотекой не так уж плоха для этого. - person Omnifarious; 02.02.2011
comment
@kingsmasher1 Я отредактировал ваш комментарий на ваш вопрос, так как это очень важная информация! Если вас это не устраивает, продолжайте редактировать его. - person ; 02.02.2011

Так как вы все равно плохо взламываете, почему бы просто не использовать макрос

#define fork() (spoon(),fork())

or

#define fork() spoon(fork())

где spoon — это функция, которая делает то, что вы хотите выполнить.

Препроцессор гарантированно не будет выполнять рекурсию и оставит только fork внутри расширения.

person Jens Gustedt    schedule 02.02.2011
comment
моя проблема заключалась не в том, как перегрузить fork(). Мне удалось перегрузить его с помощью системного вызова dlsym. Моя проблема заключалась в том, как воспроизвести работу fork(), в любом случае я смог добиться этого, используя предложение larsman, и моя проблема решена. Так или иначе. - person RajSanpui; 02.02.2011