Различное поведение при запуске программы, скомпилированной с G в Docker

#c #docker #g #compiler-optimization

#c #docker #g #оптимизация компилятора

Вопрос:

Поведение исполняемого файла отличается, если он запускается внутри docker или на хосте. Но это происходит только тогда, когда мы меняем уровень оптимизации G .

Компилятор: g (Ubuntu 7.3.0-27ubuntu1 ~ 18.04) 7.3.0

Я пытаюсь выполнить следующий код:

 #include <cstdio>
#include <cstring>
int main()
 {
    int nOrd =3395;
    char cOrd[] = "003395";
    char cAux2[256];    
    strcpy(cAux2, cOrd);
    int nRest = nOrd % 26;
    printf("BEFORE SPRINTF %snnn", cAux2);
    sprintf(cAux2, "%s%c", cAux2, (nRest 65));
    printf("AFTER SPRINTF %snnn", cAux2);
    return 0;
 }
  

Если я скомпилирую с:

 g   -o FastCompile FastCompile.c -DNDEBUG -Os
  

И я запускаю на хосте. Результат соответствует ожидаемому:

 BEFORE SPRINTF 003395


AFTER SPRINTF 003395P
  

Если я создаю образ с этим исполняемым файлом и запускаю внутри docker, у меня есть:

Версия Docker 18.09.4, сборка d14af54266

Dockerfile:

 FROM debian
RUN apt-get update amp;amp; apt-get install -y 
   libssl-dev
COPY fast/ /usr/local/
ENTRYPOINT ["usr/local/FastCompile"]
  

Быстрая компиляция $docker build -t.

$docker запустить fastcompile

 BEFORE SPRINTF 003395


AFTER SPRINTF P
  

Если я удалю -Os и повторно скомпилирую с:

 g   -o FastCompile FastCompile.c -DNDEBUG 
  

Поведение внутри Docker правильное.

Итак, это проблема Docker? Или это ожидаемое поведение?

Ответ №1:

Ваш код имеет неопределенное поведение.

 sprintf(cAux2, "%s%c", cAux2, (nRest 65));
  

считывает данные из одного и того же объекта и записывает в него. Чтобы исправить это, вы можете использовать cOrd в вызове, чтобы вы не читали из своего буфера. Это выглядело бы как

 sprintf(cAux2, "%s%c", cOrd, (nRest 65));
  

Также обратите внимание, что это (nRest 65) дает вам int , а не char , как указано в спецификаторе формата, должно быть. Это также неопределенное поведение. Вам нужно преобразовать ее в символ, чтобы исправить это следующим образом

 sprintf(cAux2, "%s%c", cOrd, char(nRest 65));
  

Комментарии:

1. Нет ли второго неопределенного поведения, поскольку в строке формата указано, %c но (nRest 65) это int ?

2. Этот фрагмент кода взят из старого кода, написанного на Visual C 6. Я переопределю его, чтобы удалить неопределенное поведение. Спасибо