PVS-Studio analyzer ဖြင့် FreeRDP ကိုစစ်ဆေးခြင်း

PVS-Studio ခွဲခြမ်းစိတ်ဖြာမှုကို အသုံးပြု၍ FreeRDP ကိုစစ်ဆေးခြင်း။
FreeRDP သည် Microsoft မှ အဝေးထိန်းကွန်ပျူတာထိန်းချုပ်မှုအတွက် တီထွင်ထားသော protocol တစ်ခုဖြစ်သည့် Remote Desktop Protocol (RDP) ၏ open-source အကောင်အထည်ဖော်မှုတစ်ခုဖြစ်သည်။ ဤပရောဂျက်သည် အပါအဝင် ပလက်ဖောင်းများစွာကို ပံ့ပိုးပေးသည်။ Windows, Linux, macOS iOS နဲ့တောင် Androidဤပရောဂျက်ကို PVS-Studio static analyzer ကို အသုံးပြု၍ RDP client များကို စမ်းသပ်ရန် ရည်စူးထားသော ဆောင်းပါးစီးရီးထဲမှ ပထမဆုံးအဖြစ် ရွေးချယ်ခဲ့သည်။

အနည်းငယ်သောသမိုင်း

စီမံကိန်း၏ FreeRDP Microsoft သည် ၎င်း၏တစ်ဦးတည်းပိုင် RDP ပရိုတိုကောအတွက် သတ်မှတ်ချက်များကို ဖွင့်ချပြီးနောက် ထွက်ပေါ်လာခြင်းဖြစ်သည်။ ထိုအချိန်တွင်၊ Reverse Engineering ၏ရလဒ်များအပေါ်အခြေခံသည့်အကောင်အထည်ဖော်မှု rdesktop client တစ်ခုရှိသည်။

ပရိုတိုကောကို အကောင်အထည် ဖော်လာသည်နှင့်အမျှ၊ ယခင်ရှိပြီးသား ပရောဂျက်ဗိသုကာလက်ရာကြောင့် လုပ်ဆောင်ချက်အသစ်များကို ထည့်သွင်းရန် ပိုမိုခက်ခဲလာသည်။ ၎င်းတွင်ပြောင်းလဲမှုများသည် rdesktop - FreeRDP ၏လမ်းဆုံတစ်ခုဖန်တီးမှုကိုဖြစ်ပေါ်စေသည့် developer များအကြားပဋိပက္ခတစ်ခုဖြစ်ပေါ်စေခဲ့သည်။ Apache License v2 သို့ လိုင်စင်ထုတ်ပေးရန် ဆုံးဖြတ်ချက်ချခဲ့သော ရလဒ်အနေဖြင့် GPLv2 လိုင်စင်ဖြင့် ထုတ်ကုန်၏နောက်ထပ်ဖြန့်ဖြူးမှုကို ကန့်သတ်ထားသည်။ သို့သော်၊ လူတိုင်းသည် ၎င်းတို့၏ကုဒ်လိုင်စင်ကို ပြောင်းလဲရန် သဘောတူကြသည်မဟုတ်သောကြောင့် developer များသည် ပရောဂျက်ကို ပြန်လည်ရေးသားရန် ဆုံးဖြတ်ခဲ့ပြီး ခေတ်မီကုဒ်ဘေ့စ်တစ်ခု ဖြစ်လာခဲ့သည်။

တရားဝင်ဘလော့ဂ်ပို့စ်တွင် ပရောဂျက်၏သမိုင်းကြောင်းကို "FreeRDP ပရောဂျက်သမိုင်း" တွင် သင်ပိုမိုဖတ်ရှုနိုင်ပါသည်။

ကုဒ်ရှိ အမှားအယွင်းများနှင့် ဖြစ်နိုင်ခြေရှိသော အားနည်းချက်များကို ရှာဖွေဖော်ထုတ်ရန် ကိရိယာတစ်ခုအဖြစ် အသုံးပြုသည်။ PVS-Studio မှ၎င်းသည် C၊ C++၊ C# နှင့် Java ပလက်ဖောင်းများပေါ်တွင် ရရှိနိုင်သော static code analyzer တစ်ခုဖြစ်သည်။ Windows, Linux и macOS.

ဆောင်းပါးသည် ကျွန်ုပ်အတွက် စိတ်ဝင်စားဆုံးဟု ထင်ရသည့် အမှားများကိုသာ တင်ပြပါသည်။

Memory ယိုစိမ့်ခြင်း။

V773 'cwd' ညွှန်ပြချက်ကို မထုတ်ဘဲ လုပ်ဆောင်ချက်သည် ထွက်ခဲ့သည်။ Memory ယိုစိမ့်မှုဖြစ်နိုင်သည်။ environment.c ၈၄

DWORD GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer)
{
  char* cwd;
  ....
  cwd = getcwd(NULL, 0);
  ....
  if (lpBuffer == NULL)
  {
    free(cwd);
    return 0;
  }

  if ((length + 1) > nBufferLength)
  {
    free(cwd);
    return (DWORD) (length + 1);
  }

  memcpy(lpBuffer, cwd, length + 1);
  return length;
  ....
}

ဤအပိုင်းအစကို winpr subsystem မှ ရယူထားပြီး၊ ၎င်းသည် non- အတွက် WINAPI wrapper ကို အကောင်အထည်ဖော်သည်။Windows စနစ်များ၊ ဆိုလိုသည်မှာ ၎င်းသည် Wine ၏ ပေါ့ပါးသော analogue တစ်ခုဖြစ်သည်။ ဤနေရာတွင် leak တစ်ခုကို သင်တွေ့မြင်နိုင်သည်- function မှ ခွဲဝေထားသော memory getcwdအထူးကိစ္စရပ်များကို ကိုင်တွယ်သည့်အခါမှသာ ထုတ်ပြန်သည်။ အမှားကိုပြင်ရန် ခေါ်ဆိုမှုတစ်ခုထည့်ရန် လိုအပ်သည်။ အခမဲ့ после မှတ်မိ.

အခင်းအကျင်းကို စည်းမထားပါ။

V557 Array overrun ဖြစ်နိုင်သည်။ 'event->EventHandlerCount' အညွှန်းကိန်း၏တန်ဖိုးသည် 32 သို့ရောက်ရှိနိုင်သည်။ PubSub.c 117

#define MAX_EVENT_HANDLERS  32

struct _wEventType
{
  ....
  int EventHandlerCount;
  pEventHandler EventHandlers[MAX_EVENT_HANDLERS];
};

int PubSub_Subscribe(wPubSub* pubSub, const char* EventName,
      pEventHandler EventHandler)
{
  ....
  if (event->EventHandlerCount <= MAX_EVENT_HANDLERS)
  {
    event->EventHandlers[event->EventHandlerCount] = EventHandler;
    event->EventHandlerCount++;
  }
  ....
}

ဤဥပမာသည် ဒြပ်စင်အရေအတွက် အများဆုံးသို့ရောက်ရှိသွားလျှင်ပင် စာရင်းထဲသို့ အစိတ်အပိုင်းအသစ်တစ်ခုကို ပေါင်းထည့်သည်။ ဤနေရာတွင် အော်ပရေတာ အစားထိုးရန် လုံလောက်ပါသည်။ <= အပေါ် <ခင်းကျင်းထားသော နယ်နိမိတ်များကို ကျော်လွန်မသွားစေရန်။

ဤအမျိုးအစား၏ နောက်ထပ်အမှားတစ်ခု တွေ့ရှိခဲ့သည်-

  • V557 Array သည် overrun ဖြစ်နိုင်သည်။ 'iBitmapFormat' အညွှန်းကိန်း၏တန်ဖိုးသည် 8. orders.c 2623 သို့ရောက်ရှိနိုင်သည်။

စာလုံးပေါင်း

တစ်ပိုင်းတစ်စ ၁

V547 စကားရပ် '!pipe->In' သည် အမြဲတမ်း လွဲမှားနေပါသည်။ MessagePipe.c ၆၃

wMessagePipe* MessagePipe_New()
{
  ....
  pipe->In = MessageQueue_New(NULL);
  if (!pipe->In)
    goto error_in;

  pipe->Out = MessageQueue_New(NULL);
  if (!pipe->In) // <=
    goto error_out;
  ....
}

ဤနေရာတွင် ဘုံစာစီစာကုံးတစ်ခုကို ကျွန်ုပ်တို့တွေ့ရသည်- ဒုတိယအခြေအနေသည် ပထမနှင့်တူညီသောကိန်းရှင်ကို စစ်ဆေးသည်။ ဖြစ်နိုင်သည်မှာ၊ ကုဒ်ကူးယူခြင်း မအောင်မြင်ခြင်းကြောင့် အမှားအယွင်း ပေါ်လာသည်။

တစ်ပိုင်းတစ်စ ၁

V760 တူညီသော စာသားတုံး နှစ်ကွက်ကို တွေ့ရှိခဲ့သည်။ ဒုတိယဘလောက်သည် စာကြောင်း 771. tsg.c 770 မှ စတင်သည်။

typedef struct _TSG_PACKET_VERSIONCAPS
{
  ....
  UINT16 majorVersion;
  UINT16 minorVersion;
  ....
} TSG_PACKET_VERSIONCAPS, *PTSG_PACKET_VERSIONCAPS;

static BOOL TsProxyCreateTunnelReadResponse(....)
{
  ....
  PTSG_PACKET_VERSIONCAPS versionCaps = NULL;
  ....
  /* MajorVersion (2 bytes) */
  Stream_Read_UINT16(pdu->s, versionCaps->majorVersion);
  /* MinorVersion (2 bytes) */
  Stream_Read_UINT16(pdu->s, versionCaps->majorVersion);
  ....
}

နောက်ထပ်အမှားတစ်ခု- ကုဒ်မှတ်ချက်သည် စာတွဲပါလာသင့်သည်ဟု ဆိုလိုသည်။ minorVersionသို့သော်၊ စာဖတ်ခြင်းသည် အမည်ပေးထားသော ကိန်းရှင်တစ်ခုအဖြစ် ဖြစ်ပေါ်သည်။ majorVersion. သို့သော်၊ ကျွန်ုပ်သည် ပရိုတိုကောနှင့် မရင်းနှီးပါ၊ ထို့ကြောင့် ဒါက ခန့်မှန်းချက်မျှသာ ဖြစ်သည်။

တစ်ပိုင်းတစ်စ ၁

V524 'trio_index_last' လုပ်ဆောင်ချက်၏ ကိုယ်ထည်သည် 'trio_index' လုပ်ဆောင်ချက်ကိုယ်ထည်နှင့် အပြည့်အဝ ညီမျှသည်မှာ ထူးဆန်းပါသည်။ triostr.c ၉၃၃

/**
   Find first occurrence of a character in a string.
   ....
 */
TRIO_PUBLIC_STRING char *
trio_index
TRIO_ARGS2((string, character),
     TRIO_CONST char *string,
     int character)
{
  assert(string);
  return strchr(string, character);
}

/**
   Find last occurrence of a character in a string.
   ....
 */
TRIO_PUBLIC_STRING char *
trio_index_last
TRIO_ARGS2((string, character),
     TRIO_CONST char *string,
     int character)
{
  assert(string);
  return strchr(string, character);
}

လုပ်ဆောင်ချက်၊ မှတ်ချက်ဖြင့် သုံးသပ်သည်။ trio_index string တစ်ခုတွင် ပထမဆုံး ဇာတ်ကောင်ကို ရှာတွေ့သည့်အခါ၊ trio_index_နောက်ဆုံး - နောက်ဆုံးအချက်။ ဒါပေမယ့် ဒီလုပ်ဆောင်ချက်တွေရဲ့ အစိတ်အပိုင်းတွေက အတူတူပါပဲ။ အများစုမှာ ၎င်းသည် typo တစ်ခုဖြစ်ပြီး function တွင် ဖြစ်နိုင်သည်။ trio_index_နောက်ဆုံး အသုံးပြုရန် လိုအပ်သည်။ strhrhr အစား Strchr. အဲဒီအခါမှာ အပြုအမူတွေ ရှိလာမယ်။

တစ်ပိုင်းတစ်စ ၁

V769 စကားရပ်ရှိ 'ဒေတာ' ညွှန်ပြချက်သည် nullptr နှင့် ညီမျှသည်။ ဤညွှန်ပြချက်ပေါ်ရှိ ဂဏန်းသင်္ချာလုပ်ဆောင်ချက်များ၏ ရလဒ်တန်ဖိုးသည် အဓိပ္ပါယ်မဲ့ပြီး ၎င်းကို အသုံးမပြုသင့်ပါ။ nsc_encode.c ၁၂၄

static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* context,
                                      const BYTE* data,
                                      UINT32 scanline)
{
  ....
  if (!context || data || (scanline == 0))
    return FALSE;
  ....
  src = data + (context->height - 1 - y) * scanline;
  ....
}

ခွဲထွက်ရေးအော်ပရေတာသည် ဤနေရာတွင် မတော်တဆ လွဲသွားပုံရသည်။ ! အနီး ဒေတာ. ဒါကို သတိမပြုမိသွားတာ ထူးဆန်းတယ်။

တစ်ပိုင်းတစ်စ ၁

V517 'if (A) {…} else if (A) {…}' ပုံစံကို တွေ့ရှိခဲ့သည်။ ယုတ္တိအမှားရှိနေခြင်း ဖြစ်နိုင်ခြေရှိပါသည်။ လိုင်းများကို စစ်ဆေးပါ- 213, 222. rdpei_common.c 213

BOOL rdpei_write_4byte_unsigned(wStream* s, UINT32 value)
{
  BYTE byte;

  if (value <= 0x3F)
  {
    ....
  }
  else if (value <= 0x3FFF)
  {
    ....
  }
  else if (value <= 0x3FFFFF)
  {
    byte = (value >> 16) & 0x3F;
    Stream_Write_UINT8(s, byte | 0x80);
    byte = (value >> 8) & 0xFF;
    Stream_Write_UINT8(s, byte);
    byte = (value & 0xFF);
    Stream_Write_UINT8(s, byte);
  }
  else if (value <= 0x3FFFFF)
  {
    byte = (value >> 24) & 0x3F;
    Stream_Write_UINT8(s, byte | 0xC0);
    byte = (value >> 16) & 0xFF;
    Stream_Write_UINT8(s, byte);
    byte = (value >> 8) & 0xFF;
    Stream_Write_UINT8(s, byte);
    byte = (value & 0xFF);
    Stream_Write_UINT8(s, byte);
  }
  ....
}

နောက်ဆုံးအခြေအနေနှစ်ခုသည် တူညီသည်- တစ်စုံတစ်ဦးသည် ကူးယူပြီးနောက် ၎င်းတို့အား စစ်ဆေးရန်မေ့သွားပုံရသည်။ နောက်ဆုံးအပိုင်းသည် လေးဘိုက်တန်ဖိုးများဖြင့် အလုပ်လုပ်ကြောင်း ကုဒ်မှ သိသာထင်ရှားစွာ သိသာသောကြောင့် နောက်ဆုံးအခြေအနေဖြစ်သင့်သည်ဟု ကျွန်ုပ်တို့ ယူဆနိုင်ပါသည်။ တန်ဖိုး <= 0x3FFFFFFFF.

ဤအမျိုးအစား၏ နောက်ထပ်အမှားတစ်ခု တွေ့ရှိခဲ့သည်-

  • V517 'if (A) {…} else if (A) {…}' ပုံစံကို တွေ့ရှိခဲ့သည်။ ယုတ္တိအမှားရှိနေခြင်း ဖြစ်နိုင်ခြေရှိပါသည်။ လိုင်းများကို စစ်ဆေးပါ- 169, 173. file.c 169

ထည့်သွင်းဒေတာကို အတည်ပြုခြင်း။

တစ်ပိုင်းတစ်စ ၁

V547 ဖော်ပြချက် 'strcat(ပစ်မှတ်၊ အရင်းအမြစ်) != NULL' သည် အမြဲမှန်သည်။ triostr.c ၄၂၅

TRIO_PUBLIC_STRING int
trio_append
TRIO_ARGS2((target, source),
     char *target,
     TRIO_CONST char *source)
{
  assert(target);
  assert(source);
  
  return (strcat(target, source) != NULL);
}

ဤဥပမာရှိ လုပ်ဆောင်ချက်၏ ရလဒ်ကို စစ်ဆေးခြင်းသည် မမှန်ကန်ပါ။ လုပ်ဆောင်ချက် strcat စာကြောင်း၏နောက်ဆုံးဗားရှင်းသို့ ညွှန်ပြချက်ကို ပြန်ပေးသည်၊ ဆိုလိုသည်မှာ၊ ပထမဘောင်ကို ကျော်သွားပါပြီ။ ဤကိစ္စတွင်၊ ပစ်မှတ်. သို့သော် တန်းတူဖြစ်လျှင် nullလုပ်ဆောင်ချက်ရှိသောကြောင့် စစ်ဆေးရန် နောက်ကျနေပြီဖြစ်သည်။ strcat ကိုးကားပါမည်။

တစ်ပိုင်းတစ်စ ၁

V547 စကားရပ် 'cache' သည် အမြဲမှန်သည်။ glyph.c ၇၃၀

typedef struct rdp_glyph_cache rdpGlyphCache;

struct rdp_glyph_cache
{
  ....
  GLYPH_CACHE glyphCache[10];
  ....
};

void glyph_cache_free(rdpGlyphCache* glyphCache)
{
  ....
  GLYPH_CACHE* cache = glyphCache->glyphCache;

  if (cache)
  {
    ....
  }
  ....
}

ဤကိစ္စတွင် variable ကို cache ကို static array တစ်ခု၏ လိပ်စာကို သတ်မှတ်ပေးထားသည်။ glyphCache->glyphCache. ထို့ကြောင့် စစ်ဆေးပါ။ အကယ်၍ (cache) ချန်လှပ်နိုင်သည်။

အရင်းအမြစ်စီမံခန့်ခွဲမှု အမှား

V1005 ရင်းမြစ်သည် 'CreateFileA' လုပ်ဆောင်ချက်ကို အသုံးပြု၍ ရယူခဲ့သော်လည်း တွဲဖက်သုံးမရသော 'fclose' လုပ်ဆောင်ချက်ကို အသုံးပြု၍ ထုတ်ပြန်ခဲ့သည်။ certificate.c ၄၄၇

BOOL certificate_data_replace(rdpCertificateStore* certificate_store,
                              rdpCertificateData* certificate_data)
{
  HANDLE fp;
  ....
  fp = CreateFileA(certificate_store->file, GENERIC_READ | GENERIC_WRITE, 0,
                   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  ....
  if (size < 1)
  {
    CloseHandle(fp);
    return FALSE;
  }
  ....
  if (!data)
  {
    fclose(fp);
    return FALSE;
  }
  ....
}

ဖိုင်ဖော်ပြချက် fpလုပ်ဆောင်ချက်ခေါ်ဆိုမှုဖြင့် ဖန်တီးထားသည်။ ဖိုင်ကိုဖန်တီးပါ။ လုပ်ဆောင်ချက်အားဖြင့် မှားယွင်း၍ ပိတ်ထားသည်။ fclose စံစာကြည့်တိုက်မှ မဟုတ်ပါ CloseHandle.

တူညီသောအခြေအနေများ

V581 တစ်ခုနှင့်တစ်ခု ယှဉ်တွဲတည်ရှိသော 'if' ကြေညာချက်များ၏ အခြေအနေအရ ဖော်ပြချက်များသည် တူညီပါသည်။ လိုင်းများကို စစ်ဆေးပါ- 269, 283. ndr_structure.c 283

void NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
      unsigned char* pMemory, PFORMAT_STRING pFormat)
{
  ....
  if (conformant_array_description)
  {
    ULONG size;
    unsigned char array_type;
    array_type = conformant_array_description[0];
    size = NdrComplexStructMemberSize(pStubMsg, pFormat);
    WLog_ERR(TAG, "warning: NdrComplexStructBufferSize array_type: "
      "0x%02X unimplemented", array_type);
    NdrpComputeConformance(pStubMsg, pMemory + size,
      conformant_array_description);
    NdrpComputeVariance(pStubMsg, pMemory + size,
      conformant_array_description);
    MaxCount = pStubMsg->MaxCount;
    ActualCount = pStubMsg->ActualCount;
    Offset = pStubMsg->Offset;
  }

  if (conformant_array_description)
  {
    unsigned char array_type;
    array_type = conformant_array_description[0];
    pStubMsg->MaxCount = MaxCount;
    pStubMsg->ActualCount = ActualCount;
    pStubMsg->Offset = Offset;
    WLog_ERR(TAG, "warning: NdrComplexStructBufferSize array_type: "
      "0x%02X unimplemented", array_type);
  }
  ....
}

ဤဥပမာသည် bug မဟုတ်ပါ။ သို့သော်၊ အခြေအနေနှစ်ခုစလုံးတွင် တူညီသောမက်ဆေ့ချ်များပါရှိပြီး ၎င်းတို့ထဲမှ တစ်ခုကို ဖယ်ရှားပစ်နိုင်ခြေများပါသည်။

null pointers များကို ရှင်းလင်းခြင်း။

V575 null pointer ကို 'free' function သို့ ပေးပို့သည်။ ပထမအငြင်းအခုံကိုစစ်ဆေးပါ။ smartcard_pcsc.c ၈၇၅

WINSCARDAPI LONG WINAPI PCSC_SCardListReadersW(
  SCARDCONTEXT hContext,
  LPCWSTR mszGroups,
  LPWSTR mszReaders,
  LPDWORD pcchReaders)
{
  LPSTR mszGroupsA = NULL;
  ....
  mszGroups = NULL; /* mszGroups is not supported by pcsc-lite */

  if (mszGroups)
    ConvertFromUnicode(CP_UTF8,0, mszGroups, -1, 
                       (char**) &mszGroupsA, 0,
                       NULL, NULL);

  status = PCSC_SCardListReaders_Internal(hContext, mszGroupsA,
                                          (LPSTR) &mszReadersA,
                                          pcchReaders);

  if (status == SCARD_S_SUCCESS)
  {
    ....
  }

  free(mszGroupsA);
  ....
}

လုပ်ဆောင်ရန် အခမဲ့ သင်သည် null pointer ကိုဖြတ်နိုင်ပြီး ၎င်းကို ခွဲခြမ်းစိတ်ဖြာသူမှ သိပါသည်။ သို့သော် ဤအတိုအထွာတွင်ကဲ့သို့ pointer ကို အမြဲတမ်း null ကျော်သွားသည့် အခြေအနေတစ်ခုကို တွေ့ရှိပါက၊ သတိပေးချက်ကို ထုတ်ပြန်ပါမည်။

pointer mszGroupsA အစကတော့ တန်းတူပဲ။ null အခြားမည်သည့်နေရာတွင်မှ အစပြုမထားပါ။ ညွှန်ပြချက်ကို စတင်လုပ်ဆောင်နိုင်သည့် တစ်ခုတည်းသော ကုဒ်အကိုင်းအခက်ကို လက်လှမ်းမမီနိုင်ပါ။

ကဲ့သို့သော အခြားမက်ဆေ့ချ်များ ရှိခဲ့သည်-

  • V575 null pointer ကို 'free' function သို့ ပေးပို့သည်။ ပထမအငြင်းအခုံကိုစစ်ဆေးပါ။ လိုင်စင်.c ၇၉၀
  • V575 null pointer ကို 'free' function သို့ ပေးပို့သည်။ ပထမအငြင်းအခုံကိုစစ်ဆေးပါ။ rdpsnd_alsa.c ၅၇၅

ဖြစ်နိုင်ချေအများစုမှာ၊ refactoring လုပ်ငန်းစဉ်အတွင်း မေ့သွားသော ကိန်းရှင်များ ပေါ်လာပြီး ရိုးရှင်းစွာ ဖယ်ရှားနိုင်သည်။

အလျှံပယ်ဖြစ်နိုင်သည်။

V1028 အလျှံပယ်ဖြစ်နိုင်သည်။ ရလဒ်မဟုတ်ဘဲ operand များကို ကာစ်လုပ်ရန် စဉ်းစားပါ။ makecert.c ၁၀၈၇

// openssl/x509.h
ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj);

struct _MAKECERT_CONTEXT
{
  ....
  int duration_years;
  int duration_months;
};

typedef struct _MAKECERT_CONTEXT MAKECERT_CONTEXT;

int makecert_context_process(MAKECERT_CONTEXT* context, ....)
{
  ....
  if (context->duration_months)
    X509_gmtime_adj(after, (long)(60 * 60 * 24 * 31 *
      context->duration_months));
  else if (context->duration_years)
    X509_gmtime_adj(after, (long)(60 * 60 * 24 * 365 *
      context->duration_years));
  ....
}

ရလဒ်ကို ယူဆောင်လာသည်။ ရှည်လျားသော အမျိုးအစားကို အသုံးပြု၍ တွက်ချက်မှုကိုယ်တိုင် ဖြစ်ပေါ်သောကြောင့် လွှမ်းမိုးကာကွယ်မှု မဟုတ်ပါ။ int.

အစပြုခြင်းတွင် ညွှန်ပြသည့် နှောင့်နှေးမှု

V595 nullptr ကို မစစ်ဆေးမီ 'context' pointer ကို အသုံးပြုခဲ့သည်။ လိုင်းများကို စစ်ဆေးပါ- 746, 748. gfx.c 746

static UINT gdi_SurfaceCommand(RdpgfxClientContext* context,
                               const RDPGFX_SURFACE_COMMAND* cmd)
{
  ....
  rdpGdi* gdi = (rdpGdi*) context->custom;

  if (!context || !cmd)
    return ERROR_INVALID_PARAMETER;
  ....
}

ဤတွင်ညွှန်ပြချက် စကားစပ် စစ်ဆေးခြင်းမပြုမီ ကနဦးသတ်မှတ်ခြင်းတွင် ရည်ညွှန်းထားသည်။

ဤအမျိုးအစား၏ အခြားအမှားများကို တွေ့ရှိခဲ့သည်-

  • V595 သည် nullptr ကို မစစ်ဆေးမီ 'ntlm' pointer ကို အသုံးပြုခဲ့သည်။ လိုင်းများကို စစ်ဆေးပါ- 236, 255. ntlm.c 236
  • V595 nullptr ကို မစစ်ဆေးမီ 'context' pointer ကို အသုံးပြုခဲ့သည်။ လိုင်းများကို စစ်ဆေးပါ- 1003, 1007. rfx.c 1003
  • V595 သည် nullptr ကို မစစ်ဆေးမီ 'rdpei' pointer ကို အသုံးပြုခဲ့သည်။ လိုင်းများကို စစ်ဆေးပါ- 176, 180. rdpei_main.c 176
  • V595 သည် nullptr ကို မစစ်ဆေးမီ 'gdi' pointer ကို အသုံးပြုခဲ့သည်။ လိုင်းများကို စစ်ဆေးပါ- 121, 123. xf_gfx.c 121

အဓိပ္ပါယ်မဲ့ အခြေအနေ

V547 စကားရပ် 'rdp->state >= CONNECTION_STATE_ACTIVE' သည် အမြဲတမ်း မှန်ပါသည်။ connection.c ၁၄၈၉

int rdp_server_transition_to_state(rdpRdp* rdp, int state)
{
  ....
  switch (state)
  {
    ....
    case CONNECTION_STATE_ACTIVE:
      rdp->state = CONNECTION_STATE_ACTIVE;          // <=
      ....
      if (rdp->state >= CONNECTION_STATE_ACTIVE)     // <=
      {
        IFCALLRET(client->Activate, client->activated, client);

        if (!client->activated)
          return -1;
      }
    ....
  }
  ....
}

သက်ဆိုင်ရာတန်ဖိုးကို အစောပိုင်းတွင် သတ်မှတ်ပေးခြင်းကြောင့် ပထမအခြေအနေသည် အဓိပ္ပါယ်မရှိသည်ကို သိမြင်ရန် လွယ်ကူသည်။

စာကြောင်းခွဲခြမ်းစိတ်ဖြာမှု မမှန်ကန်ပါ။

V576 ဖော်မတ်မမှန်ကန်ပါ။ 'scanf' လုပ်ဆောင်ချက်၏တတိယအမှန်တကယ်အငြင်းအခုံကိုစစ်ဆေးရန်စဉ်းစားပါ။ လက်မှတ်မထိုးထားသည့် int အမျိုးအစားအတွက် ညွှန်ပြချက်ကို မျှော်လင့်ထားသည်။ proxy.c ၂၂၀

V560 conditional expression ၏ အစိတ်အပိုင်းတစ်ခုသည် အမြဲမှန်သည်- (rc >= 0)။ proxy.c ၂၂၂

static BOOL check_no_proxy(....)
{
  ....
  int sub;
  int rc = sscanf(range, "%u", &sub);

  if ((rc == 1) && (rc >= 0))
  {
    ....
  }
  ....
}

ခွဲခြမ်းစိတ်ဖြာသူသည် ဤအပိုင်းအစအတွက် သတိပေးချက် ၂ ခုကို ချက်ချင်းထုတ်ပေးသည်။ သတ်မှတ်ချက် %u အမျိုးအစားကွဲပြားမှုကို မျှော်လင့်သည်။ လက်မှတ်မထိုး intဒါပေမယ့် ပြောင်းလဲနိုင်ပါတယ်။ ခွဲများ အမျိုးအစား ရှိသည်။ int. နောက်တစ်ခု ကျွန်ုပ်တို့သည် သံသယဖြစ်ဖွယ်စစ်ဆေးမှုတစ်ခုကို တွေ့ရသည်- ညာဘက်ရှိအခြေအနေသည် အဓိပ္ပာယ်မရှိပါ၊ အစတွင်တစ်ခုနှင့် နှိုင်းယှဉ်မှုတစ်ခုရှိသောကြောင့်ဖြစ်သည်။ ဤကုဒ်ရေးသားသူသည် ဘာကိုဆိုလိုသည်ကို ကျွန်ုပ်မသိသော်လည်း ဤနေရာတွင် တစ်ခုခုမှားနေပြီဖြစ်သည်။

ပြင်ပမှ စစ်ဆေးမှုများ

V547 ဖော်ပြချက် 'အခြေအနေ == 0x00090314' သည် အမြဲတမ်း လွဲမှားနေပါသည်။ ntlm.c ၂၉၉

BOOL ntlm_authenticate(rdpNtlm* ntlm, BOOL* pbContinueNeeded)
{
  ....
  if (status != SEC_E_OK)
  {
    ....
    return FALSE;
  }

  if (status == SEC_I_COMPLETE_NEEDED)            // <=
    status = SEC_E_OK;
  else if (status == SEC_I_COMPLETE_AND_CONTINUE) // <=
    status = SEC_I_CONTINUE_NEEDED;
  ....
}

စစ်ဆေးထားသော အခြေအနေများသည် အမြဲတမ်း မှားယွင်းနေမည်ဖြစ်ပြီး၊ လုပ်ဆောင်မှုသည် ဒုတိယအခြေအနေသို့သာ ရောက်ရှိမည်ဖြစ်သောကြောင့်၊ အခြေအနေ == SEC_E_OK. မှန်ကန်သောကုဒ်သည် ဤကဲ့သို့ဖြစ်နိုင်သည်-

if (status == SEC_I_COMPLETE_NEEDED)
  status = SEC_E_OK;
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
  status = SEC_I_CONTINUE_NEEDED;
else if (status != SEC_E_OK)
{
  ....
  return FALSE;
}

ကောက်ချက်

ထို့ကြောင့် ပရောဂျက်ကို စစ်ဆေးခြင်းဖြင့် ပြဿနာများစွာကို ထင်ရှားစေသော်လည်း ၎င်းတို့ထဲမှ စိတ်ဝင်စားစရာအကောင်းဆုံးအပိုင်းကိုသာ ဆောင်းပါးတွင် ဖော်ပြထားပါသည်။ ပရောဂျက် developer များသည် ဝဘ်ဆိုက်ရှိ ယာယီလိုင်စင်ကီးကို တောင်းဆိုခြင်းဖြင့် ပရောဂျက်ကို ကိုယ်တိုင်စစ်ဆေးနိုင်သည်။ PVS-Studio မှ. ခွဲခြမ်းစိတ်ဖြာသူကို ပိုမိုကောင်းမွန်အောင် လုပ်ဆောင်ပေးမည့် မှားယွင်းသော အပြုသဘောဆောင်မှုများလည်း ရှိခဲ့သည်။ သို့သော်၊ သင်သည် သင်၏ကုဒ်အရည်အသွေးကို တိုးတက်စေရုံသာမက အမှားအယွင်းများရှာဖွေသည့်အချိန်ကို လျှော့ချလိုပါက static analysis သည် အရေးကြီးပြီး ၎င်းကို PVS-Studio မှ ကူညီပေးနိုင်ပါသည်။

PVS-Studio ခွဲခြမ်းစိတ်ဖြာမှုကို အသုံးပြု၍ FreeRDP ကိုစစ်ဆေးခြင်း။

ဤဆောင်းပါးကို အင်္ဂလိပ်စကားပြောပရိသတ်နှင့် မျှဝေလိုပါက၊ ဘာသာပြန်လင့်ခ်- Sergey Larin ကို အသုံးပြုပါ။ PVS-Studio ဖြင့် FreeRDP ကိုစစ်ဆေးခြင်း။

source: www.habr.com

DDoS ကာကွယ်ရေး၊ VPS VDS ဆာဗာများပါသည့် ဆိုက်များအတွက် ယုံကြည်စိတ်ချရသော hosting ကို ဝယ်ယူပါ။ 🔥 DDoS ကာကွယ်မှု၊ VPS VDS ဆာဗာများပါရှိသော ယုံကြည်စိတ်ချရသော ဝဘ်ဆိုက် hosting ကို ဝယ်ယူပါ | ProHoster