понедельник, 24 января 2011 г.

Наследие OLE DB

С давних времен в коде различных проектов остались строки следующего вида для работы с OLE DB:
ULONG m_BLOBDATA_LENGTH;
ULONG m_BLOBDATA_STATUS;
// ...
BLOB_ENTRY_LENGTH_STATUS(4, IID_ISequentialStream, STGM_READ, m_data, m_BLOBDATA_LENGTH, m_BLOBDATA_STATUS)
Откуда это пошло — не ясно: из MSDN или из книжек Круглински про MFC 4.0. Так или иначе, это все годами работало без сбоев... Пока не настала эра 64-битных приложений. Неприятность в том, что при сборке такого кода ошибок нет, да и работает он вроде. Но не всегда корректно.

Как всегда виноваты макросы. Если посмотреть на декларацию BLOB_ENTRY_LENGTH_STATUS, то можно увидеть, что там запоминается адрес переменной m_BLOBDATA_LENGTH и позже используется как ULONG в 32-битной сборке, и как ULONGLONG в 64-битной. Т.е. несмотря на тип, который мы используем, по указанному адресу писаться будет 4 или 8 байт соответственно. В лучшем случае будет затираться m_BLOBDATA_STATUS, которая часто идет следом за m_BLOBDATA_LENGTH, а в худшем... в худшем — это UB.

Выход из ситуации следующий: нужно вместо ULONG использовать DBLENGTH и DBSTATUS.

Комментировать в ВКонтакте