Баг RTTI. Set of ...

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Баг RTTI. Set of ...

Сообщение Devil » 11.12.2008 12:27:19

Вообще, надо бы этот топик направлять разработчикам FPC. Но:
1) английский я знаю плохо
2) если я правильно понял, сдесь обитает идин (несколько) из разработчиков FPC.

Собственно, Delphi-йский код, вычисляющий размер переменной типа Set of ... :

Код: Выделить всё
type
  TSomeType = char;// 20..32;
  TDDD = set of TSomeType;

function SetOf_Size(): integer;
const
  MASK_3 = $FF shl 3;
var
  tpinfo: PTypeInfo;
  TD: PtypeData;
begin
  tpinfo := typeinfo(TDDD);

  TD := GetTypeData(tpinfo);
  TD := GetTypeData(TD.CompType^); // GetTypeData(TD.CompType) в FPC; Ошибка, кстати, здесь возникает.
  with TD^ do
  begin
     Result := (((MaxValue+7+1)and MASK_3)-(MinValue and MASK_3))shr 3;
     if (Result = 3) then Result := 4;
  end;
end; 


С чего хочу начать. Во-первых, я так и не понял, из каких соображений высчитывается sizeof(TDDD), можно ли где-то почитать ? ИМХО нужно было сделать как в Delphi, хотя бы в mode delphi - а то могут возникнуть серьёзные проблемы в чтении/записи файлов, например.
Во-вторых, TD.CompType: pptypeinfo в Delphi и ptypeinfo в FPC; но это не проблема.

Теперь переходим к ошибке. Как показали эксперименты, ошибка возникает в строчке GetTypeData(TD.CompType) в том случае, если ord(high(TSomeType)) > 31. Иначе говоря, если TSomeType - обычный небольшой enum (например: TSomeType = (_1, _2, _3)), то TD.CompType генерируется правильный. Если ord(high(TSomeType)) > 31, то TD.CompType указывает на какую-то левую область памяти (не nil), обращение к которой приводит к AccessViolation.

Буду рад, если:
1) проясните ситуация с sizeof()
2) ошибка исправится в следующих версиях компилятора


И напоследок, если можно задам пару вопросов по поводу TTypeKind.
Есть ли какое-то принципиальное отличие (в плане содержания и RTTI и обработки) между:
tkLString и tkAString, tkRecord и tkObject, tkInterface и tkInterfaceRaw ?

Заранее спасибо.
Devil
новенький
 
Сообщения: 40
Зарегистрирован: 10.12.2008 09:56:33

Re: Баг RTTI. Set of ...

Сообщение Sergei I. Gorelkin » 11.12.2008 18:36:36

Devil писал(а):2) если я правильно понял, сдесь обитает идин (несколько) из разработчиков FPC.

Если это про меня - я не являюсь разработчиком, я просто предпочитаю фиксить мешающие лично мне баги самостоятельно, а не ждать, пока это сделает кто-то другой. В связи с чем сделал несколько патчей к компилятору и более-менее знаком с его внутренностями.

Что касается таких вот "ошибок": совместимости с Дельфи на этом уровне у FPC нет и не будет. Совместимость есть на уровне _документированных_ вещей, и то тех, которые реализуемы на всех поддерживаемых платформах.
{$mode delphi} в данном случае тоже не поможет: как линковать вместе два юнита с разными mode, если у них разная структура данных?

У FPC два размера set: 32 и 256 бит. Для него вот эта хрень с вычислением максимального элемента просто не нужна.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Баг RTTI. Set of ...

Сообщение Devil » 11.12.2008 18:49:26

Если это про меня - я не являюсь разработчиком, я просто предпочитаю фиксить мешающие лично мне баги самостоятельно...

не помню, ты - не ты.
во-вторых, ты так и не понял в чём ошибка. А ошибка, насколько я понял, действительно есть.

как линковать вместе два юнита с разными mode, если у них разная структура данных?

ну достаточно просто. Под каким mode-ом скомпилирована переменная/тип, столько байт она и занимает. Кстати о документированных вещах в Delphi... sizeof() множества = 1..32 .

У FPC два размера set: 32 и 256 бит.

ну допустим, я не против. Но как определить размер множества, зная его typeinfo ?

Код: Выделить всё
TSomeType = 10..32;
TSomeTypeSet = set of TSomeType;

var
  tpinfo: PTypeInfo;
begin
  tpinfo := typeinfo(TSomeTypeSet);
  // sizeof(TSomeTypeSet) ?
Devil
новенький
 
Сообщения: 40
Зарегистрирован: 10.12.2008 09:56:33

Re: Баг RTTI. Set of ...

Сообщение Sergei I. Gorelkin » 11.12.2008 19:45:53

Я не отрицаю того, что ошибка есть/может быть. Ошибки всегда есть, к тому же эти "большие множества" не так давно переделывали, может чего и забыли.
Просто то, что не работает дельфевый код - это не ошибка.
Чтобы понять, что там на самом деле происходит, нужно сидеть разбираться. Скомпилить в тот же ассемблер, посмотреть, что получается на месте typeinfo, сравнить с описанием структур в модуле typeinfo и т.п. Станет понятно, на какое лево этот указатель указывает.
Есть вероятность, что в модуле typeinfo есть аналогичная ф-ция, которая работает.

Devil писал(а):ну достаточно просто. Под каким mode-ом скомпилирована переменная/тип, столько байт она и занимает.

А дальше что? Превращаться в интерпретатор, проверяя RTTI на каждой операции, или пихать в RTL поддержку всех операций во всех возможных комбинациях? :)
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Баг RTTI. Set of ...

Сообщение Devil » 12.12.2008 11:03:41

Ошибка есть. ОБъясняю.
по каждому типу генерируется RTTI. Доступ к этому RTTI осуществляется в первую очередь через рантайм-функция typeinfo(...);
Т.е. таким образом мы получаем typeinfo по типу TSomeTypeSet:
Код: Выделить всё
var
  tpinfo: PTypeInfo;
begin
  tpinfo := typeinfo(TSomeTypeSet);


PTypeInfo содержит Kind (tkSet) и Name ('TSomeTypeSet'). но это далеко не всё. Есть более важная функция GetTypeData(tpinfo).

Так вот. TypeData для множеств содержит информацию о подмножественном типе (TSomeType) и содержится в поле TTypeData.CompType: PTypeInfo. Т.е. для множества TSomeTypeSet, TTypeData.CompType должен содержать typeinfo(TSomeType).

На практике так и есть. НО! Если тип TSomeData "большой", то TTypeData.CompType указывает на левые данные. И обращение к этим данным приводит к AccessVialotion. В этом и есть ошибка. Куда по этому поводу можно написать ?

Добавлено спустя 59 минут 6 секунд:
а что по поводу размера множества, то...

ну есть, например, директива {$MINENUMSIZE}, в зависимости от которой расчитывается sizeof() переменной. Аналогично можно поступить и с множествами. По моему скромному мнению, sizeof() множеств надо сделать как в Delphi. Минусов от этого не будет.
Devil
новенький
 
Сообщения: 40
Зарегистрирован: 10.12.2008 09:56:33

Re: Баг RTTI. Set of ...

Сообщение Sergei I. Gorelkin » 12.12.2008 16:04:03

Я написал в багтрекер: http://bugs.freepascal.org/view.php?id=12788

Там действительно пропущен байт, причем в typinfo.pp нет ни малейшего намека на то, что этот байт должен быть. Из-за этого GetTypeData возвращает указатель на 1 больше, чем нужно.

Что касается дизайна множеств...
Дельфи пытается экономить на спичках, выделяя под множества минимально возможное количество памяти. Возможно, этот подход чем-то оправдан, особенно если учесть, сколько было памяти в типичной машине во времена, когда его писали. Однако множества - это не только относительно простые include/exclude/in, это еще и операции объединения и пересечения. С дизайном Дельфи получается, что при любой операции со множествами их приходится приводить к общей базе (все тем же 0..255), выделяя память и копируя данные со сдвигом. Этот расширение выполняется в разы дольше, чем сама операция, кода на вызов вспомогательных операций генерится опять же больше, чем 32 байта, которые заняли бы уже расширенные аргументы. Возникает вопрос - а зачем?
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Баг RTTI. Set of ...

Сообщение Devil » 12.12.2008 16:13:12

Там действительно пропущен байт, причем в typinfo.pp нет ни малейшего намека на то, что этот байт должен быть. Из-за этого GetTypeData возвращает указатель на 1 больше, чем нужно.

Большое спасибо. Что не поленился, провёл опыт и отписал в баг треке.

С дизайном Дельфи получается, что при любой операции со множествами их приходится приводить к общей базе (все тем же 0..255), выделяя память и копируя данные со сдвигом...


Не верю. Надо продизассемблить.
Devil
новенький
 
Сообщения: 40
Зарегистрирован: 10.12.2008 09:56:33

Re: Баг RTTI. Set of ...

Сообщение Sergei I. Gorelkin » 12.12.2008 17:11:12

А вот такой пример его вообще убивает (Дельфи 7 - Internal error C1118):
Код: Выделить всё
type
  tset1 = set of 25..63;
  tset2 = set of 64..75;

var
  s1: tset1; s2: tset2;
  s3: set of 0..127;

begin
  s3 := s1 + s2;
end;

Не лезет внутреннее представление в диапазон результата, а сжимать он не умеет :)
Но если s3 объявить как set of 0..255, то все нормально...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Баг RTTI. Set of ...

Сообщение Devil » 15.12.2008 10:46:24

Мда, действительно, интересно.

Но справедливости ради стоит отметить,что на практике все операции с множествами происходят над однотипными переменными. имхо.
Devil
новенький
 
Сообщения: 40
Зарегистрирован: 10.12.2008 09:56:33

Re: Баг RTTI. Set of ...

Сообщение Cheb » 21.12.2008 21:23:08

Для этого существуют директивы компилятора.
{$ifdef fpc}
работать с множествами по фри паскальски
{$else}
работать с множествами дельфийски
{$endif}

Я в своей чеперси именно такой подход использую.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: Баг RTTI. Set of ...

Сообщение Devil » 22.12.2008 14:50:47

ну нифига себе решение! :))
Devil
новенький
 
Сообщения: 40
Зарегистрирован: 10.12.2008 09:56:33


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5

Рейтинг@Mail.ru