Редактирование неизменяемых строк в C - работает со старым компилятором, но не работает с современным - PullRequest
0 голосов
/ 30 апреля 2020

Я работаю с некоторым древним унаследованным кодом, который выполнялся в Solaris 10. На старом сервере код скомпилировался и без проблем работал.

Затем этот код был перенесен на сервер Solaris 11, где код все еще компилируется, но при запуске создает дамп ядра ошибки сегмента.

В обоих случаях использовался компилятор /opt/SUNWspro/bin/cc.

Вот фрагмент кода:

#include <stdio.h>

char   *blank = "                                   ";

main(argc,argv)
int argc;
char **argv;
{

blank[35] = '\0';
printf("Success.\n");

}

Это сработало в Solaris 10, но вызывает ошибку сегментации (сбрасывается ядро) в Solaris 11. Обычно я бы сказал, что причиной segfault является попытка записи в пустое [ 35], когда пустой массив [] становится пустым [34] (он инициализируется 35 пробелами), за исключением того, что этот код работал на Solaris 10.

Кроме того, когда я изменяю строку на ' пусто [34] = '\ 0'; ' на новом сервере я по-прежнему получаю дамп ядра segfault.

Когда я заменяю пустой на обычный массив (а также модернизирую основной), все работает нормально, как я и ожидал:

#include <stdio.h>

char blank[35];

int main(int argc,char **argv)
{

  int i;

  for (i=0; i<34; i++)
  {
   blank[i] = ' ';
  }

  blank[34] = '\0';
  printf("Success.\n");
  return 0;
}

Что мне действительно нужно знать, так это почему этот код хорошо работает на старом сервере, и что я пропускаю? Я могу изменить код для использования обычного массива, чтобы он работал на новом сервере, но какие проблемы это может вызвать?

Ответы [ 3 ]

2 голосов
/ 01 мая 2020

Используют ли они точно такую ​​же версию компилятора C и точно такие же флаги?

Более старые версии компиляторов Studio (/ opt / SUNWspro / ...) помещают константы в записываемую память с помощью по умолчанию, если только вы не использовали флаг -features=conststrings, чтобы поместить их в постоянную память.

Более поздние версии компиляторов Studio сделали -features=conststrings значением по умолчанию и требуют -features=no%conststrings, чтобы сделать их снова доступными для записи, как показано в Studio 12.6 документы в https://docs.oracle.com/cd/E77782_01/html/E77788/bjapr.html#OSSCGbjaqo.

Это похоже на то, что g cc сделал с эквивалентным флагом -fwritable-strings, который был включен по умолчанию в самых старых версиях, затем был отключен по умолчанию в нескольких выпусках, после чего был удален в g cc 4.0 , в результате чего константные строки всегда оставались в постоянной памяти.

2 голосов
/ 30 апреля 2020

Обратите внимание, что у вас нет char blank[], а скорее char *blank, который указывает на строковый литерал. Строковые литералы неизменны. Этот код пытается изменить один из символов литерала, на который указывает blank, что приводит к неопределенному поведению. Самое смешное в Undefined Behavior заключается в том, что он может делать все, что угодно, включая функцию так, как вы намеревались.

Стоит также отметить, что строковый литерал уже неявно завершается нулем, поэтому явно добавьте '\ 0' в конце нет необходимости независимо.

0 голосов
/ 30 апреля 2020

Скорее всего, проблема не в версии ОС, а в компиляторе, с которым вы создали код. С этим кодом много проблем, и легко увидеть, как он может работать на одном компиляторе, но не на другом. Учитывая, что мы не знаем, какой компилятор вы используете, я не буду спекулировать.

Но я поставлю вам кофе, если машины имеют одинаковую аппаратную архитектуру (например, оба UltraSpar *) 1004 *) что если вы скомпилируете бинарный файл в Solaris 10, он будет отлично работать на Solaris 11.

...