Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ошибка при поиске библиотек? #266

Closed
Mazdaywik opened this issue Feb 3, 2020 · 0 comments
Closed

Ошибка при поиске библиотек? #266

Mazdaywik opened this issue Feb 3, 2020 · 0 comments
Assignees
Labels

Comments

@Mazdaywik
Copy link
Member

Воспроизведение ошибки

Вот такой вот сценарий работы:

  • Создаём два файла main.ref и a\xxx.ref. Первый содержит функцию Go, которая вызывает XXX, второй — определение функции XXX, R-модуль.

    D:\…\bug>copy con test.ref
    *$REFERENCE xxx
    $EXTERN XXX;
    
    $ENTRY Go { = <Prout <XXX>> }
    ^Z
    Скопировано файлов:         1.
    
    D:\…\bug>srmake test.ref
    *Compiling test.ref:
    +Linking C:\Users\…\AppData\Roaming\Refal-5-lambda\lib\references\Library.rasl
    ** Compilation succeeded **
    
    D:\…\bug>mkdir a
    
    D:\…\bug>cd a
    
    D:\…\bug\a>copy con xxx.ref
    $ENTRY XXX { = 'aaaa' }
    ^Z
    Скопировано файлов:         1.
    
    D:\…\bug\a>srmake -R xxx.ref
    *Compiling xxx.ref:
    +Linking C:\Users\…\AppData\Roaming\Refal-5-lambda\lib\references\Library.rasl
    ** Compilation succeeded **
    
    D:\…\bug\a>cd ..
  • Устанавливаем RL_MODULE_PATH на папку a и пытаемся запустить:

    D:\…\bug>set RL_MODULE_PATH=a
    
    D:\…\bug>test
    INTERNAL ERROR: can't load module Library

    Не находит библиотеку Library.

  • Копируем библиотеку Library.dll в текущую папку и ещё раз запускаем:

    D:\…\bug>copy C:\Users\…\AppData\Roaming\Refal-5-lambda\bin\Library.dll .
    Скопировано файлов:         1.
    
    D:\…\bug>test
    aaaa

    Всё работает.

  • Напишем программу со ссылкой на xxx, которая падает с дампом:

    D:\…\bug>copy con test2.ref
    *$REFERENCE xxx
    
    $EENUM Go;
    ^Z
    Скопировано файлов:         1.
    
    D:\…\bug>srmake test2.ref
    *Compiling test2.ref:
    +Linking C:\Users\AKonovalov\AppData\Roaming\Refal-5-lambda\lib\references\Library.rasl
    ** Compilation succeeded **
    
    D:\…\bug>test2 2>__err.txt
  • В дампе видно, что библиотека Library загружена дважды — как в составе префикса, так и независимо.

И это нарушение инварианта. Предполагается, что библиотека Library загружается один раз — в составе префикса. А тут она загрузилась два раза — в составе префикса и через зависимость xxx. Если исходники main.ref и xxx.ref использовали функции библиотеки с побочным эффектом (например, файловый ввод/вывод или копилку), то было бы заметно, что загружены два независимых экземпляра Library.

Попытка объяснения

Модули в дампе перечислены в следующем порядке:

  1. Library.dll
  2. a\xxx.rasl-module
  3. test2.exe

Получается, стал загружаться test2.exe, загрузчик увидел неразрешённую ссылку xxx. Приостановил загрузку test2.exe, нашёл и начал загружать xxx.rasl-module. Обнаружил неразрешённую ссылку на Library. Поскольку префикс ещё не загружен до конца, загрузчик в нём не нашёл внедрённый (incorporated) Library и продолжил поиски. На первом запуске Library не нашёлся и программа упала. На втором нашёлся Library.dll и загрузился.

Загрузчик модулей умеет разрешать циклические зависимости. Обходя рекурсивно загружаемые модули по ссылкам, он поддерживает стек недозагруженных модулей, в которых хранит структуру stat. Если вновь загруженный модуль имеет эквивалентную stat, с той, которая есть на стеке, модуль повторно не загружается. Вместо этого берётся указатель полузагруженного модуля.

Предлагаемое решение

Аналогичное поведение (см. абзац выше) нужно реализовать и для псевдонимов.

@Mazdaywik Mazdaywik added the bug label Feb 3, 2020
@Mazdaywik Mazdaywik added this to the Рефал-5λ milestone Feb 3, 2020
@Mazdaywik Mazdaywik self-assigned this Feb 3, 2020
Mazdaywik added a commit that referenced this issue Mar 9, 2020
На первый взгляд получилось более громоздко, но на самом деле рефакторинг
упрощает последующие коммиты.
Mazdaywik added a commit that referenced this issue Mar 9, 2020
• Конструктор без параметров не использовался.
• Поле stat не используется, поскольку оно же есть внутри модуля.
Mazdaywik added a commit that referenced this issue Apr 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant