Å is ir otrais apskats rakstu sÄrijÄ par atvÄrtÄ pirmkoda programmu testÄÅ”anu darbam ar RDP protokolu. TajÄ mÄs apskatÄ«sim rdesktop klientu un xrdp serveri.
Izmanto kÄ rÄ«ku kļūdu noteikÅ”anai
RakstÄ ir parÄdÄ«tas tikai tÄs kļūdas, kuras man Ŕķita interesantas. TomÄr projekti ir mazi, tÄpÄc kļūdu bija maz :).
PiezÄ«me. IepriekÅ”Äjais raksts par FreeRDP projekta verifikÄciju ir atrodams
rdesktop
Å is klients ir ļoti populÄrs ā tas tiek izmantots pÄc noklusÄjuma ReactOS, un tam var atrast arÄ« treÅ”o puÅ”u grafiskos priekÅ”galus. TomÄr viÅÅ” ir diezgan vecs: viÅa pirmÄ atbrÄ«voÅ”ana notika 4. gada 2001. aprÄ«lÄ« - rakstÄ«Å”anas laikÄ viÅam ir 17 gadi.
KÄ jau minÄju iepriekÅ”, projekts ir diezgan mazs. TajÄ ir aptuveni 30 tÅ«kstoÅ”i koda rindiÅu, kas, Åemot vÄrÄ tÄ vecumu, ir nedaudz dÄ«vaini. SalÄ«dzinÄjumam, FreeRDP satur 320 tÅ«kstoÅ”us lÄ«niju. Å eit ir Cloc programmas izvade:
Nesasniedzams kods
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);
}
Kļūda nekavÄjoties tiek parÄdÄ«ta funkcijÄ galvenais: mÄs redzam, ka kods nÄk aiz operatora atgrieÅ”anÄs ā Å”is fragments veic atmiÅas tÄ«rÄ«Å”anu. TomÄr kļūda nerada draudus: visu pieŔķirto atmiÅu operÄtÄjsistÄma notÄ«rÄ«s pÄc programmas izieÅ”anas.
Nav kļūdu apstrÄdes
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);
}
....
}
Koda fragments Å”ajÄ gadÄ«jumÄ tiek nolasÄ«ts no faila buferÄ«, lÄ«dz fails beidzas. TomÄr Å”eit nav kļūdu apstrÄdes: ja kaut kas noiet greizi, tad lasÄ«t atgriezÄ«s -1, un tad masÄ«vs tiks pÄrsniegts produkcija.
EOF izmantoÅ”ana char veidÄ
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++;
}
....
}
Å eit mÄs redzam nepareizu apstrÄdi, sasniedzot faila beigas: if fgetc atgriež rakstzÄ«mi, kuras kods ir 0xFF, tas tiks interpretÄts kÄ faila beigas (EOF).
EOF tÄ ir konstante, ko parasti definÄ kÄ -1. PiemÄram, CP1251 kodÄjumÄ krievu alfabÄta pÄdÄjam burtam ir kods 0xFF, kas atbilst skaitlim -1, ja mÄs runÄjam par mainÄ«go, piemÄram, tvertne. IzrÄdÄs, ka simbols 0xFF, piemÄram EOF (-1) tiek interpretÄts kÄ faila beigas. Lai izvairÄ«tos no Å”ÄdÄm kļūdÄm, funkcijas rezultÄts ir fgetc jÄsaglabÄ tÄdÄ mainÄ«gÄ kÄ int.
Drukas kļūdas
1. fragments
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; // <=
....
}
IespÄjams, Ŕī koda autors ir kļūdÄ«jies || Šø && stÄvoklÄ«. ApskatÄ«sim iespÄjamos vÄrtÄ«bu variantus rakstÄ«Å”anas_laiks Šø maiÅas_laiks:
- Abi mainÄ«gie ir vienÄdi ar 0: Å”ajÄ gadÄ«jumÄ mÄs nonÄksim zarÄ cits: mainÄ«gs mod_time vienmÄr bÅ«s 0 neatkarÄ«gi no turpmÄkÄ nosacÄ«juma.
- Viens no mainÄ«gajiem ir 0: mod_time bÅ«s vienÄds ar 0 (ar nosacÄ«jumu, ka otram mainÄ«gajam ir nenegatÄ«va vÄrtÄ«ba), jo MIN izvÄlÄsies mazÄko no divÄm iespÄjÄm.
- Abi mainÄ«gie nav vienÄdi ar 0: izvÄlieties minimÄlo vÄrtÄ«bu.
Nomainot nosacÄ«jumu ar rakstÄ«Å”anas_laiks un maiÅas_laiks uzvedÄ«ba izskatÄ«sies pareizi:
- Viens vai abi mainÄ«gie nav vienÄdi ar 0: izvÄlieties vÄrtÄ«bu, kas nav nulle.
- Abi mainÄ«gie nav vienÄdi ar 0: izvÄlieties minimÄlo vÄrtÄ«bu.
2. fragments
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;
....
}
AcÄ«mredzot arÄ« Å”eit ir sajaukti operatori || Šø &&Vai == Šø !=: mainÄ«gajam nevar vienlaikus bÅ«t vÄrtÄ«ba 20 un 9.
Neierobežota rindu kopÄÅ”ana
RD_NTSTATUS
disk_query_directory(....)
{
....
char *dirname, fullpath[PATH_MAX];
....
/* Get information for directory entry */
sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
....
}
Apskatot funkciju pilnÄ«bÄ, kļūs skaidrs, ka Å”is kods problÄmas nerada. TomÄr tie var rasties nÄkotnÄ: viena neuzmanÄ«ga maiÅa, un mÄs iegÅ«sim bufera pÄrplÅ«di - sprints nekas neierobežo, tÄpÄc, savienojot ceļus, mÄs varam iziet Ärpus masÄ«va robežÄm. Å o aicinÄjumu ieteicams pamanÄ«t snprintf(pilns ceļŔ, PATH_MAX,ā¦.).
Lieks stÄvoklis
static void
inRepos(STREAM in, unsigned int read)
{
SERVER_DWORD add = 4 - read % 4;
if (add < 4 && add > 0)
{
....
}
}
ŠŃŠ¾Š²ŠµŃŠŗŠ° pievienot > 0 Å”eit nav vajadzÄ«bas: mainÄ«gais vienmÄr bÅ«s lielÄks par nulli, jo lasÄ«t % 4 atgriezÄ«s atlikuÅ”o dalÄ«juma daļu, bet tas nekad nebÅ«s vienÄds ar 4.
xrdp
- xrdp - protokola ievieÅ”ana. IzplatÄ«ts saskaÅÄ ar Apache 2.0 licenci.
- xorgxrdp ā Xorg draiveru komplekts lietoÅ”anai ar xrdp. Licence ā X11 (piemÄram, MIT, bet aizliedz izmantot reklÄmÄ)
Projekta izstrÄdes pamatÄ ir rdesktop un FreeRDP rezultÄti. SÄkotnÄji, lai strÄdÄtu ar grafiku, bija jÄizmanto atseviŔķs VNC serveris vai Ä«paÅ”s X11 serveris ar RDP atbalstu - X11rdp, taÄu lÄ«dz ar xorgxrdp parÄdÄ«Å”anos nepiecieÅ”amÄ«ba pÄc tiem zuda.
Å ajÄ rakstÄ mÄs neaplÅ«kosim xorgxrdp.
Xrdp projekts, tÄpat kÄ iepriekÅ”Äjais, ir ļoti mazs un satur aptuveni 80 tÅ«kstoÅ”us rindu.
VairÄk drukas kļūdu
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++;
}
....
}
....
}
Å is kods tika Åemts no librfxcodec bibliotÄkas, kas ievieÅ” jpeg2000 kodeku RemoteFX. Å eit acÄ«mredzot ir sajaukti grafiskie datu kanÄli - āzilÄsā krÄsas vietÄ tiek ierakstÄ«ts āsarkansā. Å Ä« kļūda, visticamÄk, radÄs kopÄÅ”anas un ielÄ«mÄÅ”anas rezultÄtÄ.
TÄda pati problÄma radÄs lÄ«dzÄ«gÄ funkcijÄ rfx_encode_format_argb, ko analizators mums arÄ« teica:
while (x < 64)
{
*la_buf++ = a;
*lr_buf++ = r;
*lg_buf++ = g;
*lb_buf++ = r;
x++;
}
MasÄ«va deklarÄcija
// 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];
....
}
....
}
MasÄ«va deklarÄcija un definÄ«cija Å”ajos divos failos nav savietojama - izmÄrs atŔķiras par 1. TomÄr kļūdas nenotiek - pareizais izmÄrs ir norÄdÄ«ts failÄ evdev-map.c, tÄpÄc nav robežu. TÄtad Ŕī ir tikai kļūda, kuru var viegli novÄrst.
Nepareizs salÄ«dzinÄjums
// 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))
{
....
}
....
}
Funkcija nolasa tipa mainÄ«go neparakstÄ«ts Ä«ss mainÄ«gajÄ kÄ int. PÄrbaude Å”eit nav nepiecieÅ”ama, jo mÄs lasÄm neparakstÄ«tu mainÄ«go un pieŔķiram rezultÄtu lielÄkam mainÄ«gajam, tÄpÄc mainÄ«gais nevar iegÅ«t negatÄ«vu vÄrtÄ«bu.
NevajadzÄ«gas pÄrbaudes
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;
}
....
}
NevienlÄ«dzÄ«bas pÄrbaudÄm Å”eit nav jÄgas, jo mums jau ir salÄ«dzinÄjums sÄkumÄ. IespÄjams, ka tÄ ir drukas kļūda, un izstrÄdÄtÄjs vÄlÄjÄs izmantot operatoru || lai filtrÄtu nederÄ«gos argumentus.
SecinÄjums
RevÄ«zijas laikÄ nopietnas kļūdas netika konstatÄtas, taÄu tika konstatÄtas daudzas nepilnÄ«bas. TomÄr Ŕīs konstrukcijas tiek izmantotas daudzÄs sistÄmÄs, lai gan tÄs ir nelielas. Nelielam projektam ne vienmÄr ir daudz kļūdu, tÄpÄc nevajadzÄtu spriest par analizatora veiktspÄju tikai mazos projektos. VairÄk par to varat lasÄ«t rakstÄ "
No mums varat lejupielÄdÄt PVS-Studio izmÄÄ£inÄjuma versiju
Ja vÄlaties dalÄ«ties ar Å”o rakstu ar angliski runÄjoÅ”u auditoriju, lÅ«dzu, izmantojiet tulkoÅ”anas saiti: Sergejs Larins.
Avots: www.habr.com