Баг RTL: файл открытый первым не закрывается под голым Wine

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

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

Аватара пользователя
Cheb
энтузиаст
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34
Контактная информация:

Сообщение Cheb »

:evil: Все баги давно отловлены, всё работает как часы, и даже страшную ЕРЕСЬ c FreeLibrary() закомментировал:

Код: Выделить всё

    if Detected then WineVersionString:= 'Wine' else Exit;
    Try
      ntdll:= LoadLibrary('ntdll.dll');
      if ntdll > 0 then begin
        vWineGetVersion := GetProcAddress(ntdll, 'wine_get_version');
        if Assigned(vWineGetVersion)
          then WineVersionString+= ' ' + vWineGetVersion();
        //FreeLibrary(ntdll);
      end;
    Except
    End;

Как лбом об стенку.
Причём, только при запуске коммандой wine <путь>chentrah.exe ! :evil:
При запуске из любого файлового менеджера - дабл коммандер (родной), тотал коммандер, гном коммандер (родной), даже из >wine explorer.exe - всегда, гарантированно, работает! :evil:

Изображение

:evil: :evil: :evil: :evil:

Добавлено спустя 5 часов 27 минут 20 секунд:
Я НАШОЛ! НАШОЛ, БЛДЖАД! ЭТО БАГ В RTL ПАСКАЛЯ!!!
:D :lol: :lol: :lol: :twisted: :twisted: :twisted: :evil: :evil: :evil: :evil: :!:

У меня в начале несколько раз с одним файлом елозит: открыть файл, закрыть файл, открыть файл, закрыть файл (проверяет можно ли записывать, тупо открывая на запись). Но! Эта С-с-с-сука его не закрывает! :evil:

Дано:
c:FPC2.6.4sourcertlobjpasclassesstreams.inc

Код: Выделить всё

destructor TFileStream.Destroy;

begin
  FileClose(FHandle);
end;


, что выливается в
c:FPC2.6.4sourcertlwinsysutils.pp

Код: Выделить всё

Procedure FileClose (Handle : THandle);
begin
  if Handle<=4 then
   exit;
  CloseHandle(Handle);
end;


В виндозе - всё пучком, хэндл = 28. Но когда это - первый файл, открытый под голым вайном, то этот драный в попу Handle равен точнёхонько 4 ! :evil: :evil: :evil: :evil: :evil:

И естессно ТОЛЬКО когда запускаешь коммандной строкой из терминала :x

Кто-нить, запостите пожалста на багтрекер, а то я себе не доверяю. Полезу туда сам - могу клавиатуру об монитор раз?##@% :evil:

У себя пока применю хак: при старте программы буду открывать мусорные файлы пока хэндл не станет больше 4.

Добавлено спустя 34 минуты 3 секунды:
Re: Баг RTL: файл открытый первым не закрывается под голым Wine
P.S. А вот ХРЕН. Просто открываю файлы-затычки - хендл оказывается 116, 120, 124, 128, 132.
Открываю файл который надо потом закрыть - хендл 4.

Таки баг вайна.
Последний раз редактировалось Cheb 11.11.2019 14:22:20, всего редактировалось 1 раз.
Mirage
энтузиаст
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia
Контактная информация:

Сообщение Mirage »

А зачем там это:

Код: Выделить всё

if Handle<=4 then
   exit;

Кто-нибудь знает?
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

Mirage писал(а):А зачем там это:

Код: Выделить всё

if Handle<=4 then
   exit;

Кто-нибудь знает?

да, безымянные константы доставляяют.
Скорей всего был написан для спасения стандартных хендлов. Например: GetStdHandle(cardinal(STD_INPUT_HANDLE)) мне вернул 3 (winxp).
Но нигде в мсдн-е не гарантируется значения хендлов за исключением INVALID_HANDLE_VALUE.

код был таков изначально с первой ревизии SVN, так что возможно ответ есть в CVS версии фрипаскаля.
Ну и вообще имеет смысл либо баг-репорт сделать, либо на мейллисте спросить.
Аватара пользователя
Cheb
энтузиаст
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34
Контактная информация:

Сообщение Cheb »

http://bugs.freepascal.org/view.php?id=27221 :(

Дойдут руки - заменю у себя в виндовс версии работу с файлами на собственный класс, юникодный и работающий на нативной для винды WideString.
TIniFile тоже придётся скопипастить, поскольку он так дебильно организован (поля private а не protected) что не поддаётся расширению, потомки не имеют доступа к ним.
Аватара пользователя
pda
постоялец
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Сообщение pda »

скалогрыз писал(а):Но нигде в мсдн-е не гарантируется значения хендлов за исключением INVALID_HANDLE_VALUE.

Потому что это для Unix. Но там дефолтные потоки имеют диапазон 0..2. Т.е. в наличии:
1. Нет обёртки {$IFDEF UNIX}.
2. Слишком большой диапазон.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Для unix используется совсем другой код (в файле rtl/unix/sysutils.pp), причем в нем никогда не было такого условия.
Аватара пользователя
pda
постоялец
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Сообщение pda »

Забавно. Хотя в window 0..2 тоже предопределены для частичной совместимости с posix.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

pda писал(а):Забавно. Хотя в window 0..2 тоже предопределены для частичной совместимости с posix.

я бы рад согласится, но как я писал выше GetStdHandle(STD_INPUT_HANDLE) - вернул 3.
та же фунция с параметрами STD_ERROR_HANDLE, STD_OUTPUT_HANDLE возвращает 11 и 7 соответственно.

имхо, заглушка если и была добавленна, то только на основе каких-то тайных знаний какой-нить NT 3.0 или 9x - пережиток суеверий.
Но даже если и так, то код должен бы выглядеть так

Код: Выделить всё

const
  UNIX_COMPAT_HANDLE_VALUE = 4;
...

if Handle<=UNIX_COMPAT_HANDLE_VALUE then
   exit;


WDDD: такой заглушки в D7 нет.

2 Sergei I. Gorelkin - как можно до cvs-а добраться? :) логи почитать.

Добавлено спустя 16 минут 8 секунд:
Re: Баг RTL: файл открытый первым не закрывается под голым Wine
изучаем хендлы методом перебора :)

Код: Выделить всё

uses Windows, SysUtils;
var
  flags : LongWord;
  i : integer;
  err : LongWord;
begin
  flags :=0;
  for i:=0 to 20 do begin
    write(i,' ');
    if Windows.GetHandleInformation(THandle(i), flags) then
      write('is handle: ',IntToHex(flags, 8))
    else begin
      err:= GetLastError;
      if err = ERROR_INVALID_HANDLE then write('invalid handle')
      else write('error: ', err );
    end;
    writeln;
  end;
end.
Аватара пользователя
pda
постоялец
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Сообщение pda »

скалогрыз писал(а):я бы рад согласится, но как я писал выше GetStdHandle(STD_INPUT_HANDLE) - вернул 3.

А тут надо внимательнее читать документацию:
The value of the handles returned by GetStdHandle are not 0, 1, and 2, so the standard predefined stream constants in Stdio.h (STDIN, STDOUT, and STDERR) cannot be used in functions that require a console handle.

Т.е. 0..2 - чисто файловые дескрипторы, для совместимости с posix, годящиеся только на fileread/filewrite, а GetStdHandle может вернуть другой дескриптор, который и на fileread/filewrite и на специальные консольные функции пригоден, вроде позиционирования курсора.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

The value of the handles returned by GetStdHandle are not 0, 1, and 2, so the standard predefined stream constants in Stdio.h (STDIN, STDOUT, and STDERR) cannot be used in functions that require a console handle.

это говорит о правилах использование хендла, т.к. CreateFile может сама вернуть значение от 0 и выше, что и происходит в случае Cheb-а.
Иными словами "не пологайтесь, на то, что хендлы стандартного вывода это 0, 1 и 2, и не пытайтесь использовать константы, а передавайте реально полученные хендлы из функци GetStdHandle()".

Это ладно. А вот значения 3 и 4 это константы чего? ведь код идёт как
if Handle<=4 then Exit

pda писал(а):Т.е. 0..2 - чисто файловые дескрипторы, для совместимости с posix, годящиеся только на fileread/filewrite, а GetStdHandle может вернуть другой дескриптор, который и на fileread/filewrite и на специальные консольные функции пригоден, вроде позиционирования курсора.

это всё хорошо, но паскаль никогда не отличался совместимостью с stdio.h
например, сий код это абсурд:

Код: Выделить всё

var 
  t : string;
begin
  t:=length('test');
  FileWrite(0, t, length(t));
  FileWrite(1, t, length(t));
  FileWrite(2, t, length(t));
end.

:)
Аватара пользователя
pda
постоялец
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Сообщение pda »

скалогрыз писал(а):т.к. CreateFile может сама вернуть значение от 0 и выше, что и происходит в случае Cheb-а.

Мы, кажется, не спорим о том есть баг в rtl или нет. Есть. :)

скалогрыз писал(а):Иными словами "не пологайтесь, на то, что хендлы стандартного вывода это 0, 1 и 2, и не пытайтесь использовать константы, а передавайте реально полученные хендлы из функци GetStdHandle()".

Ниееет. Для работы с windows-специфичными консольными функциями не используйте стандартные хендлы, а пользуйтесь GetStdHandle().

скалогрыз писал(а):это всё хорошо, но паскаль никогда не отличался совместимостью с stdio.h

Ну, приведённый код и правда абсурд (t : string; t:=length('test');), но речь не об этом, да fpc использует в windows GetStdHandle() для подключения к консоли. Соответственно, имеем стандартные переменные, типа StdOutputHandle, которая в linux стандартно равна 1, а в Windows у меня, например, 7.

Так что или сравнивать с ними или... Я вообще за то, чтобы убрать все проверки, кроме INVALID_HANDLE_VALUE, т.к. если человек собирается работать со стандартными потоками через TFileStream, то он должен знать что делает, при доступности:

Код: Выделить всё

InputStream := THandleStream.Create(GetStdHandle(STD_INPUT_HANDLE));
OutputStream := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE));


Добавлено спустя 11 минут 59 секунд:
Re: Баг RTL: файл открытый первым не закрывается под голым Wine
скалогрыз писал(а):А вот значения 3 и 4 это константы чего?

Полагаю, это двойная ошибка. Изначально хотели защитить стандартные потоки, но забыли, что они начинаются с нуля. Потом хотели написать <4, но ошиблись.
Другая версия - проверили результат GetStdHandle() и решили, что надо защищать 0..4 (хотя логичнее было бы 0..5).
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

pda писал(а):
скалогрыз писал(а):т.к. CreateFile может сама вернуть значение от 0 и выше, что и происходит в случае Cheb-а.

Мы, кажется, не спорим о том есть баг в rtl или нет. Есть. :)

меня больше всего интересует почему 4.
я бы ещё согласился со стандартными хендлами, в том случае если проверка была бы Handle<3 или Handle<=2 ... но 4!
это как половинка от 42? :mrgreen:
SSerge
энтузиаст
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Сообщение SSerge »

Файловый дескриптор 4 - принтер stdprn (PRN)
Файловый дескриптор 5 - stdaux (СOM1)

наследие MS-DOS
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

SSerge писал(а):Файловый дескриптор 4 - принтер stdprn (PRN)
Файловый дескриптор 5 - stdaux (СOM1)

наследие MS-DOS

допустим... тогда дескриптор 3 это что? :)
SSerge
энтузиаст
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Сообщение SSerge »

А.И.Касаткин "Управление ресурсами" (С) Минск, 1992

Для каждой программы MS-DOS создает свою уникальную таблицу открытых файлов, но массив описаний используется только один. Сама таблица открытых файлов первоначально хранится в специальной области памяти - Program Segment Prefix (PSP), В PSP под таблицу открытых файлов используется 80 байт, начиная со смещения 0018h. Следовательно, по умолчанию программа имеет не более 20 префиксов. Учитывая, что первые пять перфиксов зарезервированы под префиксы стандартных файлов [дальше несущественно]


Оттуда же далее:
0x0000 - CON stdin, стандартное устройство ввода
0x0001 - CON stdout - стандартное устройство вывода
0x0002 - CON stderr - стандартное устройство выдачи ошибок. Обычно дублирует префикс 1
0x0003 - AUX stdaux - стандартное дополнительное устройство. По умолчанию соответствует COM1
0x0004 - PRN stdprn - стандартное устройство печати


страница 53 :)

В предыдущем высказывании насчет пятого дескриптора была Википедия. В википедии лажа. :D Этот же источник достоверен.

Так что, коллеги, лажает скорее Wine, чем RTL - не должно бы ей под пользовательские файлы отдавать дескрипторы ниже пятого.
Ибо "стандартный принтер" с дескриптором 4 во всех виндовс до миллениума влючительно был гарантированно и печатал в обход драйвера на порт LPT, начиная с XP этот поток вроде как перехватывался драйвером и направлялся как plain text на принтер по умолчанию
Ответить