设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

编程中的“末行效应”

2014-11-18 10:32| 发布者: joejoe0332| 查看: 1747| 评论: 0|原作者: Ryan Chen|来自: vaikan.com

摘要: 我研究过数百个因“拷贝-粘贴”导致的错误。可以肯定的是,程序员常常会在一大段代码的最后一段里犯错。好像还没有任何编程书讨论过这种现象,因此我决定自己写点什么。我称之为“末行效应”。 ...


Chromium

1
2
3
4
5
6
7
8
9
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;

  最后两行相同。


ReactOS

1
2
3
if (*ScanString == L'\"' ||
    *ScanString == L'^' ||
    *ScanString == L'\"')


Multi Theft Auto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 ();
  ....
}

  最后一行冗余代码来自于惯性粘贴。数组的大小是3。


Source Engine SDK

1
2
3
4
5
6
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));

  程序员忘记把最后一行的中的“BackgroundColor.y”改成“BackgroundColor.z”。


Trans-Proteomic Pipeline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 ) ... }
  ....
}

  程序员忘记把最后一个判断中的“prob > max6”改为“prob > max7”。


SeqAn

1
2
3
4
5
6
inline typename Value<Pipe>::Type const & operator*() {
  tmp.i1 = *in.in1;
  tmp.i2 = *in.in2;
  tmp.i3 = *in.in2;
  return tmp;
}


SlimDX

1
2
3
4
5
6
7
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];
}

  最后一行应该用rglFSlider。


Qt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
}

  最后一块少了‘patternRepeatX’。正确的代码应该是:

1
2
pattern->patternRepeatX = false;
pattern->patternRepeatY = false;


ReactOS

1
2
3
4
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’永远等于1。最后一行应该是:

1
const int mjstride = sizeof(mag[0][0]) / sizeof(mag[0][0][0]);


Mozilla Firefox

1
2
3
4
5
6
7
if (protocol.EqualsIgnoreCase("http") ||
    protocol.EqualsIgnoreCase("https") ||
    protocol.EqualsIgnoreCase("news") ||
    protocol.EqualsIgnoreCase("ftp") ||          <<<---
    protocol.EqualsIgnoreCase("file") ||
    protocol.EqualsIgnoreCase("javascript") ||
    protocol.EqualsIgnoreCase("ftp")) {          <<<---

  最后的“ftp”很可疑,它之前已经被比较过了。


Quake-III-Arena

1
2
3
if (fabs(dir[0]) > test->radius ||
    fabs(dir[1]) > test->radius ||
    fabs(dir[1]) > test->radius)

dir[2]的值忘记检查了。


Clang

1
2
3
4
5
6
7
8
return (ContainerBegLine <= ContaineeBegLine &&
        ContainerEndLine <= ContaineeEndLine &&
        (ContainerBegLine != ContaineeBegLine ||
         SM.getExpansionColumnNumber(ContainerRBeg) <=
         SM.getExpansionColumnNumber(ContaineeRBeg)) &&
        (ContainerEndLine != ContaineeEndLine ||
         SM.getExpansionColumnNumber(ContainerREnd) >=
         SM.getExpansionColumnNumber(ContainerREnd)));

  最后一块,“SM.getExpansionColumnNumber(ContainerREnd)”表达式在跟自己比较大小。


MongoDB

1
2
3
4
5
6
7
8
9
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;
}

  程序员把最后一行的“r”忘记了。


Unreal Engine 4

1
2
3
4
5
6
7
8
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;
}

  最后一行中,程序员忘记了两个地方。首先,“>=”应改为“<=”,其次,减号应改为加号。


Qt

1
2
3
4
5
6
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))

  最后一个qlsFinite中,传入参数应该是‘h’。

OpenSSL

1
2
3
4
5
6
7
8
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;

  字符串“BITLIST”长度为7,而非3。

  就此打住吧。我举的例子已经够说明问题了吧?


结论

  本文告诉你“拷贝-粘贴”大法在最后一个粘贴代码块中出错的概率很可能是其他块的4倍。


  这跟人类的心理学有关,与技术水平无关。文中说明了即便是像Clang或者Qt项目中的编程高手也会犯这种错误。


  我希望这个现象的发现对于程序员们有所帮助,也许可以促使他们去研究我们的bug数据库。相信如此有助于在这些错误中发现新的规律并总结出新的编程建议。


酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部