четверг, 14 апреля 2016 г.

Cache': Дефект в косвенности аргумента команд

При исследовании особенностей выполнения argument indirection в различных реализациях MUMPS, я натолкнулся на дефект его реализации в cache и msm.
Начальной целью изучения был вопрос можно ли использовать некоторую строку в косвенном аргументе write чтобы команда ничего не выводила. При попытке использовать пустую строку получил
USER>w @""
 
W @""
^
<SYNTAX>
Что, в принципе, и было ожидаемым поведением. Но уже при подстановке строки из одного пробела получил более интересный результат:
USER>w @" "
 
USER>
Cache в ответ не выдала ошибку, а признала строку из пробела за корректный аргумент команды write. Предположение о том, что это эквивалент безаргументной формы write оправдалось:
USER>s a=123
 
USER>w @" "
 
a=123
USER>
Гораздо большее удивление вызвал факт, что в строке косвенного аргумента можно подставить после пробелов текст любых команд:
USER>s a=123
 
USER>w @" "
 
a=123
USER>w @" w 456"
 
a=123456
USER>
После исследования поведения других команд выяснилось, что тот же самый дефект присутствует для косвенного задания аргументов большинства остальных команд, имеющих синтаксическую форму
command @expr
expr = V commandargument
То есть для команд, имеющих аргумент и когда его можно задать косвенно.

Например
USER>w @"# k ^aaaaa"
Исключений совсем немного, например в аргументе zload корректность косвенного аргумента отслеживается:
USER>zl @"aa"
 
<NOROUTINE>
USER>zl @"aa w 123"
 
ZL @"aa w 123"
^
<SYNTAX>
USER>
Аналогичный дефект имеет и MSM:
MSM for Windows NT, Version 4.4.1 (RC-1)  Line #1  UCI: ******* Job #2
>w @""

<INDER>*XECUTE*:::2:10:
 0) *XECUTE*:: w @""
<INDER>*XECUTE*:::2:10: w @""
>w @" "

>
Здесь сервер MSM однозначно показывает, что ошибка у него произошла не при выполнении команды write, а при косвенном выполнении команды XECUTE. И, так же как и каше, вторую форму сервер MSM признал корректной и что-то выполнил.

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

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

Нужно помнить, что нештатное (я бы сказал дефектное) поведение серверов cache и msm с синтаксически некорректным косвенным аргументом противоречит стандарту и иные М-системы могут отрабатывать синтаксис более строго, например в системе M3-Lite:
M3 logon - Job #2
For HELP with command shell, type "?"
3>w @""
<SYNTX>

3>w @" "
<SYNTX>

3>
И в системе GT.M:
GTM>w @""
%GTM-E-EXPR, Expression expected but not found
 
        ^-----
GTM>w @" "
%GTM-E-EXPR, Expression expected but not found
 
        ^-----
GTM>w @" w 456"
%GTM-E-EXPR, Expression expected but not found
         w 456
        ^-----
Поэтому при написании переносимого кода не следует опираться на особенности трактовки и реализации косвенности в cache и msm. А как проверить синтаксическую корректность именно аргумента команд для случая каждой из команд - я не знаю.

Возвращаясь к исходной задаче - задать такой аргумент write, чтобы никакого вывода не производилось - у меня пока нашлось только одно решение: использовать соглашение о пустой строке. Вставить предусловие на команду и использованием самого аргумента:
USER>w:s'="" @s
Или
USER>w:$tr(s," ")'="" @s

Евгений Каратаев
При написании статьи были использованы ценные замечания Александра Чудновского и Константина Аристова. 

Комментариев нет:

Отправить комментарий