Подарочек от FTDI

Подарочек от FTDI оказался довольно интересным.

В полном соответствии с принципом «см. рис.1» они взяли и поменяли типы данных при переходе от библиотек libftd2xx.so версий 0.4.x к libftd2xx.so.1.0.0. Подарочек влияет только на работу с 64-битными вариантами библиотек, с 32-битными проблем нет.

Библиотека ftd2xx рождалась в Windows и ещё и содержит в себе функции FT_W32_ххх() для работы с микросхемами FTDI в стиле функций работы с COM-портом в WinAPI. Поэтому в ней используются стандартные для WinAPI типы данных DWORD, BYTE и т.п. Чтобы при написании Linux-версии библиотеки не менять файл ftd2xx.h и все тексты, в проект был добавлен файл WinTypes.h с определениями нужных типов. Сам по себе шаг логичный, но…

Вот фрагмент файла WinTyped.h от libftd2xx версии 0.4.16:

typedef unsigned long    DWORD;
typedef unsigned long    ULONG;
typedef long             LONG;

Т.е. просто взяты типы из файла windef.h компиляторов для Windows.

А вот то же самое место из версии 1.0.0:

typedef unsigned int    DWORD;
typedef unsigned int    ULONG;
typedef int             LONG;

Для Windows, в том числе 64-битных, разницы между этими определениями типов на практике нет, так как в Windows-64 используется так называемая модель данных LLP64 (64 бита имеют только типы long long и pointer-types). При этом sizeof(long) == sizeof(int), оба эти типа 32-битные. Так же будет и в 32-битном Linux. В этих операционных системах старая версия avreal будет работать с новой библиотекой.

А вот в 64-бит Linux используется модель LP64, т.е. тип long также 64-битный.

Итак, для libftd2xx.so 0.4.x и 64-біт Linux типы DWORD, ULONG, LONG 64-битные, т.е. занимают вдвое больше места, чем под 32-битной версией. Но, поскольку и библиотека, и программа компилируются с одним и тем же заголовочным файлом, всё работает правильно.

Для libftd2xx 1.0.0 размеры типов в 32- и 64-битных версиях ОС совпадают, они везде 32-битные. Тоже ничего плохого, если библиотека и программа компилируются с одинми и теми же типами данных.

Но если avreal-у, собранному со старым заголовочным файлом, подсунуть новую библиотеку, то работать программа не будет. Рассмотрим такой вызов:

    DWORD chip_type, chip_id, status;
    char serno[16];
    char description[64];

    status = FT_GetDeviceInfo(handle, &chip_type, &chip_id, serno, description, 0);

В старой программе переменные chip_type, chip_id 64-битные. Новая библиотека запишет 32-битные данные в младшие половинки этих переменных. Если бы я писал аккуратнее (параноидальнее?) и инициализировал переменные chip_type и chip_id нулями, то старая программа даже не заметила бы, что новая библиотека рассматривала переменные как 32-битные (скажем спасибо тому, что что x86 — little-endian процессор). Но толку с этого было бы мало, так как в библиотеке есть ещё такой тип данных:

typedef struct _ft_device_list_info_node {
    ULONG Flags;
    ULONG Type;
    ULONG ID;
    DWORD LocId;
    char SerialNumber[16];
    char Description[64];
    FT_HANDLE ftHandle;
} FT_DEVICE_LIST_INFO_NODE;

Эта структура занимает 120 байт при работе старой версии библиотеки и 104 байта при работе новой версии. Функция построения списка подключенных устройств FT_GetDeviceInfoList() принимает указатель на массив таких структур. Понятно, что это место не будет работать в любом случае.

Хуже будет, если собрать новую версию avreal с новым заголовочным файлом, но у пользователя на компъютере будет старая библиотека. Во все переменные библиотека будет писать больше, чем размер переменных, затирая при этом содержимое соседних переменных.

Поэтому я пока не буду собирать avreal с новой библиотекой и для 64-бит Linux предлагаю брать старую версию libftd2xx 0.4.16 у меня на странице download, рядом с архивом avreal.

Я подумаю, что мне делать с этим подарком от FTDI. Возможно, начиная с какой-то версии avreal перейду на новый вариант библиотеки и все, кто обновляет avreal, должны будут обновить и библиотеку. Возможно, попробую сделать выбор одного из двух режимов работы в зависимости от версии, возвращаемой FT_GetLibraryVersion().

3 Responses to “Подарочек от FTDI”

  1. goblin says:


    и для чего существуют uint8_t .. uint64_t ?

  2. Dekar says:

    А использовать открытую libftdi?

    • ReAl says:

      Так про неё smartly уже сказал по соседству.
      Можно, и в том направлении я буду двигаться малой скоростью.
      Но и с libfd2xx особых проблем нет — когда стало ясно, в чём дело.
      В любом случае это будет не «перейти», а «поддерживать и», так как совсем отказываться от libftd2xx я не собираюсь.

Leave a Reply

[flagcounter image]