My name is Andrey Karpov. I have studied hundreds of errors caused by "copy-paste". It is safe to say that programmers often make mistakes in the last block of a large section of code. No programming book seems to have discussed this phenomenon, so I decided to write about it myself. I call it the "last line effect".

The Last Line Effect
When programming, programmers often need to write a series of similar structures. Typing line by line is boring and inefficient. That's why they use the "copy-paste" technique: a piece of code is copied and pasted several times, then modified. Everyone knows the downside of this: it's easy to forget to modify something after pasting, eventually breeding bugs. Unfortunately, there is often no better way.
So what pattern did I discover? I found that errors often occur in the last pasted block of code.
Here is a brief example:
inline Vector3int32& operator+=(const Vector3int32& other) {
x += other.x;
y += other.y;
z += other.y;
return *this;
}
Note this line: "z += other.y;". The programmer forgot to replace 'y' with 'z'.
You might think this is a hypothetical example, but it actually comes from a real application. Next, I will convince you that this is a common high-frequency error. Programmers often make this mistake at the end of a series of similar operations.
I've heard that rock climbers often fall in the last few dozen meters. It's not because they are tired, but precisely because they are overexcited about the upcoming end; they imagine the joy of success, become careless, and finally slip. I guess programmers are the same.
Now, let's look at a set of data.
After studying the database, I isolated 84 code fragments generated by the copy-paste technique. In 41 of them, the error occurred in some middle pasted block. For example:
strncmp(argv[argidx], "CAT=", 4) &&
strncmp(argv[argidx], "DECOY=", 6) &&
strncmp(argv[argidx], "THREADS=", 6) &&
strncmp(argv[argidx], "MINPROB=", 8)) {
The length of the string "THREADS=" is 8 characters, not 6.
In the other 43 code fragments, the error occurred in the last pasted block.
Of course, 43 is not much larger than 41. But note that a program may have many similar code blocks, so errors could occur in the first, second, fifth, or even tenth block. Therefore, in the other blocks we have a relatively uniform distribution, while the last block shows a peak.
On average, the total number of similar code blocks is 5.
Thus, 41 errors are uniformly distributed among the first 4 code blocks, with an average of 10 errors per block.
However, the last block contains 43 errors!
The distribution diagram below highlights this phenomenon:

Overview diagram of error distribution in five similar code segments
Therefore, we can summarize a rule:
The probability of making an error in the last pasted code block is 4 times that of other code blocks.
This rule may not be universal. It is just an interesting finding, and its practical value is to remind you to stay vigilant when writing the last block.
Example:
Now I will prove that this is not just my wild imagination but a real trend. Look at the following examples.
Of course, I won't list all examples, only simple and representative ones.
Source Engine SDK
inline void Init( float ix=0, float iy=0,
float iz=0, float iw = 0 )
{
SetX( ix );
SetY( iy );
SetZ( iz );
SetZ( iw );
}
The last line should be SetW().
Chromium
if (access & FILE_WRITE_ATTRIBUTES)
output.append(ASCIIToUTF16("\tFILE_WRITE_ATTRIBUTES\n"));
if (access & FILE_WRITE_DATA)
output.append(ASCIIToUTF16("\tFILE_WRITE_DATA\n"));
if (access & FILE_WRITE_EA)
output.append(ASCIIToUTF16("\tFILE_WRITE_EA\n"));
if (access & FILE_WRITE_EA)
output.append(ASCIIToUTF16("\tFILE_WRITE_EA\n"));
break;
The last two lines are identical.
ReactOS
if (*ScanString == L'\"' ||
*ScanString == L'^' ||
*ScanString == L'\"')
Multi Theft Auto
class CWaterPolySAInterface
{
public:
WORD m_wVertexIDs[3];
};
CWaterPoly* CWaterManagerSA::CreateQuad (....)
{
....
pInterface->m_wVertexIDs [ 0 ] = pV1->GetID ();
pInterface->m_wVertexIDs [ 1 ] = pV2->GetID ();
pInterface->m_wVertexIDs [ 2 ] = pV3->GetID ();
pInterface->m_wVertexIDs [ 3 ] = pV4->GetID ();
....
}
The redundant last line comes from habitual pasting. The size of the array is 3.
Source Engine SDK
intens.x=OrSIMD(AndSIMD(BackgroundColor.x,no_hit_mask),
AndNotSIMD(no_hit_mask,intens.x));
intens.y=OrSIMD(AndSIMD(BackgroundColor.y,no_hit_mask),
AndNotSIMD(no_hit_mask,intens.y));
intens.z=OrSIMD(AndSIMD(BackgroundColor.y,no_hit_mask),
AndNotSIMD(no_hit_mask,intens.z));
The programmer forgot to change "BackgroundColor.y" to "BackgroundColor.z" in the last line.
Trans-Proteomic Pipeline
void setPepMaxProb(....)
{
....
double max4 = 0.0;
double max5 = 0.0;
double max6 = 0.0;
double max7 = 0.0;
....
if ( pep3 ) { ... if ( use_joint_probs && prob > max3 ) ... }
....
if ( pep4 ) { ... if ( use_joint_probs && prob > max4 ) ... }
....
if ( pep5 ) { ... if ( use_joint_probs && prob > max5 ) ... }
....
if ( pep6 ) { ... if ( use_joint_probs && prob > max6 ) ... }
....
if ( pep7 ) { ... if ( use_joint_probs && prob > max6 ) ... }
....
}
The programmer forgot to change "prob > max6" to "prob > max7" in the last condition.
SeqAn
inline typename Value<Pipe>::Type const & operator*() {
tmp.i1 = *in.in1;
tmp.i2 = *in.in2;
tmp.i3 = *in.in2;
return tmp;
}
SlimDX
for( int i = 0; i < 2; i++ )
{
sliders[i] = joystate.rglSlider[i];
asliders[i] = joystate.rglASlider[i];
vsliders[i] = joystate.rglVSlider[i];
fsliders[i] = joystate.rglVSlider[i];
}
The last line should use rglFSlider.
Qt
if (repetition == QStringLiteral("repeat") ||
repetition.isEmpty()) {
pattern->patternRepeatX = true;
pattern->patternRepeatY = true;
} else if (repetition == QStringLiteral("repeat-x")) {
pattern->patternRepeatX = true;
} else if (repetition == QStringLiteral("repeat-y")) {
pattern->patternRepeatY = true;
} else if (repetition == QStringLiteral("no-repeat")) {
pattern->patternRepeatY = false;
pattern->patternRepeatY = false;
} else {
//TODO: exception: SYNTAX_ERR
}
The last block is missing 'patternRepeatX'. The correct code should be:
pattern->patternRepeatX = false; pattern->patternRepeatY = false;
ReactOS
const int istride = sizeof(tmp[0]) / sizeof(tmp[0][0][0]); const int jstride = sizeof(tmp[0][0]) / sizeof(tmp[0][0][0]); const int mistride = sizeof(mag[0]) / sizeof(mag[0][0]); const int mjstride = sizeof(mag[0][0]) / sizeof(mag[0][0]);
'mjstride' always equals 1. The last line should be:
const int mjstride = sizeof(mag[0][0]) / sizeof(mag[0][0][0]);
Mozilla Firefox
if (protocol.EqualsIgnoreCase("http") ||
protocol.EqualsIgnoreCase("https") ||
protocol.EqualsIgnoreCase("news") ||
protocol.EqualsIgnoreCase("ftp") || <<<---
protocol.EqualsIgnoreCase("file") ||
protocol.EqualsIgnoreCase("javascript") ||
protocol.EqualsIgnoreCase("ftp")) { <<<---
The final "ftp" is suspicious; it has already been compared before.
Quake-III-Arena
if (fabs(dir[0]) > test->radius ||
fabs(dir[1]) > test->radius ||
fabs(dir[1]) > test->radius)
The programmer forgot to check the value of dir
Clang
return (ContainerBegLine <= ContaineeBegLine &&
ContainerEndLine <= ContaineeEndLine &&
(ContainerBegLine != ContaineeBegLine ||
SM.getExpansionColumnNumber(ContainerRBeg) <=
SM.getExpansionColumnNumber(ContaineeRBeg)) &&
(ContainerEndLine != ContaineeEndLine ||
SM.getExpansionColumnNumber(ContainerREnd) >=
SM.getExpansionColumnNumber(ContainerREnd)));
In the last block, the expression "SM.getExpansionColumnNumber(ContainerREnd)" is being compared with itself.
MongoDB
bool operator==(const MemberCfg& r) const {
....
return _id==r._id && votes == r.votes &&
h == r.h && priority == r.priority &&
arbiterOnly == r.arbiterOnly &&
slaveDelay == r.slaveDelay &&
hidden == r.hidden &&
buildIndexes == buildIndexes;
}
The programmer forgot the 'r' in the last line.
Unreal Engine 4
static bool PositionIsInside(....)
{
return
Position.X >= Control.Center.X - BoxSize.X * 0.5f &&
Position.X <= Control.Center.X + BoxSize.X * 0.5f &&
Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f &&
Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f;
}
In the last line, the programmer forgot two things. First, ">=" should be changed to "<=", and second, the minus sign should be changed to a plus sign.
Qt
qreal x = ctx->callData->args[0].toNumber();
qreal y = ctx->callData->args[1].toNumber();
qreal w = ctx->callData->args[2].toNumber();
qreal h = ctx->callData->args[3].toNumber();
if (!qIsFinite(x) || !qIsFinite(y) ||
!qIsFinite(w) || !qIsFinite(w))
In the last qlsFinite, the argument passed should be 'h'.
OpenSSL
if (!strncmp(vstart, "ASCII", 5)) arg->format = ASN1_GEN_FORMAT_ASCII; else if (!strncmp(vstart, "UTF8", 4)) arg->format = ASN1_GEN_FORMAT_UTF8; else if (!strncmp(vstart, "HEX", 3)) arg->format = ASN1_GEN_FORMAT_HEX; else if (!strncmp(vstart, "BITLIST", 3)) arg->format = ASN1_GEN_FORMAT_BITLIST;
The string "BITLIST" has a length of 7, not 3.
Let's stop here. The examples I've given are enough to make the point, right?
Conclusion
This article tells you that the copy-paste technique is likely to have a 4 times higher probability of error in the last pasted code block than in other blocks.
This is related to human psychology, not technical skill. The article shows that even experienced programmers in projects like Clang or Qt make this kind of mistake.
I hope this discovery of the phenomenon is helpful to programmers, and perhaps it will encourage them to study our bug database. I believe this will help find new patterns in these errors and summarize new programming recommendations.
This article is reproduced from: http://www.vaikan.com/the-last-line-effect/