Pull to refresh

История с передачей переменной окружения. Разные версии msvcrt, UAC

Reading time 2 min
Views 3K
Возникла казалось бы простая задача – конфигурирование сторонней библиотеки через переменную окружения. В нашем процессе делаем следующее:
  • установить некую переменную окружения VAR=str
  • подгрузить библиотеку library.dll
  • вызвать функцию foo() этой библиотеки
Все работает, но вдруг выясняется, что на моей домашней машине библиотека перестает верно работать. Причем, если запускать с правами администратора, то по прежнему работает нормально.

Мысли самые разные, библиотека сложная и масса влияющих факторов. В конце концов выясняется следующий факт – getenv() работает не с реальным окружением процесса, а с его копией внутри библиотеки msvcrt. Узнав это вспоминаем, что сторонняя библиотека использует msvcrt8, а мы msvcrt10. Смотрим в отладчике порядок загрузки библиотек и выясняем разницу. Без прав администратора (не работает):
  • наш процесс неявно грузит msvcrt10
  • загружается hook библиотека logitech для беспроводной клавиатуры (для перехвата каких-то комбинаций кнопок, отображается во все процессы)
  • logitech неявно за собой тянет msvcrt8, инициализирует свою копию окружения
  • мы меняем окружение msvcrt10.putenv(VAR=str)
  • грузим library.dll
  • msvcrt8 уже в памяти
  • вызов library.foo(), она обращается к msvcrt8.getenv(VAR), который возвращает пустой VAR, т.к. msvcrt8 инициализировалась до изменения окружения
Теперь с правами администратора (работает верно):
  • наш процесс неявно грузит msvcrt10
  • hook библиотека logitech не загружается, по соображениям безопасности, так работает система
  • мы меняем окружение msvcrt10.putenv(VAR=str)
  • грузим library.dll
  • неявно грузится msvcrt8, считывает текущее окружение, где VAR установлен
  • вызов library.foo(), она обращается msvcrt8.getenv(VAR), который возвращает VAR=str
Вывод. Нельзя полагаться на то, что установив переменную окружения ее увидит сторонняя библиотека, т.к. нельзя гарантировать того, что кто-то неявно не подгрузит другую CRT. Правильный путь – устанавливать окружение и запускать дочерний процесс. Так и было сделано. Множественность CRT библиотек порождает не только проблемы управления памятью и объектами CRT библиотеки, но и вот такие чудесные явления.
Tags:
Hubs:
+17
Comments 52
Comments Comments 52

Articles