OberonCore
https://forum.oberoncore.ru/

Защита от выгрузки реализации
https://forum.oberoncore.ru/viewtopic.php?f=23&t=4977
Страница 1 из 1

Автор:  Пётр Кушнир [ Пятница, 14 Февраль, 2014 14:16 ]
Заголовок сообщения:  Защита от выгрузки реализации

В процессе работы столкнулся с данной "проблемой", часто бывает так, что вношу модификации в работающую реализацию. А затем по привычке выгружаю эту реализацию вместе с модулем. И получаю закономерный трэп. Это проблема этапа разработки.
Похожая ситуация происходит при закрытии ББ. Модули реализаций выгружаются и клиентский код уже не может корректно выполнить свои завершающие действия (ведь ему все еще нужна реализация). Такая проблема уже может возникнуть в боевом режиме, и будет очень неприятно.
Решений, как всегда несколько:

    Реализовать корректную обработку выгрузки в клиентском коде. Идеальный случай. В реальности получается перекладывание ответственности на клиента. Приходится часто делать проверку указателя
    Код:
    PROCEDURE Valid(a: ANYPTR): BOOLEAN;
          VAR i: Meta.Item;
       BEGIN
          Meta.GetItem(a, i);
       RETURN i.Valid();
       END Valid;
    Вручную создавать специальный модуль, импортирующий реализации (как HostMenus). Работает только для подконтрольных реализаций, и не спасает от второго случая.
    Реализовать механизм выгрузки, который бы не позволял без подтверждения выгрузить модули, у которых есть объекты, заякоренные в других модулях. В идеальном случае - дожидаться ситуации при выгрузке модулей, при которой на объекты модуля точно нет внешних ссылок. Но возникает ситуация перекрестных ссылок на объекты модулей, тогда непонятно, как выполнять выгрузку.
    Слабые ссылки, которые предполагают отсутствие гарантии получения объекта, и не якорят чужие объекты. Пример реализации слабых ссылок для ББ в ypkSysRef.
    В случае фабрик можно отказаться от передачи указателя вовне, использовать шину сообщений, например, или поиск по метаинформации. То есть, объект фабрики хранится внутри модуля реализации, и передается клиентам по запросу. Проблема может возникнуть при появлении второй реализации с таким же объектом.
    Не усложнять и перезапускать ББ целиком каждый раз.
Такая вот проблема.

Автор:  Иван Денисов [ Пятница, 14 Февраль, 2014 20:52 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

В "инфо", "загруженные модули" указывается сколько у модуля клиентов. Там реализации считаются? Тогда было бы просто пока > 0 — не выгружать...

Автор:  Пётр Кушнир [ Пятница, 14 Февраль, 2014 21:10 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Нет, клиенты это те, кто напрямую импортируют модуль. Их и так считает ядро.

Автор:  Пётр Кушнир [ Пятница, 14 Февраль, 2014 21:16 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Возможно, как простое решение, будет полезен этакий FactoryRef, статический объект, который бы помогал юзеру устанавливать одну или более скрытую реализацию заданного базового типа (хуки, фабрики, процедурные переменные, в общем, все подряд) и корректно следить за их состоянием, помогать с миграцией от одной реализации к другой в рантайме и т.д.

Автор:  Пётр Кушнир [ Пятница, 14 Февраль, 2014 21:40 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Код:
   PROCEDURE Exec (a: Action);
      VAR t: Kernel.Type;
   BEGIN
      t := Kernel.TypeOf(a);
      IF t.mod.refcnt >= 0 THEN   (* execute action if its module is not unloaded *)
         a.Do   (* warning: here the actions and candidates lists may be modified, or a trap may occur! *)
      END
   END Exec;

Вот как справляются с похожей проблемой в Services.
То есть, для типов, которые могут иметь скрытые расширения, можно и нужно выполнять проверку указателей на валидность.

Автор:  Пётр Кушнир [ Пятница, 14 Февраль, 2014 22:13 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

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

Автор:  Пётр Кушнир [ Суббота, 15 Февраль, 2014 00:36 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

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

Получается, что для проверки валидности всегда нужен промежуточный объект (возможно хранимый в объектном пуле, для эффективности).
Для критичных мест получается что-то типа:
Код:
MODULE Abase;

   TYPE
      A* = POINTER TO ABSTRACT RECORD END;
      
      (* всегда рядом с абстракцией, то есть, не выгрузится пока есть клиенты *)
      SafeA = POINTER TO RECORD (A0)
         unsafe: A;
      END;
      
   PROCEDURE (a: A) Do*, NEW, ABSTRACT;
   
   PROCEDURE (a: SafeA) Do;
   BEGIN
      IF Valid(a.unsafe) THEN a.Do END
   END Do;
   
   PROCEDURE New*(): A;
      VAR a: SafeA;
   BEGIN
      NEW(a);
      a.unsafe:=dir.New();
      RETURN a
   END New;

END Abase.

Сработает ли финализатор объекта из модуля реализаций, который заякорен в базовом модуле? По идее - должен.
Код:
MODULE Aimpl;
   
   TYPE
      HostA = POINTER TO RECORD (Abase.A)
         host: WinApi.A;
      END;
   
   PROCEDURE (a: HostA) Do;
   BEGIN
      (* smth *)
   END Do;
   
   PROCEDURE (a: HostA) FINALIZE;
   BEGIN
      Free(a.host)
   END FINALIZE;
   
END Aimpl.

Для менее критичных случаев подойдет
Код:
    TYPE   
      Ref* = RECORD
         target: ANYPTR;
      END;
      
   PROCEDURE (VAR r: Ref) Set*(x: ANYPTR), NEW;
   BEGIN
      r.target:=x;
   END Set;
   
   PROCEDURE (VAR r: Ref) This*(): ANYPTR, NEW;
      VAR ret: ANYPTR;
   BEGIN
      IF r.target#NIL THEN
         IF Valid(r.target) THEN ret:=r.target ELSE r.target:=NIL END;
      END;
      RETURN ret
   END This;

Автор:  Иван Кузьмицкий [ Понедельник, 16 Июнь, 2014 23:05 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Вот как раз столкнулся с этой проблемой. Суть в том, что объекты HostFonts связаны с объектами шрифтов, порождёнными библиотекой SDL_TTF. Следовательно, надо их корректно уничтожать средствами SDL_TTF при зачистке HostFonts.Font (в методе FINALZE). Но средства SDL_TTF загружены компонентно - в виде модуля, реализующего хук для некоего абстрактного интерфейса.

И получается так, что при закрытии BlackBox сперва выгружается хук, а потом начинают зачищаться объекты HostFonts - а они уже не могут обратиться к функциональности хука!

Автор:  Иван Кузьмицкий [ Вторник, 17 Июнь, 2014 12:17 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Провёл тут лабораторную работу.

Написал три модуля:
Код:
MODULE PrivA;
   IMPORT Log, PrivB, PrivC;
   PROCEDURE Do*;
   BEGIN
      Log.String('PrivA.Do'); Log.Ln;
   END Do;
BEGIN
   Log.String('PrivA Init'); Log.Ln;
END PrivA.

MODULE PrivB;
   IMPORT Log;
BEGIN
   Log.String('PrivB Init'); Log.Ln
CLOSE
   HALT(101)
END PrivB.

MODULE PrivC;
   IMPORT Log;
BEGIN
   Log.String('PrivC Init'); Log.Ln;
CLOSE
   HALT(102)
END PrivC.


Если выполнить PrivA.Do, то получим такие записи в журнале:
Цитата:
PrivB Init
PrivC Init
PrivA Init
PrivA.Do
А в списке загруженных модулей увидим последовательность:
Цитата:
PrivA
PrivC
PrivB
Это означает, что сперва загрузился модуль A. После чего пошла загрузка модулей с конца списка импорта модуля А и загрузился сперва модуль C, а потом B. После того, как модули оказались загружены, начинают работу секции BEGIN каждого из них - только уже в том порядке, в каком они импортированы в A.

А выгружаться они будут в том же порядке, что и загружались - A, C, B.

Довольно очевидные вещи, которые, однако, почему-то сразу не приходят в голову, когда разрабатываешь загружаемые реализации для хоста. Поскольку тут идёт речь о фреймворке в целом, то надо проектировать не только последовательность загрузки, но и последовательность выгрузки.

Автор:  Info21 [ Вторник, 17 Июнь, 2014 17:23 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Иван Кузьмицкий писал(а):
Это означает, что сперва загрузился модуль A. ...
Означает -- это только гипотеза.

Автор:  Иван Кузьмицкий [ Среда, 18 Июнь, 2014 09:09 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Info21 писал(а):
Иван Кузьмицкий писал(а):
Это означает, что сперва загрузился модуль A. ...
Означает -- это только гипотеза.
Подозреваю, что последовательности загрузки-выгрузки модулей и, главное, их инициализации не произвольны, но доказать это на данный момент выше моих сил :(

Автор:  Александр Ильин [ Среда, 18 Июнь, 2014 11:30 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Иван Кузьмицкий писал(а):
Подозреваю, что последовательности загрузки-выгрузки модулей и, главное, их инициализации не произвольны, но доказать это на данный момент выше моих сил :(
Конечно, не произвольны, а очень даже фиксированы. Это вам не ASLR какой-нибудь. Другой вопрос в том, что при смене реализации нет гарантий сохранения такого поведения в точности. Поэтому надо либо зафиксировать этот момент в документации и требованиях на реализацию, либо не менять реализацию и задокументировать, что на это есть завязка в ваших компонентах.

Ещё хорошо бы сделать автоматический тест, проверяющий совместимость вашего компонента с реализацией загрузки-выгрузки.

Автор:  Иван Кузьмицкий [ Среда, 18 Июнь, 2014 11:46 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Александр Ильин писал(а):
Другой вопрос в том, что при смене реализации нет гарантий сохранения такого поведения в точности. Поэтому надо либо зафиксировать этот момент в документации и требованиях на реализацию
Вот только сегодня утром прямо в разделе IMPORT прописал, для чего именно эти модули тут импортированы и какая связь с другими. Потому что через полгода уже не вспомнить и не объяснить, а сломать будет очень легко.
Александр Ильин писал(а):
Ещё хорошо бы сделать автоматический тест, проверяющий совместимость вашего компонента с реализацией загрузки-выгрузки.
Хорошая идея, спасибо! Надо поразмыслить.

Автор:  ilovb [ Среда, 18 Июнь, 2014 15:13 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

По теме: http://oberspace.dyndns.org/index.php/t ... l#msg20137

Автор:  GameHunter [ Воскресенье, 06 Июль, 2014 13:54 ]
Заголовок сообщения:  Re: Защита от выгрузки реализации

Цитата:
Ещё хорошо бы сделать автоматический тест, проверяющий совместимость вашего компонента с реализацией загрузки-выгрузки.


Нужно ли огород городить? Ведь последовательность загрузки-выгрузки всегда можно задать явным импортом, независимо от реализации. Я имею в виду, что, например, модуль PrivB может импортировать модуль PrivC.

Страница 1 из 1 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/