የPVS-Studio analyzerን በመጠቀም rdesktop እና xrdp በመፈተሽ ላይ

የPVS-ስቱዲዮ ተንታኝ በመጠቀም rdesktop እና xrdp በመፈተሽ ላይ
ይህ ከRDP ፕሮቶኮል ጋር ለመስራት ክፍት ምንጭ ፕሮግራሞችን ስለመሞከር በተከታታይ መጣጥፎች ውስጥ ሁለተኛው ግምገማ ነው። በእሱ ውስጥ የ rdesktop ደንበኛን እና የ xrdp አገልጋይን እንመለከታለን.

ስህተቶችን ለመለየት እንደ መሳሪያ ጥቅም ላይ ይውላል PVS- ስቱዲዮ. ለC፣ C++፣ C # እና Java ቋንቋዎች የማይንቀሳቀስ ኮድ ተንታኝ ነው፣ በዊንዶውስ፣ ሊኑክስ እና ማክሮስ መድረኮች ላይ ይገኛል።

ጽሑፉ የሚያቀርበው ለእኔ አስደሳች የሚመስሉትን ስህተቶች ብቻ ነው። ይሁን እንጂ ፕሮጀክቶቹ ትንሽ ናቸው, ስለዚህ ጥቂት ስህተቶች ነበሩ :).

አመለከተ. ስለ FreeRDP ፕሮጀክት ማረጋገጫ ያለፈ ጽሁፍ ሊገኝ ይችላል። እዚህ.

rdsktop

rdsktop - ለ UNIX-ተኮር ስርዓቶች የ RDP ደንበኛ ነፃ ትግበራ። በሲግዊን ስር ፕሮጀክቱን ከገነቡ በዊንዶውስ ስር መጠቀም ይቻላል. በ GPLv3 ፍቃድ የተሰጠው።

ይህ ደንበኛ በጣም ታዋቂ ነው - በነባሪነት በ ReactOS ውስጥ ጥቅም ላይ ይውላል፣ እና የሶስተኛ ወገን ግራፊክ የፊት-መጨረሻዎችንም ለእሱ ማግኘት ይችላሉ። ሆኖም እሱ በጣም አርጅቷል-የመጀመሪያው የተለቀቀው ሚያዝያ 4, 2001 ነበር - ይህ ጽሑፍ በተጻፈበት ጊዜ 17 ዓመቱ ነው።

ቀደም ብዬ እንደገለጽኩት ፕሮጀክቱ በጣም ትንሽ ነው. በውስጡ ወደ 30 ሺህ የሚጠጉ የኮድ መስመሮችን ይዟል, ይህም እድሜውን ግምት ውስጥ በማስገባት ትንሽ እንግዳ ነገር ነው. ለማነፃፀር, FreeRDP 320 ሺህ መስመሮችን ይዟል. የክሎክ ፕሮግራም ውፅዓት ይኸውና፡-

የPVS-ስቱዲዮ ተንታኝ በመጠቀም rdesktop እና xrdp በመፈተሽ ላይ

የማይደረስ ኮድ

V779 የማይገኝ ኮድ ተገኝቷል። ስህተት ሊኖር ይችላል. rdesktop.c 1502

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);
}

ስህተቱ ወዲያውኑ በተግባሩ ውስጥ ያጋጥመናል ዋና: ከኦፕሬተር በኋላ የሚመጣውን ኮድ እናያለን መመለስ - ይህ ቁራጭ የማስታወስ ማጽዳትን ያከናውናል. ነገር ግን, ስህተቱ ስጋት አይፈጥርም: ሁሉም የተመደበው ማህደረ ትውስታ ፕሮግራሙ ከወጣ በኋላ በስርዓተ ክወናው ይጸዳል.

የስህተት አያያዝ የለም።

V557 ድርድር ማካሄድ ይቻላል። የ'n' ኢንዴክስ ዋጋ -1 ሊደርስ ይችላል። rdesktop.c 1872

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);
  }
  ....
}

በዚህ ጉዳይ ላይ ያለው የኮድ ቅንጣቢ ፋይሉ እስኪያልቅ ድረስ ከፋይሉ ወደ ቋት ይነበባል። ሆኖም፣ እዚህ ምንም ስህተት አያያዝ የለም፡ የሆነ ችግር ከተፈጠረ፣ ከዚያ ያንብቡ ይመለሳል -1, እና ከዚያ ድርድር ይገለበጣል ውጤት.

EOFን በቻር አይነት መጠቀም

V739 EOF ከ'ቻር' አይነት ዋጋ ጋር መወዳደር የለበትም። የ'(c = fgetc(fp))' የ'int' አይነት መሆን አለበት። ctrl.c 500


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++;
  }
  ....
}

እዚህ የፋይሉ መጨረሻ ላይ ለመድረስ የተሳሳተ አያያዝ እናያለን፡ ከሆነ fgetc ኮዱ 0xFF የሆነ ቁምፊ ይመልሳል፣ እንደ ፋይሉ መጨረሻ ይተረጎማል (EOF).

EOF እሱ ቋሚ ነው፣ ብዙውን ጊዜ እንደ -1 ይገለጻል። ለምሳሌ ፣ በ CP1251 ኢንኮዲንግ ፣ የሩስያ ፊደላት የመጨረሻው ፊደል 0xFF ኮድ አለው ፣ ይህም ከቁጥር -1 ጋር የሚዛመድ ነው ፣ እንደ ተለዋዋጭ እየተነጋገርን ከሆነ ቁምፊ. ምልክቱ 0xFF ፣ እንደ EOF (-1) የፋይሉ መጨረሻ ተብሎ ይተረጎማል። እንደዚህ አይነት ስህተቶችን ለማስወገድ የተግባሩ ውጤት ነው fgetc እንደ ተለዋዋጭ ውስጥ መቀመጥ አለበት int.

ታይፖስ

ክፍል 1

V547 'write_time' የሚለው አገላለጽ ሁልጊዜ ውሸት ነው። disk.c 805

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; // <=
  ....
}

ምናልባት የዚህ ኮድ ጸሐፊ ተሳስቷል || и && በሁኔታ ላይ. ለዋጋዎች ሊሆኑ የሚችሉ አማራጮችን እናስብ የመጻፍ_ጊዜ и ለውጥ_ጊዜ:

  • ሁለቱም ተለዋዋጮች ከ 0 ጋር እኩል ናቸው: በዚህ ሁኔታ በቅርንጫፍ ውስጥ እንጨርሳለን ያለዚያተለዋዋጭ mod_time የሚቀጥለው ሁኔታ ምንም ይሁን ምን ሁልጊዜ 0 ይሆናል.
  • ከተለዋዋጮች አንዱ 0 ነው፡ mod_time ከ 0 ጋር እኩል ይሆናል (ሌላኛው ተለዋዋጭ አሉታዊ ያልሆነ እሴት ካለው) ፣ ምክንያቱም MIN ከሁለቱ አማራጮች ትንሹን ይመርጣል.
  • ሁለቱም ተለዋዋጮች ከ0 ጋር እኩል አይደሉም፡ አነስተኛውን እሴት ይምረጡ።

ሁኔታውን በሚተካበት ጊዜ የመጻፍ_ሰዓት እና ለውጥ_ጊዜ ባህሪው ትክክል ይመስላል

  • አንድ ወይም ሁለቱም ተለዋዋጮች ከ0 ጋር እኩል አይደሉም፡ ዜሮ ያልሆነ እሴት ይምረጡ።
  • ሁለቱም ተለዋዋጮች ከ0 ጋር እኩል አይደሉም፡ አነስተኛውን እሴት ይምረጡ።

ክፍል 2

V547 አገላለጽ ሁሌም እውነት ነው። ምናልባት የ«&&» ኦፕሬተር እዚህ ጥቅም ላይ መዋል አለበት። disk.c 1419

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;
  ....
}

በግልጽ ለማየት እንደሚቻለው ኦፕሬተሮች እዚህም ተደባልቀዋል || и &&, ወይም == и !=: ተለዋዋጭ እሴት 20 እና 9 በተመሳሳይ ጊዜ ሊኖረው አይችልም.

ያልተገደበ መስመር መቅዳት

V512 የ'sprintf' ተግባር ጥሪ ወደ ቋት 'ፉል ጎዳና' ከመጠን በላይ እንዲፈስ ያደርጋል። disk.c 1257

RD_NTSTATUS
disk_query_directory(....)
{
  ....
  char *dirname, fullpath[PATH_MAX];
  ....
  /* Get information for directory entry */
  sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
  ....
}

ተግባሩን ሙሉ በሙሉ ሲመለከቱ, ይህ ኮድ ችግር እንደማይፈጥር ግልጽ ይሆናል. ሆኖም፣ እነሱ ወደፊት ሊነሱ ይችላሉ፡ አንድ ግድየለሽ ለውጥ እና ቋት ሞልቶ ይጎርፍልናል - ስፕሪንት በምንም ነገር የተገደበ አይደለም፣ስለዚህ መንገዶችን ስንጣመር ከድርድር ወሰን ማለፍ እንችላለን። ይህንን ጥሪ ለማስተዋል ይመከራል snprintf(ሙሉ መንገድ፣ PATH_MAX፣ ….).

ተደጋጋሚ ሁኔታ

V560 የሁኔታዊ አገላለጽ አንድ አካል ሁል ጊዜ እውነት ነው፡ add > 0. scard.c 507

static void
inRepos(STREAM in, unsigned int read)
{
  SERVER_DWORD add = 4 - read % 4;
  if (add < 4 && add > 0)
  {
    ....
  }
}

ተቆጣጣሪነት ጨምር > 0 እዚህ ምንም አያስፈልግም: ተለዋዋጭው ሁልጊዜ ከዜሮ የበለጠ ይሆናል, ምክንያቱም አንብብ % 4 የቀረውን ክፍል ይመልሳል ፣ ግን በጭራሽ ከ 4 ጋር እኩል አይሆንም።

xrdp

xrdp - የክፍት ምንጭ ኮድ ያለው የ RDP አገልጋይ መተግበር። ፕሮጀክቱ በ 2 ክፍሎች የተከፈለ ነው.

  • xrdp - የፕሮቶኮል ትግበራ. በApache 2.0 ፍቃድ ስር ተሰራጭቷል።
  • xorgxrdp - ከ xrdp ጋር ለመጠቀም የ Xorg ሾፌሮች ስብስብ። ፍቃድ - X11 (እንደ MIT ፣ ግን በማስታወቂያ ውስጥ መጠቀምን ይከለክላል)

የፕሮጀክቱ ልማት በ rdesktop እና FreeRDP ውጤቶች ላይ የተመሰረተ ነው. መጀመሪያ ላይ ከግራፊክስ ጋር ለመስራት የተለየ የቪኤንሲ አገልጋይ ወይም ልዩ የ X11 አገልጋይ ከ RDP ድጋፍ ጋር - X11rdp መጠቀም ነበረብዎ ነገር ግን በ xorgxrdp መምጣት የእነርሱ ፍላጎት ጠፋ።

በዚህ ጽሑፍ ውስጥ xorgxrdpን አንሸፍንም.

የ xrdp ፕሮጀክት፣ ልክ እንደ ቀደመው፣ በጣም ትንሽ እና ወደ 80 ሺህ የሚጠጉ መስመሮችን ይይዛል።

የPVS-ስቱዲዮ ተንታኝ በመጠቀም rdesktop እና xrdp በመፈተሽ ላይ

ተጨማሪ የፊደል ስህተቶች

V525 ኮዱ ተመሳሳይ ብሎኮች ስብስብ ይዟል. በመስመር 87፣ 88፣ 89 ውስጥ ያሉትን 'r'፣ 'g'፣ 'r' ይመልከቱ። rfxencode_rgb_to_yuv.c 87

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++;
      }
      ....
  }
  ....
}

ይህ ኮድ የተወሰደው ከlibrfxcodec ቤተ-መጽሐፍት ነው፣ እሱም የjpeg2000 ኮዴክን RemoteFX ተግባራዊ ያደርጋል። እዚህ ፣ በግልጽ ፣ የግራፊክ ዳታ ቻናሎች ተደባልቀዋል - ከ “ሰማያዊ” ቀለም ይልቅ “ቀይ” ተመዝግቧል። ይህ ስህተት በአብዛኛው የሚታየው በመቅዳት ምክንያት ነው።

በተመሳሳይ ተግባር ውስጥ ተመሳሳይ ችግር ተከስቷል rfx_encode_ቅርጸት_argbተንታኙም እንደነገረን፡-

V525 ኮዱ ተመሳሳይ ብሎኮች ስብስብ ይዟል. በመስመር 260፣ 261፣ 262፣ 263 ንጥሎችን 'a'፣ 'r'፣ 'g'፣ 'r' ይመልከቱ። rfxencode_rgb_to_yuv.c 260

while (x < 64)
{
    *la_buf++ = a;
    *lr_buf++ = r;
    *lg_buf++ = g;
    *lb_buf++ = r;
    x++;
}

የድርድር መግለጫ

V557 የድርድር መደራረብ ይቻላል። የ'i — 8' ኢንዴክስ ዋጋ 129. genkeymap.c 142 ሊደርስ ይችላል።

// 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];
    ....
  }
  ....
}

በእነዚህ ሁለት ፋይሎች ውስጥ ያለው የድርድር መግለጫ እና ፍቺ ተኳሃኝ አይደሉም - መጠኑ በ 1 ይለያያል ፣ ሆኖም ፣ ምንም ስህተቶች አይከሰቱም - ትክክለኛው መጠን በ evdev-map.c ፋይል ውስጥ ተገልጿል ፣ ስለሆነም ምንም ወሰን የለም። ስለዚህ ይህ በቀላሉ ሊስተካከል የሚችል ስህተት ብቻ ነው.

ትክክል ያልሆነ ንጽጽር

V560 የሁኔታዊ አገላለጽ ክፍል ሁል ጊዜ ሐሰት ነው፡ (cap_len <0)። xrdp_caps.c 616

// 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))
  {
    ....
  }
  ....
}

ተግባሩ አንድ ዓይነት ተለዋዋጭ ያነባል ያልተፈረመ አጭር ወደ ተለዋዋጭ እንደ int. እዚህ ማጣራት አያስፈልግም ምክንያቱም ያልተፈረመ ተለዋዋጭ እያነበብን እና ውጤቱን ለትልቅ ተለዋዋጭ እየመደብን ነው, ስለዚህ ተለዋዋጭ አሉታዊ እሴት ሊወስድ አይችልም.

አላስፈላጊ ቼኮች

V560 ሁኔታዊ አገላለጽ አንድ አካል ሁል ጊዜ እውነት ነው፡ (bpp!= 16)። libxrdp.c 704

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;
  }
  ....
}

መጀመሪያ ላይ ንጽጽር ስላለን የእኩልነት ማረጋገጫዎች እዚህ ትርጉም የላቸውም። ይህ የትየባ ሳይሆን አይቀርም እና ገንቢው ኦፕሬተሩን ለመጠቀም ፈልጎ ሊሆን ይችላል። || ልክ ያልሆኑ ክርክሮችን ለማጣራት.

መደምደሚያ

በኦዲቱ ወቅት ምንም አይነት ከባድ ስህተቶች አልተገኙም, ነገር ግን ብዙ ጉድለቶች ተገኝተዋል. ይሁን እንጂ, እነዚህ ዲዛይኖች በብዙ ስርዓቶች ውስጥ ጥቅም ላይ ይውላሉ, ምንም እንኳን መጠኑ አነስተኛ ቢሆንም. አንድ ትንሽ ፕሮጀክት የግድ ብዙ ስህተቶች የሉትም, ስለዚህ የትንታኔውን አፈፃፀም በትንሽ ፕሮጀክቶች ላይ ብቻ መፍረድ የለብዎትም. ስለዚህ ጉዳይ በጽሁፉ ውስጥ የበለጠ ማንበብ ይችላሉ ።በቁጥር የተረጋገጡ ስሜቶች".

የPVS-ስቱዲዮን የሙከራ ስሪት ከእኛ ማውረድ ይችላሉ። ጣቢያ.

የPVS-ስቱዲዮ ተንታኝ በመጠቀም rdesktop እና xrdp በመፈተሽ ላይ

ይህን ጽሑፍ ለእንግሊዝኛ ተናጋሪ ታዳሚዎች ማጋራት ከፈለጉ፣ እባክዎ የትርጉም ማገናኛውን ይጠቀሙ፡ Sergey Larin። Rdesktop እና xrdp በPVS-Studio በመፈተሽ ላይ

ምንጭ: hab.com

አስተያየት ያክሉ