Bu RDP protokoli bilan ishlash uchun ochiq kodli dasturlarni sinovdan o'tkazish bo'yicha bir qator maqolalardagi ikkinchi sharh. Unda biz rdesktop mijozi va xrdp serverini ko'rib chiqamiz.
Xatolarni aniqlash uchun vosita sifatida ishlatiladi
Maqolada faqat men uchun qiziqarli bo'lib tuyulgan xatolar keltirilgan. Biroq, loyihalar kichik, shuning uchun kam xatolar bor edi :).
nota. FreeRDP loyihasini tekshirish haqidagi oldingi maqolani topish mumkin
ish stoli
Ushbu mijoz juda mashhur - u sukut bo'yicha ReactOS-da qo'llaniladi va siz uning uchun uchinchi tomon grafik old qismlarini ham topishingiz mumkin. Biroq, u ancha keksa: uning birinchi chiqishi 4 yil 2001 aprelda bo'lib o'tdi - yozish paytida u 17 yoshda.
Yuqorida aytib o'tganimdek, loyiha juda kichik. U taxminan 30 ming qator kodni o'z ichiga oladi, bu uning yoshini hisobga olgan holda biroz g'alati. Taqqoslash uchun, FreeRDP 320 ming qatorni o'z ichiga oladi. Mana Cloc dasturining chiqishi:
Urib bo'lmaydigan kod
int
main(int argc, char *argv[])
{
....
return handle_disconnect_reason(deactivated, ext_disc_reason);
if (g_redirect_username)
xfree(g_redirect_username);
xfree(g_username);
}
Xato bizni funksiyada darhol uchratadi asosiy: operatordan keyin keladigan kodni ko'ramiz Qaytish — bu fragment xotirani tozalashni amalga oshiradi. Biroq, xato xavf tug'dirmaydi: dastur tugagandan so'ng barcha ajratilgan xotira operatsion tizim tomonidan o'chiriladi.
Hech qanday xatolik yo'q
RD_BOOL
subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
{
int n = 1;
char output[256];
....
while (n > 0)
{
n = read(fd[0], output, 255);
output[n] = ' '; // <=
str_handle_lines(output, &rest, linehandler, data);
}
....
}
Bu holda kod parchasi fayldan buferga fayl tugaguncha o'qiydi. Biroq, bu erda hech qanday xatolik yo'q: agar biror narsa noto'g'ri bo'lsa, unda o'qib -1 ni qaytaradi va keyin massiv to'ldiriladi Chiqdi.
Belgilar turida EOF dan foydalanish
int
ctrl_send_command(const char *cmd, const char *arg)
{
char result[CTRL_RESULT_SIZE], c, *escaped;
....
while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != 'n')
{
result[index] = c;
index++;
}
....
}
Bu erda faylning oxirigacha noto'g'ri ishlov berishni ko'ramiz: if fgetc kodi 0xFF bo'lgan belgini qaytaradi, u faylning oxiri sifatida talqin qilinadi (EOF).
EOF u doimiy, odatda -1 sifatida aniqlanadi. Masalan, CP1251 kodlashda rus alifbosining oxirgi harfida 0xFF kodi mavjud bo'lib, agar biz o'zgaruvchi haqida gapiradigan bo'lsak -1 raqamiga to'g'ri keladi. char. Ma'lum bo'lishicha, 0xFF belgisi kabi EOF (-1) faylning oxiri sifatida talqin qilinadi. Bunday xatolardan qochish uchun funktsiyaning natijasi fgetc kabi o'zgaruvchida saqlanishi kerak int.
Yozuvlar
1-qism
RD_NTSTATUS
disk_set_information(....)
{
time_t write_time, change_time, access_time, mod_time;
....
if (write_time || change_time)
mod_time = MIN(write_time, change_time);
else
mod_time = write_time ? write_time : change_time; // <=
....
}
Ehtimol, ushbu kod muallifi noto'g'ri tushungan || и && holatda. Keling, qiymatlar uchun mumkin bo'lgan variantlarni ko'rib chiqaylik yozish_vaqti и vaqtni o'zgartirish:
- Ikkala o'zgaruvchi ham 0 ga teng: bu holda biz filialga tushamiz yana boshqa: o'zgaruvchan mod_time keyingi shartdan qat'iy nazar har doim 0 bo'ladi.
- O'zgaruvchilardan biri 0: mod_time 0 ga teng bo'ladi (boshqa o'zgaruvchining manfiy bo'lmagan qiymatga ega bo'lishi sharti bilan), chunki MIN ikkita variantdan kichigini tanlaydi.
- Ikkala o'zgaruvchi ham 0 ga teng emas: minimal qiymatni tanlang.
Shartni bilan almashtirganda yozish_vaqt && vaqtni o'zgartirish xatti-harakatlar to'g'ri ko'rinadi:
- Bir yoki ikkala o'zgaruvchi 0 ga teng emas: nolga teng bo'lmagan qiymatni tanlang.
- Ikkala o'zgaruvchi ham 0 ga teng emas: minimal qiymatni tanlang.
2-qism
static RD_NTSTATUS
disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in,
STREAM out)
{
....
if (((request >> 16) != 20) || ((request >> 16) != 9))
return RD_STATUS_INVALID_PARAMETER;
....
}
Bu yerda ham operatorlar aralashib ketgan shekilli || и &&, yoki == и !=: O'zgaruvchi bir vaqtning o'zida 20 va 9 qiymatiga ega bo'lishi mumkin emas.
Cheksiz qatorni nusxalash
RD_NTSTATUS
disk_query_directory(....)
{
....
char *dirname, fullpath[PATH_MAX];
....
/* Get information for directory entry */
sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
....
}
Funktsiyani to'liq ko'rib chiqsangiz, ushbu kod muammoga olib kelmasligi aniq bo'ladi. Biroq, ular kelajakda paydo bo'lishi mumkin: bir beparvo o'zgarish va biz bufer to'lib ketishini olamiz - sprint hech narsa bilan cheklanmagan, shuning uchun yo'llarni birlashtirganda biz massiv chegaralaridan tashqariga chiqishimiz mumkin. Ushbu qo'ng'iroqqa e'tibor berish tavsiya etiladi snprintf (to‘liq yo‘l, PATH_MAX, ….).
Ortiqcha holat
static void
inRepos(STREAM in, unsigned int read)
{
SERVER_DWORD add = 4 - read % 4;
if (add < 4 && add > 0)
{
....
}
}
tekshirish qo'shish > 0 bu erda hojat yo'q: o'zgaruvchi har doim noldan katta bo'ladi, chunki o'qish % 4 bo'linishning qolgan qismini qaytaradi, lekin u hech qachon 4 ga teng bo'lmaydi.
xrdp
- xrdp - protokolni amalga oshirish. Apache 2.0 litsenziyasi ostida tarqatiladi.
- xorgxrdp - xrdp bilan foydalanish uchun Xorg drayverlari to'plami. Litsenziya - X11 (masalan, MIT, lekin reklamada foydalanishni taqiqlaydi)
Loyihani ishlab chiqish rdesktop va FreeRDP natijalariga asoslangan. Dastlab, grafikalar bilan ishlash uchun alohida VNC serveridan yoki RDP qo'llab-quvvatlanadigan maxsus X11 serveridan - X11rdp dan foydalanish kerak edi, lekin xorgxrdp paydo bo'lishi bilan ularga ehtiyoj yo'qoldi.
Ushbu maqolada biz xorgxrdp-ni ko'rib chiqmaymiz.
Xrdp loyihasi, oldingi kabi, juda kichik va taxminan 80 ming qatorni o'z ichiga oladi.
Ko'proq imlo xatolari
static int
rfx_encode_format_rgb(const char *rgb_data, int width, int height,
int stride_bytes, int pixel_format,
uint8 *r_buf, uint8 *g_buf, uint8 *b_buf)
{
....
switch (pixel_format)
{
case RFX_FORMAT_BGRA:
....
while (x < 64)
{
*lr_buf++ = r;
*lg_buf++ = g;
*lb_buf++ = r; // <=
x++;
}
....
}
....
}
Ushbu kod RemoteFX uchun jpeg2000 kodekni amalga oshiradigan librfxcodec kutubxonasidan olingan. Bu erda, ehtimol, grafik ma'lumotlar kanallari aralashtiriladi - "ko'k" rang o'rniga "qizil" yoziladi. Ushbu xato, ehtimol, nusxa ko'chirish va joylashtirish natijasida paydo bo'lgan.
Xuddi shu muammo shunga o'xshash funktsiyada yuz berdi rfx_encode_format_argb, buni analizator bizga ham aytdi:
while (x < 64)
{
*la_buf++ = a;
*lr_buf++ = r;
*lg_buf++ = g;
*lb_buf++ = r;
x++;
}
Massiv deklaratsiyasi
// evdev-map.c
int xfree86_to_evdev[137-8+1] = {
....
};
// genkeymap.c
extern int xfree86_to_evdev[137-8];
int main(int argc, char **argv)
{
....
for (i = 8; i <= 137; i++) /* Keycodes */
{
if (is_evdev)
e.keycode = xfree86_to_evdev[i-8];
....
}
....
}
Bu ikki fayldagi massivning deklaratsiyasi va ta'rifi mos kelmaydi - o'lcham 1 ga farq qiladi. Biroq, hech qanday xatolik yuzaga kelmaydi - evdev-map.c faylida to'g'ri o'lcham ko'rsatilgan, shuning uchun chegaradan tashqarida bo'lmaydi. Demak, bu osonlikcha tuzatilishi mumkin bo'lgan xato.
Noto'g'ri taqqoslash
// common/parse.h
#if defined(B_ENDIAN) || defined(NEED_ALIGN)
#define in_uint16_le(s, v) do
....
#else
#define in_uint16_le(s, v) do
{
(v) = *((unsigned short*)((s)->p));
(s)->p += 2;
} while (0)
#endif
int
xrdp_caps_process_confirm_active(struct xrdp_rdp *self, struct stream *s)
{
int cap_len;
....
in_uint16_le(s, cap_len);
....
if ((cap_len < 0) || (cap_len > 1024 * 1024))
{
....
}
....
}
Funktsiya turdagi o'zgaruvchini o'qiydi imzosiz kalta kabi o'zgaruvchiga aylanadi int. Bu erda tekshirish kerak emas, chunki biz imzosiz o'zgaruvchini o'qiymiz va natijani kattaroq o'zgaruvchiga tayinlaymiz, shuning uchun o'zgaruvchi manfiy qiymat qabul qila olmaydi.
Keraksiz tekshiruvlar
int EXPORT_CC
libxrdp_send_pointer(struct xrdp_session *session, int cache_idx,
char *data, char *mask, int x, int y, int bpp)
{
....
if ((bpp == 15) && (bpp != 16) && (bpp != 24) && (bpp != 32))
{
g_writeln("libxrdp_send_pointer: error");
return 1;
}
....
}
Tengsizlikni tekshirish bu erda mantiqiy emas, chunki bizda boshida taqqoslash bor. Ehtimol, bu xato va ishlab chiquvchi operatordan foydalanmoqchi bo'lgan || noto'g'ri dalillarni filtrlash uchun.
xulosa
Tekshiruv davomida jiddiy xatolar aniqlanmadi, biroq ko‘plab kamchiliklar aniqlandi. Biroq, bu dizaynlar kichik hajmga ega bo'lsa-da, ko'plab tizimlarda qo'llaniladi. Kichkina loyihada ko'p xatolar bo'lishi shart emas, shuning uchun siz analizatorning ishlashini faqat kichik loyihalarda baholamasligingiz kerak. Bu haqda ko'proq maqolada o'qishingiz mumkin "
PVS-Studio ning sinov versiyasini bizdan yuklab olishingiz mumkin
Agar siz ushbu maqolani ingliz tilida so'zlashuvchi auditoriya bilan baham ko'rmoqchi bo'lsangiz, tarjima havolasidan foydalaning: Sergey Larin.
Manba: www.habr.com