===[ Программизм ]=== #post-id: 7863-19-05 #original-date: 4.02.2022 Fri #original-time: 7:05 PM #original-day: 7863 #original-host: Win7 Ultimate SP1 (Build 7601) Короче, есть библиотека на FreeBasic, которую я использую в программах на VB6. Все объявления функций – в TLB файле. Добавила пару функций для кое-каких манипуляций с датой. Функция принимает один параметр типа Date (Double), производит манипуляции и возвращает дату в другой параметр того же типа. Возвращаемое значение Boolean (VARIANT_BOOL) сообщает, получилось произвести манипуляции или нет. Внутрях в том числе используются функции вроде VariantTimeToSystemTime() для конвертации в SYSTEMTIME. Вооот. Начались вылеты тестовой программы. Сначала выполнялась функция, а в конце случалось исключение. При чём WinDbg говорил, что беда случается в функциях категории SysStringLen(), которые работают с BSTR. Учитывая, что проблемный код не оперирует никакими BSTR, зато в тестовой программе функции вызывались прямо при конструировании строки с «отчётом» о проверке, выглядело всё так, словно где-то в библиотеке портится память, а потом всё ломается в программе. Ибо в программе не использовалось ничего особенного кроме для манипуляций со строками. Я долго вдумчиво смотрела в код, думала, какие-то проблемы с указателями, что-то не так передаётся во второй параметр, который указатель, либо не так вызываются функции конвертации даты из Date в SYSTEMTIME. Но там всё выглядело нормально. Кроме того, меня как-то настораживало сообщение: «Инструкция по адресу "0x77159d90" обратилась к памяти по адресу "0x0000fffb"». И второй адрес-то был всегда один и тот же. Откуда же он такой интересный? В общем, я посмотрела ещё раз исходник TLB и обнаружила, что по причине, связанной с ночным копипастингом, у меня возвращаемое значение (на самом деле – последний параметр функции) объявлено не как VARIANT_BOOL, а как BSTR. Я сваяла объявления в самом начале и больше даже не заглядывала туда. И вот что происходило. VARIANT_BOOL – это двухбайтовое целое со знаком (потому что совместимость с OLE в Win16), которое принимает значения 0 или -1 (кстати, частый вопрос, почему именно -1, а не 1), а BSTR – это четырёхбайтовый указатель на массив двухбайтных символов. Функция, возвращая True, записывала -1 в параметр, а код на VB6 получал указатель 0x0000FFFF. «FFFF» – потому что -1, а нули, полагаю, из-за выравнивания. Так как рантайм думал, что получает BSTR, а VB код возвращаемое значение прямо к строке присобачивал, полагаясь на автоматическую конвертацию, то рантайм вызывал BSTR функцию. Функция, чтобы получить реальный адрес строки, вычитала четыре байта (перед массивом у BSTR идёт длина строки), получала 0x0000FFFB, обращалась к этому адресу и благополучно вылетала. Вот такая история невнимательности.