time () Функция Сегфолты с g ++ -stati c Скомпилировано в Centos 6 и Выполнено в Debian 10 - PullRequest
0 голосов
/ 31 марта 2020

люди! Я пишу программное обеспечение, которое должно устанавливать и запускать как можно больше версий Linux, но я должен быть в состоянии скомпилировать его на одном подчиненном устройстве Jenkins.

Сейчас это в основном работает. Но я столкнулся со случаем, когда специальная комбинация вещей приведет к ошибке в Debian 10, но не в любом из моих многочисленных поддерживаемых вариантов Linux. Мне удалось воспроизвести это в 3 разных приложениях (некоторые из которых работали в течение многих лет), включая упрощенный прототип, который я перечислил ниже.

// g++ -g -o ttt -static tt.cpp
// The above compile of this code on Centos 6 will produce a segfault
// when run on Debian 10, but not on any other tested flavor of Linux.
// Dozens of them. The version of g++ is 4.7.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int _argc, char* _argv[])
{
  srand(time(0));
  printf("success\n");
  return 0;
}

Что я нашел, запустив каждое из моих 3 Приложения на Debian 10 с gdb состоят в том, что при этих условиях он будет зависать.

  1. Они должны быть скомпилированы с флагом -stati c. Если я не использую -stati c, он будет работать нормально, независимо от того, из какого типа он скомпилирован.
  2. Они должны вызывать функцию time (). Неважно, как я это называю, но это нужно называть. Я попробовал обычные подозреваемые, такие как передача нулевого указателя и передача реального указателя. При статической компиляции приложения всегда происходит сбой.
  3. Они должны быть скомпилированы в Centos 6 и запущены в Debian 10. Если я статически компилирую в Debian 10, прототип работает нормально.

Итак, вот мои ограничения, над которыми я работаю.

  1. Я должен скомпилировать на одном Linux ведомом, потому что я распространяю только один двоичный файл. Отслеживание нескольких двоичных файлов и того, какие из них используются, какой вариант Linux на самом деле не подходит.
  2. Мне приходится компилировать статически, или это создает несовместимости с другими поддерживаемыми вариантами Linux.
  3. Я должен использовать g ++ 4.7 также для совместимости кода.

В ваших ответах я надеюсь на какую-то хитрость кода. Может быть, хорошая, надежная замена функции time (). Или предложение другого варианта Linux, совместимого с Debian 10.

Бонусные баллы go дадут тому, кто сможет объяснить черным волхвам c, почему основа c вездесуща Функция, подобная time (), будет полностью совместима с Debian 9, но сбои в Debian 10 ТОЛЬКО при статической компиляции в Centos 6 ...

EDIT:

strace на сервере Centos 6:

execve("./ttt", ["./ttt"], [/* 37 vars */]) = 0
uname({sys="Linux", node="testcent6", ...}) = 0
brk(0)                                  = 0x238c000
brk(0x238d180)                          = 0x238d180
arch_prctl(ARCH_SET_FS, 0x238c860)      = 0
brk(0x23ae180)                          = 0x23ae180
brk(0x23af000)                          = 0x23af000
gettimeofday({1585687633, 358976}, NULL) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f682c82f000
write(1, "success\n", 8success
)                = 8
exit_group(0)                           = ?
+++ exited with 0 +++

strace на сервере Debian 10:

execve("./ttt", ["./ttt"], 0x7fff0430dfd0 /* 18 vars */) = 0
uname({sysname="Linux", nodename="deletemedebian10", ...}) = 0
brk(NULL)                               = 0x1f6f000
brk(0x1f70180)                          = 0x1f70180
arch_prctl(ARCH_SET_FS, 0x1f6f860)      = 0
brk(0x1f91180)                          = 0x1f91180
brk(0x1f92000)                          = 0x1f92000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xffffffffff600400} ---
+++ killed by SIGSEGV +++
Segmentation fault

1 Ответ

1 голос
/ 01 апреля 2020

Исполняемый файл пытается использовать интерфейс vsyscall для реализации системного вызова, используемого для функции time.

Этот интерфейс давно устарел в пользу vdso. Некоторое время назад он был полностью удален, но все еще может быть эмулирован.

Похоже, что Debian 10 отключил эмуляцию vsyscall, что сделано из соображений безопасности, поскольку это может упростить атаки. Вы должны иметь возможность повторно включить эмуляцию, передав при запуске параметр командной строки ядра vsyscall=emulate, разумеется, с упомянутыми последствиями безопасности, если это возможно.

Версия glib c включена CentOS 6, кажется, 2.12, который слишком стар, чтобы использовать vdso. Таким образом, чтобы скомпилировать совместимый двоичный файл для более новых конфигураций ядра, вам нужен как минимум glib c 2.14. Я не знаю, может ли это быть легко установлено в CentOS или будет ли оно корректно работать с ядром, поставляемым с ним.

Вам также следует подумать, нужен ли вам полностью статический c двоичный файл. Вы можете связать все статически, кроме lib c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...