Я играю с Python C модулями расширения, и у меня есть эта простая функция:
static PyObject *e_parse_metadata(PyObject *self, PyObject *args) {
Py_buffer buf;
if(!PyArg_ParseTuple(args, "y#", &buf)) {
// interpreter raises exception, we return NULL to indicate failure
return NULL;
}
fprintf(stdout, "extension: %c%c\n\n", *((char *) buf.buf) + 0, *((char*) buf.buf + 1)); // should print "BM"
PyBuffer_Release(&buf);
return PyLong_FromLong(33l);
}
Он пытается получить Py_buffer
из аргумента, переданного ему из в пределах Python. Затем он отображает первые 2 байта из буфера в виде символов для stdout
, освобождает буфер и возвращает ссылку на новый PyObject
, представляющий целое число 33
.
Далее у меня есть Python пример использования указанной функции:
#!/usr/bin/env python3
import bbmp_utils # my module
with open('./mit.bmp', 'rb') as mit:
if(mit.readable()):
filedata = mit.read()
res = bbmp_utils.parse_metadata(filedata) # call to my function in the extension module
print(res, type(res))
В результате модуль расширения успешно печатает первые 2 байта из потока байтов (extension: BM
) в стандартный вывод, но затем он завершается: fish: “env PYTHONPATH=./build_dbg pyth…” terminated by signal SIGSEGV (Address boundary error)
Как ни странно, прямая передача экземпляра bytes
в мою функцию расширения не вызывает кражу sh вообще, например
res = bbmp_utils.parse_metadata(mit.read())
Почему первый пример приводит к cra sh, а второй - нет?