﻿# Common patterns of typos in programming

The developers have an endless amount of ways to make mistakes while writing code\. However, sometimes we can find obvious and interesting patterns in how and where developers make mistakes\. Let's talk about the code as a "magnet" for typos\.

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

## Research background

In order to test and promote the PVS\-Studio static code analyzer, we check various open\-source projects\. If we find errors, we report about them to the authors of projects\. We [collect](https://pvs-studio.com/en/blog/examples/) errors and write [articles](https://pvs-studio.com/en/blog/inspections/) about the most interesting cases\.

When looking at all these errors, I notice various repeating patterns of typos\. With only a few exceptions, they are independent of the programming language\. At least, they are common to code written in C, C\+\+, C\#, and Java\. In this article, I'll outline 7 patterns that I've noticed by now:

1. The last line effect
1. The most dangerous _memset_ function
1. The incorrect comparison functions
1. The incorrect copy functions
1. The errors related to data and time
1. The unlucky numbers: 0, 1, 2
1. The off\-by\-one error

The fact that these error patterns are noticeable shows that they are common\. It's useful to know how to avoid potentially dangerous coding or how to find errors more efficiently during code reviews\. In other words, you'll learn which code attracts errors and how to review code more carefully\. PVS\-Studio can indeed detect a lot of errors, but it cannot detect them all\. So, more attention to them isn't out of place\.

## The last line effect

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

It's my first found pattern\. I first described it in an article of 2014\. Here's the description of the pattern: when writing code blocks of the same type, you may make a mistake in the last block\.

Let me explain it by an example of code from the Godot Engine project \(C\+\+\)\.

```cpp
String SoftBody::get_configuration_warning() const {
  ....
  Transform t = get_transform();
  if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 ||
       ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 ||
       ABS(t.basis.get_axis(0).length() - 1.0) > 0.05)) {
    if (!warning.empty())
  ....
}
```

It's a classic [copy\-paste](https://pvs-studio.com/en/blog/terms/0068/) error\. The developers don't want to retype similar lines of code\. That's why, they just double the code line:

```cpp
ABS(t.basis.get_axis(0).length() - 1.0) > 0.05
```

After that, they replace 0 by 1 in the second line, but they forget to replace 0 by 2 in the last line\. When we separately review such code fragment, it seems surprising to find such simple error\. But that's exactly how this pattern looks like\.

Here's another example found in the unit tests of the LLVM \(C\+\+\) project\.

```cpp
TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_64) {
  MinidumpContext_x86_64 Context;
  ....
  Context.rax = 0x0001020304050607;
  Context.rbx = 0x08090a0b0c0d0e0f;
  ....
  Context.eflags = 0x88898a8b;
  Context.cs = 0x8c8d;
  Context.fs = 0x8e8f;
  Context.gs = 0x9091;
  Context.ss = 0x9293;    // <=
  Context.ds = 0x9495;
  Context.ss = 0x9697;    // <=
  llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context),
                                     sizeof(Context));
  ....
}
```

Let's take a look at the code lines highlighted with the code comments\. This code was hardly written using copy\-paste, but an error is still in the last line\. The developer hurried and inattentively made a typo when repeatedly writing the value into the _ss_ register instead of the _es_ register\.

**Note\.** Another interesting thing is that the error shows how a static analyzer complements unit testing\. Unit tests can also contain errors that cause certain untested or not fully tested scenarios\. However, writing unit tests for unit tests is not practical\. Code analyzers will help you here\.

To avoid the impression that such errors are common only in C and C\+\+ languages, I will show you an example of the Java code\. I found the following typo in the IntelliJ IDEA Community Edition project \(Java\)\.

```cpp
private static boolean isBeforeOrAfterKeyword(String str, boolean trimKeyword) {
  return (trimKeyword ? LoadingOrder.BEFORE_STR.trim() :
           LoadingOrder.BEFORE_STR).equalsIgnoreCase(str) ||
         (trimKeyword ? LoadingOrder.AFTER_STR.trim() :
           LoadingOrder.AFTER_STR).equalsIgnoreCase(str) ||
         LoadingOrder.BEFORE_STR_OLD.equalsIgnoreCase(str) ||         // <=
         LoadingOrder.BEFORE_STR_OLD.equalsIgnoreCase(str);           // <=
}
```

Here we notice an obvious pattern\. You can see other similar examples in the old article "[The last line effect](https://pvs-studio.com/en/blog/posts/cpp/0260/)"\.

Why did I name this pattern in such a way? The "last meters effect" from the world of mountaineering — this is my source of inspiration\. I've read the observation that climbers often make a mistake at the end of a climb\. The reason is not because they are tired — they are less concentrated\. They mistakenly think that they've already reached the mountain top and soon they can rest, and enjoy the end of the journey\. The climber loses concentration, rushes to finish the climb and does something wrong\.

When writing code, developers can experience the same thing\. It's boring to write code blocks of the same type\. We will prove it below when we talk about the comparison functions\. So, developers rush to finish a monotonous job\. When writing the last code line, they are glad that they are done with routine and may start to think about what to write next\.

In any case, the concentration declines, and developers make errors\. Well, they can make errors randomly, but the observation says it's more likely to happen in the last code block of the same type\.

The same story happens with a code review\. It's boring to review the code of the same type\. That's why the concentration quickly declines, and developers carelessly check the last code lines or don't check them at all\. This is how errors occur in code and can remain unnoticed\. When you find these errors, their simplicity can surprise\.


> \*\*Tip:\*\* When reviewing code, you should pay more attention to the last code lines\\\.

## The most dangerous memset function

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

In addition to common patterns, there are patterns which are specific to a particular language\. For example, the _memset_ function causes a great amount of errors\. It's mostly used in the C programs, but you can often find it in the C\+\+ code as well\.

```cpp
void* memset( void* dest, int ch, size_t count );           // C
void* std::memset( void* dest, int ch, std::size_t count ); // C++
```

The _memset_ function copies the value _\(unsigned char\) ch_ into each of the first _count_ characters of the object pointed to by _dest_\. The description:

* The [memset](https://en.cppreference.com/w/c/string/byte/memset) is the C variant of the function\.
* The [std::memset](https://en.cppreference.com/w/cpp/string/byte/memset) is the C\+\+ variant of the function\.

In my opinion, this function is the leader of C and C\+\+ languages in attracting bugs to itself\. Most often the error is related to incorrect calculation of the buffer size\.

Typos occur when unnecessary indirection operator \(\*\) is used or when it is absent where it is needed\. Or in the redundant address\-of operator \(&\)\. Now, let's take a look at examples of such errors\.

**The developer forgot to dereference the pointer \(\*\)\.** The code fragment is taken from the FAR Manager v2 project for Linux \(Far2l, C\+\+\)\. Due to a typo, the _sizeof_ operator evaluates the pointer size instead of the structure size\.

```cpp
int64_t FileList::VMProcess(int OpCode,
                            void *vParam,
                            int64_t iParam)
{
  ....
  PluginInfo *PInfo = (PluginInfo *)vParam;
  memset(PInfo, 0, sizeof(PInfo));
  ....
}
```

The correct version:

```cpp
memset(PInfo, 0, sizeof(*PInfo));
```

**The unnecessary address\-of operator \(&\)\.** Here is the code from the Energy Checker SDK project \(C\)\. The _sizeof_ operator evaluates the pointer size instead of the size of the _WIN32\_FIND\_DATA_ structure\. As a result, only the first 4 or 8 bytes of the structure will be zeroed out\. It depends on whether Win32 or Win64 application is being built\.

```cpp
int plh_read_pl_folder(PPLH_PL_FOLDER_INFO pconfig) {
  ....
  WIN32_FIND_DATA file_data;
  ....
  memset(
    &file_data,
    0,
    sizeof(&file_data)
  );
  ....
}
```

The correct version: _sizeof\(file\_data\)_\. It's even better to get rid of the _memset_ function at all\. To do this, you can initialize the object with zeros at the declaration:

```cpp
WIN32_FIND_DATA file_data = { };
```

**The developer confused & with \*\.** The example is taken from the Wolfenstein 3D project \(C\)\. Here, the developer had to dereference the pointer to correctly evaluate the structure size instead of using the address\-of operator\.

```cpp
void CG_RegisterItemVisuals( int itemNum ) {
  ....
  itemInfo_t *itemInfo;
  ....
  memset( itemInfo, 0, sizeof( &itemInfo ) );
  ....
}
```

**The buffer overflow\.** In the Open source emulator PS4 \(C\+\+\) project, the developer carelessly confused the _sizeof_ argument with the _countof_ argument\. They thought that the _sizeof_ operator would evaluate the number of elements\. That's why they multiplied this value by the size of one element\.

```cpp
struct GnmCmdPSShader
{
  ....
  uint32_t reserved[27];
};

int PS4API sceGnmSetPsShader350(....)
{
  ....
  memset(param->reserved, 0, sizeof(param->reserved) * sizeof(uint32_t)); 
  return SCE_OK;
}
```

The correct version of the code:

```cpp
memset(param->reserved, 0, sizeof(param->reserved));
```

**Note\.** By the way, the _memset_ function attracts not only typos but other errors as well\. You can read about them in the article: "[The most dangerous function in the C/C\+\+ world](https://pvs-studio.com/en/blog/posts/cpp/0360/)"\. For example, potential vulnerabilities occur when the developers use the _memset_ function at the end to overwrite private data\. Here is the example from the WebRTC project \(C\+\+\)\.

```cpp
void AsyncSocksProxySocket::SendAuth() {
  ....
  char * sensitive = new char[len];
  pass_.CopyTo(sensitive, true);
  request.WriteString(sensitive);  // Password
  memset(sensitive, 0, len);
  delete [] sensitive;
  ....
}
```

The point is that compilers will delete the call of the _memset_ function to optimize the code\. In terms of the compiler, since the buffer is freed, we may not fill it\. As a result, the private data will remain in memory\. This topic is beyond the scope of the article about typos\. So, if you want more details, I suggest you click the following links:

* [V597](https://pvs-studio.com/en/docs/warnings/v597/): the PVS\-Studio diagnostic
* [CWE\-14](https://cwe.mitre.org/data/definitions/14.html): Compiler Removal of Code to Clear Buffers
* [Safe clearing of private data](https://pvs-studio.com/en/blog/posts/cpp/0388/)


> \*\*Tip:\*\* Carefully review the code which contains the call of the \_memset\_ function\\\. Moreover, during a code review, you can try to use a different way to fill a memory\\\.

The _memset_ function is frequently used during initialization to fill all structure fields with zero values\. Here is an abstract example:

```cpp
MyStruct foo;
memset(foo, 0, sizeof(foo));
```

It's easier and safer to immediately fill structures with zeroes at declaration:

```cpp
MyStruct foo = { };
```

If you need to zeroize an array in C\+\+, it's better to use the _std::fill_ function\. Let me explain it using an example from the Notepad\+\+ project \(C\+\+\)\.

```cpp
#define CONT_MAP_MAX 50
int _iContMap[CONT_MAP_MAX];
....
DockingManager::DockingManager()
{
  ....
  memset(_iContMap, -1, CONT_MAP_MAX);
  ....
}
```

The developers think that they initialize an array of the _int_ type, containing 50 elements, with the value \-1\. But the _memset_ function works with bytes\. In fact, the 0xFFFFFFFF value will initialize the first 12 elements\. They will be filled with the correct value \-1, but that's just luck\. One more element will get the 0x0000FFFF value\. Other array elements will remain uninitialized\.

If we use the [_std::fill_](https://en.cppreference.com/w/cpp/algorithm/fill) function, it's more difficult to make an error:

```cpp
// since C++11
std::fill(std::begin(_iContMap), std::end(_iContMap), -1);

// since C++20
std::ranges::fill(_iContMap, -1);
```

## The incorrect comparison functions

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

It's boring to write the comparison functions\. In fact, this helper code is simple and uninteresting\. So, there's no place for creativity\. We just have to compare all the variables to each other\.

That's why developers rush when writing such functions\. They rush when reviewing code as well\. It's hard to focus on such simple code\. Such functions are diagonally viewed during a code review\. It leads to many unnoticed typos\.

Let's start with a classic typo in a large block of comparisons of the same type\. The example is taken from the Apache Flink project \(Java\)\.

```cpp
@Override
public boolean equals(Object o) 
{
  ....
  CheckpointStatistics that = (CheckpointStatistics) o;
  return id == that.id &&
    savepoint == that.savepoint &&
    triggerTimestamp == that.triggerTimestamp &&
    latestAckTimestamp == that.latestAckTimestamp &&
    stateSize == that.stateSize &&
    duration == that.duration &&
    alignmentBuffered == that.alignmentBuffered &&
    processedData == processedData &&
    persistedData == that.persistedData &&
    numSubtasks == that.numSubtasks &&
    numAckSubtasks == that.numAckSubtasks &&
    status == that.status &&
    Objects.equals(checkpointType, that.checkpointType) &&
    Objects.equals(
      checkpointStatisticsPerTask, 
      that.checkpointStatisticsPerTask);
}
```

Found an error? I guess, no\. This code is boring to write and boring to read\. You didn't probably care to scrutinize it\. Here is a string with a typo\.

```cpp
processedData == processedData
```

The variable is compared to itself\. The correct version:

```cpp
processedData == that.processedData
```

We can find the same typos in smaller functions from the eShopOnContainers project \(C\#\)\.

```cpp
private bool CheckSameOrigin(string urlHook, string url)
{
  var firstUrl = new Uri(urlHook, UriKind.Absolute);
  var secondUrl = new Uri(url, UriKind.Absolute);

  return firstUrl.Scheme == secondUrl.Scheme &&
         firstUrl.Port == secondUrl.Port &&
         firstUrl.Host == firstUrl.Host;
}
```

Take a look at the last line\. The field of a class is compared to itself\. By the way, there's a double magnet for error\. Firstly, it's the comparison function\. Secondly, here is the last line effect\. Bingo\! That's why the typo may be not found in a quite simple and short function\. The simple and boring function is a major reason to pay attention to it during the code review\.

But it turns out that a typo can be made even in such short comparison function\. Here is the example from the Skia Graphics Engine project \(C\+\+\)\.

```cpp
inline bool operator==(const SkPDFCanon::BitmapGlyphKey& u,
                       const SkPDFCanon::BitmapGlyphKey& v)
{
  return memcmp(&u, &u, sizeof(SkPDFCanon::BitmapGlyphKey)) == 0;
}
```

The _u_ object is byte\-by\-byte compared to itself\.

However, errors in the comparison functions are not limited to something that is compared to itself\. Errors are diverse\. I took an interesting typo from the Azure Service Fabric project as an example \(C\+\+\)\.

```cpp
template <typename TK, typename TV>
static bool MapCompare(const std::map<TK, TV>& lhs,
                       const std::map<TK, TV>& rhs)
{
  if (lhs.size() != rhs.size()) { false; }

  return std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
```

Take a look at the lonely _false_ keyword\. The code is compiled, but doesn't make any sense\. Here the developer forgot to write the _return_ statement\. The correct version:

```cpp
if (lhs.size() != rhs.size()) { return false; }
```

Here is the example from the Roslyn project \(C\#\)\.

```cpp
protected override bool AreEqual(object other)
{
  var otherResourceString = other as LocalizableResourceString;
  return
    other != null &&
    _nameOfLocalizableResource ==
      otherResourceString._nameOfLocalizableResource &&
    _resourceManager == otherResourceString._resourceManager &&
    _resourceSource == otherResourceString._resourceSource &&
    ....
}
```

The [_NullReferenceException_](https://pvs-studio.com/en/blog/posts/csharp/1049/) may occur here\. The developers need to check the _otherResourceString _reference instead of _other_ for the _null_ inequality\.

You can find other examples of errors in the article "[The Evil within the Comparison Functions](https://pvs-studio.com/en/blog/posts/cpp/0509/)"\.

If I say "pay more attention to the comparison functions during code reviews", I don't think that it's going to motivate you\. So, I'll answer this question in a more practical way\.


> \*\*Tip:\*\* You can use static code analyzers, like PVS\\\-Studio, to assist yourself\\\. Such analyzers carefully work on any code\\\.
> 
> You can use the table\\\-style formatting of code\\\.

I wrote more about the table\-style formatting of code in my mini\-book "[60 terrible tips for a C\+\+ developer](https://pvs-studio.com/en/blog/posts/cpp/1053/)" — see "Terrible Tip N20\. Compact code"\. The tip starts with explaining how not to do, and then gives a useful tip\. The table\-style formatting does not guarantee the absence of typos, but it definitely reduces their number\.

I should note that since C\+\+20, there is a way to request the compiler to [generate](https://en.cppreference.com/w/cpp/language/default_comparisons) the code of the comparison operators: equality, inequality, and relation\. You rarely need to write your own comparison functions\. This reduces the chance of making an error\. Use the modern features of the C\+\+ language\!

## The incorrect copy functions

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

While comparison functions seem boring for developers, the implementation of copy functions provokes them to an excessive enthusiasm\. I occasionally find errors in such functions\. It's interesting that the function text seems overcomplicated to me\. Actually, this excessive complexity is the source of errors\.

Here is a custom implementation of the _strdup_ function from the Zephyr RTOS project \(C\)\.

```cpp
static char *mntpt_prepare(char *mntpt)
{
  char *cpy_mntpt;

  cpy_mntpt = k_malloc(strlen(mntpt) + 1);
  if (cpy_mntpt) {
    ((u8_t *)mntpt)[strlen(mntpt)] = '\0';
    memcpy(cpy_mntpt, mntpt, strlen(mntpt));
  }
  return cpy_mntpt;
}
```

The _memcpy_ function copies the line but fails to copy the [terminal null](https://pvs-studio.com/en/blog/terms/0088/)\. So, additional code is written to copy the terminal null:

```cpp
((u8_t *)mntpt)[strlen(mntpt)] = '\0';
```

But it doesn't work\! The code contains a typo that causes the terminal null to get copied into itself\. Notice that the target array is _mntpt_, not _cpy\_mntpt_\. As a result, the _mntpt\_prepare_ function returns a non\-null\-terminated string\.

The correct version:

```cpp
((u8_t *)cpy_mntpt)[strlen(mntpt)] = '\0';
```

You may be confused why the developer has written this code in such a messy and strange way\. We can simplify it to this version:

```cpp
static char *mntpt_prepare(char *mntpt)
{
  char *cpy_mntpt;

  cpy_mntpt = k_malloc(strlen(mntpt) + 1);
  if (cpy_mntpt) {
    strcpy(cpy_mntpt, mntpt);
  }
  return cpy_mntpt;
}
```

The code from the LFortran project \(C\) — the error in the concatenation of two strings in the new buffer\.

```cpp
void _lfortran_strcat(char** s1, char** s2, char** dest)
{
    int cntr = 0;
    char trmn = '\0';
    int s1_len = strlen(*s1);
    int s2_len = strlen(*s2);
    int trmn_size = strlen(&trmn);
    char* dest_char = (char*)malloc(s1_len+s2_len+trmn_size);
    for (int i = 0; i < s1_len; i++) {
        dest_char[cntr] = (*s1)[i];
        cntr++;
    }
    for (int i = 0; i < s2_len; i++) {
        dest_char[cntr] = (*s2)[i];
        cntr++;
    }
    dest_char[cntr] = trmn;
    *dest = &(dest_char[0]);
}
```

It's hard to say whether some errors are typos or not\. The code above is just the case\.

I think I'll take it as a typo after all\. The developer used _strlen_ instead of _sizeof_ to determine the size of the terminal null in bytes\.

The explanation:

```cpp
char trmn = '\0';
int trmn_size = strlen(&trmn);
```

Here, the _trmn_ character is interpreted as an empty string with the zero length\. Thus, the _trmn\_size_ variable, whose name means the size of the terminal null, will always be 0\.

You don't need to evaluate the length of an empty string\. It's good idea to use the _sizeof_ operator to evaluate how many bytes a terminal character occupies\. Here is the correct code:

```cpp
int trmn_size = sizeof(trmn);
```

We can improve this code, but it's beyond the scope of this article\. For other improvements, get a chance to read the article "[A beautiful error in the implementation of the string concatenation function](https://pvs-studio.com/en/blog/posts/cpp/0845/)"\.

And now we are going to discuss the last example\. I took it from the QuantConnect Lean project \(C\#\)\.

```cpp
/// <summary>
/// Copy contents of the portfolio collection to a new destination.
/// </summary>
/// <remarks>
/// IDictionary implementation calling the underlying Securities collection
/// </remarks>
/// <param name="array">Destination array</param>
/// <param name="index">Position in array to start copying</param>
public void CopyTo(KeyValuePair<Symbol, SecurityHolding>[] array, int index)
{
  array = new KeyValuePair<Symbol, SecurityHolding>[Securities.Count];
  var i = 0;
  foreach (var asset in Securities)
  {
    if (i >= index)
    {
      array[i] = new KeyValuePair<Symbol,SecurityHolding>(asset.Key,
                                                          asset.Value.Holdings);
    }
    i++;
  }
}
```

The method gets the collection and immediately overwrites its value\. The comment and the method name suggest that one array should be copied to another\. However, this will not happen, and the _array_ value outside the current method will remain unchanged\.

The case is that the _array_ argument is passed to the method by value, not by reference\. Thus, after the assignment operation, the _array_ variable which is available within the method will store a reference to the new object\. The variable value within the method will remain unchanged\.

This is a version of the typo where the developer forgot the _out_ modifier\. Here's the correct code: 

```cpp
public void CopyTo(out KeyValuePair<Symbol, SecurityHolding>[] array,
                   int index)
{
  array = new KeyValuePair<Symbol, SecurityHolding>[Securities.Count];
  ....
}
```


> \*\*Tip:\*\* Write unit tests for your copy functions\\\.

Indeed, unit tests are useful to write for finding errors of other varieties as well\. However, they are more relevant here\.

For example, I didn't mention unit tests when we discussed comparison functions\. It is a thankless task to check comparison functions with unit tests:

1. It's boring to write unit tests for comparison functions\. Anyway, we have already known that boring code is rarely successful :\)\.
1. In the unit tests, you need to think about many special scenarios\. For example, you need to separately check the correctness of comparison to each class member\. The unit test code will be dozens of times larger than the comparison functions' code\. Thus, the using of unit tests may not be practical from the benefit\-cost ratio perspective\.

Copy functions are another matter\. Take a look at the above errors again\. Even the simplest set of unit tests will detect them all\. Unit tests will show that functions return the wrong things\.

## The errors related to data and time

![1064_patterns_of_typos/image6.png](https://import.viva64.com/docx/blog/1064_patterns_of_typos/image6.png)

You can find many typos in the code that manages time and dates\. These errors are inherently different\. That's why it's hard for me to explain why such code is a magnet for errors\. So, I'll just give you a few examples\. I invite readers to speculate on this topic in comments\.

The example from the Umbraco project \(C\#\) — the constructors of the _DateTime_ class are called incorrectly\.

```cpp
public static DateTime TruncateTo(this DateTime dt,
                                  DateTruncate truncateTo)
{
  if (truncateTo == DateTruncate.Year)
    return new DateTime(dt.Year, 0, 0);
  if (truncateTo == DateTruncate.Month)
    return new DateTime(dt.Year, dt.Month, 0);
  ....
}
```

The developers made a typo because they got used to numbering everything starting from zero — the array indexes, for example\. But here we have dates instead of arrays\. The first day or month has the number 1 instead of 0\. The call of constructors in the above code leads to _ArgumentOutOfRangeException_\. The correct version:

```cpp
if (truncateTo == DateTruncate.Year)
  return new DateTime(dt.Year, 1, 1);
if (truncateTo == DateTruncate.Month)
  return new DateTime(dt.Year, dt.Month, 1);
```

The example from the MPC\-HC project \(C\+\+\) — the uninitialized variable may be used here\.

```cpp
void CSyncAP::RenderThread()
{
  ....
  REFERENCE_TIME rtRefClockTimeNow;
  if (m_pRefClock) {
    m_pRefClock->GetTime(&rtRefClockTimeNow);
  }
  LONG lLastVsyncTime =
    (LONG)((m_llEstVBlankTime - rtRefClockTimeNow) / 10000);
  ....
```

\}

If the condition is not met, the _rtRefClockTimeNow_ variable will remain uninitialized\. It will still be used in evaluations\. The developers might forget to initialize the variable when declaring it with the default value\.

Here is a beautiful typo from the Tizen project \(C\)\. The developers made a mistake with the data view\. 

```cpp
static void preview_down_cb(....)
{
  ....
  int delay = 0.5;
  double fdelay;
  fdelay = ((double)delay / 1000.0f);
  DbgPrint("Long press: %lf\n", fdelay);
  ....
}
```

The idea to write the _0\.5_ value into the _int_ type variable is bad\. The delay is actually counted in milliseconds\. The correct default delay value of 500 milliseconds should be written like this:

```cpp
int delay = 500;
```

Here is the example of the incorrect type conversion from the MSBuild project \(C\#\)\.

```cpp
internal static void Trace(....)
{
  ....
  long now = DateTime.UtcNow.Ticks;

  float millisecondsSinceLastLog =
    (float)((now - s_lastLoggedTicks)/10000L);
  ....
}
```

Here the integer division occurs first, and only then the explicit conversion to the _float_ type is performed\. Type conversion should be performed before division, not after\. The typo is that developer made a mistake with parentheses\. The correct code:

```cpp
float millisecondsSinceLastLog = (float)(now - s_lastLoggedTicks)/10000L;
```

Here is an example of a forgotten comma from the Linux Kernel project \(C\)\.

```cpp
static ssize_t lp8788_show_eoc_time(struct device *dev,
        struct device_attribute *attr, char *buf)
{
  struct lp8788_charger *pchg = dev_get_drvdata(dev);
  char *stime[] = { "400ms", "5min", "10min", "15min",
      "20min", "25min", "30min" "No timeout" };
  ....
}
```

There is no comma between the penultimate and the last string literal\. So, they stick together and the result is "30minNo timeout"\.

I think, it's enough\. You can see examples of other errors in articles "[February 31](https://pvs-studio.com/en/blog/posts/cpp/0550/)" and "[Date processing attracts bugs or 77 defects in Qt 6](https://pvs-studio.com/en/blog/posts/cpp/0801/)"\.

I have shown how varied the errors related to dates and time are\. In this chapter, there is no pattern of errors\. At least I don't see one\.


> \*\*Tip:\*\* Just be aware that the code that handles time and dates is difficult and attracts errors for some reason\\\. You should pay more attention to such code during code reviews\\\.
> 
> And don't forget about unit tests, they are useful too\\\.

## Unlucky numbers: 0, 1, 2

![1064_patterns_of_typos/image7.png](https://import.viva64.com/docx/blog/1064_patterns_of_typos/image7.png)

The numbers 0, 1, 2 are frequently used in programming as the array indexes or as part of variable names\. The presence of such numbers indicates that the code is typical\.

Since the code is typical, it's hard to focus on it\. As a result, such code attracts various typos\. This relates the error pattern in question to the last line effect and incorrect comparisons\.

### Let's start with the typos in the indexes

Here is a classic copy\-paste error from the LibreOffice project \(C\+\+\)\.

```cpp
Sequence< OUString > FirebirdDriver::
  getSupportedServiceNames_Static() throw (RuntimeException)
{
  Sequence< OUString > aSNS( 2 );
  aSNS[0] = "com.sun.star.sdbc.Driver";
  aSNS[0] = "com.sun.star.sdbcx.Driver";
  return aSNS;
}
```

To avoid retyping the boring line, the developer copies it\. They replace _sdbc_ with _sdbcx_ in the duplicated line, but they forget to correct the array index\.

Here is another Copy\-Paste error from the Quake III Arena project \(C\)\.

```cpp
int VL_FindAdjacentSurface(....)
{
  ....
  if (fabs(dir[0]) > test->radius ||
      fabs(dir[1]) > test->radius ||
      fabs(dir[1]) > test->radius)
  {
  ....
}
```

You can see the last line effect again\. It's a combo\. Such code is a magnet for errors\.

Here is a more unexpected typo \(the array index is 2 instead of 1\) from the OpenCOLLADA project \(C\+\+\)\.

```cpp
struct short2
{
  short values[2];
  short2(short s1, short s2)
  {
    values[0] = s1;
    values[2] = s2;
  }
  ....
};
```

There is an overlap with the off\-by\-one error, which we will discuss at the end of the article\.

Note to self :\)\. Once again, we see how patterns increase the probability of error\. It's an interesting topic\. It may be good idea to broach it in the future article\.

Here is another example of the typo from the \.NET Core SDK project \(C\#\)\.

```cpp
public bool MatchesXmlType(IList<XPathItem> seq, int indexType)
{
  ....
  typBase = typBase.Prime;
  for (int i = 0; i < seq.Count; i++)
  {
    if (!CreateXmlType(seq[0]).IsSubtypeOf(typBase))
      return false;
  }

  return true;
}
```

The first element of the _seq_ array is handled inside the loop all the time\. The correct version:

```cpp
if (!CreateXmlType(seq[i]).IsSubtypeOf(typBase))
```

### Let's take a look at typos in the named variables

Here is the example from the Doom project \(C\+\+\)\.

```cpp
uint AltOp::fixedLength()
{
  uint l1 = exp1->fixedLength();
  uint l2 = exp1->fixedLength();

  if (l1 != l2 || l1 == ~0u)
    return ~0;

  return l1;
}
```

Most likely, the developer copied and pasted code and forgot to replace _exp1_ with _exp2_ in the second line\.

Here is the example from the Vangers project \(C\+\+\)\.

```cpp
const char* iGetJoyBtnNameText(int vkey, int lang)
{
  ....
  if (vkey >= VK_STICK_SWITCH_1 && vkey <= VK_STICK_SWITCH_9)
  {
     ret = (lang)
      ? iJoystickStickSwitch2[vkey - VK_STICK_SWITCH_1]
      : iJoystickStickSwitch2[vkey - VK_STICK_SWITCH_1];
    return ret;
  }
  ....
}
```

Here is the opposite case\. The correct version:

```cpp
ret = (lang)
  ? iJoystickStickSwitch2[vkey - VK_STICK_SWITCH_1]
  : iJoystickStickSwitch1[vkey - VK_STICK_SWITCH_1];
```

Here is the example from the Boost project \(C\+\+\)\.

```cpp
point3D operator/(const point3D &p1, const point3D &p2)
{
  return point3D(p1.x/p2.x, p1.y/p2.y, p1.z/p1.z);
}
```

There's a typo here: _p1\.z/p1\.z_\.

### The other variants of typos

Here is the error of formatting from the Azure PowerShell project \(C\#\)\.

```cpp
protected override void ProcessRecordInternal()
{
  ....
  if (this.ShouldProcess(this.Name,
    string.Format("Creating Log Alert Rule '{0}' in resource group {0}",
      this.Name, this.ResourceGroupName)))
  ....
}
```

The correct version:

```cpp
string.Format("Creating Log Alert Rule '{0}' in resource group {1}",
              this.Name, this.ResourceGroupName))
```

I think we've looked at enough examples\. If you want even more, I suggest checking out the article "[Zero, one, two, Freddy's coming for you](https://pvs-studio.com/en/blog/posts/cpp/0713/)"\.

If you have to use numbers in the names of variables or in the array indexing, you will probably find such code boring\. Of course, sometimes developers have to write such code anyway\. Unfortunately, it's difficult to focus on writing and checking boring code\.

Let's take a look again at this code:

```cpp
point3D operator/(const point3D &p1, const point3D &p2)
{
  return point3D(p1.x/p2.x, p1.y/p2.y, p1.z/p1.z);
}
```

We can't say that the code is difficult\. Just the opposite, it's too simple\. We can't be just accurate in writing such code\. Instead, we start to think about algorithms and how to write any class better\. And this is what we get\.


> \*\*Tip:\*\* Make yourself to be more attentive during the code reviews where unlucky numbers 0, 1, 2 occur\\\.
> 
> A static code analyzer will be a good assistant during code reviews\\\.

## The off\-by\-one error

![1064_patterns_of_typos/image8.png](https://import.viva64.com/docx/blog/1064_patterns_of_typos/image8.png)

This is a long\-known error pattern\. So, I don't take a credit for its discovery\. It was described a long time ago:

* Wikipedia\. [Off\-by\-one error](https://en.wikipedia.org/wiki/Off-by-one_error)\.
* Common Weakness Enumeration\. [CWE\-193: Off\-by\-one Error](https://cwe.mitre.org/data/definitions/193.html)\.

The most common error is accessing a one\-past\-the\-end array element\. I think everyone has encountered them when starting to learn programming\. These are the same cases where you were confused by the fact that the elements in the array are numbered from zero instead of one\.

So, the errors of this type have been known to everyone for a long time\. However, I could detect this error pattern even if I hadn't known about it before\. Unfortunately, even experienced developers continue to make such errors\. I regularly see them in the code of projects\. I'll give you a few examples\. 

Here is an example of the index typo from the Umbraco project \(C\#\)\.

```cpp
protected virtual string VisitMethodCall(MethodCallExpression m)
{
    ....
    if (m.Arguments.Count == 2)
    {
      var n1 = Visit(m.Arguments[0]);
      var f = m.Arguments[2];
      ....
}
```

The correct code:

```cpp
var f = m.Arguments[1];
```

By the way, this code could be referred to the part about unlucky numbers 0, 1, 2\. I guess that the mutual attraction of different error patterns doesn't surprise you\.

Here is an example of the typo when checking the range of values from the CMake project \(C\)\.

```cpp
static int64_t
expand(struct archive_read *a, int64_t end)
{
  ....
  if ((lensymbol = read_next_symbol(a, &rar->lengthcode)) < 0)
    goto bad_data;

  if (lensymbol > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
    goto bad_data;
  ....
  len = lengthbases[lensymbol] + 2;
  ....
}
```

When accessing the _lengthbases_ array, the array overrun is possible because the developers wrote the _operator \>_ instead of the _operator \>\=_ above\. The correct version of check:

```cpp
if (lensymbol >= (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
```

Here is an example of the index typo from the ELKI project \(Java\)\.

```cpp
public List<double[]> points;

@Override
public double[] computeMean() {
  // Not supported except for singletons.
  return points.size() == 1 ? points.get(1) : null;
}
```

The correct code:

```cpp
return points.size() == 1 ? points.get(0) : null;
```


> \*\*Tip:\*\* Even though everyone knows about this type of error, they are still common\\\. Be more careful\\\.
> 
> Static and dynamic code analyzers are good helpers in detecting errors of array overrun\\\.

## Share your experience with us\!

Thank you for your attention\! If you know similar patterns of errors, feel free to share them in the comments\. First, you can help warn your teammate about such patterns\. Second, we may write new diagnostics for the PVS\-Studio static analyzer to detect such errors\.

I may also find some new patterns and describe them in the future\. To make sure you don't miss interesting news, you can subscribe to the monthly [digest](https://pvs-studio.com/en/subscribe/)\.

## PVS\-Studio

The PVS\-Studio analyzer helped detect all the bugs described in this article\. This tool will help you quickly detect typos and other defects in new code, thereby shortening the cost of fixing them\. You can try the trial version of PVS\-Studio for free: [download PVS\-Studio](https://pvs-studio.com/en/pvs-studio/download/)\.

## Additional links: 

1. [Errors collection](https://pvs-studio.com/en/blog/examples/)\.
1. [The Last Line Effect](https://pvs-studio.com/en/blog/posts/cpp/0260/)\.
1. [The last line effect explained](https://pvs-studio.com/en/blog/posts/0485/)\.
1. [The most dangerous function in the C/C\+\+ world](https://pvs-studio.com/en/blog/posts/cpp/0360/)\.
1. [The Evil within the Comparison Functions](https://pvs-studio.com/en/blog/posts/cpp/0509/)\.
1. [Starting my collection of bugs found in copy functions](https://pvs-studio.com/en/blog/posts/cpp/0723/)\.
1. [A beautiful error in the implementation of the string concatenation function](https://pvs-studio.com/en/blog/posts/cpp/0845/)\.
1. [February 31](https://pvs-studio.com/en/blog/posts/cpp/0550/)\.
1. [Date processing attracts bugs or 77 defects in Qt 6](https://pvs-studio.com/en/blog/posts/cpp/0801/)\.
1. [Zero, one, two, Freddy's coming for you](https://pvs-studio.com/en/blog/posts/cpp/0713/)\.
1. [60 terrible tips for a C\+\+ developer](https://pvs-studio.com/en/blog/posts/cpp/1053/)\.