Комментарии 52
dll hell продолжается
Это совсем другая история. Работает механизм DLL здесь правильно и прозрачно, а проблема в том, что CRT кэширует у себя окружение, от этого вся беда.
Как-то читал обсуждение проблемы передачи FILE* между модулями — это тоже может быть недопустимо по причине разных CRT. Об этом надо помнить и учитывать. Тот кто с этим столкнулся привык к ситуации linux-ов, где libc все время одинаковая грузится. Кстати очень интересно, можно ли добиться подгрузки разных libc в разных .so библиотеках? Мне кажется нет.
Как-то читал обсуждение проблемы передачи FILE* между модулями — это тоже может быть недопустимо по причине разных CRT. Об этом надо помнить и учитывать. Тот кто с этим столкнулся привык к ситуации linux-ов, где libc все время одинаковая грузится. Кстати очень интересно, можно ли добиться подгрузки разных libc в разных .so библиотеках? Мне кажется нет.
Ну тривиальным образом можно зачрутить и тогда libc может быть какая угодно. Нетривиально — перекомпилить с другим путём к ld-linux.so.
Т.е. и в Linux может возникать проблема с разными библиотеками? К примеру сторонняя библиотека давно не менялась и зависит от одной версии libc, а разрабатываемая уже от другой. Или такое на практике пресекается и никто это не поддерживает?
Концептуально, наверное, можно. На практике для этого потребуются десятилетия. Мы весной вывели из эксплуатации одну системку на RedHat EL 4, так даже там libc была бинарно-совместима с более новыми версиями из RedHat EL 5, SUSE и.т.д. (а вот версия библиотеки С++ — libstdc++ сменилась, так как в RH4 был GCC 3, а в более новых — 4.*). Возможно, я ошибаюсь, но лично я не видел реальных приложений, ситуаций, где такая проблема могла бы возникнуть в Linux.
Проблема dll-hell в Windows, в данном случае, из-за того, что в C-рантайме от MSVC с бинарной совместимостью все очень печально. Правильнее сказать, что между двумя версиями рантайма ее нет вообще. Из-за этого различные exe и dll приходиться линьковать с msvcrt строго определенной версии, так как другие версии просто будут иметь другой ABI.
А такие проблемы с ABI, в одной из основных библиотек Windows, возникают из-за того, что MS никак не может решиться просто реализовать libc и libstdc++ по соответствующим стандартам языков, а все время придумывают свои расширения, объявляют функции устаревшими, включают отладочные проверки в релиз-версиях (при этом отключение этих проверок ломает ABI даже в пределах версии crt) и производят другие действия с аналогично-непонятным смыслом.
Я сейчас тоже вплотную столкнулся с проблемами из-за подобной политики MS, но в моем случае оказалось возможно просто перекомпилировать все зависимые библиотеки со строго одинаковым набором опций компилятора. Но это на текущий момент закрытая разработка, поэтому мы можем позволить себе такие вольности. В открытом или тиражируемом продукте такой подход, скорее всего, будет непозволительной роскошью.
Проблема dll-hell в Windows, в данном случае, из-за того, что в C-рантайме от MSVC с бинарной совместимостью все очень печально. Правильнее сказать, что между двумя версиями рантайма ее нет вообще. Из-за этого различные exe и dll приходиться линьковать с msvcrt строго определенной версии, так как другие версии просто будут иметь другой ABI.
А такие проблемы с ABI, в одной из основных библиотек Windows, возникают из-за того, что MS никак не может решиться просто реализовать libc и libstdc++ по соответствующим стандартам языков, а все время придумывают свои расширения, объявляют функции устаревшими, включают отладочные проверки в релиз-версиях (при этом отключение этих проверок ломает ABI даже в пределах версии crt) и производят другие действия с аналогично-непонятным смыслом.
Я сейчас тоже вплотную столкнулся с проблемами из-за подобной политики MS, но в моем случае оказалось возможно просто перекомпилировать все зависимые библиотеки со строго одинаковым набором опций компилятора. Но это на текущий момент закрытая разработка, поэтому мы можем позволить себе такие вольности. В открытом или тиражируемом продукте такой подход, скорее всего, будет непозволительной роскошью.
В windows они оставили за собой право менять версии библиотек и при этом не сохранять бинарную совместимость и я считаю, что это верно, иначе никакого развития библиотеки не получилось бы. Одна из сторон DLL hell как раз состоит в том, что иногда пытались подменить одну библиотеку на другую якобы сохраняя совместимость. На практике это очень и очень сложно, т.к. код может быть завязан даже на ошибки, которые после исправления приведут к проблемам. Короче говоря должно быть четкое версионирование, это было сразу заложено в имени библиотеки, но это и другая культура разработки, надо понимать, что каждый модуль имеет свою CRT и надо думать об аллокаторах, не использовать FILE* и пр.
С другой стороны DLL hell забороли тотальным версионированием, которое уже давно работает для DLL. Рекомендуется private развертывание, когда копируется все в папку с кодом, остальное работает через winsxs куда попадает куча разных вариантов зарегистрированных библиотек.
Кстати механизм форсированной подмены есть и в winsxs и наверное его иногда применяют.
С другой стороны DLL hell забороли тотальным версионированием, которое уже давно работает для DLL. Рекомендуется private развертывание, когда копируется все в папку с кодом, остальное работает через winsxs куда попадает куча разных вариантов зарегистрированных библиотек.
Кстати механизм форсированной подмены есть и в winsxs и наверное его иногда применяют.
Возможно, но почему тогда в Linux библиотеки (libc, libstdc++) развиваются, а ABI остается стабильным и обратно совместимым на протяжении многих лет? А то, что делает Microsoft скорее напоминает деградацию. Как минимум деградацию производительности.
К сожалению, эта не другая культура разработки. Это бардак разработки. Культура разработки — это когда все взаимодействия зафиксированы на уровне различного рода договоренностей (таких как API, ABI и т.д.). В случае Windows такие договоренности отсутствуют даже в пределах одной программы.
К тому же для С-библиотек сохранять ABI не так сложно. Для С++ сложнее, но для STL-библиотеки не на много.
Это было бы можно понять, если бы речь шла о какой-либо собственной разработке Microsoft, но когда речь идет о стандартизированных языках, то очень странно, что даже в пределах одной программы полноценно использовать возможности языка просто опасно.
К сожалению, эта не другая культура разработки. Это бардак разработки. Культура разработки — это когда все взаимодействия зафиксированы на уровне различного рода договоренностей (таких как API, ABI и т.д.). В случае Windows такие договоренности отсутствуют даже в пределах одной программы.
К тому же для С-библиотек сохранять ABI не так сложно. Для С++ сложнее, но для STL-библиотеки не на много.
надо понимать, что каждый модуль имеет свою CRT и надо думать об аллокаторах, не использовать FILE* и пр.
Это было бы можно понять, если бы речь шла о какой-либо собственной разработке Microsoft, но когда речь идет о стандартизированных языках, то очень странно, что даже в пределах одной программы полноценно использовать возможности языка просто опасно.
Есть такой факт — очень сложно обновлять библиотеку в бинарном виде, сохраняя ее API и при этом не вызвать проблем. Даже исправление ошибки может привести к проблеме в пользовательском коде. Поэтому, то что делают с libc — это нечто героическое. Я слышал на эту тему историю с приложениями под meego — был апдейт qt библиотек, который привел к проблемам с частью софта. Идея была та-же — мы ничего не меняли, а только улучшили, не меняя версию. Вот это пример таких граблей. Конечно libc меняют реже и очень тщательно вылизывают, но гарантий все равно нет. Надежный способ — это версионирование, так поступают и в managed языках, компоненты четко версионируются, включая базовые библиотеки.
Теперь о культуре. Есть API и он реализуется библиотекой, это первое, второе — авторы сразу сказали, что версии будут меняться, при этом максимально сохраняя преемственость. Тут все ясно и понятно, такой путь реализуют большинство разработчиков компонент.
Про стандарты тут спорить не буду. Microsoft развязал себе руки, сделал так как им удобнее и гибче, плюс политические мотивы. Но надо сказать, что в мире UNIX наличие стандартов не решает всех проблем, портирование все равно является головной болью.
Теперь о культуре. Есть API и он реализуется библиотекой, это первое, второе — авторы сразу сказали, что версии будут меняться, при этом максимально сохраняя преемственость. Тут все ясно и понятно, такой путь реализуют большинство разработчиков компонент.
Про стандарты тут спорить не буду. Microsoft развязал себе руки, сделал так как им удобнее и гибче, плюс политические мотивы. Но надо сказать, что в мире UNIX наличие стандартов не решает всех проблем, портирование все равно является головной болью.
Деградация производительности CRT — это откуда такие сведения?
Я несколько неточно выразился. Я имел ввиду библиотеку STL, которую в случае MSVC можно отнести к CRT, да и вроде-бы даже часть кода рантайма С++ находится именно там.
Начиная с MSVC 2005 в STL добавляли различный отладочный функционал (включается/отключается дефайнами _SECURE_SCL, _HAS_ITERATOR_DEBUGGING, _ITERATOR_DEBUG_LEVEL). Я согласен, что этот функционал хорош при отладке, НО он по умолчанию включен в релиз-сборках! Это было-бы не так плохо, если бы включение/выключение этих опций не ломало ABI, но так как ABI ломается, то требуется чтобы во всем проекте эти опции были установлены одинаково.
Выключение этих опций в моем случае давало прирост производительности примерно в 2 раза, что не мало. Вот еще одно мнение по поводу этих опций blogs.warwick.ac.uk/ahazelden/entry/visual_studio_stl/. По сути оно совпадает с моим.
Начиная с MSVC 2005 в STL добавляли различный отладочный функционал (включается/отключается дефайнами _SECURE_SCL, _HAS_ITERATOR_DEBUGGING, _ITERATOR_DEBUG_LEVEL). Я согласен, что этот функционал хорош при отладке, НО он по умолчанию включен в релиз-сборках! Это было-бы не так плохо, если бы включение/выключение этих опций не ломало ABI, но так как ABI ломается, то требуется чтобы во всем проекте эти опции были установлены одинаково.
Выключение этих опций в моем случае давало прирост производительности примерно в 2 раза, что не мало. Вот еще одно мнение по поводу этих опций blogs.warwick.ac.uk/ahazelden/entry/visual_studio_stl/. По сути оно совпадает с моим.
А то, что делает Microsoft скорее напоминает деградацию. Как минимум деградацию производительности.
Деградацией является динамической линковка, особенно динамическая линковка CRT.
Деградацией является динамической линковка, особенно динамическая линковка CRT.
Деградацией является динамической линковка, особенно динамическая линковка CRT.
Почему?
Например, зачем мне в каждый exe-файл проекта статически линьковать по 20-30Мбайт библиотек, если их можно сделать динамическими и тем самым получить дополнительные преимущества, такие как возможность централизованного обновления, отсутствие дублей кода библиотек в памяти и т.д.
Возможно, я чего-то не понимаю в экосистеме Windows, но мне, как разработчику, который пришел из мира Linux, такие подходы к разработке, отсутствие совместимости ABI и отсутствие простого способа указать пути поиска тех же библиотек (RPATH, LD_LIBRARY_PATH) кажутся дикими.
такие как возможность централизованного обновления
Не бывает обновления DLL без обновления EXE. Только в ооооочень редких случаях, и всё равно чревато. А раз EXE там же где и DLL — нет смысла её шарить и отказываться от IPO.
отсутствие дублей кода библиотек в памяти
Было актуально во времена 286/386. По легенде оттуда же __stdcall пошёл, чтобы на объёме байткода сэкономить. Сегодня это всё неактуально.
отсутствие совместимости ABI
Совместимость ABI есть, просто не надо пользоваться зоопарком компиляторов. Для Win есть MSVC, всё остальное — от лешего.
Не бывает обновления DLL без обновления EXE. Только в ооооочень редких случаях, и всё равно чревато. А раз EXE там же где и DLL — нет смысла её шарить и отказываться от IPO.
отсутствие дублей кода библиотек в памяти
Было актуально во времена 286/386. По легенде оттуда же __stdcall пошёл, чтобы на объёме байткода сэкономить. Сегодня это всё неактуально.
отсутствие совместимости ABI
Совместимость ABI есть, просто не надо пользоваться зоопарком компиляторов. Для Win есть MSVC, всё остальное — от лешего.
P.S: и 20-30 мегабайт при статической линковке не будет, т.к. слинкуется только то, что реально используется.
Не бывает обновления DLL без обновления EXE.
Бывает. Достаточно посмотреть на любой Linux. В Windows из-за отсутствия совместимого ABI системных библиотек с этим сложнее.
Совместимость ABI есть, просто не надо пользоваться зоопарком компиляторов. Для Win есть MSVC, всё остальное — от лешего.
В том-то и проблема, что в MSVC совместимого ABI нет. CRT из VC 10 нельзя подсунуть вместо CRT из VC 9. Да и с совместимостью STL проблемы есть.
Бывает. Достаточно посмотреть на любой Linux. В Windows из-за отсутствия совместимого ABI системных библиотек с этим сложнее.
Зато проще с установкой софта — не приходится половину библиотек апдейтить на нужные версии, собирая часть их них на коленке, когда в публичном репозитарии оказывается слишком старая версия dependency.
В том-то и проблема, что в MSVC совместимого ABI нет. CRT из VC 10 нельзя подсунуть вместо CRT из VC 9. Да и с совместимостью STL проблемы есть.
CRT — не простая DLL, чтобы к ней применять термин ABI (собс-но поэтому мне и кажется странным её вынос в DLL по умолчанию — не так уж она много весит, и жервтование IPO на CRT в угоду DLL выглядит сомнительным). Для остальных DLL/OBJ/LIB ABI есть, по крайней мере между разными версиями MSVC.
Да и с совместимостью STL проблемы есть.
STL — дело комилятора, а не линковкщика.
По большому счёту, динамическая линковка — это эстетство в угоду практичности.
Зато проще с установкой софта — не приходится половину библиотек апдейтить на нужные версии, собирая часть их них на коленке, когда в публичном репозитарии оказывается слишком старая версия dependency.
В том-то и проблема, что в MSVC совместимого ABI нет. CRT из VC 10 нельзя подсунуть вместо CRT из VC 9. Да и с совместимостью STL проблемы есть.
CRT — не простая DLL, чтобы к ней применять термин ABI (собс-но поэтому мне и кажется странным её вынос в DLL по умолчанию — не так уж она много весит, и жервтование IPO на CRT в угоду DLL выглядит сомнительным). Для остальных DLL/OBJ/LIB ABI есть, по крайней мере между разными версиями MSVC.
Да и с совместимостью STL проблемы есть.
STL — дело комилятора, а не линковкщика.
По большому счёту, динамическая линковка — это эстетство в угоду практичности.
Чем проще? Тем что каждый exe тянет за собой over 9000 разный DLL забивая диск и память? Это не практичность, а глупость какая-то. Конечно можно заставить пользователя покупать новый компьютер каждый 2-3 года, но вот что делать с embedded системами, где память и процессор ограничены?
Если работать в рамках дистрибутива, то никаких проблем с библиотеками не будет, так как они все будут совместимы, если нет, и нужно что-то очень экзотическое и новое, тогда gentoo вам в помощь, соберете каким угодно компилятором с какими угодно зависимостями.
Если работать в рамках дистрибутива, то никаких проблем с библиотеками не будет, так как они все будут совместимы, если нет, и нужно что-то очень экзотическое и новое, тогда gentoo вам в помощь, соберете каким угодно компилятором с какими угодно зависимостями.
Чем проще? Тем что каждый exe тянет за собой over 9000 разный DLL забивая диск и память? Это не практичность, а глупость какая-то.
Я о том же. Каждый exe тянет только себя, хоть и весит под 10Mb. Статически слинкованный с необходимыми частями своих библиотек.
но вот что делать с embedded системами, где память и процессор ограничены?
Использовать ограниченную OS :)
Я о том же. Каждый exe тянет только себя, хоть и весит под 10Mb. Статически слинкованный с необходимыми частями своих библиотек.
но вот что делать с embedded системами, где память и процессор ограничены?
Использовать ограниченную OS :)
Ну вот вы написали foo.exe, я написал bar.exe, а Вася написал baz.exe и все мы используем функции из quz.dll, то все её тянут за собой что ли? Ещё и все разных версий.
>>Использовать ограниченную OS :)
Ну вообще-то ещё в 70ых поняли, что надо бы отдать железо операционке, а программисту оставить системные вызовы, чтобы он вообще не думал на каком железе он свою программу запускает.
>>Использовать ограниченную OS :)
Ну вообще-то ещё в 70ых поняли, что надо бы отдать железо операционке, а программисту оставить системные вызовы, чтобы он вообще не думал на каком железе он свою программу запускает.
Ну вот вы написали foo.exe, я написал bar.exe, а Вася написал baz.exe и все мы используем функции из quz.dll, то все её тянут за собой что ли? Ещё и все разных версий.
Все тянут за собой части quz.lib нужной версии в своём статически слинкованном теле exe'шника.
Ну вообще-то ещё в 70ых поняли, что надо бы отдать железо операционке, а программисту оставить системные вызовы, чтобы он вообще не думал на каком железе он свою программу запускает.
Речь не о kernel-mode, где динамическая линковка — вынужденная мера для изоляции, а о user-mode dll, где актуальность динамической линковки осталась в тех же 70ых (вместе с философией unix'ов).
Все тянут за собой части quz.lib нужной версии в своём статически слинкованном теле exe'шника.
Ну вообще-то ещё в 70ых поняли, что надо бы отдать железо операционке, а программисту оставить системные вызовы, чтобы он вообще не думал на каком железе он свою программу запускает.
Речь не о kernel-mode, где динамическая линковка — вынужденная мера для изоляции, а о user-mode dll, где актуальность динамической линковки осталась в тех же 70ых (вместе с философией unix'ов).
>Все тянут за собой части quz.lib нужной версии в своём статически слинкованном теле exe'шника.
то есть в каждом есть своя fopen(), например, если все её юзают? Зачем тогда операционка вообще. Вкомпилить всё в один exe и как livecd распространять. Зато никаких глюков.
Вот я и думаю, почему дрова для HP принтера под винду занимают 500 метров, а под linux 500кб. Ну хотя там есть инсталлер с картинкой улыбающихся тётек и дядек, видать на философией unix смеются ;)
то есть в каждом есть своя fopen(), например, если все её юзают? Зачем тогда операционка вообще. Вкомпилить всё в один exe и как livecd распространять. Зато никаких глюков.
Вот я и думаю, почему дрова для HP принтера под винду занимают 500 метров, а под linux 500кб. Ну хотя там есть инсталлер с картинкой улыбающихся тётек и дядек, видать на философией unix смеются ;)
то есть в каждом есть своя fopen(), например, если все её юзают? Зачем тогда операционка вообще.
Для наименее инвазивного взаимодействия этих exe.
Вот я и думаю, почему дрова для HP принтера под винду занимают 500 метров, а под linux 500кб.
Думаю потому что их пишут любители компонетного программирования, таскающие Qt для about box'а (garbage collector coding style).
Для наименее инвазивного взаимодействия этих exe.
Вот я и думаю, почему дрова для HP принтера под винду занимают 500 метров, а под linux 500кб.
Думаю потому что их пишут любители компонетного программирования, таскающие Qt для about box'а (garbage collector coding style).
>Для наименее инвазивного взаимодействия этих exe.
Тогда можно и ядро запускать отдельное для каждой программы на вирутальном оборудовании. Вообще никакого взаимодействия.
> таскающие Qt для about box'а
А зачем таскать fopen, если они уже в системе есть?
Тогда можно и ядро запускать отдельное для каждой программы на вирутальном оборудовании. Вообще никакого взаимодействия.
> таскающие Qt для about box'а
А зачем таскать fopen, если они уже в системе есть?
Тогда можно и ядро запускать отдельное для каждой программы на вирутальном оборудовании. Вообще никакого взаимодействия.
По сути так оно и работает (virtual address space), когда exe не хотят друг с другом контачить.
А зачем таскать fopen, если они уже в системе есть?
Затем что своё подконтрольней. Всякие хуки, размеры буферов, IPO в конце концов. А при relocate base address от copy-on-write всё равно никуда не денетесь — память как ело, так и будет есть под разные копии.
По сути так оно и работает (virtual address space), когда exe не хотят друг с другом контачить.
А зачем таскать fopen, если они уже в системе есть?
Затем что своё подконтрольней. Всякие хуки, размеры буферов, IPO в конце концов. А при relocate base address от copy-on-write всё равно никуда не денетесь — память как ело, так и будет есть под разные копии.
Зато проще с установкой софта — не приходится половину библиотек апдейтить на нужные версии, собирая часть их них на коленке, когда в публичном репозитарии оказывается слишком старая версия dependency.
Возможно, у нас с Вами разный опыт, но в своей жизни, как пользователя, я с таким не сталкивался. Все конфликты разруливали мэйнтейнеры репозиториев и я получал уже работающие пакеты.
Как программисту, мне приходилось собирать свои пакеты с другими версиями библиотек, но это приходилось делать только если была необходимость пропатчить библиотеку какими-либо специфичными для проекта патчами.
CRT — не простая DLL, чтобы к ней применять термин ABI
Правильно! CRT — это такая библиотека, экспортируемые функции которой строго стандартизированы международными стандартами С/С++. Вот именно по этому CRT и должна иметь фиксированный интерфейс, как на уровне API, так и на уровне ABI для стандартизированных функций. И уж тем более не допустима такая самодеятельность, как отсутствие обратной совместимости, из-за чего возможна абсурдная ситуация, при которой одно приложение использует несколько несовместимых между собой CRT.
STL — дело комилятора, а не линковкщика.
И линковщика. Не вся STL помещается в шаблонах и заголовочных файлах. Часть ее вкомпилирована в CRT.
Все конфликты разруливали мэйнтейнеры репозиториев и я получал уже работающие пакеты.
В репозиториях часто бывают доступны только слишком старые версии.
CRT — это такая библиотека, экспортируемые функции которой строго стандартизированы международными стандартами С/С++.
CRT — это библиотека с точки зрения языка C/C++, но не библиотека с точки зрения ОС (т.е. не полностью независимый файл). CRT — это часть компилятора, часть его кодогенератора если хотите. Захочет компилятор инлайнить fopen() в каждой строчке — флаг ему в руки. Реализация CRT в виде .lib, .dll, .obj или еще какого-то os-library-одобного способа — всего лишь вариант реализации этого аспекта C/C++.
И линковщика. Не вся STL помещается в шаблонах и заголовочных файлах. Часть ее вкомпилирована в CRT.
STL вообще не обязана быть модулем. Вы знаете, почему сделали #include , а не #include <list.h>? Потому что даже хедер-файл с именем list существовать не обязан. В общем виде эта директива делает видимым в коде std::list, и больше ничего она делать не обязана. Реализация этого поведения #include через чтение файла с именем 'list', в котором что-то написано на языке C++ — всего лишь способ реализации, но по сути (по стандарту) STL — это часть парзера/кодогенератора компилятора, и ни в какие .h/.lib/.dll файлы она отображаться не обязана, это всего лишь простейшая её реализация.
В репозиториях часто бывают доступны только слишком старые версии.
CRT — это такая библиотека, экспортируемые функции которой строго стандартизированы международными стандартами С/С++.
CRT — это библиотека с точки зрения языка C/C++, но не библиотека с точки зрения ОС (т.е. не полностью независимый файл). CRT — это часть компилятора, часть его кодогенератора если хотите. Захочет компилятор инлайнить fopen() в каждой строчке — флаг ему в руки. Реализация CRT в виде .lib, .dll, .obj или еще какого-то os-library-одобного способа — всего лишь вариант реализации этого аспекта C/C++.
И линковщика. Не вся STL помещается в шаблонах и заголовочных файлах. Часть ее вкомпилирована в CRT.
STL вообще не обязана быть модулем. Вы знаете, почему сделали #include , а не #include <list.h>? Потому что даже хедер-файл с именем list существовать не обязан. В общем виде эта директива делает видимым в коде std::list, и больше ничего она делать не обязана. Реализация этого поведения #include через чтение файла с именем 'list', в котором что-то написано на языке C++ — всего лишь способ реализации, но по сути (по стандарту) STL — это часть парзера/кодогенератора компилятора, и ни в какие .h/.lib/.dll файлы она отображаться не обязана, это всего лишь простейшая её реализация.
А можно было попробовать GetEnvironmentVariable()/GetEnvironmentStrings(). Да, проблемы с переносимостью, но есть и плюсы.
Это не поможет, т.к. сторонняя библиотека использует crt-шные ф-ии, следовательно читать она будет не из реального окружения, а из копии. А putenv в реальное окружение тоже пишет, иначе бы не работал старый вариант, да и пришлось бы при старте процесса им как-то специально сбрасывать окружение из кэша в систему.
Да, сильно. Я вначале подумал, что библиотека именно Ваша. В таком случае (да и вообще) идеологически верно запускать дочерний процесс с нужным окружением.
Правда тут ещё в голову пришла шальная мыслишка: явно загрузить msvcrt8 и вызвать её putenv(), до вызова library.foo(). Но это так, из области извращений. =)
Правда тут ещё в голову пришла шальная мыслишка: явно загрузить msvcrt8 и вызвать её putenv(), до вызова library.foo(). Но это так, из области извращений. =)
А где про C++?
Я просматривал разделы «программирование», там разве что «visual studio» подходит, но уклон там все-же иной. Здесь же речь идет о стандартной библиотеке C/C++ со спецификой windows, пошел в раздел языки, там есть «c++».
Можно в системное программирование.
>>Узнав это вспоминаем, что сторонняя библиотека использует msvcrt8, а мы msvcrt10.
с другой стороны
>>наш процесс неявно грузит msvcrt10
>>logitech неявно за собой тянет msvcrt8, инициализирует свою копию окружения
>>мы меняем окружение msvcrt9.putenv(VAR=str)
Так у вас три версии используется (8,9,10)? Или тут где-то одна лишняя.
с другой стороны
>>наш процесс неявно грузит msvcrt10
>>logitech неявно за собой тянет msvcrt8, инициализирует свою копию окружения
>>мы меняем окружение msvcrt9.putenv(VAR=str)
Так у вас три версии используется (8,9,10)? Или тут где-то одна лишняя.
Интересная грабля. Кстати, если цель исключительно в том, чтобы установить переменную окружения для library.dll, то можно ручками позвать msvcrt8.putenv если я правильно понимаю. Хотя устанавливать окружение до старта процесса это, конечно, правильнее.
Можно конечно, но это уже слишком изощренно. К тому-же та библиотека тоже обновляется и они могут вдруг перейти на другую версию CRT. Проще и правильнее все установить в родителе.
Не, изощренно это было бы detours'ом повесить хук на GetEnvironmentVariable ;)
Если есть возможность установить в родителе, то конечно так лучше. Мне не очень понятно почему вы изначально так не сделали, а стали «изнутри» переменные пытаться устанавливать.
Если есть возможность установить в родителе, то конечно так лучше. Мне не очень понятно почему вы изначально так не сделали, а стали «изнутри» переменные пытаться устанавливать.
Этот процесс уже был отдельным (был и родитель) и служил только одной цели — выполнить некое сложное действие с использованием сторонней библиотеки. Дело в том, что настройка окружения этой библиотеки дело не очень простое, там десяток переменных и ряд других настроек, поэтому все было в этот модуль помещено. Родитель не знает специфику и там эти настройки архитектурно делать неверно. Сделать их один раз перманентно и сохранить тоже нельзя, т.к. раз от раза могут меняться параметры.
В итоге сделали так — этот процесс в начале конфигурируется потом запускает второй экземпляр самого себя и уже в нужном окружении делает загрузку библиотеки и остальные шаги.
В итоге сделали так — этот процесс в начале конфигурируется потом запускает второй экземпляр самого себя и уже в нужном окружении делает загрузку библиотеки и остальные шаги.
Второй экземпляр самого себя тоже не выглядит архитектурно верно…
Я бы сделал «некое сложное действие с использованием сторонней библиотеки» отдельным приложением, запускающимся из родителя (ещё одного), устанавливающего переменные. Хотя вам, конечно, виднее, поди ещё дополнительные ограничения есть.
Я бы сделал «некое сложное действие с использованием сторонней библиотеки» отдельным приложением, запускающимся из родителя (ещё одного), устанавливающего переменные. Хотя вам, конечно, виднее, поди ещё дополнительные ограничения есть.
Тут безусловно есть некое трюкачество, но это очень простой и компактный вариант, удобен тем, что не приходится выделять еще один модуль, экспортировать ф-ии и пр. только ради утсановки окружения. Зашаривать это решение не нужно и не думаю что когда либо потребуется. Выходит, что это делается ради единственной цели и в таком случае наше решение на мой взгляд оправдано. Приложение небольшое, пока библиотеки не грузит, поэтому первый экземпляр никому не мешает. Все это живет только на время выполнения некоторого непродолжительного действия.
Я вообще не понимаю, как можно в код процесса подгружать стороннюю библиотеку (как это делают всякие пунто и прочие программы), это же почти 100% вероятность труднообнаружимых багов, конфликтов, тормозов, зависаний, и т.д. Впрочем, что взять с разработчиков майкрософт — у них раньше вообще программы при установке клали свои библиотеки и конфиги в папку Windows.
Но справедливости ради, переменные окружения передаются в программу извне, и ставить их внутри самой программы через putenv() — это тоже неправильно. Вы должны конфигурировать библиотеку явно, через какую-нибудь функцию вроде fooLibraryInit({… configuration… } ). Переменные окружения — это если пользователь захочет что-то поменять.
Но справедливости ради, переменные окружения передаются в программу извне, и ставить их внутри самой программы через putenv() — это тоже неправильно. Вы должны конфигурировать библиотеку явно, через какую-нибудь функцию вроде fooLibraryInit({… configuration… } ). Переменные окружения — это если пользователь захочет что-то поменять.
> Я вообще не понимаю, как можно в код процесса подгружать стороннюю библиотеку
А куда ее тогда подгружать? Не понял смысла утверждения?
> Но справедливости ради, переменные окружения передаются в программу извне, и ставить их внутри самой программы через putenv() — это тоже неправильно. Вы должны конфигурировать библиотеку явно, через какую-нибудь функцию вроде fooLibraryInit({… configuration… } )
Такая вот библиотека, она получает конфигурацию частично через окружение. Там на самом деле еще хитрее — одна из подкомпонент, которая подгружается этой библиотекой так конфигурируется.
А куда ее тогда подгружать? Не понял смысла утверждения?
> Но справедливости ради, переменные окружения передаются в программу извне, и ставить их внутри самой программы через putenv() — это тоже неправильно. Вы должны конфигурировать библиотеку явно, через какую-нибудь функцию вроде fooLibraryInit({… configuration… } )
Такая вот библиотека, она получает конфигурацию частично через окружение. Там на самом деле еще хитрее — одна из подкомпонент, которая подгружается этой библиотекой так конфигурируется.
> А куда ее тогда подгружать? Не понял смысла утверждения?
В свое, отдельное адресное пространство. В многозадачной системе процессы специально изолированы друг от друга, и эти виндовые трюки с подгрузкой чужих библиоткек (а также игры с вызовами типа read/writeprocessmemory) — нарушение этой изоляции. Которое может влечь за собой трудно обнаружимые баги например.
В свое, отдельное адресное пространство. В многозадачной системе процессы специально изолированы друг от друга, и эти виндовые трюки с подгрузкой чужих библиоткек (а также игры с вызовами типа read/writeprocessmemory) — нарушение этой изоляции. Которое может влечь за собой трудно обнаружимые баги например.
> В свое, отдельное адресное пространство.
И взаимодействовать с библиотеками только через межпроцессные каналы? Это влечет за собой слишком большие накладные расходы.
> В многозадачной системе процессы специально изолированы друг от друга, и эти виндовые трюки с подгрузкой чужих библиоткек (а также игры с вызовами типа read/writeprocessmemory) — нарушение этой изоляции.
Динамические библиотеки есть в unix (.so) и windows (.dll), непонятно чем здесь windows выделяется. Писать в адресное пространство чужого процесса конечно нехорошо, но причем здесь это?
Взять практически любой исполняемый модуль — он зависит от массы разных динамических библиотек, те в свою очередь от других. Это совершенно стандартная практика на всех платформах. Если я правильно понял вы предлагаете все грузить в отдельных процессах и пользоваться межпроцессным взаимодействием. По моему это неприемлемо в плане производительности.
И взаимодействовать с библиотеками только через межпроцессные каналы? Это влечет за собой слишком большие накладные расходы.
> В многозадачной системе процессы специально изолированы друг от друга, и эти виндовые трюки с подгрузкой чужих библиоткек (а также игры с вызовами типа read/writeprocessmemory) — нарушение этой изоляции.
Динамические библиотеки есть в unix (.so) и windows (.dll), непонятно чем здесь windows выделяется. Писать в адресное пространство чужого процесса конечно нехорошо, но причем здесь это?
Взять практически любой исполняемый модуль — он зависит от массы разных динамических библиотек, те в свою очередь от других. Это совершенно стандартная практика на всех платформах. Если я правильно понял вы предлагаете все грузить в отдельных процессах и пользоваться межпроцессным взаимодействием. По моему это неприемлемо в плане производительности.
В случае перехвата нажатий клавиш, то, что вы написали, это бред. Человек не способен нажимать клавиши с такой скоростью, чтобы это вызвало хоть сколько-нибудь значительные накладные расходы.
> Взять практически любой исполняемый модуль — он зависит от массы разных динамических библиотек, те в свою очередь от других.
Покажите мне, каким образом, например, браузер Opera зависит от модуля pshook.dll (PuntoSwitcher Hook), которые написали криворукие ребята из Яндекса? Никаким. авторы оперы могут и не знать об этой программе. Есть разница между теми библиотеками, которые указаны в импортах исполняемого файла (которые явно подключил разработчик программы) и теми, которые без спросу лезут в адресное пространство всех процессов и там выполняются.
> Взять практически любой исполняемый модуль — он зависит от массы разных динамических библиотек, те в свою очередь от других.
Покажите мне, каким образом, например, браузер Opera зависит от модуля pshook.dll (PuntoSwitcher Hook), которые написали криворукие ребята из Яндекса? Никаким. авторы оперы могут и не знать об этой программе. Есть разница между теми библиотеками, которые указаны в импортах исполняемого файла (которые явно подключил разработчик программы) и теми, которые без спросу лезут в адресное пространство всех процессов и там выполняются.
> В случае перехвата нажатий клавиш, то, что вы написали, это бред. Человек не способен нажимать клавиши с такой скоростью, чтобы это вызвало хоть сколько-нибудь значительные накладные расходы.
Я не говорил о перехвате нажатий клвиш, а в целом о любой задаче. Не все же существующие библиотеки обрабатывают нажатие клавиш. Даже в результате нажатия на клавишу может выполняться некое действие внутри которого будет обращение к десятку библиотек и если между ними всеми будет межроцессное взаимодействие, то время работы может неоправдано возрасти. Вызов становится тяжелым, требуется синхронизация, оборачивание и передача данных туда и обратно.
> Покажите мне, каким образом, например, браузер Opera зависит от модуля pshook.dll (PuntoSwitcher Hook), которые написали криворукие ребята из Яндекса?
Никаким. Забудем о хуках, таких библиотек может быть единицы в адресном пространстве. Кроме этого туда подгружена сотня других dll, с ними что прикажете делать?
Я не говорил о перехвате нажатий клвиш, а в целом о любой задаче. Не все же существующие библиотеки обрабатывают нажатие клавиш. Даже в результате нажатия на клавишу может выполняться некое действие внутри которого будет обращение к десятку библиотек и если между ними всеми будет межроцессное взаимодействие, то время работы может неоправдано возрасти. Вызов становится тяжелым, требуется синхронизация, оборачивание и передача данных туда и обратно.
> Покажите мне, каким образом, например, браузер Opera зависит от модуля pshook.dll (PuntoSwitcher Hook), которые написали криворукие ребята из Яндекса?
Никаким. Забудем о хуках, таких библиотек может быть единицы в адресном пространстве. Кроме этого туда подгружена сотня других dll, с ними что прикажете делать?
Вы вообще ничего не поняли из моего первого комментария. Я нигде не предлагал грузить каждую динамическую библиотеку в отдельное адресное пространство.
У меня такое ощущение, что я объясняю вам элементарные вещи. Библиотеки, используемые программой, загружаются явно, по желанию разработчика программы, он знает о них, об их особенностях работы, он имеет возможность протестировать свою программу с ними и убедиться, что все работает. Никто не говорит, что их надо куда-то выносить. В этом нет необходимости.
В то же время, библиотеки, которые подгружаются сторонними программами от яндекса или программами идущими в поставке со всякими планшетами и прочим железом, грузятся сами, не спрашивая мнения разработчика. Как люди, которые лезут в чужой дом без спроса. Протестировать свой продукт на совместимость с ними он не может. Если программа свалится из-за них, пользователь будет жаловаться разработчику, и напишет в обзоре на сайте, что программа кривая (хотя на самом деле виноват не он).
> Забудем о хуках, таких библиотек может быть единицы в адресном пространстве.
Вообще-то мой комментарий относится ИМЕННО к таким и ТОЛЬКО к таким случаям.
Это типичный пример каши, которая была в голове разработчиков МС, так же как они раньше позволяли всем программам сваливать свой хлам в папку Windows (благополучно ломая всю систему в случае конфликта), так же они и позволяют программам разных разработчиков лезть в память друг к другу.
Я сейчас специально посмотрел — в память редактора кода scite подгрузились сами собой такие библиотеки:
dropboxext.13.dll
thgshell.x86.dll (от TortoiseHg)
intl3_tsvn.dll (от TortoiseSVN)
libaprutil_tsvn.dll
libapr_tsvn.dll
tortoisesvn.dll
tortoisestub.dll
tortoiseoverlays.dll
pshook.dll
Я удивляюсь, как мой компьютер вообще еще работает. Недаром Windows считается самой глючной платформой.
У меня такое ощущение, что я объясняю вам элементарные вещи. Библиотеки, используемые программой, загружаются явно, по желанию разработчика программы, он знает о них, об их особенностях работы, он имеет возможность протестировать свою программу с ними и убедиться, что все работает. Никто не говорит, что их надо куда-то выносить. В этом нет необходимости.
В то же время, библиотеки, которые подгружаются сторонними программами от яндекса или программами идущими в поставке со всякими планшетами и прочим железом, грузятся сами, не спрашивая мнения разработчика. Как люди, которые лезут в чужой дом без спроса. Протестировать свой продукт на совместимость с ними он не может. Если программа свалится из-за них, пользователь будет жаловаться разработчику, и напишет в обзоре на сайте, что программа кривая (хотя на самом деле виноват не он).
> Забудем о хуках, таких библиотек может быть единицы в адресном пространстве.
Вообще-то мой комментарий относится ИМЕННО к таким и ТОЛЬКО к таким случаям.
Это типичный пример каши, которая была в голове разработчиков МС, так же как они раньше позволяли всем программам сваливать свой хлам в папку Windows (благополучно ломая всю систему в случае конфликта), так же они и позволяют программам разных разработчиков лезть в память друг к другу.
Я сейчас специально посмотрел — в память редактора кода scite подгрузились сами собой такие библиотеки:
dropboxext.13.dll
thgshell.x86.dll (от TortoiseHg)
intl3_tsvn.dll (от TortoiseSVN)
libaprutil_tsvn.dll
libapr_tsvn.dll
tortoisesvn.dll
tortoisestub.dll
tortoiseoverlays.dll
pshook.dll
Я удивляюсь, как мой компьютер вообще еще работает. Недаром Windows считается самой глючной платформой.
> Вы вообще ничего не поняли из моего первого комментария. Я нигде не предлагал грузить каждую динамическую библиотеку в отдельное адресное пространство.
Да, я неверно вас понял, вы говорили именно о хуках.
Но даже, если бы не было хука от Logitech, то в моем случае это не снимает проблемы которая описана в посте. Если исполняемый модуль зависел бы от нескольких компонент, а обычно так и есть, то нужно было бы следить, чтобы ни в коем случае не подгрузился msvcrt8 раньше явной подгрузки library.dll, что неудобно, т.к. те модули могут зависеть от других и т.д. Правильнее было бы полностью себя обезопасить от этого.
> Я сейчас специально посмотрел — в память редактора кода scite подгрузились сами собой такие библиотеки:
> dropboxext.13.dll
> thgshell.x86.dll (от TortoiseHg)
> intl3_tsvn.dll (от TortoiseSVN)
> libaprutil_tsvn.dll
> libapr_tsvn.dll
> tortoisesvn.dll
> tortoisestub.dll
> tortoiseoverlays.dll
> pshook.dll
Хуки были сделаны для перехвата очереди ввода, решение безусловно не самое удачное с точки зрения безопасности. Хотя сам механизм внедрения есть и в Linux — LD_PRELOAD, но не знаю используют ли его для перехвата ввода. В списке последняя dll видимо от punto switcher, другие может и не являются хуками, а грузятся по каким-то иным причнам? Тут надо взглянуть на дерево зависимостей. Не очень понятно зачем бы svn потребовалось перехватывать ввод. В целом мне кажется хуки не очень часто используются.
Да, я неверно вас понял, вы говорили именно о хуках.
Но даже, если бы не было хука от Logitech, то в моем случае это не снимает проблемы которая описана в посте. Если исполняемый модуль зависел бы от нескольких компонент, а обычно так и есть, то нужно было бы следить, чтобы ни в коем случае не подгрузился msvcrt8 раньше явной подгрузки library.dll, что неудобно, т.к. те модули могут зависеть от других и т.д. Правильнее было бы полностью себя обезопасить от этого.
> Я сейчас специально посмотрел — в память редактора кода scite подгрузились сами собой такие библиотеки:
> dropboxext.13.dll
> thgshell.x86.dll (от TortoiseHg)
> intl3_tsvn.dll (от TortoiseSVN)
> libaprutil_tsvn.dll
> libapr_tsvn.dll
> tortoisesvn.dll
> tortoisestub.dll
> tortoiseoverlays.dll
> pshook.dll
Хуки были сделаны для перехвата очереди ввода, решение безусловно не самое удачное с точки зрения безопасности. Хотя сам механизм внедрения есть и в Linux — LD_PRELOAD, но не знаю используют ли его для перехвата ввода. В списке последняя dll видимо от punto switcher, другие может и не являются хуками, а грузятся по каким-то иным причнам? Тут надо взглянуть на дерево зависимостей. Не очень понятно зачем бы svn потребовалось перехватывать ввод. В целом мне кажется хуки не очень часто используются.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
История с передачей переменной окружения. Разные версии msvcrt, UAC