Segfault возникает, когда моя общая библиотека оптимизирована с помощью icc -O3 или -O2 и используется через ctypes Python.

Это странное поведение, потому что я не мог не получить segfault

  • если разделяемая библиотека была скомпилирована без или с более слабой оптимизацией (-O0 или -O1)
  • если разделяемая библиотека была скомпилирована с помощью gcc, даже с флагом оптимизации (-O3)
  • если бы я запускал код из программы на чистом C (не через ctypes)

Кроме того, я не мог получить segfault на некоторых машинах.

Если вы найдете ошибку в моем коде, это лучше, но у меня есть другие более общие вопросы:

  1. Это может быть ошибка icc или ctypes? Можно ли отправить ошибку в систему отслеживания проблем, даже если я могу воспроизвести странное поведение в моей конкретной среде?
  2. Я пытался отладить код, но, поскольку эта ошибка видна только тогда, когда код оптимизирован, я получил много "xxx определено, но не выделено (оптимизировано)" при использовании отладчика. Есть ли лучший способ отлаживать оптимизированный код?

Как воспроизвести баг

Предположим, у меня есть исходный код библиотеки странно.c и скрипт hte python run.py, я получаю segfault с:

icc -O3 -Wall -shared strange.c -o libstrange.so
python run.py

Обратите внимание, что я мог воспроизвести эту ошибку на одном из моих компьютеров.

  • uname -m: i868
  • ОС: Ubuntu 10.04.2 LTS
  • icc: 12.0.0 20101006
  • Питон: 2.6.5
  • Нампи: 1.3.0

но нет в

  • uname -m: i868
  • ОС: Убунту 10.10
  • icc: 12.0.3 20110309
  • Питон: 2.6.6
  • Нампи: 1.3.0

or

  • uname -m: x86_64
  • ОС: Scientific Linux SL версии 5.5 (Boron)
  • icc: 12.0.0 20101006
  • Питон: 2.6.5
  • Нампи: 1.5.0b1

Код

Набор кода можно найти здесь (tkf / ctypes_icc / source — Bitbucket) или ниже. Вы можете найти Makefile и сценарий оболочки для запуска программы и проверки кода выхода со всеми флагами оптимизации и компиляторами (gcc и icc). Первоначальная версия этой программы — программа моделирования для моих исследований, но эта программа — просто бессмысленная программа.

странно.с:

typedef struct{
  int num_n;
  double dt, ie, gl, isyn, ssyn, tau1, tau2, lmd1, lmd2, k1_mean, k2_mean;
  double *vi, *v0;
} StrangeStruct;


void
func(double * v0, double * vt, double dt,
     double gl, double isyn, double ie, double isyn_estimate, int num_n)
{
  int i;
  for (i = 0; i < num_n; ++i){
    v0[i] = vt[i] + dt + gl + isyn + ie + isyn_estimate;
  }
}

int
StrangeStruct_func(StrangeStruct *self)
{
  double isyn_estimate;
  isyn_estimate =
    self->ssyn * (self->lmd1 * self->k1_mean - self->lmd2 * self->k2_mean) /
    (self->tau1 - self->tau2);
  func(self->v0, self->vi, self->dt, self->gl, self->isyn,
       self->ie, isyn_estimate, self->num_n);
  return 0;
}

запустить.py:

from ctypes import POINTER, pointer, c_int, c_double, Structure
import numpy

c_double_p = POINTER(c_double)


class StrangeStruct(Structure):
    _fields_ = [
        ("num_n", c_int),
        ("dt", c_double),
        ("ie", c_double),
        ("gl", c_double),
        ("isyn", c_double),
        ("ssyn", c_double),
        ("tau1", c_double),
        ("tau2", c_double),
        ("lmd1", c_double),
        ("lmd2", c_double),
        ("k1_mean", c_double),
        ("k2_mean", c_double),
        ("vi", c_double_p),
        ("v0", c_double_p),
        ]


StrangeStruct_p = POINTER(StrangeStruct)

ifnet_a2a2 = numpy.ctypeslib.load_library('libstrange.so', '.')
ifnet_a2a2.StrangeStruct_func.restype = c_int
ifnet_a2a2.StrangeStruct_func.argtypes = [StrangeStruct_p]


def func(struct):
    ifnet_a2a2.StrangeStruct_func(pointer(struct))


if __name__ == '__main__':
    ifn = StrangeStruct(
        num_n=100, dt=0.1, gl=0.1, vrest=-60, ie=-3.7, th=-40,
        ssyn=0.5, tau1=3, tau2=1,
        )
    v0 = numpy.zeros(ifn.num_n, dtype=float)
    vi = numpy.zeros(ifn.num_n, dtype=float)
    ifn.v0 = v0.ctypes.data_as(c_double_p)
    ifn.vi = vi.ctypes.data_as(c_double_p)

    func(ifn)

    v0 + vi

person tkf    schedule 27.04.2011    source источник


Ответы (1)


Обычно невозможно смешивать двоичные файлы, скомпилированные с помощью gcc и icc (и в этом случае python собран с помощью gcc). Вы можете попробовать использовать режим совместимости icc с gcc, который устанавливается флагом -gcc-version. Это может заставить его работать, но все же возможно, что у вас будут проблемы.

person talonmies    schedule 27.04.2011
comment
Большое спасибо! Почему-то я всегда думал, что вы можете загрузить общую библиотеку, скомпилированную любым компилятором. Но как тогда pypy поддерживает ctypes и ctypes может загружать библиотеку Haskell? Может быть, они используют gcc внутри? - person tkf; 28.04.2011
comment
Это не вопрос загрузки библиотеки - все общие библиотеки Linux являются эльфийскими, а ОС предоставляет стандартные механизмы загрузки. Он находится внутри самого кода. Все современные компиляторы используют какой-либо ABI, а стандартный ABI icc C++ не работает с gcc. Это не ограничивается только icc, даже разные основные версии gcc используют разные ABI и несовместимы (например, попытка связать код C++, скомпилированный с помощью gcc 3 и gcc 4, также не сработает). - person talonmies; 28.04.2011
comment
Тогда похоже, что мне нужно скомпилировать Python с помощью icc, чтобы использовать общую библиотеку, скомпилированную с помощью icc. О последнем вопросе: означает ли это, что pypy и Haskel используют ABI, совместимый с gcc? Я не знаком с pypy и Haskel, но думаю, что они не зависят от gcc. - person tkf; 28.04.2011