Хотя ваша логика c имеет какой-то смысл, вещи намного, намного более сложные, чем это. Мой ответ будет содержать большинство комментариев, уже сделанных здесь, только в форме ответа ...
Предположим, у вас есть указатель на функцию. Если в этой функции есть инструкция перехода, то эти инструкции перехода могут перейти к абсолютному адресу. Это означает, что когда вы десериализуете функцию, у вас должен быть способ заставить ее загружаться на тот же адрес, чтобы абсолютный переход перешел на правильный адрес.
, что подводит нас к следующей точке , Учитывая, что ваш вопрос помечен posix
, POSIX-совместимого способа загрузки кода в указанный c адрес не существует, есть MAP_FIXED
, но он не будет работать, если вы не напишите свой собственный динамический c компоновщик , Почему это имеет значение? потому что код сборки функции может ссылаться на начальный адрес функции, по разным причинам, наиболее заметной из которых является то, что сама функция дает свой собственный адрес в качестве аргумента другой функции.
Что фактически приводит нас к следующей точке , Если сериализованная функция вызывает другие функции, вам также придется их сериализовать. Но это самая легкая часть. Трудная часть состоит в том, что функция переходит в середину другой функции, а не вызывает другую функцию, что может произойти, например, в результате оптимизации хвостового вызова. Это означает, что вы должны сериализовать все, к чему функция переходит (рекурсивно), но если функция переходит на 0x00000000ff173831
, сколько байтов вы сериализуете с этого адреса?
В этом отношении, как вы узнаете, когда какая-нибудь функция заканчивается переносимым способом?
Еще хуже, вы даже гарантируете, что эта функция непрерывна в памяти? Конечно, все существующие, здравомыслящие аппаратные диспетчеры памяти ОС и аппаратные архитектуры делают его непрерывным в памяти, но гарантированно он будет таким через 1 год?
Еще одна проблема: что, если пользователь передает другую функцию на основе чего-то динамического c? т.е. если переменная окружения X
равна true
, нам нужна функция x()
, в противном случае мы хотим y()
?
Мы даже не собираемся думать о обсуждении переносимости через аппаратные архитектуры, операционные системы или даже версии одной аппаратной архитектуры.
Но мы поговорим о безопасности. Предполагая, что вам больше не требуется, чтобы пользователь указывал вам код, который мог содержать ошибку, исправленную в новой версии, вы будете продолжать использовать версию с ошибкой, пока пользователь не запомнит «refre sh». «ваши структуры данных с новым кодом.
И когда я говорю« ошибка »выше, вы должны прочитать« уязвимость безопасности ». Если уязвимая функция, которую вы сериализуете, запускает оболочку или действительно ссылается на что-то вне процессов, она становится постоянным эксплойтом.
Короче говоря, нет никакого способа сделать то, что вы хотите делать в здравом уме и Экономный c способ. Вместо этого вы можете заставить пользователя упаковать эти функции для вас.
Самый очевидный способ сделать это - попросить его передать имя файла библиотеки, которую вы затем откроете с помощью dlopen()
.
Еще один способ сделать это - передать что-то вроде Lua или JavaScript строки и встроить механизм для выполнения этих строк в виде кода.
Еще один способ - передать пути к исполняемые файлы и выполняйте их, когда необходимо обработать данные. Это , что git делает .
Но, вероятно, вам следует просто потребовать, чтобы пользователь всегда передавал эти функции. Будьте проще.