Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 18.09.06 08:11
Оценка: 54 (7)
#Имя: FAQ.com.counitialize.bug
Доброго всем понедельника.

У меня от тоже добрый. На протяжении последнего времени меня, время от времени, долбило сообщение об AV (чур меня, чур меня) при деинициализации COM-а.

Вчера меня оно стало уже конкретно напрягать и сегодня, приготовив ведро с вазелином, решил ... багу до смерти.

Что выяснил.
1. В COM-объекте, используемом в программе, происходила ошибка. Которую он честно возвращал клиенту через SetErrorInfo. Клиент, так уж получалось, на это дело ложил и оставлял объект ошибки висеть в памяти.
2. Объект с описанием ошибки был нестандартный и реализовывался не стандартным комом (в ole32.dll?), а в oledb32.dll. Естественно, интерфейс IErrorInfo у него был.
3. При вызове CoUninitialize, сначала выгружаются все библиотеки с COM-объектами (в том числе моя и oledb32.dll), а потом освобождается объект ошибки.
Но объекта ошибки, ясный пень, в памяти уже нет (DLL-то уже тю-тю) — так что появляется злополучный AV

Бага проявляется как на Win2000 так и на XP со всеми обновлениями.

Я требую пустить кровь тому кто реализовывал CoUninitialize или, что хуже, израсходовать на него остатки вазелина!

Пока что решил перед вызовом CoUninitialize самому вызывать SetErrorInfo(0,NULL) — это реально помогает
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 18.09.06 11:58
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Доброго всем понедельника.


Наверное, надо пояснить, где подобная ошибка может произойти.

Ну во-первых, если вы, для своего ActiveX-объекта, самостоятельно реализуете объект ошибки с интерфейсом IErrorInfo.

Во-вторых, если вы юзаете такой объект и забиваете на получение объектов ошибок.

В третьих, если вы прямо или косвенно работаете с OLEDB-провайдерами. Провайдеры, как правило, используют объекты ошибок из oledb32.dll. Это был как раз мой случай

--------------
И, кстати говоря, тут сформулировалось очередное правило компоненто-писателям. При разрушении вашего COM-объекта не стоит обрабатывать внутренние ошибки и пытаться сообщить о них клиенту через пресловутый объект-ошибки. Я про реализацию деструкторов, если вы пишете на C++.

Во-первых, вы можете затереть действительно полезную ошибку другого COM-объекта (который юзал и инициировал разрушение вашего COM-объекта)
Во-вторых, вы потенциально нарываетесь на ранее описанную ошибку с CoUninitialize. Клиенту, как правило, по-барабану ошибки освобождения COM-объектов.

--------------
Вот. Обожаю COM и все его грабли
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 18.09.06 13:17
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Ну во-первых, если вы, для своего ActiveX-объекта, самостоятельно реализуете объект ошибки с интерфейсом IErrorInfo.


КД>>2. Объект с описанием ошибки был нестандартный и реализовывался не стандартным комом (в ole32.dll?), а в oledb32.dll. Естественно, интерфейс IErrorInfo у него был.


А можно поподробнее о нестандартном объекте ошибок. Что это за объект, кто написал, кто создает и т.п.

Видишь ли, тут не предъявить претензии именно к CoUninitialize: она работает как умеет. Если кто-то не закрыл счетчик ссылок объекта и позволил серверу этого объекта уйти, вот этот кто-то — злобный буратино. Так что решение SetErrorInfo(0,NULL) уничтожает зловредное влияние этого "кто-то", а не CoUninitialize. Аналог этому действию — End в VB, когда приложение не думает завершаться по Unload.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[3]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 18.09.06 13:38
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>>Ну во-первых, если вы, для своего ActiveX-объекта, самостоятельно реализуете объект ошибки с интерфейсом IErrorInfo.


КД>>>2. Объект с описанием ошибки был нестандартный и реализовывался не стандартным комом (в ole32.dll?), а в oledb32.dll. Естественно, интерфейс IErrorInfo у него был.


Vi2>А можно поподробнее о нестандартном объекте ошибок. Что это за объект, кто написал, кто создает и т.п.


В OLEDB есть собственная реализация объекта ошибки. Помимо IErrorInfo она реализует интерфейс IErrorRecords, что позволяет создавать коллекции ошибок. Создается этот объект через CoCreateInstance(CLSID_EXTENDEDERRORINFO,...). Создается OLEDB-провайдером, когда он хочет вернуть клиенту "правильный" объект OLEDB-ошибки. Устанавливается как обычная ошибка автоматизации через SetErrorInfo. Живет в oledb32.dll.

Помимо коллекции ошибок, этот объект еще хранит параметры ошибки, которые потом используются при формировании сообщения об ошибки (с учетом языка пользователя). То есть, создаешь такой объект-ошибки, запихиваешь в него параметры, а он потом передает эти параметры и lcid твоему другому "спец-объекту" OLEDB-провайдера с интерфейсом IErrorLookup, чтобы последний сформировал текст ошибки.

Vi2>Видишь ли, тут не предъявить претензии именно к CoUninitialize: она работает как умеет. Если кто-то не закрыл счетчик ссылок объекта и позволил серверу этого объекта уйти, вот этот кто-то — злобный буратино. Так что решение SetErrorInfo(0,NULL) уничтожает зловредное влияние этого "кто-то", а не CoUninitialize. Аналог этому действию — End в VB, когда приложение не думает завершаться по Unload.


Ха. Извините меня — я зарегистрировал в окружении COM-а объект-ошибку и он вызвал для нее AddRef. Все — он за неё отвечает. Клиент и, тем более, сам COM-объект (зарегистрировавший эту ошибку) за этот объект-ошибку не отвечают. За него отвечает окружение. Оно же вызывает, в конечном итоге, для него Relеase и соответственно нарывается на AV — так что оно (окружение) это понимает, но разработчик CoUninitialize тестировал только с тем объектом ошибки, который живет в ole32.dll.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[4]: Бага в CoUninitialize
От: Константин Л. Франция  
Дата: 18.09.06 13:43
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Ха. Извините меня — я зарегистрировал в окружении COM-а объект-ошибку и он вызвал для нее AddRef. Все — он за неё отвечает. Клиент и, тем более, сам COM-объект (зарегистрировавший эту ошибку) за этот объект-ошибку не отвечают. За него отвечает окружение. Оно же вызывает, в конечном итоге, для него Relеase и соответственно нарывается на AV — так что оно (окружение) это понимает, но разработчик CoUninitialize тестировал только с тем объектом ошибки, который живет в ole32.dll.


Вот тут позволю себе не согласиться. Кто-то должен управлять временем жизни этой ошибки. Этот "кто-то" либо клиент, либо сервер, тк среда, похоже by design, за нее не отвечает. Так что тут банальный interface leak
Re[5]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 18.09.06 14:11
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Вот тут позволю себе не согласиться. Кто-то должен управлять временем жизни этой ошибки. Этот "кто-то" либо клиент, либо сервер, тк среда, похоже by design, за нее не отвечает. Так что тут банальный interface leak


Пожалуйста, это дело такое. Никто не заставляет.

Но рекомендую бросать молится на тех, кто сидит в MS. Я встречал у них баги и пострашнее, чем этот несчастный CoUnitialize.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[6]: Бага в CoUninitialize
От: Константин Л. Франция  
Дата: 18.09.06 14:15
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, Константин Л., Вы писали:


КЛ>>Вот тут позволю себе не согласиться. Кто-то должен управлять временем жизни этой ошибки. Этот "кто-то" либо клиент, либо сервер, тк среда, похоже by design, за нее не отвечает. Так что тут банальный interface leak


КД>Пожалуйста, это дело такое. Никто не заставляет.


КД>Но рекомендую бросать молится на тех, кто сидит в MS. Я встречал у них баги и пострашнее, чем этот несчастный CoUnitialize.

дык, никто и не молится
Re[5]: Бага в CoUninitialize
От: Лазар Бешкенадзе СССР  
Дата: 18.09.06 15:18
Оценка: +1
Здравствуйте, Константин Л., Вы писали:

КЛ>Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>>Ха. Извините меня — я зарегистрировал в окружении COM-а объект-ошибку и он вызвал для нее AddRef. Все — он за неё отвечает. Клиент и, тем более, сам COM-объект (зарегистрировавший эту ошибку) за этот объект-ошибку не отвечают. За него отвечает окружение. Оно же вызывает, в конечном итоге, для него Relеase и соответственно нарывается на AV — так что оно (окружение) это понимает, но разработчик CoUninitialize тестировал только с тем объектом ошибки, который живет в ole32.dll.


КЛ>Вот тут позволю себе не согласиться. Кто-то должен управлять временем жизни этой ошибки. Этот "кто-то" либо клиент, либо сервер, тк среда, похоже by design, за нее не отвечает. Так что тут банальный interface leak


В данном случае именно "среда" этим управляет потому как от сервера
предполагается только вызов SetErrorInfo, а от клиента ожидают вызова
GetErrorInfo, причем ни от одного этого не требуют. Ошибка живет в
потоке и именно "среда" освобождает не съеденную клиентом ошибку, если
сервер пытается установить новую. Так что и в недрах CoUninitialize
разумно ожидать сначала освобождения объекта ошибки, а потом уже
выгрузки DLL, которая этот объект реализует.

Я проэксперементировал с custom error object и все происходит именно
так, как описывает Дмитрий. Я с ним согласен, здесь MS явно ошиблась.

Лазар
Re[3]: Бага в CoUninitialize
От: Аноним  
Дата: 18.09.06 17:08
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Видишь ли, тут не предъявить претензии именно к CoUninitialize: она работает как умеет. Если кто-то не закрыл счетчик ссылок объекта и позволил серверу этого объекта уйти, вот этот кто-то — злобный буратино. Так что решение SetErrorInfo(0,NULL) уничтожает зловредное влияние этого "кто-то", а не CoUninitialize. Аналог этому действию — End в VB, когда приложение не думает завершаться по Unload.


Не согласен. Если вы намекаете на неправильные module locks — правильные не помогут в случае вызова CoUninitialize — ему на DllCanUnloadNow плевать.
ИМХО: Интерфейс отдаётся в распоряжение системы, она принимает на себя ответственность за его своевременное уничтожение перед до вызова CoUninitialize, или же такое требование к интерфейсу (перехват вызова CoUninitialize и самоуничтожение) должно быть документировано. ИМХО — это баг.
Re[5]: Бага в CoUninitialize
От: Аноним  
Дата: 18.09.06 17:10
Оценка: +1
Здравствуйте, Константин Л., Вы писали:

КЛ>Вот тут позволю себе не согласиться. Кто-то должен управлять временем жизни этой ошибки. Этот "кто-то" либо клиент, либо сервер, тк среда, похоже by design, за нее не отвечает. Так что тут банальный interface leak

Да ну? И что же, если я пишу код пользующий СОМ сервер я должен после каждого вызова дергать GetErrorInfo, дабы этот ErrorInfo не утёк?
ИМХО: Интерфейс отдаётся в распоряжение системы, она принимает на себя ответственность за его своевременное уничтожение перед до вызова CoUninitialize, или же такое требование к интерфейсу (перехват вызова CoUninitialize и самоуничтожение) должно быть документировано. ИМХО — это баг.
Re[7]: Бага в CoUninitialize
От: Аноним  
Дата: 18.09.06 17:27
Оценка: :)
Здравствуйте, Константин Л., Вы писали:

КД>>Но рекомендую бросать молится на тех, кто сидит в MS. Я встречал у них баги и пострашнее, чем этот несчастный CoUnitialize.

КЛ>дык, никто и не молится
Не правда ваша, многие как раз. А почему — действительно непонятно. Когда-то — да, каждый из нескольких десятков программеров работавших в МС был профи, теперь это тысячи индусов и русских закончивших институт год-два-три назад, ещё ничему не научившихся и способных делать любые глупейшие ошибки. Хорошо хоть тестеров там больше чем кодеров.
ИМХО — БГ от этого и бежит. ИМХО: они ошиблись в том, что подумали что набрав тысячи програмеров они смогут свернуть горы. Годах в 96-98 набрали — результат плачевный — больше никогда и ничего не смогли сделать в срок даже близко (Vista — апофеоз) и хотя бы с 50% запланированного функционала. НТ тим был вроде 50 человек и сделали его "играючи". 2к тим был вроде 2000 програмеров + 3000 тестеров — еле-еле сделали не уложившись в сроки в 2-3 раза (он же НТ 5 должен был зваться и выйти в 97-98). ИМХО: оригинальный НТ тим легко сделал бы в срок. Сверхприбылей уже нет — всё явно съедает эта толпа програмеров. Права на бизнес-ошибку (коих в истории майкрософта навалом) больше нет — нет денежного резерва как раньше, когда доходы сильно превышали расходы. И выгнать всю эту толпу никак — не простит биржа, трудовое законодательство, да и самим обидно.
Re[4]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 05:39
Оценка: 8 (1)
Здравствуйте, Аноним, Вы писали:

А>Не согласен. Если вы намекаете на неправильные module locks — правильные не помогут в случае вызова CoUninitialize — ему на DllCanUnloadNow плевать.

А>ИМХО: Интерфейс отдаётся в распоряжение системы, она принимает на себя ответственность за его своевременное уничтожение перед до вызова CoUninitialize, или же такое требование к интерфейсу (перехват вызова CoUninitialize и самоуничтожение) должно быть документировано.

У-у, как страшно! А ты читал про DllCanUnloadNow? При правильном module locks сервер для объекта никогда не выгрузится, пока есть активные ссылки на его объекты. Наверное, дело в том, что нестандартный объект-ошибка не блокирует выгрузку своего сервера. Но это уже не проблема для CoUninitialize. Вот то, что я хотел сказать.

А>ИМХО — это баг.


Да, очевидно. Но чей? И если без разницы, то SetErrorInfo(0,NULL) — решение. За что и были поставлены баллы.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 05:45
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Извините меня — я зарегистрировал в окружении COM-а объект-ошибку и он вызвал для нее AddRef. Все — он за неё отвечает. Клиент и, тем более, сам COM-объект (зарегистрировавший эту ошибку) за этот объект-ошибку не отвечают. За него отвечает окружение. Оно же вызывает, в конечном итоге, для него Relеase и соответственно нарывается на AV — так что оно (окружение) это понимает, но разработчик CoUninitialize тестировал только с тем объектом ошибки, который живет в ole32.dll.


Естественно. После вызова SetErrorInfo объект-ошибку можно релизить — ее счетчик на совести СОМ системы. Но почему ушла oledb32.dll, если, ты говоришь, в ней реализован объект-ошибка? Наверное, из-за тог, что приложение завершается. Значит, что-то не так с самим выходом.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[5]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 05:55
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Аноним, Вы писали:


А>>Не согласен. Если вы намекаете на неправильные module locks — правильные не помогут в случае вызова CoUninitialize — ему на DllCanUnloadNow плевать.

А>>ИМХО: Интерфейс отдаётся в распоряжение системы, она принимает на себя ответственность за его своевременное уничтожение перед до вызова CoUninitialize, или же такое требование к интерфейсу (перехват вызова CoUninitialize и самоуничтожение) должно быть документировано.

Vi2>У-у, как страшно! А ты читал про DllCanUnloadNow? При правильном module locks сервер для объекта никогда не выгрузится, пока есть активные ссылки на его объекты. Наверное, дело в том, что нестандартный объект-ошибка не блокирует выгрузку своего сервера. Но это уже не проблема для CoUninitialize. Вот то, что я хотел сказать.


Дык это, того — CoUninitialize это завершение работы. Это его основное назначение. То что он, извините, во время деинициализации сам себе наступает на ..., то это его проблема. Причем очевидно, что он выполняет деинициализацию в неправильном порядке — сначало нужно освободить COM-объекты, потом выгружать DLL.

Кстати говоря, ведь COM может держать не только объект ошибки, но и другие COM-объекты. Есть же функции регистрации активных ActiveX объектов (их названия сходу я не скажу). И что? Я более чем уверен — освобождение этих ActiveX-ов выполняется перед выгрузкой DLL-ей. Потому что иначе вообще любая более менее сложная программа основанная на COM завершалась бы по AV.

А>>ИМХО — это баг.


Vi2>Да, очевидно. Но чей? И если без разницы, то SetErrorInfo(0,NULL) — решение.


Это да. Удивляет то, что этот баг, по всей видимости, живет с самого рождения COM-а
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 06:09
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Коваленко Дмитрий, Вы писали:


Vi2>Естественно. После вызова SetErrorInfo объект-ошибку можно релизить — ее счетчик на совести СОМ системы. Но почему ушла oledb32.dll, если, ты говоришь, в ней реализован объект-ошибка? Наверное, из-за тог, что приложение завершается. Значит, что-то не так с самим выходом.


Вообще это было злополучное стечение багов. Коротко говоря, у меня при последнем Release внутри компонента возникала ошибка и я радостно пытался сообщить о ней клиенту через объект-ошибку из oledb32.dll. Ясный пень, клиент не будет проверять результаты работы Release, поэтому объект-ошибки продолжал висеть в памяти до деинициализции COM-а.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[6]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 06:36
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Дык это, того — CoUninitialize это завершение работы. Это его основное назначение. То что он, извините, во время деинициализации сам себе наступает на ..., то это его проблема. Причем очевидно, что он выполняет деинициализацию в неправильном порядке — сначало нужно освободить COM-объекты, потом выгружать DLL.


Это заблуждение: CoUninitialize — это не завершение работы.

CoUninitialize
Closes the COM library on the current thread, unloads all DLLs loaded by the thread, frees any other resources that the thread maintains, and forces all RPC connections on the thread to close.

Это не мешает заново в потоке вызвать CoInitialize и потом снова CoUninitialize. Так, конечно, никто не делает, но этот путь возможен.

А фраза "forces all RPC connections on the thread to close" может трактоваться как освобождение памяти под внутренние буфера для прокси/стабов. Но это освобождение никак не зависит от соответствия AddRef и Release, т.е. от наличия или отсутствия сервера поддержки.

КД>Кстати говоря, ведь COM может держать не только объект ошибки, но и другие COM-объекты. Есть же функции регистрации активных ActiveX объектов (их названия сходу я не скажу). И что? Я более чем уверен — освобождение этих ActiveX-ов выполняется перед выгрузкой DLL-ей. Потому что иначе вообще любая более менее сложная программа основанная на COM завершалась бы по AV.


В том-то и дело, что "объект ошибки и другие COM-объекты" ничем не отличаются. Вернее, отличаются только тем, кто реализовал код поддержки. И как криво. Поэтому это может быть не баг в CoUninitialize, а баг в обработчике ошибок DB и тому подобное. И может быть продулирован в их, DB, разделе для борьбы с надоедливым AV.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[7]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 06:52
Оценка:
Здравствуйте, Vi2, Вы писали:

КД>>Дык это, того — CoUninitialize это завершение работы. Это его основное назначение. То что он, извините, во время деинициализации сам себе наступает на ..., то это его проблема. Причем очевидно, что он выполняет деинициализацию в неправильном порядке — сначало нужно освободить COM-объекты, потом выгружать DLL.


Vi2>Это заблуждение: CoUninitialize — это не завершение работы.


Я просто не стал распинаться по этому поводу

КД>>Кстати говоря, ведь COM может держать не только объект ошибки, но и другие COM-объекты. Есть же функции регистрации активных ActiveX объектов (их названия сходу я не скажу). И что? Я более чем уверен — освобождение этих ActiveX-ов выполняется перед выгрузкой DLL-ей. Потому что иначе вообще любая более менее сложная программа основанная на COM завершалась бы по AV.


Vi2>В том-то и дело, что "объект ошибки и другие COM-объекты" ничем не отличаются. Вернее, отличаются только тем, кто реализовал код поддержки. И как криво. Поэтому это может быть не баг в CoUninitialize, а баг в обработчике ошибок DB и тому подобное. И может быть продулирован в их, DB, разделе для борьбы с надоедливым AV.


Чего-то ты сам себе противоречишь. И я прям удивляюсь твоему упорству признать, что клоун, реализовываший деинициализацию не подумал, что объект ошибки может быть реализован в другой DLL.

Предлагаю написать баг-репорт в микрософт и посмотреть что они скажут по этому поводу. Я правда не знаю в какую дверь надо стучаться
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[8]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 07:36
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>И я прям удивляюсь твоему упорству признать, что клоун, реализовываший деинициализацию не подумал, что объект ошибки может быть реализован в другой DLL.


Хорошо. Предположим, этот клоун все же подумал об этом. Какие действия функция CoUninitialize должна совершить в свете этих новых знаний/дум? Простой Release на указателе. Но это ясно и БЕЗ информации о том, где расположен сервер. Ах вылетает, а я тут причем? Библиотека ушла? Хм, ну и придурок ее писал.

КД>Предлагаю написать баг-репорт в микрософт и посмотреть что они скажут по этому поводу. Я правда не знаю в какую дверь надо стучаться


А оно надо? Они же уже в НЕТе все. А там сборщик мусора, с ним не забалуешь.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[7]: Бага в CoUninitialize
От: Лазар Бешкенадзе СССР  
Дата: 19.09.06 07:39
Оценка: 1 (1)
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>>Дык это, того — CoUninitialize это завершение работы. Это его основное назначение. То что он, извините, во время деинициализации сам себе наступает на ..., то это его проблема. Причем очевидно, что он выполняет деинициализацию в неправильном порядке — сначало нужно освободить COM-объекты, потом выгружать DLL.


Vi2>Это заблуждение: CoUninitialize — это не завершение работы.


Очевидно, что имелось ввиду завершение работы с библиотекой COM

Vi2>CoUninitialize

Vi2>Closes the COM library on the current thread, unloads all DLLs loaded by the thread, frees any other resources that the thread maintains,

Я бы подвел освобождение объекта ошибки под этот пункт если, конечно, не возражают уважаемые присяжные.
Красивое обязательство — frees any other resources that the thread maintains

Vi2> and forces all RPC connections on the thread to close.


Vi2>Это не мешает заново в потоке вызвать CoInitialize и потом снова CoUninitialize. Так, конечно, никто не делает, но этот путь возможен.


Действительно никто не мешает после завершения работы снова начать работу.

Vi2>А фраза "forces all RPC connections on the thread to close" может трактоваться как освобождение памяти под внутренние буфера для прокси/стабов. Но это освобождение никак не зависит от соответствия AddRef и Release, т.е. от наличия или отсутствия сервера поддержки.


КД>>Кстати говоря, ведь COM может держать не только объект ошибки, но и другие COM-объекты. Есть же функции регистрации активных ActiveX объектов (их названия сходу я не скажу). И что? Я более чем уверен — освобождение этих ActiveX-ов выполняется перед выгрузкой DLL-ей. Потому что иначе вообще любая более менее сложная программа основанная на COM завершалась бы по AV.


Vi2>В том-то и дело, что "объект ошибки и другие COM-объекты" ничем не отличаются. Вернее, отличаются только тем, кто реализовал код поддержки. И как криво. Поэтому это может быть не баг в CoUninitialize, а баг в обработчике ошибок DB и тому подобное. И может быть продулирован в их, DB, разделе для борьбы с надоедливым AV.


Чтобы было нечто конкретное, что можно обсуждать я берусь реализовать код ошибки и предлагаю определить тензор его кривизны:

#define _WIN32_WINNT 0x0400

#include <msxml2.h>

class ErrorObject : IErrorInfo
{
    ULONG m_cRef;
    IXMLDOMDocument *m_pXmlDoc;

    ErrorObject() : m_cRef(1) {
        CoCreateInstance(__uuidof(DOMDocument), 0, CLSCTX_INPROC_SERVER, __uuidof(IXMLDOMDocument), (void **) &m_pXmlDoc);
    }
    ~ErrorObject() {
        if (m_pXmlDoc != 0)
            m_pXmlDoc->Release();
    }

    HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject) {
        if (iid == __uuidof(IErrorInfo) || iid == __uuidof(IUnknown)) {
            *ppvObject = this;
            return S_OK;
        }
        else {
            *ppvObject = 0;
            return E_NOINTERFACE;
        }
    }
    ULONG __stdcall AddRef(void) { return ::InterlockedIncrement((LONG *) &m_cRef); }
    ULONG __stdcall Release(void) {
        ULONG cRef = ::InterlockedDecrement((LONG *) &m_cRef);
        if (cRef == 0)
            delete this;
        return cRef;
    }

    HRESULT __stdcall GetGUID(GUID *pGUID) {
        *pGUID = GUID_NULL;
        return S_OK;
    }
    HRESULT __stdcall GetSource(BSTR *pBstrSource) {
        *pBstrSource = 0;
        return S_OK;
    }
    HRESULT __stdcall GetDescription(BSTR *pBstrDescription) {
        *pBstrDescription = 0;
        return S_OK;
    }
    HRESULT __stdcall GetHelpFile(BSTR *pBstrHelpFile) {
        *pBstrHelpFile = 0;
        return S_OK;
    }
    HRESULT __stdcall GetHelpContext(DWORD *pdwHelpContext) {
        *pdwHelpContext = 0;
        return S_OK;
    }

public:
    static HRESULT CreateInstance( IErrorInfo **ppErrorInfo) {
        *ppErrorInfo = new ErrorObject();
        return S_OK;
    }
};

int main()
{
    ::CoInitializeEx(0, COINIT_MULTITHREADED);

    IErrorInfo *pError;
    ErrorObject::CreateInstance(&pError);
    SetErrorInfo(0, pError);
    pError->Release();

    ::CoUninitialize();
}
Re[9]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 08:03
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>>И я прям удивляюсь твоему упорству признать, что клоун, реализовываший деинициализацию не подумал, что объект ошибки может быть реализован в другой DLL.


Vi2>Хорошо. Предположим, этот клоун все же подумал об этом. Какие действия функция CoUninitialize должна совершить в свете этих новых знаний/дум? Простой Release на указателе. Но это ясно и БЕЗ информации о том, где расположен сервер.


Я не догнал — какую информацию ты имеешь в виду.

Vi2>Ах вылетает, а я тут причем? Библиотека ушла? Хм, ну и придурок ее писал.


Куда именно она уйдет? С какого перепугу? Еще раз

[правильный порядок деинициализации]

1. Освобождаем COM-объекты удерживаемые системой. Ясный пень, удерживаемые в текущем потоке. В том числе и объект-ошибки, который был зарегистрирован в текущем потоке.

Здесь никто и никуда не уходит. DLL-и продолжают жить в памяти, потому что COM еще не вызывал для них FreeLibrary.

2. Вызываем FreeLibrary для всех DLL-ей которые были загружены в качестве COM-серверов. Если у DLL-и счетчик ссылок обнулился — система её выгрузит. Повторю — счетчик ссылок DLL-и, а не тех COM-объектов, которые ею обслуживаются.

И все. Я в упор не вижу где я тут и чему противоречу.

КД>>Предлагаю написать баг-репорт в микрософт и посмотреть что они скажут по этому поводу. Я правда не знаю в какую дверь надо стучаться


Vi2>А оно надо? Они же уже в НЕТе все. А там сборщик мусора, с ним не забалуешь.


Кто это все? Вообще говоря, это не правда и это тема для другого форума

Я как-то совсем недавно заглядывал на форум MSSQL-я (сообщал им о другом баге, гы-гы) так там висело объявление — кто хочет познакомиться с новейшими возможностями ODBC-драйвера и OLEDB-провайдера для MSSQL 2005, типа добро пожаловать к нам на семинар. И первое, и второе, как впрочем и третье (сам MSSQL) явно не на .NET написаны. Аналогичную вещь я наблюдал в обвязке VirtualServer, там тоже предоставляются COM-интерфейсы для взаимодейстивия с этим сервисом. Так что не будем так категоричны.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[8]: Бага в CoUninitialize
От: Константин Л. Франция  
Дата: 19.09.06 08:17
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, Vi2, Вы писали:


КД>>>Дык это, того — CoUninitialize это завершение работы. Это его основное назначение. То что он, извините, во время деинициализации сам себе наступает на ..., то это его проблема. Причем очевидно, что он выполняет деинициализацию в неправильном порядке — сначало нужно освободить COM-объекты, потом выгружать DLL.


Vi2>>Это заблуждение: CoUninitialize — это не завершение работы.


КД>Я просто не стал распинаться по этому поводу


КД>>>Кстати говоря, ведь COM может держать не только объект ошибки, но и другие COM-объекты. Есть же функции регистрации активных ActiveX объектов (их названия сходу я не скажу). И что? Я более чем уверен — освобождение этих ActiveX-ов выполняется перед выгрузкой DLL-ей. Потому что иначе вообще любая более менее сложная программа основанная на COM завершалась бы по AV.


Vi2>>В том-то и дело, что "объект ошибки и другие COM-объекты" ничем не отличаются. Вернее, отличаются только тем, кто реализовал код поддержки. И как криво. Поэтому это может быть не баг в CoUninitialize, а баг в обработчике ошибок DB и тому подобное. И может быть продулирован в их, DB, разделе для борьбы с надоедливым AV.


КД>Чего-то ты сам себе противоречишь. И я прям удивляюсь твоему упорству признать, что клоун, реализовываший деинициализацию не подумал, что объект ошибки может быть реализован в другой DLL.


КД>Предлагаю написать баг-репорт в микрософт и посмотреть что они скажут по этому поводу. Я правда не знаю в какую дверь надо стучаться


тебе говорят о том, что oledb32.dll Не должна была выгружаться, пока есть живые ссылки на любой интерфейс, ею реализуемый, даже наследник IErrorInfo . Те баг скорее в oledb32.dll, чем в CoUninit... тк в ней, похоже, неправильно реализован module lock

И еще. Кто и где обещал следить за временем жизни реализаций IErrorInfo? Это обычный интерфейс и будь добр следить за refcount самому
Re: Бага в CoUninitialize при работе с OLEDB-провайдерами
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 08:19
Оценка:
Пропуская текст моего изумления, просто спрошу — а чего это найденную мною багу в поддержке COM связали с багой в обвязке OLEDB.

Я конечно не охеренный спец по всему COM-у, но в состоянии определить кто и за что отвечает. Потому что, грубо говоря, сожрал ни одну собаку в этом деле. В том числе, писал и собственный менеджер DLL-ных COM-серверов. Поэтому более чем хорошо себе представляю то, о чем я тут пишу.

Так что верните название темы взад!

Блин, это все равно что багу в любой библиотеке начинать сваливать на приложение, которое эту библиотеку использует.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[8]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 08:19
Оценка:
Здравствуйте, Лазар Бешкенадзе, Вы писали:

ЛБ>Чтобы было нечто конкретное, что можно обсуждать я берусь реализовать код ошибки и предлагаю определить тензор его кривизны:


Нужно в QueryInterface добавить прирост счетчика. А так — ничего, работать будет.

Но если добавить еще функциональный объект, то могут возникнуть проблемы, т.к. этот объект (ErrorObject) не будет держать DLL сервер.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[9]: Бага в CoUninitialize
От: Лазар Бешкенадзе СССР  
Дата: 19.09.06 08:30
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Лазар Бешкенадзе, Вы писали:


ЛБ>>Чтобы было нечто конкретное, что можно обсуждать я берусь реализовать код ошибки и предлагаю определить тензор его кривизны:


Vi2>Нужно в QueryInterface добавить прирост счетчика.


Действительно, ошибочка вышла. Делаю вторую попытку.

#define _WIN32_WINNT 0x0400

#include <msxml2.h>

class ErrorObject : IErrorInfo
{
    LONG m_cRef;
    IXMLDOMDocument *m_pXml;

    ErrorObject() : m_cRef(1) {
        ::CoCreateInstance(__uuidof(DOMDocument), 0, CLSCTX_INPROC_SERVER, __uuidof(IXMLDOMDocument), (void **) &m_pXml);
    }
    ~ErrorObject() {
        if (m_pXml != 0)
            m_pXml->Release();
    }

    HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject) {
        if (iid == __uuidof(IErrorInfo) || iid == __uuidof(IUnknown)) {
            ErrorObject::AddRef();
            *ppvObject = this;
            return S_OK;
        }
        else {
            *ppvObject = 0;
            return E_NOINTERFACE;
        }
    }
    ULONG __stdcall AddRef(void) { return ::InterlockedIncrement(&m_cRef); }
    ULONG __stdcall Release(void) {
        LONG cRef = ::InterlockedDecrement(&m_cRef);
        if (cRef == 0)
            delete this;
        return cRef;
    }

    HRESULT __stdcall GetGUID(GUID *pGUID) {
        *pGUID = GUID_NULL;
        return S_OK;
    }
    HRESULT __stdcall GetSource(BSTR *pBstrSource) {
        *pBstrSource = 0;
        return S_OK;
    }
    HRESULT __stdcall GetDescription(BSTR *pBstrDescription) {
        *pBstrDescription = 0;
        return S_OK;
    }
    HRESULT __stdcall GetHelpFile(BSTR *pBstrHelpFile) {
        *pBstrHelpFile = 0;
        return S_OK;
    }
    HRESULT __stdcall GetHelpContext(DWORD *pdwHelpContext) {
        *pdwHelpContext = 0;
        return S_OK;
    }

public:
    static HRESULT CreateInstance(IErrorInfo **ppErrorInfo) {
        *ppErrorInfo = new ErrorObject();
        return S_OK;
    }
};

int main()
{
    ::CoInitializeEx(0, COINIT_MULTITHREADED);

    IErrorInfo *pError;
    ErrorObject::CreateInstance(&pError);
    ::SetErrorInfo(0, pError);
    pError->Release();

    ::CoUninitialize();
}


Vi2> А так — ничего, работать будет.


Так не работает. Access Violation!

Vi2>Но если добавить еще функциональный объект, то могут возникнуть проблемы, т.к. этот объект (ErrorObject) не будет держать DLL сервер.


Можно тут поподробнее?

Лазар
Re[9]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 08:36
Оценка: -1
Здравствуйте, Константин Л., Вы писали:

КД>>Чего-то ты сам себе противоречишь. И я прям удивляюсь твоему упорству признать, что клоун, реализовываший деинициализацию не подумал, что объект ошибки может быть реализован в другой DLL.


КД>>Предлагаю написать баг-репорт в микрософт и посмотреть что они скажут по этому поводу. Я правда не знаю в какую дверь надо стучаться


КЛ>тебе говорят о том, что oledb32.dll Не должна была выгружаться, пока есть живые ссылки на любой интерфейс, ею реализуемый, даже наследник IErrorInfo . Те баг скорее в oledb32.dll, чем в CoUninit... тк в ней, похоже, неправильно реализован module lock


КЛ>И еще. Кто и где обещал следить за временем жизни реализаций IErrorInfo? Это обычный интерфейс и будь добр следить за refcount самому


Слушайте, бросайте курить дурь за компьютером. Это очень вредно для неокрепших мозгов.

oledb32.dll как и любая DLL себя не выгружает! И не загружает! DLL — это пассивное существо. Тем более DLL, которая обслуживает COM-сервера. Берем Рихтера "Windows для этих" и читаем главу про динамические библиотеки. Потом "Основы COM" Роджерсона и читаем что там написано про DLL.

Специально для тугодумов.

1. Загрузите руками любую DLL. Через LoadLibrary
2. Получите адрес любой фукнции из этой DLL, которую вы сможете вызывать.
3. Выгрузите DLL. Через FreeLibrary
4. Вызовите функцию, которую вы получили в пунте два.

AV? И конечно же виновата DLL — я же держу указатель на неё функцию. Чего это она себя выгрузила!
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[10]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 09:04
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

Vi2>>Хорошо. Предположим, этот клоун все же подумал об этом. Какие действия функция CoUninitialize должна совершить в свете этих новых знаний/дум? Простой Release на указателе. Но это ясно и БЕЗ информации о том, где расположен сервер.

КД>Я не догнал — какую информацию ты имеешь в виду.

Предположим, есть явное место, содержащее указатель на активный объект ошибок, т.е. IErrorInfo * pCurrentError. CoUninitialize, как умная Маша, должна освободить этот указатель. Какое обвинение можно предъявить автору/содеру CoUninitialize, если первое требование СОМа — отсутствие знаний о конкретной реализации кода, стоящего за указателем? Т.е. это не важно какая библиотека реализует код объекта, главное, взаимодействие должно идти по правилам. Итак, что он может сделать еще кроме if(pCurrentError) pCurrentError->Release();? Вот этот Release и может вывалится. Вызовом SetErrorInfo(0,NULL) ты помогаешь обойти этот взрывоопасный вызов Release. Но у меня язык не повернется сказать, что приведенный код есть ошибка или что в нем есть потенциальная ошибка.

А почему вылетает Release() — этот вопрос не в компетенции CoUninitialize. Наверное, потому что какой-то поток, освободив объекты в oledb.dll и вызвав правильный CoUninitialize, выгрузил oledb.dll, т.к. она ответила S_OK из DllCanUnloadNow(), потому что других объектов, кроме объекта-ошибки, в ней нет, а объект-ошибка может и не держать ее.

Но я не в курсе объектной модели oledb.dll и применительно к базам данных, поэтому могу ошибаться. Я слышал, что там многое кэшируется для удобства повторного использования. Наверное, слишком кэшируют.

КД>Куда именно она уйдет? С какого перепугу? Еще раз


Ну ведь она ушла! Ты сам писал, что ни твоей DLL, ни oledb.dll уже нет. Хотя я что-то стал сомневаться, что объект живет именно в oledb.dll. Там много мест, в которых он может жить.

КД>Я в упор не вижу где я тут и чему противоречу.


Я и не говорю, что ты чему-то противоречишь. Просто нужно докопать до логического конца.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[10]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 09:10
Оценка:
Здравствуйте, Лазар Бешкенадзе, Вы писали:

Vi2>> А так — ничего, работать будет.

ЛБ>Так не работает. Access Violation!

Действительно, не работает. У меня сообщения не было, но я посмотрел в лог, чтобы убедиться. Так это проблема не в объекте ErrorObject, а в IXMLDOMDocument *m_pXmlDoc. Так что я правильно предположил, что дело не в oledb.dll. У меня показывает, что библиотеки msxml3.dll и shlwapi.dll благополучно смылись во время CoUninitialize.

Vi2>>Но если добавить еще функциональный объект, то могут возникнуть проблемы, т.к. этот объект (ErrorObject) не будет держать DLL сервер.

ЛБ>Можно тут поподробнее?

Поместил ты объект в DLL-ку, которая выгружается по требованию DllCanUnloadNow. Если не предусмотреть возврат S_FALSE при живом ErrorObject, то DLL может быть выгружена, если поток, использующий функциональный объект, закончит работу с этим объектом и вызовет функцию CoFreeUnusedLibraries по тем или иным причинам.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[10]: Бага в CoUninitialize
От: Константин Л. Франция  
Дата: 19.09.06 09:31
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, Константин Л., Вы писали:


слышь ты, хами друзьям своим

КД>Слушайте, бросайте курить дурь за компьютером. Это очень вредно для неокрепших мозгов.


КД>oledb32.dll как и любая DLL себя не выгружает! И не загружает! DLL — это пассивное существо. Тем более DLL, которая обслуживает COM-сервера. Берем Рихтера "Windows для этих" и читаем главу про динамические библиотеки. Потом "Основы COM" Роджерсона и читаем что там написано про DLL.


и где это я писал, что она сама себя выгружает?
не тупи, если DllCanUnloadNow вернет TRUE, то COM ее выгрузит.

КД>Специально для тугодумов.


сразу виден уровень развития....

КД>1. Загрузите руками любую DLL. Через LoadLibrary

КД>2. Получите адрес любой фукнции из этой DLL, которую вы сможете вызывать.
КД>3. Выгрузите DLL. Через FreeLibrary
КД>4. Вызовите функцию, которую вы получили в пунте два.

КД>AV? И конечно же виновата DLL — я же держу указатель на неё функцию. Чего это она себя выгрузила!
Re[2]: Бага в CoUninitialize при работе с OLEDB-провайдерами
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 09:40
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Пропуская текст моего изумления, просто спрошу — а чего это найденную мною багу в поддержке COM связали с багой в обвязке OLEDB.


Да, дело не в обвязке OLEDB. А именно в:

КД>3. При вызове CoUninitialize, сначала выгружаются все библиотеки с COM-объектами (в том числе моя и oledb32.dll), а потом освобождается объект ошибки.


причем я применил пример Лазара Бешкенадзе, но заменил на свою DLL. Так вот при входе в CoUninitialize, идет запрос на освобождение библиотек и, несмотря на то, что я возвращаю S_FALSE, моя библиотека выгружается. И потом идет запрос на освобождение объекта-ошибки.

КД>Я конечно не охеренный спец по всему COM-у, но в состоянии определить кто и за что отвечает. Потому что, грубо говоря, сожрал ни одну собаку в этом деле. В том числе, писал и собственный менеджер DLL-ных COM-серверов. Поэтому более чем хорошо себе представляю то, о чем я тут пишу.


КД>Так что верните название темы взад!


Присоединяюсь. Это не зависит от провайдера.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[11]: Бага в CoUninitialize
От: Лазар Бешкенадзе СССР  
Дата: 19.09.06 09:43
Оценка: 8 (2)
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Лазар Бешкенадзе, Вы писали:


Vi2>>> А так — ничего, работать будет.

ЛБ>>Так не работает. Access Violation!

Vi2>Действительно, не работает. У меня сообщения не было, но я посмотрел в лог, чтобы убедиться. Так это проблема не в объекте ErrorObject, а в IXMLDOMDocument *m_pXmlDoc. Так что я правильно предположил, что дело не в oledb.dll. У меня показывает, что библиотеки msxml3.dll и shlwapi.dll благополучно смылись во время CoUninitialize.


Так именно в этом проблема. Мне что-то совершенно не хочется ручками реализовывать целиком DLL,
а если воспользуюсь ATL, мне, конечно, скажут, что виновата ATL, а не CoUninitialize. А эта,
последняя, судя по всему, вовсе не спрашивает DllCanUnloadNow, а просто берет и выгружает.
Причем выгружает до того, как делает Release на объекте ошибки. Что ясно видно под отладчиком.
Но мне, собственно, не важно спрашивают ли они DllCanUnloadNow, да я и не намерен пользоваться
этими DLL после CoUninitialize, но ребенку должно быть очевидно, что Release на объекте ошибки
надо делать до выгрузки DLL, а не до, как это наблюдается.

Vi2>>>Но если добавить еще функциональный объект, то могут возникнуть проблемы, т.к. этот объект (ErrorObject) не будет держать DLL сервер.

ЛБ>>Можно тут поподробнее?

Vi2>Поместил ты объект в DLL-ку, которая выгружается по требованию DllCanUnloadNow. Если не предусмотреть возврат S_FALSE при живом ErrorObject, то DLL может быть выгружена, если поток, использующий функциональный объект, закончит работу с этим объектом и вызовет функцию CoFreeUnusedLibraries по тем или иным причинам.


Ну так я же и не брался реализовывать DllCanUnloadNow, и не помещал свой класс в библиотеку,
да и факторию для него не делал. Предлагаю журналу RSDN сделать все это и отчитаться перед
товарищами за проделанную работу.

Лазар
Re[12]: Бага в CoUninitialize
От: Константин Л. Франция  
Дата: 19.09.06 10:02
Оценка:
Здравствуйте, Лазар Бешкенадзе, Вы писали:

ЛБ>Здравствуйте, Vi2, Вы писали:


Vi2>>Здравствуйте, Лазар Бешкенадзе, Вы писали:


Vi2>>>> А так — ничего, работать будет.

ЛБ>>>Так не работает. Access Violation!

Vi2>>Действительно, не работает. У меня сообщения не было, но я посмотрел в лог, чтобы убедиться. Так это проблема не в объекте ErrorObject, а в IXMLDOMDocument *m_pXmlDoc. Так что я правильно предположил, что дело не в oledb.dll. У меня показывает, что библиотеки msxml3.dll и shlwapi.dll благополучно смылись во время CoUninitialize.


ЛБ>Так именно в этом проблема. Мне что-то совершенно не хочется ручками реализовывать целиком DLL,

ЛБ>а если воспользуюсь ATL, мне, конечно, скажут, что виновата ATL, а не CoUninitialize. А эта,
ЛБ>последняя, судя по всему, вовсе не спрашивает DllCanUnloadNow, а просто берет и выгружает.
ЛБ>Причем выгружает до того, как делает Release на объекте ошибки. Что ясно видно под отладчиком.
ЛБ>Но мне, собственно, не важно спрашивают ли они DllCanUnloadNow, да я и не намерен пользоваться
ЛБ>этими DLL после CoUninitialize, но ребенку должно быть очевидно, что Release на объекте ошибки
ЛБ>надо делать до выгрузки DLL, а не до, как это наблюдается.

ИМХО, вызов DllCanUnloadNow совершенно бессмыслен внутри CoUninit.., тк не имеет смысла внутри ее ждать, пока все библиотеки готовы выгрузиться.
А в целом, согласен, баг явный.

[]
Re[11]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 10:21
Оценка: 3 (1)
Здравствуйте, Vi2, Вы писали:

Ну, судя по ответам которые пришли пока я бился головой об стол, разобрались. А то у мне осталось только упасть под стол и забился в конвульсиях от чтения ответов в этой ветке.

Я рад, что все рады.



Vi2>Предположим, есть явное место, содержащее указатель на активный объект ошибок, т.е. IErrorInfo * pCurrentError. CoUninitialize, как умная Маша, должна освободить этот указатель. Какое обвинение можно предъявить автору/содеру CoUninitialize, если первое требование СОМа — отсутствие знаний о конкретной реализации кода, стоящего за указателем? Т.е. это не важно какая библиотека реализует код объекта, главное, взаимодействие должно идти по правилам. Итак, что он может сделать еще кроме if(pCurrentError) pCurrentError->Release();? Вот этот Release и может вывалится.

Так, давайте-ка вернемся к тому с чего мы начинали.

Напоминаю, внутри CoUninitialize происходит AV. Как показали иследования, AV происходит только в том случае если была установлен объект-ошибки с нестандартной реализацией. И эта реализация находится в DLL-и оформленной как COM-сервер.

AV не может происходить только потому что внутри COM висит объект ошибки. Значит с ним что-то делают. Что могут делать с указателем на COM-объект при деинициализации? Все правильно — для него вызывают Release. Но перед этим были выгружены DLL-и COM-серверов.

И поэтому pCustomeErorr->Release() не "может вываливаться", а именно вываливается по AV.

Vi2>Вызовом SetErrorInfo(0,NULL) ты помогаешь обойти этот взрывоопасный вызов Release. Но у меня язык не повернется сказать, что приведенный код есть ошибка или что в нем есть потенциальная ошибка.


Vi2>А почему вылетает Release() — этот вопрос не в компетенции CoUninitialize.

Кот сидит и орет. У него спрашивают
 - чего орешь-то?
 - я сел себе на ... 
 - так встань!
 - не хочу.

Конечно не в его. За то что в CoUninitialize левая рука вызвала FreeLibrary для DLL-ей COM-серверов, правая рука CoUninitialize не отвечает.

Vi2>Наверное, потому что какой-то поток, освободив объекты в oledb.dll и вызвав правильный CoUninitialize, выгрузил oledb.dll, т.к. она ответила S_OK из DllCanUnloadNow(), потому что других объектов, кроме объекта-ошибки, в ней нет, а объект-ошибка может и не держать ее.


Знаешь, проверять в падлу, но гарантирую — DllCanUnloadNow внутри CoUninitialize не вызывается. Потому что наличие активных объектов в выгружаемых DLL-ях CoUninitialize абсолютно не интересует. Это раз. А во вторых, даю гарантию что объект-ошибки, как в прочем и фабрики классов (которые вроде как являются служебными COM-объектами) увеличивают счетчик COM-блокировок DLL-и. Именно COM-блокировок, которые анализируются в DllCanUnloadNow, а не тех блокировок DLL, которые увеличиваются при вызове LoadLibrary и уменьшаются при FreeLibrary.

<вырезано>

Vi2>Я и не говорю, что ты чему-то противоречишь. Просто нужно докопать до логического конца.


Конец заключается в том, что CoUnitialize должен освобождать объект ошибки (который он все равно освобождает) до того как начнет вызывать FreeLibrary для DLL-ей с COM-серверами загруженными в текущем потоке.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[11]: Бага в CoUninitialize
От: Ivan Россия www.rsdn.ru
Дата: 19.09.06 10:26
Оценка: +2
Здравствуйте, Vi2, Вы писали:

Vi2> Итак, что он может сделать еще кроме if(pCurrentError) pCurrentError->Release();?

может вызвать его не вовремя, когда нужный модуль уже выгрузился. Во время вызова CoUninitialize DllCanUnload уже вряд ли способен на что-то повилять — dll выгружаются форсированно, а код CoUninitialize может быть написан так, что освобождает обхект ошибки после форсированной выгрузки остальных модулей (рассчитывая, что объект ошибки "проживает" в ole32.dll) — вот и грабли.
Re[12]: Бага в CoUninitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 19.09.06 11:49
Оценка: 5 (1) +1
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Знаешь, проверять в падлу, но гарантирую — DllCanUnloadNow внутри CoUninitialize не вызывается.


Вызывается. Но потом, наверное, идет контрольный CoFreeAllLibraries.

КД>Конец заключается в том, что CoUnitialize должен освобождать объект ошибки (который он все равно освобождает) до того как начнет вызывать FreeLibrary для DLL-ей с COM-серверами загруженными в текущем потоке.


Возможно было бы правильнее, если в начале CoUnitialize объект-ошибка был освобожден принудительно, как ты делаешь перед его вызовом. Но освобождаться окончательно он должен в самом конце, т.к. во время выгрузки СОМ inproc-серверов могут быть СОМ вызовы и есть вероятность, что объект-ошибка может снова появится. Поэтому он и не освобождается из-за оптимизации. Да, круто замешано.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[13]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 12:18
Оценка:
Здравствуйте, Vi2, Вы писали:

КД>>Знаешь, проверять в падлу, но гарантирую — DllCanUnloadNow внутри CoUninitialize не вызывается.


Vi2>Вызывается.


Но это уже никого не спасает от последующей выгрузки.

КД>>Конец заключается в том, что CoUnitialize должен освобождать объект ошибки (который он все равно освобождает) до того как начнет вызывать FreeLibrary для DLL-ей с COM-серверами загруженными в текущем потоке.


Vi2>Возможно было бы правильнее, если в начале CoUnitialize объект-ошибка был освобожден принудительно, как ты делаешь перед его вызовом. Но освобождаться окончательно он должен в самом конце, т.к. во время выгрузки СОМ inproc-серверов могут быть СОМ вызовы и есть вероятность, что объект-ошибка может снова появится. Поэтому он и не освобождается из-за оптимизации. Да, круто замешано.


Не помню кто именно, ... хотя вот, нашел
Автор: korzhik
Дата: 20.06.06
этот документ с рекомендациями по созданию DLL. Сам пока не читал — но скоро прийдется вникать в его содержимое

Формально, конечно есть потенциальные грабли, когда при выгрузке DLL она возьмет и зарегистрирует объект-ошибку. Которую к тому же сама же и реализует. Но тут уж явно засада будет в этой DLL, а не CoUnitialize

Лично мне больше нравятся грабли связанные с COM и такими разделяемыми ресурсами как управляющий флаг сопроцессора. Реально ощущаешь всю тщетность бытия.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[8]: Бага в CoUninitialize
От: Left2 Украина  
Дата: 19.09.06 15:38
Оценка:
КД>>>Но рекомендую бросать молится на тех, кто сидит в MS. Я встречал у них баги и пострашнее, чем этот несчастный CoUnitialize.
КЛ>>дык, никто и не молится
А>Не правда ваша, многие как раз. А почему — действительно непонятно. Когда-то — да, каждый из нескольких десятков программеров работавших в МС был профи, теперь это тысячи индусов и русских закончивших институт год-два-три назад, ещё ничему не научившихся и способных делать любые глупейшие ошибки. Хорошо хоть тестеров там больше чем кодеров.
А>ИМХО — БГ от этого и бежит. ИМХО: они ошиблись в том, что подумали что набрав тысячи програмеров они смогут свернуть горы. Годах в 96-98 набрали — результат плачевный — больше никогда и ничего не смогли сделать в срок даже близко (Vista — апофеоз) и хотя бы с 50% запланированного функционала. НТ тим был вроде 50 человек и сделали его "играючи". 2к тим был вроде 2000 програмеров + 3000 тестеров — еле-еле сделали не уложившись в сроки в 2-3 раза (он же НТ 5 должен был зваться и выйти в 97-98). ИМХО: оригинальный НТ тим легко сделал бы в срок. Сверхприбылей уже нет — всё явно съедает эта толпа програмеров. Права на бизнес-ошибку (коих в истории майкрософта навалом) больше нет — нет денежного резерва как раньше, когда доходы сильно превышали расходы. И выгнать всю эту толпу никак — не простит биржа, трудовое законодательство, да и самим обидно.

Не скажу что ты неправ в корне, но ты ИМХО смотришь на проблему однобоко. А именно, забываешь о немерянном грузе совместимости, который МС тянет за собой. Помнишь, как во времена 95 и NT народ держал у себя на машине 2 системы — NT для того чтобы педалить серьёзные программы под винду и 95(98) для того чтобы иметь возможность запускать старые досовские игрухи и приложения? Ты почитай про то как майкрософтовцы мучались, заставляя работать старые досовские программы под 95 — как писали в системе workaround-ы вокруг багов, которые были в самих досовских приложениях... А это огромный кусок работы. А когда выходила 2000-я — пришлось держать обратную совместимость и с NT тоже. И этот груз совместимости просто захлестнул MS — задача создания новой операционки, на которой будут работать большинство старых программ становится абсолютно неподьёмной. Поменять что-то кардинально в архитектуре сейчас архисложно — вспомни хотя бы их попытку переписать весь Win32 на .Net и как они благополучно предпочли о ней забыть когда поняли что задача просто нереальна.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: Бага в CoUninitialize
От: Константин Л. Франция  
Дата: 19.09.06 15:42
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Константин Л., Вы писали:


КД>>>Но рекомендую бросать молится на тех, кто сидит в MS. Я встречал у них баги и пострашнее, чем этот несчастный CoUnitialize.

КЛ>>дык, никто и не молится

я про себя

А>Не правда ваша, многие как раз. А почему — действительно непонятно. Когда-то — да, каждый из нескольких десятков программеров работавших в МС был профи, теперь это тысячи индусов и русских закончивших институт год-два-три назад, ещё ничему не научившихся и способных делать любые глупейшие ошибки. Хорошо хоть тестеров там больше чем кодеров.

А>ИМХО — БГ от этого и бежит. ИМХО: они ошиблись в том, что подумали что набрав тысячи програмеров они смогут свернуть горы. Годах в 96-98 набрали — результат плачевный — больше никогда и ничего не смогли сделать в срок даже близко (Vista — апофеоз) и хотя бы с 50% запланированного функционала. НТ тим был вроде 50 человек и сделали его "играючи". 2к тим был вроде 2000 програмеров + 3000 тестеров — еле-еле сделали не уложившись в сроки в 2-3 раза (он же НТ 5 должен был зваться и выйти в 97-98). ИМХО: оригинальный НТ тим легко сделал бы в срок. Сверхприбылей уже нет — всё явно съедает эта толпа програмеров. Права на бизнес-ошибку (коих в истории майкрософта навалом) больше нет — нет денежного резерва как раньше, когда доходы сильно превышали расходы. И выгнать всю эту толпу никак — не простит биржа, трудовое законодательство, да и самим обидно.

отвечать в лом
Re[6]: Бага в CoUninitialize
От: Tom Россия http://www.RSDN.ru
Дата: 19.09.06 16:48
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, Vi2, Вы писали:


Vi2>>Здравствуйте, Коваленко Дмитрий, Вы писали:


Vi2>>Естественно. После вызова SetErrorInfo объект-ошибку можно релизить — ее счетчик на совести СОМ системы. Но почему ушла oledb32.dll, если, ты говоришь, в ней реализован объект-ошибка? Наверное, из-за тог, что приложение завершается. Значит, что-то не так с самим выходом.


КД>Вообще это было злополучное стечение багов. Коротко говоря, у меня при последнем Release внутри компонента возникала ошибка и я радостно пытался сообщить о ней клиенту через объект-ошибку из oledb32.dll. Ясный пень, клиент не будет проверять результаты работы Release, поэтому объект-ошибки продолжал висеть в памяти до деинициализции COM-а.


Тупой баг CoUninitialize, перед выгрузкой ессно надо сделать релиз обьекту ошибки
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[13]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.06 17:48
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Возможно было бы правильнее, если в начале CoUnitialize объект-ошибка был освобожден принудительно, как ты делаешь перед его вызовом. Но освобождаться окончательно он должен в самом конце, т.к. во время выгрузки СОМ inproc-серверов могут быть СОМ вызовы и есть вероятность, что объект-ошибка может снова появится. Поэтому он и не освобождается из-за оптимизации. Да, круто замешано.

Я что придумал на ночь глядя — во время деинициализации COM-а он должен давать отлуп попыткам вызова SetErrorInfo — вуаля
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[8]: Бага в CoUninitialize
От: Лазар Бешкенадзе СССР  
Дата: 20.09.06 11:30
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, Vi2, Вы писали:


КД>Предлагаю написать баг-репорт в микрософт и посмотреть что они скажут по этому поводу. Я правда не знаю в какую дверь надо стучаться


В эту.

Лазар
Re[9]: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 20.09.06 13:00
Оценка:
Здравствуйте, Лазар Бешкенадзе, Вы писали:

КД>>Предлагаю написать баг-репорт в микрософт и посмотреть что они скажут по этому поводу. Я правда не знаю в какую дверь надо стучаться


ЛБ>В эту.


ЛБ>Лазар


Спасибо. Вот состряпал пример
int main(int argc, char* argv[])
{
 //OLEDB Error-object
 const GUID CLSID_EXTENDEDERRORINFO=
  {0xc8b522cfL,0x5cf3,0x11ce,{0xad,0xe5,0x00,0xaa,0x00,0x44,0x77,0x3d}};

 ::CoInitialize(0);

 IErrorInfo* pErrorInfo=NULL;

 if(::CoCreateInstance(CLSID_EXTENDEDERRORINFO,
                       NULL,
                       CLSCTX_INPROC_SERVER,
                       IID_IErrorInfo,
                       (void**)&pErrorInfo)!=S_OK)
  return -1;

 ::SetErrorInfo(0,pErrorInfo);

 pErrorInfo->Release();

 ::CoUninitialize(); //Access Violation

 return 0;
}//main
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[10]: Бага в CoUninitialize
От: Лазар Бешкенадзе СССР  
Дата: 20.09.06 13:08
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, Лазар Бешкенадзе, Вы писали:


КД>>>Предлагаю написать баг-репорт в микрософт и посмотреть что они скажут по этому поводу. Я правда не знаю в какую дверь надо стучаться


ЛБ>>В эту.


ЛБ>>Лазар


КД>Спасибо. Вот состряпал пример

КД>
КД>int main(int argc, char* argv[])
КД>{
КД> //OLEDB Error-object
КД> const GUID CLSID_EXTENDEDERRORINFO=
КД>  {0xc8b522cfL,0x5cf3,0x11ce,{0xad,0xe5,0x00,0xaa,0x00,0x44,0x77,0x3d}};

КД> ::CoInitialize(0);

КД> IErrorInfo* pErrorInfo=NULL;

КД> if(::CoCreateInstance(CLSID_EXTENDEDERRORINFO,
КД>                       NULL,
КД>                       CLSCTX_INPROC_SERVER,
КД>                       IID_IErrorInfo,
КД>                       (void**)&pErrorInfo)!=S_OK)
КД>  return -1;

КД> ::SetErrorInfo(0,pErrorInfo);

КД> pErrorInfo->Release();

КД> ::CoUninitialize(); //Access Violation

КД> return 0;
КД>}//main
КД>

Здорово. Коротко и ясно.

Лазар
Re: Бага в CoUninitialize
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 26.01.09 08:59
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Доброго всем понедельника.


Симметрично!

Вчера решил подолбенится с другой загадокой от MS-а, которая также была связана с объектом ошибок из oledb32.dll. Нашел заготовку, которыю я лобал для демонстрации бага в CoUninitialize. И, подумав — чем черт не шутит, выполнил её на своей Vista x64.

Не падает

Видать либо сами допетрили, либов все таки мой баг репорт дошел до адресата.

---
Хотя, конечно, это капля в море.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.