Как исправить ошибку Segfault (Segmentation fault) в 1С на Linux при работе с Атол ДТО10 и сканером штрихкодов?

Системный администратор 1С v8.3 (Управляемые формы) 1С:Управление торговлей Торговля и дистрибуция
← На главную

Перевод рабочих мест кассиров и операторов на операционные системы семейства Linux (такие как Lubuntu, Ubuntu, Linux Mint, Astra Linux и др.) — это популярный тренд в автоматизации розничной торговли. Однако в процессе настройки торгового оборудования технические специалисты часто сталкиваются со специфическими системными ошибками. Одна из самых неприятных проблем — мгновенное падение платформы «1С:Предприятие» с ошибкой Segmentation fault (сегментирование памяти) при попытке открыть журнал чеков, чек КМ или форму настройки торгового оборудования.

В этой статье мы подробно разберем, почему возникает этот конфликт, проанализируем системные логи отладчика GDB и рассмотрим пошаговые методы полного устранения этой проблемы.

Симптомы и проявление проблемы

Типичный сценарий выглядит следующим образом. На рабочем месте под управлением Linux развернута база «1С:Управление торговлей» (или «1С:Розница»). К компьютеру подключена касса (например, Атол 30Ф через ДТО10) и стандартный сканер штрихкодов, работающий через нативную компоненту 1С. При попытке выполнить любое действие, инициализирующее кассовый аппарат, клиент 1С аварийно завершает работу без вывода каких-либо предупреждений.

При этом отладка в конфигураторе показывает, что падение происходит сразу после завершения серверной процедуры ПриСозданииНаСервере, перед передачей управления клиенту. Примечательно, что если отключить сканер штрихкода в списке подключаемого оборудования, касса начинает работать стабильно. Также стабильность восстанавливается, если перед открытием рабочего места кассира один раз зайти в настройки оборудования ККТ и вызвать тест устройства.

Анализ логов отладчика GDB

Для того чтобы понять истинную причину падения, проанализируем лог системного отладчика 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

Давайте детально разберем эту цепочку вызовов:

  1. В строке #9 платформа 1С загружает внешнюю компоненту интеграции Атол из временного каталога и пытается инициализировать библиотеку драйвера.
  2. В строке #8 и #7 вызывается метод инициализации логгера драйвера __log_api и создания экземпляра библиотеки libfptr_create.
  3. В строке #5 и #4 драйвер пытается прочитать путь к файлу конфигурации логирования fptr10_log.properties и присвоить его строковой переменной типа std::basic_string.
  4. В строках #3, #2 и #0 происходит обращение к стандартным механизмам очистки памяти строк в C++ — удалению старого содержимого строки (_M_dispose) и атомарному декременту счетчика ссылок (__exchange_and_add).
  5. На этом этапе происходит обращение к некорректному адресу памяти 0xfffffffc, что мгновенно генерирует системный сигнал SIGSEGV и аварийно завершает работу всей программы 1С.

Выясняем причину: конфликт ABI и Dual ABI в GCC

Данный сбой — классический пример конфликта двоичного интерфейса приложений (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С и подключаем оборудование, происходит следующее:

  1. Первой инициализируется нативная компонента сканера штрихкодов 1С. Она принудительно загружает в адресное пространство процесса устаревшую библиотеку libstdc++.so.6, поставляемую вместе с 1С.
  2. Затем загружается библиотека драйвера Атол libfptr10.so, которая была скомпилирована в современной среде (например, под Ubuntu 18.04/20.04) с поддержкой нового стандарта C++11 ABI.
  3. Драйвер Атол вызывает функции работы со строками std::basic_string, ожидая новую структуру памяти. Однако из-за того, что в оперативной памяти процесса уже зарегистрированы символы устаревшей библиотеки libstdc++ от 1С, вызовы перенаправляются туда.
  4. Из-за несовместимости структур данных при первом же вызове деструктора или метода присвоения строк программа пытается очистить память по несуществующему указателю, получая Segmentation fault.

Если мы сначала открываем тест ККТ, драйвер Атол успевает первым загрузить в память процесса корректную системную библиотеку libstdc++.so.6 из операционной системы, которая поддерживает оба стандарта ABI. Сканер штрихкодов затем бесконфликтно использует эту же системную библиотеку, и падения не происходит.

Инструкции по решению проблемы

Для того чтобы решить эту проблему раз и навсегда, необходимо заставить платформу 1С использовать современную системную библиотеку libstdc++.so.6 вашей операционной системы вместо устаревшей встроенной.

Способ 1. Переименование встроенных библиотек 1С (Рекомендуемый)

Самый простой и надежный способ — временно переименовать или удалить встроенные файлы библиотек в папках установленной платформы 1С. В этом случае операционная система автоматически подставит более новую системную версию библиотеки из каталога /usr/lib/.

Рассмотрим по шагам выполнение этой операции в терминале Linux:

  1. Закроем все запущенные сеансы «1С:Предприятие».
  2. Откроем эмулятор терминала.
  3. Выполним команды переименования файлов во всех каталогах платформы. Обратите внимание, что вместо 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С и проверим совместную работу оборудования. В большинстве случаев этого действия достаточно, чтобы полностью прекратить падения.

Способ 2. Замена файлов символическими ссылками (Symlink)

Если после простого переименования платформа 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

Способ 3. Устранение сопутствующих конфликтов компилятора (libgcc_s.so.1)

Иногда вместе с библиотекой 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

Альтернативный вариант запуска через LD_PRELOAD

Если вы по каким-то причинам не хотите изменять файлы в каталоге установки 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-компоненты сканеров штрихкодов и эквайринга). Теперь ККТ и сканер могут стабильно работать одновременно в рамках одного сеанса пользователя.

← На главную