OneScript icon indicating copy to clipboard operation
OneScript copied to clipboard

Ошибка при рефлексии свойств у загруженного с контекстом сценария

Open sfaqer opened this issue 1 year ago • 21 comments

Опишите ошибку В случае если в сценарий, который был загружен через ЗагрузитьСценарий() с передачей во втором параметре контекст, попробую себе отрефлексировать таблицу свойств через ЭтотОбъект, будет получена ошибка:

Внешнее исключение (System.ArgumentOutOfRangeException): Индекс за пределами диапазона. Индекс должен быть положительным числом, а его размер не должен превышать размер коллекции.
Имя параметра: index}

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

// test.os

ЗагрузитьСценарий("./Загружаемый.os"); // Ок

Контекст = Новый Структура(
	"АргументыКоманднойСтроки",
	Новый Массив
); 

ЗагрузитьСценарий("./Загружаемый.os", Контекст); // Ошибка
// Загружаемый.os

Рефлектор = Новый Рефлектор();
Рефлектор.ПолучитьТаблицуСвойств(
	ЭтотОбъект
);

Сообщить("Ок");
oscript test.os

image

Ожидаемое поведение В ошибку не падает

Окружение

  • ОС: Win11 23H2
  • Версия: 1.9.1.80

Дополнительная информация OsReflectorBug.zip

sfaqer avatar Jul 16 '24 00:07 sfaqer

/CC @EvilBeaver @Mr-Rm

sfaqer avatar Jul 16 '24 00:07 sfaqer

Кажется, таких извращений рефлектор не предусматривает by design. Ну т.е. примерно понятно где ошибка, такое просто не предусмотрели.

EvilBeaver avatar Jul 16 '24 08:07 EvilBeaver

Кажется, таких извращений рефлектор не предусматривает by design. Ну т.е. примерно понятно где ошибка, такое просто не предусмотрели.

Дык в 1.8 работало, в 1.9 сломалось

sfaqer avatar Jul 16 '24 10:07 sfaqer

Даже так? Спасибо, посмотрю (но не знаю когда)

EvilBeaver avatar Jul 16 '24 10:07 EvilBeaver

Падает на https://github.com/EvilBeaver/OneScript/blob/ffe8dbecd6b17b54aae7f5e391da08460b08c56b/src/ScriptEngine/Machine/IRuntimeContextInstance.cs#L78 Сломалось в 1.8.1

Mr-Rm avatar Jul 16 '24 11:07 Mr-Rm

К @Absolemus по PR #1242 Верно ли, что Рефлектор.ПолучитьТаблицуСвойств(ЭтотОбъект,Истина); должен получать то же, что и ПолучитьТаблицуСвойств(ЭтотОбъект, Ложь), включая переданный контекст, плюс глобальные неэкспортные переменные модуля? А неглобальные?

Mr-Rm avatar Jul 18 '24 12:07 Mr-Rm

Что-то я не помню, чтобы переданный контекст когда-то отдавался рефлектором (и не думаю, что должен). Это же просто символы, доступные для обращения, как имя модуля.

nixel2007 avatar Jul 18 '24 20:07 nixel2007

По описанию метода "ЗагрузитьСценарий", да и фактически, передаваемый контекст - это полноценный набор глобальных переменных, экспортируемых в вызывающий модуль:

Контекст = Новый Структура("Арг", 1);
ЗагрузитьСценарийИзСтроки("Арг=2;", Контекст);
Сообщить("Арг="+Контекст.Арг);

Арг=2

И это несмотря на возникающую ошибку: {Модуль <string 8A9886C3> / Ошибка в строке: 1 / Свойство недоступно для записи} Баг?

Mr-Rm avatar Jul 18 '24 21:07 Mr-Rm

К @Absolemus по PR #1242 Верно ли, что Рефлектор.ПолучитьТаблицуСвойств(ЭтотОбъект,Истина); должен получать то же, что и ПолучитьТаблицуСвойств(ЭтотОбъект, Ложь), включая переданный контекст, плюс глобальные неэкспортные переменные модуля? А неглобальные?

По задумке - должен. Контекст это внешние видимые части объекта, как реквизиты в модуле документа, например.

EvilBeaver avatar Jul 19 '24 04:07 EvilBeaver

По задумке - должен. Контекст это внешние видимые части объекта, как реквизиты в модуле документа, например.

А это разве не "глобальный контекст" типа как "АргументыКоманднойСтроки" ?

sfaqer avatar Jul 19 '24 04:07 sfaqer

Передаваемый контекст перекрывает глобальный:

Контекст = Новый Структура("АргументыКоманднойСтроки", "Перекрыто!");
ЗагрузитьСценарийИзСтроки("Cообщить(АргументыКоманднойСтроки)", Контекст);

Перекрыто!

То же для , например Консоль. Но:

Контекст = Новый Структура("ЭтотОбъект", "Перекрыто!");
ЗагрузитьСценарийИзСтроки("Cообщить(ЭтотОбъект)", Контекст);

{Модуль C:_lab\OneScript\OsReflectorBug\test.os / Ошибка в строке: 2 / Внешнее исключение (System.InvalidOperationException): Symbol already defined in the scope (ЭтотОбъект)}
ЗагрузитьСценарийИзСтроки("Cообщить(ЭтотОбъект)", Контекст);

Замеченный выше баг со "Свойство недоступно для записи" воспроизвести не удалось. Значит, переданные через контекст свойства - всё же строго r/o (так ли задумывалось?)

Mr-Rm avatar Jul 19 '24 12:07 Mr-Rm

Странное с Рефлектором:

Ст = Новый Структура("Поле1, Поле2", -1, -2);
ТСв=Рефлектор.ПолучитьТаблицуСвойств(Ст);
Сообщить("Т0:"+ТСв.Количество());
ТСв=Рефлектор.ПолучитьТаблицуСвойств(Ст, Истина); // <--
Сообщить("Т1:"+ТСв.Количество());

Т0:2 Т1:0 // ?? GetPropertiesWithPrivate и GetPropertiesWithoutPrivate сделаны существенно по-разному

Mr-Rm avatar Jul 19 '24 13:07 Mr-Rm

Баг?

Нет. Передаваемый контекст доступен только для чтения, так и задумано.

С перекрытием то же самое, перекрывать должен, как перекрывает Перем в методе

EvilBeaver avatar Jul 21 '24 14:07 EvilBeaver

Сейчас получается, что Рефлектор.ПолучитьТаблицуСвойств(..., Истина); возвращает только приватные свойства, а не все, включая приватные. Верно ли это? Изменение может затронуть библиотеки autumn и decorator, возможно и другие. Исключение при попытке перекрытия ЭтотОбъект нужно более информативное. В таблицу свойств не передаётся признак свойства о возможности записи.

Это для v1. В v2 всё реализовано и работает по-другому, в т. ч. "System.NotImplementedException" в ряде случаев

Mr-Rm avatar Jul 22 '24 13:07 Mr-Rm

@nixel2007 @sfaqer вы основные клиенты рефлектора, подскажите, как правильно? Я полагал, что "все, включая приватные"

EvilBeaver avatar Jul 24 '24 10:07 EvilBeaver

GetPropertiesWithPrivate и GetPropertiesWithoutPrivate сделаны существенно по-разному

@Mr-Rm там ужас что и давно бы пора навести там порядок со свойствами, полями, экспортными неэкспортными и тем, что выставляется в контекст.

EvilBeaver avatar Jul 24 '24 10:07 EvilBeaver

@nixel2007 @sfaqer вы основные клиенты рефлектора, подскажите, как правильно? Я полагал, что "все, включая приватные"

Полагаю так же, "все включая приватные", ей богу я был уверен что оно так и работает.

sfaqer avatar Jul 24 '24 12:07 sfaqer

Полагаю так же, "все включая приватные", ей богу я был уверен что оно так и работает.

Оно даже тестами вроде как покрыто....

EvilBeaver avatar Jul 25 '24 09:07 EvilBeaver

Тесты покрывают не все типы объектов, а сосредоточены, в основном, на Сценариях - там всё работает. Можно, конечно, ограничить применение Рефлектора только Сценариями. Аннотаций у свойств/методов других типов не бывает.

Mr-Rm avatar Jul 25 '24 11:07 Mr-Rm

Отмечу здесь

Ст = Новый Структура("Поле1, Поле2", -1, -2);
ТСв=Рефлектор.ПолучитьТаблицуСвойств(Ст);
Сообщить("КСт="+ТСв.Количество());

В v1 КСт=2, v2 падает с NotImplemented

ФСт = Новый ФиксированнаяСтруктура("Поле1, Поле2", -1, -2);
ТСв=Рефлектор.ПолучитьТаблицуСвойств(ФСт);
Сообщить("КФСт="+ТСв.Количество());

Обе версии показывают КФСт=0, всегда. Причина - у ФиксированнаяСтруктура нет переопределения функции GetPropCount(), а из базового DynamicPropertiesAccessor приходит 0. (Посмотреть в других объектах)

Mr-Rm avatar Aug 09 '24 13:08 Mr-Rm

Я от флага "включая приватные" ожидаю, что будут возвращены все, включая приватные :) В плане либ - практически все высокоуровневые либы используют Хоревский reflector, так что главное, чтобы он работал. Но выпустить фикс, конечно же, не проблема, главное понять, что там сломается. Тесты у либы тоже в избытке.

nixel2007 avatar Aug 11 '24 19:08 nixel2007

@Mr-Rm вижу коммит. Добьешь до пуллреквеста?

EvilBeaver avatar Feb 05 '25 18:02 EvilBeaver

Для v2 сделаю, там отмеченного в начале бага нет. Но там всё через LINQ, нет ли вопросов к быстродействию рефлектора?

Mr-Rm avatar Feb 06 '25 07:02 Mr-Rm

Для v2 сделаю, там отмеченного в начале бага нет. Но там всё через LINQ, нет ли вопросов к быстродействию рефлектора?

А Linq сильно медленнее по факту? В яве стримы, например, очень хорошо оптимизированы, я им тоже поначалу не доверял, но они реально быстрые

EvilBeaver avatar Feb 06 '25 18:02 EvilBeaver

нет ли вопросов к быстродействию рефлектора?

А про какие конкретно операции идёт речь? У него кмк конструктор тяжеловат, или речь про что-то другое?

sfaqer avatar Feb 07 '25 01:02 sfaqer

ПолучитьТаблицуСвойств самая тяжелая. А конструктор же почти пустой (для v2). О конструкторе Рефлектора: нужен ли он? Не перевести ли Рефлектор в глобальный синглтон, подобно Консоль?

Mr-Rm avatar Feb 07 '25 08:02 Mr-Rm

С консолью в прошлый раз огребли проблем. Лучше не надо пока

EvilBeaver avatar Feb 07 '25 19:02 EvilBeaver

@Mr-Rm а эта задача закрывается реквестом #1503 или еще что-то надо будет по ней сделать после вливания реквеста?

EvilBeaver avatar Feb 09 '25 14:02 EvilBeaver

v2 закрывается #1503, Для v1 готовится PR

Mr-Rm avatar Feb 09 '25 15:02 Mr-Rm