Porting is a Delicate Matter: Checking Far Manager under Linux

About Far Manager

Figure 1 — Far Manager 2 on Windows (click to enlarge)
Figure 2 — Far Manager 2 on Linux (click to enlarge)

Enough talking

Analysis results

Copy-Paste

int KeyMacro::GetKey()
{
....
DWORD Key = !MR ? MCODE_OP_EXIT : GetOpCode(MR, Work.ExecLIBPos++);
....
switch (Key)
{
....
case MCODE_F_BM_POP:
{
TVar p1, p2;
if (Key == MCODE_F_BM_GET)
VMStack.Pop(p2);
if ( Key == MCODE_F_BM_GET // <=
|| Key == MCODE_F_BM_DEL
|| Key == MCODE_F_BM_GET // <=
|| Key == MCODE_F_BM_GOTO)
{
VMStack.Pop(p1);
}
....
}
}
}
  • V501 There are identical sub-expressions ‘!StrCmpN(CurStr, L”!/”, 2)’ to the left and to the right of the ‘||’ operator. fnparce.cpp 291
  • V501 There are identical sub-expressions ‘!StrCmpN(CurStr, L”!=/”, 3)’ to the left and to the right of the ‘||’ operator. fnparce.cpp 291
  • V501 There are identical sub-expressions ‘KEY_RCTRL’ to the left and to the right of the ‘|’ operator. keyboard.cpp 1830
static BOOL WINPORT(GetStringType)( DWORD type,
LPCWSTR src,
INT count,
LPWORD chartype )
{
....
while (count--)
{
int c = *src;
WORD type1, type3 = 0; /* C3_NOTAPPLICABLE */
....
if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH; // <=
if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_SYMBOL; // <=
....
}
....
}
....
if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH | C3_SYMBOL;
....
  • V581 The conditional expressions of the ‘if’ operators situated alongside each other are identical. Check lines: 272, 273. APIStringMap.cpp 273
  • V581 The conditional expressions of the ‘if’ operators situated alongside each other are identical. Check lines: 274, 275. APIStringMap.cpp 275
  • V581 The conditional expressions of the ‘if’ operators situated alongside each other are identical. Check lines: 6498, 6503. macro.cpp 6503
  • V581 The conditional expressions of the ‘if’ operators situated alongside each other are identical. Check lines: 1800, 1810. vmenu.cpp 1810
  • V581 The conditional expressions of the ‘if’ operators situated alongside each other are identical. Check lines: 3353, 3355. wrap.cpp:3355
void FTP::AddToQueque(FAR_FIND_DATA* FileName, 
LPCSTR Path,
BOOL Download)
{
....
char *m;
....
if(Download)
m = strrchr(FileName->cFileName, '/'); // <=
else
m = strrchr(FileName->cFileName, '/'); // <=
....
}

Undefined behavior

int Dialog::Do_ProcessSpace()
{
....
if (Item[FocusPos]->Flags & DIF_3STATE)
(++Item[FocusPos]->Selected) %= 3; // <=
else
Item[FocusPos]->Selected = !Item[FocusPos]->Selected;
....
}
  • V567 Undefined behavior. The ‘::ViewerID’ variable is modified while being used twice between sequence points. viewer.cpp 117
#define rechar wchar_t
#define RE_CHAR_COUNT (1 << sizeof(rechar) * 8)
int RegExp::Optimize()
{
....
for (op=code; ; op=op->next)
{
switch (OP.op)
{
....
case opType:
{
for (int i = 0; i < RE_CHAR_COUNT; i++) // <=
{
if (ISTYPE(i, OP.type))
{
first[i]=1;
}
}

break;
}
}
....
}
....
}
#define rechar wchar_t
#define RE_CHAR_COUNT (static_cast<int64_t>(1) << sizeof(rechar) * 8)
int RegExp::Optimize()
{
....
for (int64_t i = 0; i < RE_CHAR_COUNT; i++)
{
....
}
....
}
  • V610 Undefined behavior. Check the shift operator ‘<<’. The right operand ‘sizeof (wchar_t) * 8’ is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4473
  • V610 Undefined behavior. Check the shift operator ‘<<’. The right operand ‘sizeof (wchar_t) * 8’ is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4490
  • V610 Undefined behavior. Check the shift operator ‘<<’. The right operand ‘sizeof (wchar_t) * 8’ is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4537
  • V610 Undefined behavior. Check the shift operator ‘<<’. The right operand ‘sizeof (wchar_t) * 8’ is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4549
  • V610 Undefined behavior. Check the shift operator ‘<<’. The right operand ‘sizeof (wchar_t) * 8’ is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4561

Incorrect memory handling

class UnicodeString
{
....
UnicodeString(const wchar_t *lpwszData)
{
SetEUS();
Copy(lpwszData);
}
....
const wchar_t *CPtr() const { return m_pData->GetData(); }
operator const wchar_t *() const { return m_pData->GetData(); }
....
}
typedef UnicodeString FARString;struct TreeItem
{
FARString strName;
....
}
TreeItem **ListData;void TreeList::SetTitle()
{
....
if (GetFocus())
{
FARString strTitleDir(L"{");
const wchar_t *Ptr = ListData
? ListData[CurFile]->strName
: L"";
....
}
....
}
....
const wchar_t *Ptr = ListData
? ListData[CurFile]->strName.CPtr()
: L"";
....
  • V779 Unreachable code detected. It is possible that an error is present. 7z.cpp 203
  • V773 The function was exited without releasing the ‘t’ pointer. A memory leak is possible. 7z.cpp 202
BOOL WINAPI _export SEVENZ_OpenArchive(const char *Name,
int *Type)
{
Traverser *t = new Traverser(Name);
if (!t->Valid())
{
return FALSE;
delete t;
}

delete s_selected_traverser;
s_selected_traverser = t;
return TRUE;
}
  • V568 It’s odd that ‘sizeof()’ operator evaluates the size of a pointer to a class, but not the size of the ‘PInfo’ class object. filelist.cpp 672
  • V568 It’s odd that ‘sizeof()’ operator evaluates the size of a pointer to a class, but not the size of the ‘PInfo’ class object. filelist.cpp 673
int64_t FileList::VMProcess(int OpCode,
void *vParam,
int64_t iParam)
{
switch (OpCode)
{
....
case MCODE_V_PPANEL_PREFIX: // PPanel.Prefix
{
PluginInfo *PInfo = (PluginInfo *)vParam;
memset(PInfo, 0, sizeof(PInfo)); // <=
PInfo->StructSize = sizeof(PInfo); // <=
....
}
....
}
}
....
PluginInfo *PInfo = (PluginInfo*)vParam;
memset(PInfo, 0, sizeof(*PInfo));
PInfo->StructSize = sizeof(*PInfo);
....
  • V568 It’s odd that ‘sizeof()’ operator evaluates the size of a pointer to a class, but not the size of the ‘HistoryItem’ class object. history.cpp 594
  • V568 It’s odd that ‘sizeof()’ operator evaluates the size of a pointer to a class, but not the size of the ‘handle’ class object. plugins.cpp 682

Strange conditions

int FTP::ProcessKey(int Key, unsigned int ControlState)
{
....
if( !ShowHosts
&& (ControlState == 0 || ControlState == PKF_SHIFT)
&& Key == VK_F6)
{
FTP *ftp = OtherPlugin(this);
int rc;
if( !ftp
&& ControlState == 0
&& Key == VK_F6)
{
return FALSE;
}
....
}
....
}
....
if( !ftp
&& ControlState == 0)
{
return FALSE;
}
....
  • V560 A part of conditional expression is always true: !cps. DString.cpp 47
  • V560 A part of conditional expression is always true: !ShowHosts. FGet.cpp 139
  • V560 A part of conditional expression is always false: !wsz. cnDownload.cpp 190
  • V560 A part of conditional expression is always true: !UserReject. extract.cpp 485
  • And 8 additional diagnostic messages.
char *WINAPI StrCpy(char *dest, LPCSTR src, int dest_sz)
{
if(dest <= 0) // <=
return NULL;
....
}
....
if(dest == nullptr)
return NULL;
....
enum FINDASKDLGCOMBO
{
FADC_ALLDISKS,
FADC_ALLBUTNET,
....
};
FindFiles::FindFiles()
{

....
if ( FADC_ALLDISKS + SearchMode == FADC_ALLDISKS // <=
|| FADC_ALLDISKS + SearchMode == FADC_ALLBUTNET)
{
....
}
....
}
if (   0 + SearchMode == 0
|| 0 + SearchMode == 1)
{
....
}
if (   SearchMode == FADC_ALLDISKS
|| SearchMode == FADC_ALLBUTNET)
{
....
}

Incorrect format string handling

void FarEditor::showOutliner(Outliner *outliner)
{
....
wchar_t cls =
Character::toLowerCase((*region)[region->indexOf(':') + 1]);

si += swprintf(menuItem+si, 255-si, L"%c ", cls); // <=
....
}
si += swprintf(menuItem+si, 255-si, L"%lc ", cls);
void CommandData::ReadConfig()
{
....
wchar Cmd[16];
....
wchar SwName[16+ASIZE(Cmd)];
swprintf(SwName,ASIZE(SwName), L"switches_%s=",Cmd); // <=
....
}
swprintf(SwName,ASIZE(SwName), L"switches_%ls=",Cmd);
  • V576 Incorrect format. Consider checking the third actual argument of the ‘fprintf’ function. The char type argument is expected. vtansi.cpp 1033
  • V576 Incorrect format. Consider checking the third actual argument of the ‘fprintf’ function. The char type argument is expected. vtansi.cpp 1038

Conclusion

--

--

--

The developer, the debugger, the unicorn. I know all about static analysis and how to find bugs and errors in C, C++, C#, and Java source code.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to implement autocomplete with Search-As-You-Type  —  Elastic Search

Introducing Masterbrick

How to Install Kali Linux 2.0 on a Rooted Android Smartphone (Offline Method)

loadtest: an R Package for Load Testing

My first iOSapp

How Much Free Space Must Be Remained in Your Computer Drive?

How to Remove EXIF Data from an Image in Go

Visure Solutions

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Unicorn Developer

Unicorn Developer

The developer, the debugger, the unicorn. I know all about static analysis and how to find bugs and errors in C, C++, C#, and Java source code.

More from Medium

MuditaOS: Will your alarm clock go off? Part I

Code with C

Static Library in C Programming

A Byte of Coding Issue #219