OberonCore https://forum.oberoncore.ru/ |
|
Как починить тип SIZE? https://forum.oberoncore.ru/viewtopic.php?f=22&t=6805 |
Страница 1 из 1 |
Автор: | budden [ Суббота, 02 Октябрь, 2021 14:40 ] |
Заголовок сообщения: | Как починить тип SIZE? |
Если мы правильно перевели сообщение о языке, то имеет место такой факт: Цитата: Хотя тип SIZE - со знаком, а ADDRESS - без знака, эти типы считаются совместимыми по присваиванию в обоих направлениях. Учитывая, что тип SIZE интенсивно применяется, получается дыра в типобезопасности размером почти с адресную арифметику, а то и шире. У меня уже был один случай, когда из-за этого мой код не работал (перепутал параметр и вместо кода записи в реестре строк передавал адрес записи, или наоборот). С учётом того, что эта проблема была закопана и проявлялась только косвенно, это доставило немало неприятных минут (или часов, не помню уже). По смыслу SIZE - это разность адресов и именно так она у меня и переведёна в настоящее время. Сам по себе адрес отрицательным быть не может. Поэтому присваивание от SIZE к адресу смысла не имеет: отрицательные адреса ничему не соответствуют, а положительные не покрывают всего диапазона адресов. Обратная ситуация не лучше: адреса, превышающие MAX(SIGNED32), превратятся в отрицательные значения SIZE. Полагаясь на поведение при переполнении, всё же этим типом иногда можно пользоваться. Хотя в языке я не заметил, чтобы поведение при переполнении было определено, значит, по-хорошему, им пользоваться нельзя. Кроме использования для вычислений над адресами и размерами объектов в байтах, SIZE используется в качестве счётчика. Таким образом, мы можем написать что-то такое: Код: PROCEDURE z(ptr: POINTER TO myRecord, arr: ARRAY OF INTEGER); VAR counter : SIZE; VAR adrOfNextRecord : SIZE; BEGIN adrOfNextRecord := ADDRESS(ptr); (* или VAL(ADDRESS,ptr), не помню и не суть. Но случайно результат оказался MAX(INTEGER)-1 *) FOR counter := 0 TO LEN(arr)-1 DO adrOfNextRecord := adr + counter (* ошибка размерности: сложили счётчик с адресом *) (* неопределённое поведение: переполнение целого числа *) END; RETURN VAL(POINTER TO myRecord, adrOfNextRecord) END z Я не каждый месяц использую VAL и ADDRESS, поэтому мог ошибиться с преобразованиями, но я думаю, смысл ясен: совместимость по присваиванию порождает ряд ошибок. Как починить? Я бы сделал следующее:
Далее придётся написать инструмент для автотрансляции, который для каждого применения типа SIZE решит, в какой из двух типов его превратить. Пока не уверен, что это будет легко. Общая идея - смотреть, как применяется данная переменная и решать, превратить ли её в SIGNED32 (если это чисто счётчик) или в "разностьАдресов" (если она участвует в вычислениях с адресами). В последнем случае трудность состоит в анализе вызовов процедуры, что требует глобального анализа всей кодовой базы. Мой текущий инструментарий и с первой задачей едва справится, а со второй - вообще не справится. SIZE встречается в соврменных исходниках ЯОС 13000 раз, а ADDRESS - 8000 раз. Т.е. делать вручную малореально. Как более простой вариант - во всех местах, где происходит присвоение SIZE к ADDRESS и обратно, вставить явное преобразование - это должно быть нетрудно, а далее грепом найти эти преобразования и, возможно, руками или автоматически разметить, что в этом месте нужно превратить SIZE в разностьАдресов. В остальных случаях превратить в SIGNED32. Но при этом не трогать сигнатуры процедур. |
Автор: | budden [ Суббота, 02 Октябрь, 2021 17:11 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
Да, блин, задача какая-то эпическая. Мало того, что вряд ли обойдётся без глобального исследования (т.е. изучать процедуры и их вызовы), так ещё и семантически проблемы возникают. Например, на сегодня SIZEOF(T) возвращает SIZE. Но ведь куча - это тоже объект в памяти, и он может занимать более половины диапазона адресов. Но тогда у неё получается отрицательный размер. Это то, что мы имеем на сегодня, и чтобы в этом разобраться, нужно изучать устройство диапазонов допустимых адресов на всех платформах. Это я даже не говорю про исправление размера объекта, а про те проблемы, которые есть уже сейчас с типом SIZE. Если же речь идёт об исправлении, то мы заходим в тупик с таким невинным кодом: Код: PROCEDURE sumOfElements(CONST arr: ARRAY OF CHAR); VAR i: SIZE; VAR res : UNSIGNED64; BEGIN res := 0; FOR i := 0 TO LEN(arr)-1 DO INC(res,ORD(arr[i])) END END sumOfElements Т.е., нельзя иметь массив длиннее, чем MAX(INTEGER), и это только часть проблемы. Если мы попытаемся превратить i в SIGNED32, то мы сломаемся на 64 разрядной платформе, если речь идёт о переборе объектов в памяти (например, если это алгоритм сборщика мусора). Но не только. Мы также сломаемся, если попытаемся создать строку размером более 2 или 4Гб (или сколько там получается?). А такие строки в природе можно себе представить - какие-нибудь базы данных в памяти вполне могут быть представлены как ARRAY OF CHAR. Похоже, что решение этой задачи нужно дробить на много этапов, на каждом из которых придётся делать сколько-то ручной работы. Поэтому, видимо, нужно начать с того, чтобы изучить примерно следующее:
|
Автор: | budden [ Суббота, 02 Октябрь, 2021 22:46 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
В общем, на исходе дня я не вижу решения. Возможный вариант - перестать лицемерить, признать, что защиты от перепутывания числа с адресом нет, и не называть тип SIZE типом SIZE, поскольку он на самом деле не обозначает размер чего-то в памяти. Можно даже слить тип SIZE с типом INTEGER, поскольку разницы между ними всё равно никакой почти что нет (в меру моих незнаний). Чтобы энтропия не возрастала, можно перевести INTEGER "системноЗависимоеЦелое", а SIZE - "СистемноЗависимоеЦелое" (с большой буквы). Тогда они останутся разными типами. В перспективе автоматически вставить явные преобразования везде, где происходит превращение SIZE в ADDRESS и обратно. Тогда остаётся из плохого (для ЯОС), что название ужасно длинное. Оно так и должно быть - потому что в прикладном коде зависимость арифметики от платформы должна быть выписана явно (во всяком случае, таково моё текущее мнение). Т.е. тот, кто применяет этот тип, должен постараться сначала этого избежатЬ, а не пихать этот тип везде. Короткие названия имеют типы платформо-независимые, такие, как цел32 и бцел32. Вместо системно-зависимого можно было бы, слегка приврав, сказать "машинноеЦелое" или даже мцел, бмцел, или целШС (целое ширины слова). Но выбор перевода не относится к теме данного форума. |
Автор: | budden [ Суббота, 02 Октябрь, 2021 22:53 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
Для справки - ссылка на новость о переименовании числовых типов, которое было сделано в 2019 году. http://cas.inf.ethz.ch/news/1 Коммит называется "Merged rename branch", от 10.09.2019 До этого важным коммитом было "Merged size branch", когда LEN стала возвращать тип SIZE, 20.08.2019 (и это я считаю большой ошибкой, когда был заложен фундамент того, что размер и индекс представлены одним типом). Хотя, возможно, до меня начало доходить, откуда ноги растут: https://stackoverflow.com/questions/255 ... ize-t-in-c "As an implication, size_t is a type guaranteed to hold any array index" Т.е. скопировали size_t с Си. Но у Оберона свой путь, поэтому его сделали знаковым, а не беззнаковым. |
Автор: | Sergej Durmanov [ Воскресенье, 03 Октябрь, 2021 12:34 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
Зачем итерировать адреса через знаковый тип size? |
Автор: | budden [ Воскресенье, 03 Октябрь, 2021 14:02 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
Зачем вот такое компилируется без предупреждений? Код: MODULE Proba;
PROCEDURE z*; VAR a :ADDRESS; b :SIZE; BEGIN a:=b; b:=a; END z; END Proba. |
Автор: | budden [ Воскресенье, 03 Октябрь, 2021 14:42 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
Хотя и такое компилируется: Код: MODULE Proba; PROCEDURE z*; VAR a :ADDRESS; b :UNSIGNED32; c : SIZE; d : SIGNED32; BEGIN a:=b; a:=c; a:=d; b:=a; b:=c; b:=d; c:=a; c:=b; c:=d; d:=a; d:=b; d:=c; END z; END Proba. И только одна ошибка, на d:=b Ясно теперь. Проблема в том, что я думал, что в сказку попал, а оказывается, не в сказку ![]() |
Автор: | Sergej Durmanov [ Воскресенье, 03 Октябрь, 2021 17:32 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
budden писал(а): Зачем вот такое компилируется без предупреждений? Затем, что эти типы совместимы по присваиванию в обоих направлениях - отображаются друг на друга без потери точности. |
Автор: | budden [ Воскресенье, 03 Октябрь, 2021 17:38 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
Спасибо, всё понятно. |
Автор: | Sergej Durmanov [ Воскресенье, 03 Октябрь, 2021 18:02 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
budden писал(а): И только одна ошибка, на d:=b Очевидно, что количество ошибок будет зависеть от архитектуры и у меня здесь 5 ошибок.Очевидно, что, в соответстии с репортом, беззнаковый тип address поглощает знаковые и беззнаковые типы меньшей и равной размерности (без потери точности ), обратное поглощение возможно, естественно, только некоторыми типами в соотвествии с табличкой, указанной в этом же репорте. Так для 64 битного адреса это тип size и unsigned64. Проблема ещё в том, что на одной и той же архитектуре в разных режимах адрес может быть разной размерности и, в общем случае, вероятно, не получится сделать жесткое ограничерие без привлечения конверсии типов |
Автор: | budden [ Воскресенье, 03 Октябрь, 2021 20:22 ] |
Заголовок сообщения: | Re: Как починить тип SIZE? |
А в чём смысл того, что знаковый SIGNED32 поглощает адрес (на 32-разрядных платформах)? |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |