Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Очередной баг или так и задумано [D7]


Страницы:   1 2

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо