通过代码静态工具检查看编码细节
发布日期:2021-06-29 14:42:44 浏览次数:3 分类:技术文章

本文共 2667 字,大约阅读时间需要 8 分钟。

个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

近来做代码静态检视,发现除了比较严重的内存泄漏、逻辑错误等问题外,代码的细节、规范性问题很多。 

静态工具检查出的点,经不起推敲,会发现代码逻辑中确实有许多不严谨的地方。 

1.  在null 检查前解引用

如下面的例子:pT != nullptr判空前,已经有使用pT->a()了,判空就不起作用了,如果有异常,已经崩溃了。

class TestClass

{

   int a;

   int b;

};

 

TestClass* pT = getTestClass();

int c = pT->a();

if (pT != nullptr)

{

  …

}

 

2.  在null 检查后解引用

如下面的例子:

pT != nullptr判空后做了某些处理;但在随后的处理中,再使用pT时,没有做判空处理。

在这种情况下,如果pT为空,就会崩溃在下面,判空处理的范围没有覆盖全。

TestClass* pT = getTestClass();

if (pT != nullptr)

{

  …

}

int c = pT->a;

 

3. 

这种不易察觉,在某个分支对元素赋值,另一分支未赋值,这种情况对于未赋值情况可能会出现崩溃。

如下面的例子:

TestClass* pT = nullptr;

if (y == 0)

{

   pT = getTestClass();

}

int c = pT->a;

 

4.  逻辑死代码

有简单的,例如这种,最后一行无论如何走不进来:

if (xxx)

{

   return 1;

}

else

{

  return 0;

}

return 0;

 

逻辑上自相矛盾的地方,例如上面if包含的逻辑,else又做判定,如下面这种

if (pA == nullptr || pB == nullptr)

{

   b = 1;

}

else

{

   if (pB == nullptr)

   {

      do something

   }

}

 

 

 

5.  未检查的 dynamic_cast

我们已知dynamic_cast对于类型是会做相应的检查,如果类型不在范围内的话,会返回false的,可是对于dynamic_cast,我们有时没有对返回的值做结果判定,这就有一定风险了;

 

例如:下面的show1,show2没有做dynamic_cast结果判定,当传入的值不是对应类型的时候,就会产生崩溃了。

class A

{};

class B : publice A

{void showB();};

class C: public A

{void showC();};

void show1(A* pA)

{

B* pB = dynamic_cast<B*>(pA);

pB->showB();

}

void show2(A* pA)

{

B* pC = dynamic_cast<C*>(pA);

pC->showC();

}

 

 

6.  混合了枚举类型

枚举类型,一般我们使用的时候,是各个对应各个的,但有时,因为值一样,我们可能就存在混用的情况。这个也是一种风险。

 

例如:getTypeA() 定义的返回是EnumTypeA,但判断时,使用了enumBDefault,虽然值是一样,但类型实际是不对应的,存在风险,万一哪天改了呢。

 

enum EnumTypeA

{

   enumADefault = -1,

   enumA1 = 0

};

enum EnumTypeB

{

   enumBDefault = -1;

   enumB1 = 0

};

 

EnumTypeA getTypeA()

{…}

 

if (getTypeA() == enumBDefault)

{

  do something

}

 

 

7.  未初始化的标量字段

对于int/boo/指针/double等基本的数据类型,都是没有构造函数的,如果在struct/class中定义了,构造函数都需要赋值的,否则就会存在随机的情况。

 

例如下面的例子,getA函数,访问了TestClass p->a变量,a变量是有初值的,但是b变量是没有初值的,b的值实际上是随机的,这种情况就是一种潜在的风险。

我们无法确保所有的类似getA函数(当前不使用b)未来不会使用b变量作为参考。而且随机变量传递本身也是不建议出现的,好的做法是在class构造函数中,把基本数据类型变量都初始化了。

class TestClass

{

   int a;

   int b;

   void * p

   TestClass : p(nullptr), a(0){}

};

 

void getA(TestClass* p)

{

  return p->a;

};

 

TestClass* pT = getTestClass();

int c = getA(pT);

 

 

8.  赋值而不是比较

从标题上就可以看出,问题比较清晰

例如:放入if语句的是一个赋值语句,这种一般都是写错了。

if (n = 0)

{

   do something;

};

 

9.  (如 &&与||用错)

问题也比较清晰

例如:两处都是有问题的,第一处if判定恒true,第二处恒false

if (n != 0 || n != 1)

{

   do something;

};

 

if (n == 0 && n == 1)

{

   do something

}

 

 

10.

出现 if (pT != nullptr && pT != nullptr)这种情况,这种情况通常是想写别的。

 

如下面的例子:

if 中使用 pT1 != nullptr判断两次,但从上下文看,实际是也想判定pT2 != nullptr,这种情况是我们需要注意的。

TestClass* pT1 = getTestClass(xx);

TestClass* pT2 = getTestClass(yy);

if (pT1 != nullptr && pT1 != nullptr)

{

   pT1 do something

   pT2 do something

}

 

11. 适用于不同分支的相同代码

if与else的内容一致

 

例如:这种是if/else的处理一致,那还用if判定就没有意义了

if (a == 0)

{

   b = 1;

}

else

{

   b = 1;

}

 

个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

转载地址:https://chunyexiyu.blog.csdn.net/article/details/78220210 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:输出宏的输入变量名称和内容样例
下一篇:windows补丁卸载失败的处理

发表评论

最新留言

很好
[***.229.124.182]2024年04月24日 16时28分16秒