﻿# Debugging bugs in x64dbg debugger\. No debugger

We can't develop programs without debugging\. Modern IDEs have a built\-in debugger, but there are cases when using IDE for debugging is superfluous or impossible\. So, standalone debuggers come to the rescue\. One of such debuggers is x64dbg\.

![1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image1.png](https://import.viva64.com/docx/blog/1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image1.png)

## Introduction

[x64dbg](https://x64dbg.com/) is an open\-source debugger for 32\-bit and 64\-bit versions of Windows\. It provides an "intuitive and familiar, yet new user interface"\. It looks similar to [OllyDbg](https://www.ollydbg.de/) but with a little bit better interface and enhanced functionality\.

![1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image2.png](https://import.viva64.com/docx/blog/1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image2.png)

The debugger doesn't have regular releases\. Instead, developers release snapshot builds about [once a month](https://sourceforge.net/projects/x64dbg/files/snapshots/)\. The [cross\-platform version](https://github.com/x64dbg/x64dbg/tree/cross-platform) is being developed in parallel\.

When a developer needs a standalone debugger? For example, Visual Studio 2022 builds executables with Windows Vista support by default\. However, we can't install it on Windows Vista and use remote debugging because Vista is [unsupported OS](https://learn.microsoft.com/en-us/visualstudio/debugger/remote-debugging?view=vs-2022#supported-operating-systems)—we need at least Windows 7\.

In general, developers use a standalone debugger to analyze executables whose source code and debug symbols are not accessible\. Antivirus labs define the malware algorithm to describe it in their knowledge base and then add its definition to AV databases\. Various communities for reviving old\-school online games or programs don't keep their hands off the debugger that helps resurrect their servers\. And not just the old ones—[server emulators](https://pvs-studio.com/en/blog/posts/csharp/1118/) are released even for recent online games\. So, how well made is a "Swiss army knife" for reverse\-engineering? So, it's time to run the PVS\-Studio analyzer\.

## PVS\-Studio installation

You can download PVS\-Studio [here](https://pvs-studio.com/en/pvs-studio/download/)\. To analyze the project, you'll need a license\. Here you can get a [trial version](https://pvs-studio.com/en/pvs-studio/try-free/)\. The PVS\-Studio has a user\-friendly installation interface: each step is explained, and if you have any difficulties, the guide for a quick start on [Windows](https://pvs-studio.com/en/pvs-studio-quickstart-cppwindows/) is always at your service\. We need two additional IDE integrations: for Qt Creator \(the installer will extract it in the PVS\-Studio folder\) and for Visual Studio\. The current version of the analyzer at the moment of writing the article is 7\.31\.

## Build and analysis configuration

The debugger consists of two components: the core and the GUI\. The first component is built in Visual Studio, and the second is in Qt Creator\. The project's wiki has a guide on [how to compile a project](https://github.com/x64dbg/x64dbg/wiki/Compiling-the-whole-project), and the author strongly recommends using certain versions of dependencies\. In this part of the article, we'll analyze the debugger core\. The code matches the [f518e50](https://github.com/x64dbg/x64dbg/tree/f518e507c24a04d9c82161ef1e89a7a70a73c0f2) commit in the _development_ branch\.

## Analysis of detected errors

Let's open the _x64dbg\.sln_ solution file and exclude third\-party libraries from the check\. This would help us not to drown in the noise of the x64dbg\-unreleated code warnings\. These libraries are listed in the _Third Party_ filter of the _x64dbg\_dbg_ project in the header file section:

```cpp
\dbghelp\
\DeviceNameResolver\
\jansson\
\LLVMDemangle\
\lz4\
\msdia\
\ntdll\
\TitanEngine\
\WinInet-Downloader\
\XEDParse\
```

Now, let's exclude the folders from the analysis in the Visual Studio plugin settings: **Extensions \> PVS\-Studio \> Options \> Don't Check Files**\. Alternative ways to manage the list of excluded paths are described in our [documentation](https://pvs-studio.com/en/docs/manual/6640/)\.

Shake your insecticide spray and let's get rid of the debugger bugs\! No debugger, as promised\.

### No time to explain, overwrite it\!

[V570](https://pvs-studio.com/en/docs/warnings/v570/) The 'mLastChar' variable is assigned to itself\. [lexer\.cpp 149](https://github.com/x64dbg/btparser/blob/200221b4151b614017c9564709452e795b3c6c82/btparser/lexer.cpp#L149)

```cpp
class Lexer
{
....
private:
  ....
  int mLastChar = ' ';
  ....
....
}

Lexer::Token Lexer::getToken()
{
  ....
  //character literal
  if(mLastChar == '\'')
  {
    std::string charLit;
    while(true)
    {
      ....
      if(mLastChar == '\\') //escape sequence
      {
        nextChar();
        if(mLastChar == EOF)
          return reportError("unexpected end of file in character literal (2)");
        if(mLastChar == '\r' || mLastChar == '\n')
          return reportError("unexpected newline in character literal (2)");
        if(   mLastChar == '\'' || mLastChar == '\"'
           || mLastChar == '?' || mLastChar == '\\')
          mLastChar = mLastChar;                                   // <=
        else if(mLastChar == 'a')
          mLastChar = '\a';
        ....
      }
      ....
    }
    ....
  }
}
```

This function escapes certain characters: newlines, backslashes, quotation marks, and other control characters\. The _mLastChar_ variable is a member of the _Lexer_ class and contains the last read literal\. The [_nextChar_](https://github.com/x64dbg/btparser/blob/200221b4151b614017c9564709452e795b3c6c82/btparser/lexer.cpp#L379) function reads the next character and writes it to _mLastChar_\. If the _mLastChar_ value updates it via calling, why should we reassign the same value? Here's a similar warning:

* [V570](https://pvs-studio.com/en/docs/warnings/v570/) The 'mLastChar' variable is assigned to itself\. [lexer\.cpp 215](https://github.com/x64dbg/btparser/blob/200221b4151b614017c9564709452e795b3c6c82/btparser/lexer.cpp#L215)

### What if?

[V547](https://pvs-studio.com/en/docs/warnings/v547/) Expression '\!expr' is always true\. [parser\.cpp 118](https://github.com/x64dbg/btparser/blob/200221b4151b614017c9564709452e795b3c6c82/btparser/parser.cpp#L118)

```cpp
uptr<Expr> Parser::ParseExpr()
{
  return nullptr;
}

uptr<Return> Parser::ParseReturn()
{
  if(CurToken.Token == Lexer::tok_return)
  {
    NextToken();
    auto expr = ParseExpr();
    if(!expr)                              // <=
    {
      ReportError("failed to parse Return (ParseExpr failed)");
      return nullptr;
    }
    return make_uptr<Return>(move(expr));
  }
  return nullptr;
}
```

What is the chance that something can come from nothing? Is the medieval superstition that mice grow out from sweaty shirts true? Science has proven that it is not\. Obtaining other data from _nullptr_ is also unfeasible\.

I'll also give here the definition of the _uptr_ class, which is actually the common [std::unique\_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr):

```cpp
template<class T>
using uptr = unique_ptr<T>;
```

### What if not?

[V560](https://pvs-studio.com/en/docs/warnings/v560/) A part of conditional expression is always false: \!haveCurrValue\. [watch\.cpp 61](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/watch.cpp#L61)

```cpp
....
currValue = val;
haveCurrValue = true;
if(getType() != WATCHVARTYPE::TYPE_INVALID)
{
  switch(getWatchdogMode())
  {
  ....
  case WATCHDOGMODE::MODE_CHANGED:
    if(currValue != origVal || !haveCurrValue)         // <=
    {
      duint cip = GetContextDataEx(hActiveThread, UE_CIP);
      dprintf(....);
      watchdogTriggered = 1;
    }
    break;
  case WATCHDOGMODE::MODE_UNCHANGED:
    if(currValue == origVal || !haveCurrValue)         // <=
    {
      duint cip = GetContextDataEx(hActiveThread, UE_CIP);
      dprintf(....);
      watchdogTriggered = 1;
    }
    break;
  }
}
return val;
....
```

At least we have a case of copy\-paste\-oriented programming, at most, we have a case when the _haveCurrValue_ variable is never modified before the end of the switch statement\.

Here's a similar warning:

* [V560](https://pvs-studio.com/en/docs/warnings/v560/) A part of conditional expression is always false: \!haveCurrValue\. [watch\.cpp 69](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/watch.cpp#L69)

### Huge ambitions of tiny lambda

[V783](https://pvs-studio.com/en/docs/warnings/v783/) Dereferencing of the invalid iterator might take place\. [LinearPass\.cpp 130](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/analysis/LinearPass.cpp#L130)

```cpp
void LinearPass::AnalyseOverlaps()
{
  ....
  // Erase blocks marked for deletion
  m_MainBlocks.erase(std::remove_if(
    m_MainBlocks.begin(), m_MainBlocks.end(), [](BasicBlock & Elem)
    {
      return Elem.GetFlag(BASIC_BLOCK_FLAG_DELETE);
    }));
  ....
}
```

Developers often use the [erase\-remove idiom](https://en.wikipedia.org/wiki/Erase–remove_idiom) to eliminate data from an array\. Its essence is as follows: the _std::remove_ function selects the array elements and moves them to the end\. Then the function will return the iterator from which the _std::erase_ function will start removing the moved elements\. The code author has thought that this call will delete all elements with the _erase_ flag—that's what the comment above the _m\_MainBlocks\.erase_ call hints at\.

This code has two issues:

1. If there are no elements in the array with the flag, the _std::remove_ function will return an iterator to _end\(\)_, which we can't pass to the _std::erase_ function\! The point is that although the _end\(\)_ iterator is valid, it can't be dereferenced\.
1. Overloading _std::erase_ with one parameter not only doesn't accept the _end\(\)_ iterator, but it also removes only one value\! This directly contradicts the comment above\. If the x64dbg developers had written the code using C\+\+20 specifications, it'd have been better to use _std::erase\_if_ to avoid such an issue\. However, at the time of Visual C\+\+ 2013, the C\+\+11 specification was still a novelty\.

Let's try to fix both issues at once: we'll use the second _std::erase_ function overload, which accepts iterators to the beginning and the end of the sub\-array to delete\.

```cpp
m_MainBlocks.erase(std::remove_if(
  m_MainBlocks.begin(), m_MainBlocks.end(), [](BasicBlock & Elem)
  {
      return Elem.GetFlag(BASIC_BLOCK_FLAG_DELETE);
  }), m_MainBlocks.end());
```

Thus, we've fixed the erasing of only one element, and at the same time, we protected against an erasing an empty list\. The documentation clearly states that nothing will be executed in this case\.

### 1\-minute maths

[V560](https://pvs-studio.com/en/docs/warnings/v560/) A part of conditional expression is always true: addr < \_base \+ \_size\. [cmd\-undocumented\.cpp 382](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/commands/cmd-undocumented.cpp#L382)

```cpp
bool cbInstrVisualize(int argc, char* argv[])
{
  if(IsArgumentsLessThan(argc, 3))
    return false;
  duint start;
  duint maxaddr;
  ....
  {
    ....
    //initialize
    Zydis zydis;
    duint _base = start;
    duint _size = maxaddr - start;
    Memory<unsigned char*> _data(_size);
    MemRead(_base, _data(), _size);
    for(duint addr = start, fardest = 0; addr < maxaddr;)
    {
      ....
      //continue algorithm
      const unsigned char* curData =
        (addr >= _base && addr < _base + _size)         // <=
          ? _data() + (addr - _base)
          : nullptr;
      if(zydis.Disassemble(addr, curData, MAX_DISASM_BUFFER))
      {
        if(addr + zydis.Size() > maxaddr)
          break; //we went past the maximum allowed address
        ....
      }
      ....
    }
    ....
  }
  ....
}
```

The _\_base_ variable is assigned the _start_ variable value\. This means that the check for the maximum allowed address has already been in the loop condition \(_addr < maxaddr_\) and doesn't make sense in the ternary operator when we initialize the _curData_ variable\. It's clear that nothing is clear\. Now watch this:

* the loop condition is _addr < maxaddr_;
* the ternary operator condition is _addr < \_base \+ \_size_;
* the _\_size_ variable value is: _maxaddr – start_;
* the _\_base_ variable is assigned the _start_ variable value\.

To get _maxaddr_, let's add _\_size_ up to _start_\. Using some simple math, we get the following expression:

```cpp
maxaddr = start + _size
```

Thus, we understand that the _addr < maxaddr_ loop condition is identical to the _addr < \_base \+ \_size_ condition inside the loop\. It turns out to be the same thing but in a more "complete" form\. 

### "Copied right"

[V1053](https://pvs-studio.com/en/docs/warnings/v1053/) Calling the 'AddRef' virtual function in the constructor may lead to unexpected result at runtime\. [pdbdiafile\.cpp 23](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/pdbdiafile.cpp#L23)

```cpp
//Taken from: https://msdn.microsoft.com/en-us/library/ms752876(v=vs.85).aspx
class FileStream : public IStream
{
  FileStream(HANDLE hFile)
  {
    AddRef();                         // <=
    _hFile = hFile;
  }

....
public:
  virtual ULONG STDMETHODCALLTYPE AddRef(void)
  {
    return (ULONG)InterlockedIncrement(&_refcount);
  }
....
}
```

I see the phrase "Taken from", look at the sample code from Microsoft Learn, and notice that a developer just uses the _\_refcount_ variable instead of calling the _AddRef_ function:

```cpp
class FileStream : public IStream  
{
  FileStream(HANDLE hFile)   
  {
    _refcount = 1;  
    _hFile = hFile;  
  }
....
}
```

What can the virtual function call in constructors or destructors lead to? It's fraught with that [there](https://pvs-studio.com/en/blog/posts/cpp/0891/) may be errors in their invocation in inherited classes\. Yes, it is "copied right", but developers could call the [_InterlockedIncrement_](https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedincrement) function with the reference to _\_refcount_ right away? It's even part of the system API\!

### Bloating code for dummies

[V547](https://pvs-studio.com/en/docs/warnings/v547/) Expression '\!bRedirectSupported' is always true\. [x64dbg\_launcher\.cpp 76](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/launcher/x64dbg_launcher.cpp#L76)

```cpp
static BOOL isWowRedirectionSupported()
{
  BOOL bRedirectSupported = FALSE;

  _Wow64DisableRedirection = (LPFN_Wow64DisableWow64FsRedirection)
    GetProcAddress(GetModuleHandle(TEXT("kernel32")),
                   "Wow64DisableWow64FsRedirection");
  _Wow64RevertRedirection = (LPFN_Wow64RevertWow64FsRedirection)
    GetProcAddress(GetModuleHandle(TEXT("kernel32")),
                   "Wow64RevertWow64FsRedirection");

  if(!_Wow64DisableRedirection || !_Wow64RevertRedirection)
    return bRedirectSupported;
  else
    return !bRedirectSupported;     // <=
}
```

At first glance, the warning seems completely illogical\. I looked at these lines for a long time, even had to take eye drops\. I've already seen [the abuse of memory in strings](https://pvs-studio.com/en/blog/posts/cpp/1122/#IDC99E53BA04), but that\.\.\. That's a victim of a dentist with a slightly unconventional approach to pulling out a bad tooth\. Well, let's leave frightening metaphors aside, we have a great reason to refactor here\! The static analyzer [will serve us well](https://pvs-studio.com/en/blog/posts/cpp/1115/) here\.

The [_GetProcAddress_](https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress) function returns the address of the exported function via its name, via its ordinal value from the module, or _NULL_ if the requested function hasn't been located\. You don't need another variable here at all to return the result of checking [file system redirection support](https://learn.microsoft.com/en-us/windows/win32/winprog64/file-system-redirector) for the _WoW64_ subsystem\. If we miss one of the functions, the default _FALSE_ is returned\. Therefore, the entire function can be reduced to literally three operations:

```cpp
static BOOL isWowRedirectionSupported()
{
  _Wow64DisableRedirection = (LPFN_Wow64DisableWow64FsRedirection)
    GetProcAddress(GetModuleHandle(TEXT("kernel32")),
                  "Wow64DisableWow64FsRedirection");
  _Wow64RevertRedirection = (LPFN_Wow64RevertWow64FsRedirection)
    GetProcAddress(GetModuleHandle(TEXT("kernel32")),
                  "Wow64RevertWow64FsRedirection");

  return !_Wow64DisableRedirection || !_Wow64RevertRedirection;
}
```

However, my eyes go up to the Microsoft Learn documentation, to the description of the [_Wow64RevertWow64FsRedirection_](https://learn.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-wow64revertwow64fsredirection) function:

> This function should not be called without a previous call to the [Wow64DisableWow64FsRedirection](https://learn.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-wow64disablewow64fsredirection) function\.
>
> Any data allocation on behalf of the [Wow64DisableWow64FsRedirection](https://learn.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-wow64disablewow64fsredirection) function is cleaned up by this function\.

One function can't exist without the other, so checking for redirection support is fundamentally wrong\! Let's refine the refinement and fix the return value:

```cpp
return _Wow64DisableRedirection && _Wow64RevertRedirection;
```

Now everything is correct; if at least one function is missing, redirection isn't supported\.

### Macro with shifting surprise

[V1003](https://pvs-studio.com/en/docs/warnings/v1003/) The macro 'TITANGETDRX' is a dangerous expression\. The parameter 'titantype' must be surrounded by parentheses\. [breakpoint\.h 8](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/breakpoint.h#L8)

```cpp
#define TITANGETDRX(titantype) UE_DR0 + ((titantype >> 8) & 0xF)
```

Through the code, I didn't find any case where the _titantype_ parameter was represented as any expression—only options with a single variable pass\. However, if someone stumbled and forgot to do exactly that and passed something like a mathematical expression to a macro, the debugger might have suddenly been visited by [Dr\. Watson or WER](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/windows-error-reporting)\.

We can fix it quickly: the parameter is simply wrapped in a single pair of parentheses\.

```cpp
#define TITANGETDRX(titantype) UE_DR0 + (((titantype) >> 8) & 0xF)
```

Here are similar warnings:

* [V1003](https://pvs-studio.com/en/docs/warnings/v1003/) The macro 'TITANGETTYPE' is a dangerous expression\. The parameter 'titantype' must be surrounded by parentheses\. [breakpoint\.h 11](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/breakpoint.h#L11)
* [V1003](https://pvs-studio.com/en/docs/warnings/v1003/) The macro 'TITANGETSIZE' is a dangerous expression\. The parameter 'titantype' must be surrounded by parentheses\. [breakpoint\.h 13](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/breakpoint.h#L13)

### Read less datasheets

[V560](https://pvs-studio.com/en/docs/warnings/v560/) A part of conditional expression is always true: \* memorySize <\= 512\. The value range of unsigned char type: \[0, 255\]\. [TraceRecord\.cpp 239](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/TraceRecord.cpp#L239)

```cpp
//See https://www.felixcloutier.com/x86/FXSAVE.html, max 512 bytes
#define memoryContentSize 512

static void HandleZydisOperand(
                 const Zydis & zydis, int opindex,
                 DISASM_ARGTYPE* argType, duint* value,
                 unsigned char memoryContent[memoryContentSize],
                 unsigned char* memorySize)
{
  ....
  case ZYDIS_OPERAND_TYPE_MEMORY:
  {
    *argType = arg_memory;
    const auto & mem = op.mem;
    if(mem.segment == ArchValue(ZYDIS_REGISTER_FS, ZYDIS_REGISTER_GS))
    {
      *value += ThreadGetLocalBase(ThreadGetId(hActiveThread));
    }
    *memorySize = op.size / 8;
    if(*memorySize <= memoryContentSize && DbgMemIsValidReadPtr(*value))  // <=
    {
      MemRead(*value, memoryContent, max(op.size / 8, sizeof(duint)));
    }
  }
  break;
  ....
}
```

Here we go again: the code where the debugger developer left a comment with a link to the documentation\. The developer attached the _FXSAVE_ instruction of the x86 architecture\. The instruction saved the state of the floating\-point unit as well as the _MMX_, _XMM_, and _MXCSR_ registers to a 512\-byte memory block\. A colleague doubted the internet docs and deemed it unreliable\. The result was a clamorous debate for a few minutes\. While we were talking, I remembered that I had seen this table somewhere before\.\.\.

![1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image3.png](https://import.viva64.com/docx/blog/1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image3.png)

With a sly grin on my face, I languidly walked over to the bookshelf and slowly pulled out the second volume of "IA\-32 Intel Architecture Software Developer's Manual", published in 2002\! The book described every supported instruction of the fresh and piping hot Pentium 4 processor\. A heavy thick book landed on my desk with an ear\-shattering smack, and I opened it to the page where I'd left a bookmark beforehand\. In front of my opponent, the same table appeared in all its grandeur as it did in the e\-book\. That was the end of the debate\. I could only suggest deleting the redundant size check\. The _unsigned char_ type can't take a value greater than 255—it's too small to reach all the data of the _FXSAVE_ instruction\.

```cpp
....
*memorySize = op.size / 8;
if(DbgMemIsValidReadPtr(*value))
{
  MemRead(*value, memoryContent, max(op.size / 8, sizeof(duint)));
}
....
```

### Size matters

[V1048](https://pvs-studio.com/en/docs/warnings/v1048/) The 'titsize' variable was assigned the same value\. [cmd\-breakpoint\-control\.cpp 427](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/commands/cmd-breakpoint-control.cpp#L427)

```cpp
bool cbDebugSetHardwareBreakpoint(int argc, char* argv[])
{
  ....
  DWORD titsize = UE_HARDWARE_SIZE_1;
  if(argc > 3)
  {
    duint size;
    if(!valfromstring(argv[3], &size))
      return false;
    switch(size)
    {
    case 1:
      titsize = UE_HARDWARE_SIZE_1;         // <=
      break;
    case 2:
      titsize = UE_HARDWARE_SIZE_2;
      break;
    case 4:
      titsize = UE_HARDWARE_SIZE_4;
      break;
#ifdef _WIN64
    case 8:
      titsize = UE_HARDWARE_SIZE_8;
      break;
#endif // _WIN64
    default:
      titsize = UE_HARDWARE_SIZE_1;        // <=
      dputs(QT_TRANSLATE_NOOP("DBG", "Invalid size, using 1"));
      break;
    }
    ....
  }
  ....
}
```

Numeric variables are usually initialized with a null value\. It's not forbidden to do it with a specific value\. Besides, it's not forbidden to overwrite a variable with the same value during the program execution\. But what's the point of it? Is it to make it look convincing, or to back it up?

### Backup, though?

[V1037](https://pvs-studio.com/en/docs/warnings/v1037/) Two or more case\-branches perform the same actions\. Check lines: 42, 45 [commandparser\.cpp 42](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/dbg/commandparser.cpp#L42)

```cpp
Command::Command(const String & command)
{
  ParseState state = Default;
  int len = (int)command.length();
  for(int i = 0; i < len; i++)
  {
    char ch = command[i];
    switch(state)
    {
    ....
    case Escaped:
      switch(ch)
      {
      case '\t':
      case ' ':
        dataAppend(' ');
        break;
      case ',':
        dataAppend(ch);         // <=
        break;
      case '\"':
        dataAppend(ch);         // <=
        break;
      default:
        dataAppend('\\');
        dataAppend(ch);
        break;
      }
      state = Default;
      break;
    ....
    }
  }
}
```

This code block has both _fallthrough_ and duplicated parts\. The _fallthrough_ is used for tab and space—it means that the code author is obviously sure that both characters will add space without any problems\. What's wrong with a comma or a double quote, why couldn't they make _fallthrough_ for that pair of characters as well? The same action is executed: the _ch_ variable value is added, not the other character\. If we use _fallthrough_ here, as we do for space and tab, the Earth won't explode:

```cpp
switch(ch)
{
case '\t':
case ' ':
  dataAppend(' ');
  break;
case ',':
case '\"':
  dataAppend(ch);       // <=
  break;
default:
  dataAppend('\\');
  dataAppend(ch);
  break;
}
```

It looks like saving on bytes, but actually on the eyes of the code readers and the ticks of their brains to realize what is happening\.

### Hit the brakes, it's deprecated

[V1109](https://pvs-studio.com/en/docs/warnings/v1109/) The 'InitCommonControls' function is deprecated\. Consider switching to an equivalent newer function\. [x64dbg\_launcher\.cpp 426](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/launcher/x64dbg_launcher.cpp#L426)

```cpp
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine, int nShowCmd)
{
  InitCommonControls();
  ....
}
```

This feature is declared as deprecated for a reason\. First, it clutters up the import table\. Secondly, there are the [application manifests,](https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests) support for which was introduced in Windows XP\! First, developers could enable the support for the visual styles in app windows and select specific library versions\. When Windows Vista was released, they could set the [privilege level of an application](https://learn.microsoft.com/en-us/cpp/security/how-user-account-control-uac-affects-your-application?view=msvc-170)\. Visual Studio 2013 is used to build the project, where you can even integrate these manifests\! This feature isn't so new that you should neglect it—the functionality of the manifest integration directly into the project appeared in Visual Studio 2005\. Let's blow the dust off that IDE to see if my memory lets me down\.

![1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image4.png](https://import.viva64.com/docx/blog/1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image4.png)

The feature to enable the manifest in the Windows apps or libraries has long been a common development activity that is executed once\. Moreover, some functions [won't operate correctly](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexw) without the manifest\.

[V1109](https://pvs-studio.com/en/docs/warnings/v1109/) The 'PathRemoveFileSpecW' function is deprecated\. Consider switching to an equivalent newer function\. [x64dbg\_launcher\.cpp 114](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/launcher/x64dbg_launcher.cpp#L114)

```cpp
static HRESULT AddDesktopShortcut(TCHAR* szPathOfFile,
                                  const TCHAR* szNameOfLink)
{
  HRESULT hRes = NULL;

  //Get the working directory
  TCHAR pathFile[MAX_PATH + 1];
  _tcscpy_s(pathFile, szPathOfFile);
  PathRemoveFileSpec(pathFile);
  ....
}
```

There are still some deprecated calls, such as to [_PathRemoveFileSpecW_](https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathremovefilespecw) via a macro\. The function enables us to remove the closing backslash from the path\. It would be better to use [_PathCchRemoveFileSpec_](https://learn.microsoft.com/en-us/windows/win32/api/pathcch/nf-pathcch-pathcchremovefilespec) instead, but this function is only available on Windows 8 or higher\. Since the application is deliberately written to support Windows XP, this warning can be [suppressed](https://pvs-studio.com/en/docs/manual/0030/#ID4633590AF4) if you need to work with deprecated functions:

```cpp
PathRemoveFileSpec(pathFile); //-V1109 //-VH"2078475722"
```

Pay attention to a new mechanism we used, the suppression with hash\. It allows us to auto\-remove all **False Alarm** marks if the line code has changed\. This also protects you against replacing one deprecated function with another\. If we manually rewrite the macro into a function \(_PathRemoveFileSpecW_ for Unicode, _PathRemoveFileSpecA_ for ANSI\) or replace the macro with another function, the hash won't match the string\. Moreover, the analyzer will issue the [V1109](https://pvs-studio.com/en/docs/warnings/v1109/) warning in this line again if it occurs\.

Here are similar warnings:

* [V1109](https://pvs-studio.com/en/docs/warnings/v1109/) The 'PathRemoveFileSpecW' function is deprecated\. Consider switching to an equivalent newer function\. [x64dbg\_launcher\.cpp 479](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/launcher/x64dbg_launcher.cpp#L479)
* [V1109](https://pvs-studio.com/en/docs/warnings/v1109/) The 'PathRemoveFileSpecW' function is deprecated\. Consider switching to an equivalent newer function\. [x64dbg\_launcher\.cpp 503](https://github.com/x64dbg/x64dbg/blob/f518e507c24a04d9c82161ef1e89a7a70a73c0f2/src/launcher/x64dbg_launcher.cpp#503)

## Conclusions

The legends say that we've got to repair one soldering iron using another\. Roughly speaking, here's the same case with debugger\. So, how shall we debug a debugger? We can try to search for bugs using the static analyzer\. Let's say, [PVS\-Studio](https://pvs-studio.com/en/pvs-studio/try-free/)? x64dbg also keeps track of you and of the spent time, so don't forget that time is valuable\!

![1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image5.png](https://import.viva64.com/docx/blog/1146_Debugging_Bugs_In_x64dbg_Debugger_Without_Debugger/image5.png)

The story doesn't end here: we should "step out" in the Qt GUI—it has lots of surprises in store for us\! Stay tuned for part two\. Don't switch processor contexts\!