segfault на Win XP x64, не происходит на XP x32 - проблема с strncpy? Как исправить? - PullRequest
0 голосов
/ 25 февраля 2009

Я довольно неопытен в использовании C ++, но я пытаюсь скомпилировать версию 2.0.2 SBML toolbox для matlab на 64-битной платформе XP. Набор инструментов SBML зависит от Xerces 2.8 и libsbml 2.3.5.

Мне удалось собрать и скомпилировать набор инструментов на 32-разрядной машине, и он работает, когда я тестирую его. Однако после его перекомпоновки на 64-битной машине (это ОГРОМНАЯ ПИТА!) Я получаю ошибку сегментации, когда пытаюсь читать с нее длинные XML-файлы.

Я подозреваю, что проблема вызвана указателем проблем с адресами .

Трассировка стека от ошибки сегментации начинается с:

[ 0] 000000003CB3856E libsbml.dll+165230 (StringBuffer_append+000030)
[ 6] 000000003CB1BFAF libsbml.dll+049071 (EventAssignment_createWith+001631)
[ 12] 000000003CB1C1D7 libsbml.dll+049623 (SBML_formulaToString+000039)
[ 18] 000000003CB2C154 libsbml.dll+115028 (

Итак, я смотрю на функцию StringBuffer_append в коде libsbml:

LIBSBML_EXTERN
void
StringBuffer_append (StringBuffer_t *sb, const char *s)
{
  unsigned long len = strlen(s);


  StringBuffer_ensureCapacity(sb, len);

  strncpy(sb->buffer + sb->length, s, len + 1);
  sb->length += len;
}

Обеспечить емкость выглядит следующим образом:

LIBSBML_EXTERN
void
StringBuffer_ensureCapacity (StringBuffer_t *sb, unsigned long n)
{
  unsigned long wanted = sb->length + n;
  unsigned long c;


  if (wanted > sb->capacity)
  {
    /**
     * Double the total new capacity (c) until it is greater-than wanted.
     * Grow StringBuffer by this amount minus the current capacity.
     */
    for (c = 2 * sb->capacity; c < wanted; c *= 2) ;
    StringBuffer_grow(sb, c - sb->capacity);
  }                   
}

и StringBuffer_grow выглядит так:

LIBSBML_EXTERN
void
StringBuffer_grow (StringBuffer_t *sb, unsigned long n)
{
  sb->capacity += n;
  sb->buffer    = (char *) safe_realloc(sb->buffer, sb->capacity + 1);
}

Вполне вероятно, что

strncpy(sb->buffer + sb->length, s, len + 1);

в StringBuffer_append это источник моего segfault?

Если так, может кто-нибудь предложить исправление? Я действительно не знаю C ++, и меня особенно смущают указатели и адресация памяти, поэтому я, скорее всего, понятия не имею, о чем вы говорите - мне понадобится немного руки.

Кроме того, я выложил подробности моего процесса сборки онлайн здесь , на случай, если кто-то еще попытается скомпилировать C ++ для 64-битных систем с использованием Microsoft Visual C ++ Express Edition.

Заранее спасибо!

-Бен

Ответы [ 8 ]

1 голос
/ 25 июня 2011

, будучи одним из разработчиков libsbml, я просто наткнулся на это. Это все еще проблема для вас? Тем временем мы выпустили libsbml 5 с отдельными 64-битными и 32-битными версиями и значительно улучшили тестирование, пожалуйста, посмотрите:

http://sf.net/projects/sbml/files/libsbml

1 голос
/ 25 февраля 2009

Попробуйте распечатать или использовать отладчик, чтобы увидеть, какие значения вы получаете для некоторых из ваших промежуточных переменных. В StringBuffer_append () O / P len, в StringBuffer_ensureCapacity () наблюдайте sb- >acity и c до и в цикле. Посмотрите, имеют ли значения смысл.

Ошибка сегментации может быть вызвана доступом к данным за концом строки.

Странный факт, что он работал на 32-битной машине, а не на 64-битной операционной системе, также является подсказкой. Одинаков ли размер физической памяти и файла подкачки для двух машин? Кроме того, в 64-разрядной машине пространство ядра может быть больше, чем в 32-разрядной машине, и потребляет некоторое доступное пространство памяти, которое было в пользовательской части пространства памяти для 32-разрядной операционной системы. Для XML весь документ должен уместиться в памяти. Возможно, есть некоторые параметры для установки размера, если это проблема. Разница в машинах, являющаяся причиной проблемы, должна быть только в том случае, если вы работаете с очень большой строкой. Если строка небольшая, это может быть связано с библиотечным или служебным методом, который не работает в 64-битной среде.

Кроме того, для начала используйте простой / маленький xml-файл, если вам больше нечего попробовать.

Где вы инициализируете sb-> length. Вероятно, ваша проблема в strncpy (), хотя я не знаю, почему 32/64-битное изменение O / S имеет значение. Лучшая ставка - на промежуточные значения, и тогда ваша проблема станет очевидной.

0 голосов
/ 10 марта 2011

unsigned long не является безопасным типом для размеров на 64-битной машине в Windows. В отличие от Linux, Windows определяет long как 32-разрядные на 32- и 64-разрядных архитектурах. Поэтому, если размер добавляемого буфера превышает 4 ГБ (или если вы пытаетесь добавить строку, длина которой> 4 ГБ), вам необходимо изменить объявления типа unsigned long на size_t (что составляет 64 бита). на 64-битных архитектурах, во всех операционных системах).

Однако, если вы читаете только файл размером 1,5 МБ, я не вижу, как вы когда-нибудь получите StringBuffer размером более 4 ГБ, так что это может быть тупик.

0 голосов
/ 26 февраля 2009

В ответ на комментарий bk1e по этому вопросу - к сожалению, мне нужна версия 2.0.2 для использования с набором инструментов COBRA, который не работает с более новой версией 3. Итак, я застрял с этой более старой версией на данный момент .

Я также пытаюсь отладить некоторые стены - я создаю .dll, поэтому в дополнение к перекомпиляции xerces, чтобы убедиться, что в MSVC ++ есть те же параметры отладки, мне также нужно присоединиться к процессу Matlab, чтобы выполнить отладку - это довольно большой скачок для моего ограниченного опыта в этой среде, и я еще не углубился в это.

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

0 голосов
/ 26 февраля 2009

Давайте предположим, что safe_malloc и safe_realloc делают что-то разумное, например, прерывание программы, когда они не могут получить запрошенную память. Таким образом, ваша программа не будет продолжать работать с неверными указателями.

Теперь давайте посмотрим, насколько велико StringBuffer_ensureCapacity, до которого увеличивается буфер, по сравнению с требуемой емкостью. Это не ошибочная ошибка. Это ошибка с коэффициентом два.

Как ваша программа работала в x32, я не могу догадаться.

0 голосов
/ 26 февраля 2009

Кажется, если бы это было в любой из функций StringBuffer_ *, это было бы в трассировке стека. Я не согласен с тем, как _ensureCapacity и _grow реализованы. Ни одна из функций не проверяет, работает ли realloc или нет. Отказ Realloc, безусловно, приведет к segfault. Я бы вставил проверку на нуль после _ensureCapacity. При наличии _ensureCapacity и _grow, кажется, возможно получить ошибочную ошибку. Если вы работаете в Windows, 64-битные и 32-битные системы могут иметь разные механизмы защиты страниц, которые приводят к сбою. (В системах со слабой защитой страниц вы часто можете пережить отдельные ошибки в памяти, размещенной в malloc.)

0 голосов
/ 25 февраля 2009

StringBuffer определяется следующим образом:

/**
 * Creates a new StringBuffer and returns a pointer to it.
 */
LIBSBML_EXTERN
StringBuffer_t *
StringBuffer_create (unsigned long capacity)
{
  StringBuffer_t *sb;


  sb           = (StringBuffer_t *) safe_malloc(sizeof(StringBuffer_t));
  sb->buffer   = (char *)           safe_malloc(capacity + 1);
  sb->capacity = capacity;

  StringBuffer_reset(sb);

  return sb;
}

Немного больше трассировки стека:

[  0] 000000003CB3856E              libsbml.dll+165230 (StringBuffer_append+000030)
[  6] 000000003CB1BFAF              libsbml.dll+049071 (EventAssignment_createWith+001631)
[ 12] 000000003CB1C1D7              libsbml.dll+049623 (SBML_formulaToString+000039)
[ 18] 000000003CB2C154              libsbml.dll+115028 (Rule::setFormulaFromMath+000036)
[ 20] 0000000001751913              libmx.dll+137491 (mxCheckMN_700+000723)
[ 25] 000000003CB1E7B2              libsbml.dll+059314 (KineticLaw_getFormula+000018)
[ 37] 0000000035727749              TranslateSBML.mexw64+030537 (mexFunction+009353)
0 голосов
/ 25 февраля 2009

Проблема может быть почти любой. Правда, может быть причиной того, что strncpy делает что-то плохое, но, скорее всего, ему просто передают плохой указатель. Который может возникнуть откуда угодно. Segfault (или нарушение прав доступа в Windows) просто означает, что приложение попыталось прочитать или записать адрес, к которому у него нет прав доступа. Итак, настоящий вопрос в том, откуда взялся этот адрес? Функция, которая пыталась следовать за указателем, вероятно, в порядке. Но был передан плохой указатель откуда-то еще. Возможно.

К сожалению, отладка кода C не является тривиальной в лучшем случае. Если код не ваш, это не облегчает. :)

...