Skip to content

native: ДобавитьОбработчик молча не создаёт подписку #1738

Description

@nixel2007

Описание

Оператор ДобавитьОбработчик, выполненный внутри #native-модуля, не создаёт подписку
на событие. Ни ошибки компиляции, ни исключения в рантайме — обработчик просто никогда
не вызывается.

То же и с УдалитьОбработчик.

Это опаснее падения: код компилируется, выполняется, выглядит рабочим, но ведёт себя
иначе, чем в стековом режиме.

Воспроизведение

Источник события, Классы/ИсточникСобытия.os (стековый):

Процедура Стрельнуть() Экспорт
	ВызватьСобытие("Событие", Новый Массив());
КонецПроцедуры

Процедура Событие() Экспорт
КонецПроцедуры

Процедура ПриСозданииОбъекта()
КонецПроцедуры

Подписчик, Классы/Подписчик.os — считает вызовы:

Перем Вызовов Экспорт;

Процедура Обработчик() Экспорт
	Вызовов = Вызовов + 1;
КонецПроцедуры

Процедура ПриСозданииОбъекта()
	Вызовов = 0;
КонецПроцедуры

Два подписывателя, различаются ровно одной директивой.

Классы/ПодписывательСтековый.os:

Процедура Подписать(Источник, Подписчик) Экспорт
	ДобавитьОбработчик Источник.Событие, Подписчик.Обработчик;
КонецПроцедуры

Процедура ПриСозданииОбъекта()
КонецПроцедуры

Классы/ПодписывательНативный.os:

#native

Процедура Подписать(Источник, Подписчик) Экспорт
	ДобавитьОбработчик Источник.Событие, Подписчик.Обработчик;
КонецПроцедуры

Процедура ПриСозданииОбъекта()
КонецПроцедуры

Сценарий запуска:

#Использовать "."

Процедура Проверить(Имя, Подписыватель, Подписчик)
	Источник = Новый ИсточникСобытия();
	Подписыватель.Подписать(Источник, Подписчик);
	Источник.Стрельнуть();
	Сообщить(Имя + ": вызовов обработчика = " + Подписчик.Вызовов);
КонецПроцедуры

Проверить("стек-подписыватель  ", Новый ПодписывательСтековый(), Новый Подписчик());
Проверить("native-подписыватель", Новый ПодписывательНативный(), Новый Подписчик());

Фактическое поведение

стек-подписыватель  : вызовов обработчика = 1
native-подписыватель: вызовов обработчика = 0

Режим модуля подписчика на результат не влияет — важен только режим того модуля,
в котором выполняется сам оператор ДобавитьОбработчик:

стек-подписыватель   + стек-подписчик   : вызовов обработчика = 1
стек-подписыватель   + native-подписчик : вызовов обработчика = 1
native-подписыватель + стек-подписчик   : вызовов обработчика = 0
native-подписыватель + native-подписчик : вызовов обработчика = 0

Ожидаемое поведение

вызовов обработчика = 1 во всех четырёх сочетаниях. Если подписка из native
не поддерживается — нужна ошибка компиляции, а не тихий no-op.

Окружение

Воспроизводится одинаково на:

  • 2.2.0, linux-x64
  • 2.3.0-dev+6 (ночная сборка), linux-x64

Влияние

В autumn после перевода класса-сканера
на #native беззвучно отключилась вся валидация компонентов: приемки перестали
получать события фабрики. Компиляция прошла, приложение запустилось, ошибок нет —
поймали только по упавшему тесту, который проверял, что некорректный компонент
вызывает исключение.

Обход есть: вынести ДобавитьОбработчик/УдалитьОбработчик в отдельный стековый
класс-помощник и делегировать подписку ему.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    nativeКомпиляция в CLR в движке 2.0

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions