Bosh sahifa Wiki FFI

FFI

FFI — bir dasturlash tilida yozilgan kodga boshqa til yoki binary interfeysda yaratilgan funksiya va kutubxonalarni chaqirish imkonini beradigan mexanizm. Uning to‘liq nomi Foreign Function Interface hisoblanadi.

FFI yordamida yuqori darajali til operatsion tizim APIlari, C kutubxonalari, qurilma drayverlari, ilmiy hisoblash paketlari yoki avvaldan mavjud native kod bilan ishlaydi.

Asosiy vazifa

Dasturlash tillari xotira, type, exception va function callni turlicha boshqaradi. FFI shu farqlar orasida ko‘prik vazifasini bajaradi.

U quyidagilarni belgilashi kerak:

  • function nomi;
  • calling convention;
  • argument type’lari;
  • return type;
  • structure layout;
  • pointer;
  • string encoding;
  • memory ownership;
  • error qaytarish;
  • callback;
  • thread qoidalari.

Eng kichik mos kelmaslik ham noto‘g‘ri natija yoki process crashiga olib kelishi mumkin.

C ABI

Ko‘p FFI tizimlari C ABI’ni umumiy chegara sifatida tanlaydi.

Buning sabablari:

  • C calling convention sodda;
  • ko‘p platformada barqaror;
  • boshqa tillar C-compatible function eksport qila oladi;
  • system librarylar ko‘pincha C API beradi;
  • name mangling kamroq murakkab.

C++ class, template va exceptionni bevosita eksport qilishdan ko‘ra, ularning ustiga C wrapper yozish keng tarqalgan.

Function chaqirish

C kutubxonasida quyidagi funksiya bo‘lsin:

int add(int a, int b);

FFI deklaratsiyasi boshqa tilda shu functionning binary signature’ini ifodalaydi.

Runtime:

  1. libraryni yuklaydi;
  2. add symbolini topadi;
  3. argumentlarni ABIga mos register yoki stackka joylaydi;
  4. native functionga o‘tadi;
  5. return qiymatini tilning ichki type’iga aylantiradi.

Dynamic library yuklash

FFI libraryni runtime’da yuklashi mumkin.

Platformaga qarab:

  • .so;
  • .dll;
  • .dylib

formatlari ishlatiladi.

Loader library path, architecture va dependencylarni tekshiradi.

Library topilmasa yoki kerakli symbol eksport qilinmagan bo‘lsa, FFI chaqiruvi boshlanmaydi.

Type mapping

Har til type’lari C type’lariga bir xil mos kelmaydi.

Masalan:

  • int hajmi platformaga bog‘liq;
  • boolean representation farq qilishi mumkin;
  • string obyekt va null-terminated char* bir xil emas;
  • enum width farq qiladi;
  • managed object pointerini native kod to‘g‘ridan-to‘g‘ri tushunmaydi.

Fixed-width type, masalan int32_t, binary interfeysni aniqroq qiladi.

String

String FFI’da eng ko‘p xato beradigan obyektlardan biri.

Aniqlanishi kerak:

  • UTF‑8, UTF‑16 yoki boshqa encoding;
  • null terminator;
  • uzunlik alohida beriladimi;
  • buffer kimga tegishli;
  • native function stringni o‘zgartiradimi;
  • natijani kim bo‘shatadi.

String ichida nol bayt bo‘lsa, null-terminated C API uni erta tugagan deb qabul qilishi mumkin.

Structure

Structure field tartibi, alignment va padding ABIga mos bo‘lishi kerak.

Misol:

struct Point {
    int32_t x;
    int32_t y;
};

FFI tomonda fieldlar boshqa tartib yoki boshqa width bilan e’lon qilinsa, native kod noto‘g‘ri qiymat o‘qiydi.

Packed structure ishlatilsa, alignment va performance oqibatlari hisobga olinadi.

Pointer

Pointer native memory manzilini bildiradi.

FFI orqali pointer bilan ishlashda:

  • null;
  • lifetime;
  • mutability;
  • alignment;
  • buffer length;
  • dangling pointer

nazorat qilinadi.

Managed runtime garbage collector objectni ko‘chirishi mumkin. Native kod ishlatayotgan paytda object pinned qilinishi yoki alohida native bufferga nusxalanishi mumkin.

Memory ownership

Kim xotira ajratgani va kim bo‘shatishi aniq belgilanadi.

Misollar:

  • caller buffer beradi;
  • callee yangi buffer qaytaradi;
  • maxsus free_result() function mavjud;
  • natija keyingi chaqiriqqacha amal qiladi;
  • reference counting ishlatiladi.

Bir allocator ajratgan blokni boshqa runtime allocatorida bo‘shatish heap corruptionga sabab bo‘lishi mumkin.

Callback

Native library boshqa tildagi functionni keyinroq chaqirishi mumkin. Bu callback hisoblanadi.

FFI callback uchun:

ni boshqaradi.

Callback garbage collector tomonidan yig‘ilib qolmasligi uchun reference saqlanadi.

Thread

Native library callbackni o‘zi yaratgan threaddan chaqirishi mumkin.

Managed runtime threaddan xabardor bo‘lmasa:

talab qilinadi.

GUI callbackini background native threaddan to‘g‘ridan-to‘g‘ri chaqirish xavfli bo‘lishi mumkin.

Exception

Bir til exceptionini boshqa ABI chegarasidan nazoratsiz o‘tkazish mumkin emas.

C wrapper odatda exceptionni ushlab:

  • error code;
  • null;
  • status structure;
  • thread-local error

ko‘rinishida qaytaradi.

Native function ichidan managed runtime exceptioni chiqib ketsa stack unwinding mos kelmasligi mumkin.

Error modeli

C API ko‘pincha:

  • return code;
  • errno;
  • output parameter;
  • error object

ishlatadi.

FFI wrapper bu xatoni target til exception yoki result type’iga aylantiradi.

errno qiymati keyingi system call bilan o‘zgarishi mumkin, shuning uchun darhol olinadi.

Performance

FFI boundary’da:

  • argument conversion;
  • string nusxalash;
  • memory pinning;
  • runtime transition;
  • callback;
  • lock

overhead mavjud.

Kichik amalni million marta alohida chaqirishdan ko‘ra, katta batch bilan chaqirish samaraliroq.

Binding generator

Header yoki interface description asosida FFI binding avtomatik yaratilishi mumkin.

Vosita:

ni target tilga aylantiradi.

Generated binding ham library versiyasi va ABI bilan mos bo‘lishi kerak.

Xavfsizlik

FFI memory-safe tilning himoya chegarasini zaiflashtiradi.

Native kod:

  • buffer overflow;
  • use-after-free;
  • data race;
  • invalid pointer;
  • arbitrary code execution

keltirib chiqarishi mumkin.

FFI wrapper input uzunligi va ownershipni qat’iy tekshiradi.

Diagnostika

FFI muammosida:

tekshiriladi.

Tasodifiy crash ko‘pincha chaqiriqdan oldingi noto‘g‘ri declaration yoki xotira umri bilan bog‘liq bo‘ladi.

Bog‘liq tushunchalar

ABI, C API, Dynamic library, Calling convention, Pointer, Memory ownership, Callback, Native code, Binding, Marshaling