Перевод рабочих мест кассиров и операторов на операционные системы семейства Linux (такие как Lubuntu, Ubuntu, Linux Mint, Astra Linux и др.) — это популярный тренд в автоматизации розничной торговли. Однако в процессе настройки торгового оборудования технические специалисты часто сталкиваются со специфическими системными ошибками. Одна из самых неприятных проблем — мгновенное падение платформы «1С:Предприятие» с ошибкой Segmentation fault (сегментирование памяти) при попытке открыть журнал чеков, чек КМ или форму настройки торгового оборудования.
В этой статье мы подробно разберем, почему возникает этот конфликт, проанализируем системные логи отладчика GDB и рассмотрим пошаговые методы полного устранения этой проблемы.
Типичный сценарий выглядит следующим образом. На рабочем месте под управлением Linux развернута база «1С:Управление торговлей» (или «1С:Розница»). К компьютеру подключена касса (например, Атол 30Ф через ДТО10) и стандартный сканер штрихкодов, работающий через нативную компоненту 1С. При попытке выполнить любое действие, инициализирующее кассовый аппарат, клиент 1С аварийно завершает работу без вывода каких-либо предупреждений.
При этом отладка в конфигураторе показывает, что падение происходит сразу после завершения серверной процедуры ПриСозданииНаСервере, перед передачей управления клиенту. Примечательно, что если отключить сканер штрихкода в списке подключаемого оборудования, касса начинает работать стабильно. Также стабильность восстанавливается, если перед открытием рабочего места кассира один раз зайти в настройки оборудования ККТ и вызвать тест устройства.
Для того чтобы понять истинную причину падения, проанализируем лог системного отладчика GDB, полученный при падении процесса 1С:
Program received signal SIGSEGV, Segmentation fault.
0xb638c7a1 in __exchange_and_add (__val=-1, __mem=0xfffffffc)
at /build/gcc-4.8-CiR0YN/gcc-4.8-4.8.4/build/i686-linux-gnu/libstdc++-v3/include/ext/atomicity.h:49
#0 0xb638c7a1 in __exchange_and_add (__val=-1, __mem=0xfffffffc)
#1 __exchange_and_add_dispatch (__val=-1, __mem=0xfffffffc)
#2 std::basic_string<wchar_t>::_Rep::_M_dispose (this=0xfffffff4, __a=...)
#3 0xb63f8082 in _M_dispose (__a=..., this=<optimized out>)
#4 std::basic_string<wchar_t>::assign (this=0x9d1e792c, __str=L"/home/user/.atol/drivers10/fptr10_log.properties")
#5 0x9cd300b6 in Logger::reconfigure() () from /opt/1C/v8.3/i386/libfptr10.so
#6 0x9cd30252 in Logger::instance() () from /opt/1C/v8.3/i386/libfptr10.so
#7 0x9cc690da in __log_api(char const*, wchar_t const*, ...) () from /opt/1C/v8.3/i386/libfptr10.so
#8 0x9cc6ae72 in libfptr_create () from /opt/1C/v8.3/i386/libfptr10.so
#9 0x9d223232 in Atol::Component1C::FiscalPrinter::Fptr10Library::create(void**) () from /tmp/v8_301LWv_c.tmp
Давайте детально разберем эту цепочку вызовов:
__log_api и создания экземпляра библиотеки libfptr_create.fptr10_log.properties и присвоить его строковой переменной типа std::basic_string._M_dispose) и атомарному декременту счетчика ссылок (__exchange_and_add).0xfffffffc, что мгновенно генерирует системный сигнал SIGSEGV и аварийно завершает работу всей программы 1С.Данный сбой — классический пример конфликта двоичного интерфейса приложений (ABI) динамических библиотек в Linux. Начиная с версии GCC 5, в стандартной библиотеке C++ (libstdc++.so.6) была радикально изменена реализация классов строк std::string и std::list для соответствия стандарту C++11 (был убран механизм Copy-On-Write и внедрена оптимизация коротких строк SSO). Чтобы сохранить совместимость со старым софтом, разработчики компилятора реализовали так называемый Dual ABI.
Платформа «1С:Предприятие» для Linux поставляется с собственным набором системных библиотек, которые копируются в папку установки (например, /opt/1cv8/x86_64/8.3.XX.YYYY/). Среди этих файлов всегда присутствуют встроенные версии libstdc++.so.6 и libgcc_s.so.1. Как правило, эти библиотеки собраны под устаревшие стандарты ABI.
Когда мы запускаем 1С и подключаем оборудование, происходит следующее:
libstdc++.so.6, поставляемую вместе с 1С.libfptr10.so, которая была скомпилирована в современной среде (например, под Ubuntu 18.04/20.04) с поддержкой нового стандарта C++11 ABI.std::basic_string, ожидая новую структуру памяти. Однако из-за того, что в оперативной памяти процесса уже зарегистрированы символы устаревшей библиотеки libstdc++ от 1С, вызовы перенаправляются туда.Если мы сначала открываем тест ККТ, драйвер Атол успевает первым загрузить в память процесса корректную системную библиотеку libstdc++.so.6 из операционной системы, которая поддерживает оба стандарта ABI. Сканер штрихкодов затем бесконфликтно использует эту же системную библиотеку, и падения не происходит.
Для того чтобы решить эту проблему раз и навсегда, необходимо заставить платформу 1С использовать современную системную библиотеку libstdc++.so.6 вашей операционной системы вместо устаревшей встроенной.
Самый простой и надежный способ — временно переименовать или удалить встроенные файлы библиотек в папках установленной платформы 1С. В этом случае операционная система автоматически подставит более новую системную версию библиотеки из каталога /usr/lib/.
Рассмотрим по шагам выполнение этой операции в терминале Linux:
8.3.XX.YYYY необходимо указать конкретный номер релиза вашей платформы (например, 8.3.22.1709), а вместо x86_64 указать i386, если используется 32-битный клиент:
# Переименовываем библиотеку stdc++ в общей папке платформы 1С
sudo mv /opt/1cv8/common/libstdc++.so.6 /opt/1cv8/common/libstdc++.so.6.old
# Переименовываем библиотеку stdc++ в каталоге конкретного релиза
sudo mv /opt/1cv8/x86_64/8.3.XX.YYYY/libstdc++.so.6 /opt/1cv8/x86_64/8.3.XX.YYYY/libstdc++.so.6.old
После этого запустим 1С и проверим совместную работу оборудования. В большинстве случаев этого действия достаточно, чтобы полностью прекратить падения.
Если после простого переименования платформа 1С выдает ошибки при старте или не может найти необходимые компоненты, создадим жесткие символические ссылки на библиотеки вашей операционной системы. Это гарантирует, что 1С получит доступ к актуальной версии системной библиотеки под тем именем, которое она ожидает увидеть.
Проанализируем команды создания символических ссылок для 64-битных систем:
# Создаем ссылки на системную библиотеку libstdc++ вашей ОС
sudo ln -sf /usr/lib/x86_64-linux-gnu/libstdc++.so.6 /opt/1cv8/common/libstdc++.so.6
sudo ln -sf /usr/lib/x86_64-linux-gnu/libstdc++.so.6 /opt/1cv8/x86_64/8.3.XX.YYYY/libstdc++.so.6
Если вы настраиваете 32-разрядный клиент (например, на старых версиях Lubuntu i386), системный путь к библиотеке изменится. Выполним следующие команды:
sudo ln -sf /usr/lib/i386-linux-gnu/libstdc++.so.6 /opt/1cv8/common/libstdc++.so.6
sudo ln -sf /usr/lib/i386-linux-gnu/libstdc++.so.6 /opt/1cv8/x86_64/8.3.XX.YYYY/libstdc++.so.6
Иногда вместе с библиотекой C++ аналогичные конфликты версий вызывает низкоуровневая библиотека времени выполнения GCC — libgcc_s.so.1. Если после выполнения предыдущих шагов проблема с Segfault сохраняется, проделаем ту же процедуру и с этим файлом:
# Переименовываем сопутствующую библиотеку времени выполнения в каталогах 1С
sudo mv /opt/1cv8/common/libgcc_s.so.1 /opt/1cv8/common/libgcc_s.so.1.old
sudo mv /opt/1cv8/x86_64/8.3.XX.YYYY/libgcc_s.so.1 /opt/1cv8/x86_64/8.3.XX.YYYY/libgcc_s.so.1.old
Затем свяжем ее с системным файлом вашей ОС с помощью символических ссылок:
# Для 64-битных дистрибутивов
sudo ln -sf /lib/x86_64-linux-gnu/libgcc_s.so.1 /opt/1cv8/common/libgcc_s.so.1
sudo ln -sf /lib/x86_64-linux-gnu/libgcc_s.so.1 /opt/1cv8/x86_64/8.3.XX.YYYY/libgcc_s.so.1
Если вы по каким-то причинам не хотите изменять файлы в каталоге установки 1С (например, если папка смонтирована в режиме "только чтение" или администрируется централизованно), можно использовать механизм предварительной загрузки библиотек ядра Linux — переменную окружения LD_PRELOAD.
Этот способ позволяет принудительно загрузить системную версию libstdc++.so.6 в память процесса 1С непосредственно при его старте. Для этого запустим 1С через терминал следующей командой:
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 /opt/1cv8/x86_64/8.3.XX.YYYY/1cv8c
Если этот запуск прошел успешно и оборудование работает стабильно, мы можем отредактировать ярлык запуска 1С (файл с расширением .desktop на рабочем столе или в меню приложений) и прописать эту переменную в поле команды запуска Exec.
Мы успешно устранили причину падения 1С на Linux. Перенаправление платформы на использование системных библиотек libstdc++.so.6 и libgcc_s.so.1 позволяет полностью исключить конфликты ABI между компонентами оборудования разных вендоров (Атол, Штрих-М, native-компоненты сканеров штрихкодов и эквайринга). Теперь ККТ и сканер могут стабильно работать одновременно в рамках одного сеанса пользователя.