![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Очередной баг или так и задумано [D7]
oxffff © (2007-07-29 23:26:00)Существует непустая глобальная переменная
b:Iunknown;
Представьте два потока, которые одновременно пытаются выполнить следующий код
b:=nil;
Вот непосредственно код соответствия на Asm
function _IntfClear(var Dest: IInterface): Pointer;
asm
MOV EDX,[EAX]
TEST EDX,EDX
JE @@1
MOV DWORD PTR [EAX],0
PUSH EAX
PUSH EDX
MOV EAX,[EDX]
CALL DWORD PTR [EAX] + VMTOFFSET IInterface._Release
POP EAX
@@1:
end;
Я его слегка упрощу, чтобы более легче понять его. Уберем проверку на nil и сохранение eax;
function _IntfClear(var Dest: IInterface): Pointer;
asm
MOV EDX,[EAX]
MOV DWORD PTR [EAX],0
PUSH EDX
MOV EAX,[EDX]
CALL DWORD PTR [EAX] + VMTOFFSET IInterface._Release
end;
Теперь вернемся к нашем двум потокам.
Вообразите ситуацию, когда первый поток еще не выполнил _IntfClear.
Происходит переключение на второй поток, который выполняет _IntfClear и выделяет память по потому же адресу и обнуляет ее.
Вот сериализованный поток иструкций с комментариями
procedure TForm1.Button1Click(Sender: TObject);
var a:TinterfacedObject;
begin
a:=TinterfacedObject.Create;
b:=a;
asm
push ebx; //Сохраняем ebx.
//Первый поток
mov eax,b;
push eax; //Сохранение контекста потока и переключение на второй поток.
//Второй поток
mov eax,b; //
mov b,0;
push eax;
push eax;
mov eax,[eax];
call [eax+$08];
pop eax; // Была выделена память на том же самом месте, где и объект и была очищена.
mov [eax],0;
//обратное переключение на первый поток
pop eax; //Восстановление контекста потока .
mov b,0;
push eax;
mov eax,[eax];
call [eax+$08]; // Здесь мы получаем AV.
pop ebx;//Восстанавливаем ebx
end;
b:=nil;
end;
Получение AV вызвано тем, что текущая реализация _IntfClear расчитана на один поток.
Вопрос такой
это баг. Или As designed?
oxffff (2007-07-29 23:41:00) [21]
> jack128_ (29.07.07 23:35) [2]
> А с чего ты взял, что дельфя такие вещи должна синхронизировать?
> ?
А взял я это с того, что interface это тип Delphi. И код финализации должен быть потокозащищенным.
:)
oxffff (2007-07-29 23:40:00) [22]
> jack128_ (29.07.07 23:35) [2]
> А с чего ты взял, что дельфя такие вещи должна синхронизировать?
> ?
В смысле?
Я привел пример, который демонстрирует потенциальную возможность AV при одновременной очистке интерфейсной переменной из двух разных потоков.
Собственно _IntfCopy и _IntfClear можно поправить, чтобы подобной ситуации не возникло.
jack128_ (2007-07-29 23:35:00) [23]А с чего ты взял, что дельфя такие вещи должна синхронизировать??
oxffff (2007-07-29 23:28:00) [24]Такая ситуация может возникнуть и для _IntfCopy