
FreeRDP అనేది రిమోట్ కంప్యూటర్ నియంత్రణ కోసం మైక్రోసాఫ్ట్ అభివృద్ధి చేసిన రిమోట్ డెస్క్టాప్ ప్రోటోకాల్ (RDP) యొక్క ఓపెన్-సోర్స్ అమలు. ఈ ప్రాజెక్ట్ కింది వాటితో సహా బహుళ ప్లాట్ఫారమ్లకు మద్దతు ఇస్తుంది. Windows, Linux, macOS మరియు iOS తో కూడా AndroidPVS-Studio స్టాటిక్ అనలైజర్ను ఉపయోగించి RDP క్లయింట్లను పరీక్షించడానికి అంకితమైన వ్యాసాల శ్రేణిలో మొదటిదిగా ఈ ప్రాజెక్ట్ ఎంపిక చేయబడింది.
ఒక బిట్ చరిత్ర
ప్రాజెక్ట్ మైక్రోసాఫ్ట్ దాని యాజమాన్య RDP ప్రోటోకాల్ కోసం స్పెసిఫికేషన్లను తెరిచిన తర్వాత వచ్చింది. ఆ సమయంలో, ఒక rdesktop క్లయింట్ ఉంది, దీని అమలు రివర్స్ ఇంజనీరింగ్ ఫలితాలపై ఆధారపడి ఉంటుంది.
ప్రోటోకాల్ అమలు చేయబడినందున, అప్పటికి ఉన్న ప్రాజెక్ట్ ఆర్కిటెక్చర్ కారణంగా కొత్త కార్యాచరణను జోడించడం చాలా కష్టంగా మారింది. దానిలో మార్పులు డెవలపర్ల మధ్య సంఘర్షణకు దారితీశాయి, ఇది rdesktop - FreeRDP యొక్క ఫోర్క్ను రూపొందించడానికి దారితీసింది. ఉత్పత్తి యొక్క తదుపరి పంపిణీ GPLv2 లైసెన్స్ ద్వారా పరిమితం చేయబడింది, దీని ఫలితంగా Apache లైసెన్స్ v2కి మళ్లీ లైసెన్స్ ఇవ్వాలని నిర్ణయం తీసుకోబడింది. అయినప్పటికీ, ప్రతి ఒక్కరూ వారి కోడ్ యొక్క లైసెన్స్ను మార్చడానికి అంగీకరించలేదు, కాబట్టి డెవలపర్లు ప్రాజెక్ట్ను తిరిగి వ్రాయాలని నిర్ణయించుకున్నారు, ఫలితంగా ఆధునిక కోడ్బేస్ ఏర్పడింది.
మీరు అధికారిక బ్లాగ్ పోస్ట్లో ప్రాజెక్ట్ చరిత్ర గురించి మరింత చదువుకోవచ్చు: “The History of the FreeRDP ప్రాజెక్ట్”.
కోడ్లో లోపాలు మరియు సంభావ్య దుర్బలత్వాలను గుర్తించడానికి సాధనంగా ఉపయోగించబడుతుంది. ఇది C, C++, C# మరియు జావా కోసం ప్లాట్ఫారమ్లలో లభించే ఒక స్టాటిక్ కోడ్ అనలైజర్. Windows, Linux и macOS.
వ్యాసం నాకు చాలా ఆసక్తికరంగా అనిపించిన లోపాలను మాత్రమే అందిస్తుంది.
మెమరీ లీక్
'cwd' పాయింటర్ను విడుదల చేయకుండానే ఫంక్షన్ నిష్క్రమించబడింది. మెమరీ లీక్ సాధ్యమే. పర్యావరణం.సి 84
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 సబ్సిస్టమ్ నుండి తీసుకోబడింది, ఇది నాన్- కోసం WINAPI వ్రాపర్ను అమలు చేస్తుంది.Windows సిస్టమ్స్, అంటే, ఇది వైన్ యొక్క తేలికపాటి అనలాగ్. ఇక్కడ మీరు ఒక లీక్ను చూడవచ్చు: ఫంక్షన్ ద్వారా కేటాయించబడిన మెమరీ. getcwd, ప్రత్యేక కేసులను నిర్వహించినప్పుడు మాత్రమే విడుదల చేయబడుతుంది. లోపాన్ని పరిష్కరించడానికి మీరు కాల్ని జోడించాలి ఉచిత после మెమ్పిపి.
శ్రేణి హద్దులు దాటిపోయింది
అర్రే ఓవర్రన్ సాధ్యమే. '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 అర్రే ఓవర్రన్ సాధ్యమే. 'iBitmapFormat' సూచిక విలువ 8కి చేరవచ్చు. orders.c 2623
అక్షర దోషాలు
శకలం 1
వ్యక్తీకరణ '!pipe->In' ఎల్లప్పుడూ తప్పు. MessagePipe.c 63
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;
....
}ఇక్కడ మనం ఒక సాధారణ అక్షర దోషాన్ని చూస్తాము: రెండవ కండిషన్ మొదటిది అదే వేరియబుల్ని తనిఖీ చేస్తుంది. చాలా మటుకు, వైఫల్యం కోడ్ కాపీయింగ్ ఫలితంగా లోపం కనిపించింది.
శకలం 2
ఒకే రకమైన వచనం యొక్క రెండు బ్లాక్లు కనుగొనబడ్డాయి. రెండవ బ్లాక్ లైన్ 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);
....
}మరొక అక్షర దోషం: కోడ్ వ్యాఖ్య థ్రెడ్ రావాలని సూచిస్తుంది చిన్న వెర్షన్, అయితే, పఠనం అనే వేరియబుల్గా ఏర్పడుతుంది ప్రధాన వెర్షన్. అయితే, నాకు ప్రోటోకాల్ గురించి తెలియదు, కాబట్టి ఇది కేవలం ఊహ మాత్రమే.
శకలం 3
'trio_index_last' ఫంక్షన్ యొక్క శరీరం పూర్తిగా 'trio_index' ఫంక్షన్ యొక్క శరీరానికి సమానం కావడం విచిత్రం. triostr.c 933
/**
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);
}వ్యాఖ్య, ఫంక్షన్ ద్వారా నిర్ణయించడం త్రయం_సూచిక ఎప్పుడు అనే స్ట్రింగ్లో మొదటి అక్షరం సరిపోలికను కనుగొంటుంది త్రయం_సూచిక_చివరి - చివరి విషయం. కానీ ఈ ఫంక్షన్ల శరీరాలు ఒకేలా ఉంటాయి! చాలా మటుకు ఇది అక్షర దోషం, మరియు ఫంక్షన్లో త్రయం_సూచిక_చివరి ఉపయోగించాలి strchr బదులుగా strchr. అప్పుడు ప్రవర్తన అంచనా వేయబడుతుంది.
శకలం 4
వ్యక్తీకరణలోని 'డేటా' పాయింటర్ nullptrకి సమానం. ఈ పాయింటర్లోని అంకగణిత ఆపరేషన్ల ఫలితంగా వచ్చే విలువ అర్ధంలేనిది మరియు దీనిని ఉపయోగించకూడదు. nsc_encode.c 124
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;
....
}ప్రతికూల ఆపరేటర్ అనుకోకుండా ఇక్కడ తప్పిపోయినట్లు కనిపిస్తోంది ! పక్కన సమాచారం. ఇది గమనించక పోవడం విచిత్రం.
శకలం 5
'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
ఇన్పుట్ డేటా యొక్క ధృవీకరణ
శకలం 1
వ్యక్తీకరణ 'strcat(టార్గెట్, సోర్స్) != NULL' ఎల్లప్పుడూ నిజం. triostr.c 425
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 అది dereference చేయబడుతుంది.
శకలం 2
వ్యక్తీకరణ 'కాష్' ఎల్లప్పుడూ నిజం. glyph.c 730
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)
{
....
}
....
}ఈ సందర్భంలో వేరియబుల్ కాష్ స్టాటిక్ అర్రే యొక్క చిరునామా కేటాయించబడింది glyphCache->glyphCache. అందువలన, తనిఖీ చేయండి ఉంటే (కాష్) విస్మరించవచ్చు.
వనరుల నిర్వహణ లోపం
వనరు 'CreateFileA' ఫంక్షన్ని ఉపయోగించి పొందబడింది కానీ అననుకూలమైన 'fclose' ఫంక్షన్ని ఉపయోగించి విడుదల చేయబడింది. certificate.c 447
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 ప్రామాణిక లైబ్రరీ నుండి కాదు క్లోజ్హ్యాండిల్.
అవే పరిస్థితులు
ఒకదానికొకటి పక్కన ఉన్న '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);
}
....
}ఈ ఉదాహరణ బగ్ కాకపోవచ్చు. అయినప్పటికీ, రెండు షరతులు ఒకే సందేశాలను కలిగి ఉంటాయి, వాటిలో ఒకటి తొలగించబడవచ్చు.
శూన్య పాయింటర్లను శుభ్రపరచడం
శూన్య పాయింటర్ 'ఉచిత' ఫంక్షన్లోకి పంపబడుతుంది. మొదటి వాదనను పరిశీలించండి. smartcard_pcsc.c 875
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);
....
}పనిచేయడానికి ఉచిత మీరు శూన్య పాయింటర్ను పాస్ చేయవచ్చు మరియు దాని గురించి ఎనలైజర్కు తెలుసు. కానీ ఈ స్నిప్పెట్లో వలె పాయింటర్ ఎల్లప్పుడూ శూన్యంగా పాస్ అయ్యే పరిస్థితిని గుర్తించినట్లయితే, హెచ్చరిక జారీ చేయబడుతుంది.
పాయింటర్ mszGroupsA ప్రారంభంలో సమానం NULL మరియు మరెక్కడా ప్రారంభించబడలేదు. పాయింటర్ను ప్రారంభించగల ఏకైక కోడ్ బ్రాంచ్ అందుబాటులో లేదు.
ఇలాంటి ఇతర సందేశాలు ఉన్నాయి:
- V575 శూన్య పాయింటర్ 'ఉచిత' ఫంక్షన్లోకి పంపబడింది. మొదటి వాదనను పరిశీలించండి. లైసెన్స్.సి 790
- V575 శూన్య పాయింటర్ 'ఉచిత' ఫంక్షన్లోకి పంపబడింది. మొదటి వాదనను పరిశీలించండి. rdpsnd_alsa.c 575
చాలా మటుకు, అటువంటి మరచిపోయిన వేరియబుల్స్ రీఫ్యాక్టరింగ్ ప్రక్రియలో ఉత్పన్నమవుతాయి మరియు వాటిని తీసివేయవచ్చు.
సాధ్యం ఓవర్ఫ్లో
సాధ్యం ఓవర్ఫ్లో. కాస్టింగ్ ఆపరాండ్లను పరిగణించండి, ఫలితం కాదు. makecert.c 1087
// 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));
....
}ఫలితాన్ని తీసుకురావడం దీర్ఘ ఓవర్ఫ్లో ప్రొటెక్షన్ కాదు, ఎందుకంటే గణన కూడా రకాన్ని ఉపయోగించి జరుగుతుంది పూర్ణాంకానికి.
ప్రారంభించడంలో పాయింటర్ డిరిఫరెన్స్
nullptrకి వ్యతిరేకంగా ధృవీకరించబడటానికి ముందు 'సందర్భం' పాయింటర్ ఉపయోగించబడింది. చెక్ లైన్లు: 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 'ntlm' పాయింటర్ nullptrకి వ్యతిరేకంగా ధృవీకరించబడటానికి ముందు ఉపయోగించబడింది. చెక్ లైన్లు: 236, 255. ntlm.c 236
- V595 'సందర్భం' పాయింటర్ nullptrకి వ్యతిరేకంగా ధృవీకరించబడటానికి ముందు ఉపయోగించబడింది. చెక్ లైన్లు: 1003, 1007. rfx.c 1003
- V595 'rdpei' పాయింటర్ nullptrకి వ్యతిరేకంగా ధృవీకరించబడటానికి ముందు ఉపయోగించబడింది. చెక్ లైన్లు: 176, 180. rdpei_main.c 176
- V595 'gdi' పాయింటర్ nullptrకి వ్యతిరేకంగా ధృవీకరించబడటానికి ముందు ఉపయోగించబడింది. చెక్ లైన్లు: 121, 123. xf_gfx.c 121
అర్థంకాని పరిస్థితి
వ్యక్తీకరణ 'rdp->state >= CONNECTION_STATE_ACTIVE' ఎల్లప్పుడూ నిజం. connection.c 1489
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;
}
....
}
....
}ముందుగా కేటాయించిన సంబంధిత విలువ కారణంగా మొదటి షరతు అర్థరహితంగా ఉందని చూడటం సులభం.
తప్పు స్ట్రింగ్ పార్సింగ్
తప్పు ఆకృతి. 'sscanf' ఫంక్షన్ యొక్క మూడవ వాస్తవ వాదనను తనిఖీ చేయడాన్ని పరిగణించండి. సంతకం చేయని పూర్ణ రకానికి పాయింటర్ ఆశించబడుతుంది. proxy.c 220
షరతులతో కూడిన వ్యక్తీకరణలో కొంత భాగం ఎల్లప్పుడూ నిజం: (rc >= 0). proxy.c 222
static BOOL check_no_proxy(....)
{
....
int sub;
int rc = sscanf(range, "%u", &sub);
if ((rc == 1) && (rc >= 0))
{
....
}
....
}ఎనలైజర్ వెంటనే ఈ భాగానికి 2 హెచ్చరికలను జారీ చేస్తుంది. స్పెసిఫైయర్ %u రకం యొక్క వేరియబుల్ను ఆశిస్తుంది సంతకం చేయని పూర్ణాంకానికి, కానీ వేరియబుల్ ఉప రకం ఉంది పూర్ణాంకానికి. తరువాత మనం అనుమానాస్పద తనిఖీని చూస్తాము: కుడి వైపున ఉన్న పరిస్థితి అర్ధవంతం కాదు, ఎందుకంటే ప్రారంభంలో ఒకదానితో పోలిక ఉంది. ఈ కోడ్ యొక్క రచయిత అర్థం ఏమిటో నాకు తెలియదు, కానీ ఇక్కడ ఏదో స్పష్టంగా తప్పు ఉంది.
అవుట్-ఆఫ్-ఆర్డర్ తనిఖీలు
'స్థితి == 0x00090314' అనే వ్యక్తీకరణ ఎల్లప్పుడూ తప్పు. ntlm.c 299
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;
}తీర్మానం
అందువలన, ప్రాజెక్ట్ను తనిఖీ చేయడం అనేక సమస్యలను వెల్లడించింది, కానీ వాటిలో అత్యంత ఆసక్తికరమైన భాగం మాత్రమే వ్యాసంలో వివరించబడింది. ప్రాజెక్ట్ డెవలపర్లు వెబ్సైట్లో తాత్కాలిక లైసెన్స్ కీని అభ్యర్థించడం ద్వారా ప్రాజెక్ట్ను స్వయంగా తనిఖీ చేయవచ్చు . తప్పుడు పాజిటివ్లు కూడా ఉన్నాయి, ఎనలైజర్ను మెరుగుపరచడంలో సహాయపడే పని. అయితే, మీరు మీ కోడ్ నాణ్యతను మెరుగుపరచడమే కాకుండా, లోపాలను కనుగొనడంలో గడిపిన సమయాన్ని తగ్గించాలనుకుంటే స్టాటిక్ విశ్లేషణ ముఖ్యం మరియు PVS-Studio దీనికి సహాయపడుతుంది.
మీరు ఈ కథనాన్ని ఇంగ్లీష్ మాట్లాడే ప్రేక్షకులతో పంచుకోవాలనుకుంటే, దయచేసి అనువాద లింక్ని ఉపయోగించండి: సెర్గీ లారిన్.
మూలం: www.habr.com
