PVS-Studio 7.34 版本在分析器中引入了一系列新的诊断规则:Java 的污点分析、C# 的 Unity 特定诊断规则、深入研究 OWASP 等等!本文将涵盖所有这些。
在此版本中,C 团队重点关注通用分析诊断规则以及对各种软件开发标准的支持。
但是请戴好帽子,这只是开始!该团队计划涵盖更多 MISRA 标准诊断规则,敬请关注更多新闻:)
现在,我们来看看 7.34 版本中的主要规则。
此诊断规则旨在检测在没有解释消息的情况下创建的异常。
缺少消息可能会阻碍错误检测和修复的过程,以及整体代码的可读性。
以下是使 PVS-Studio 分析器生成警告的代码示例:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
如果发生错误,SomeCheck 函数会抛出一个带有空消息的异常,该异常将在 Foo 函数中处理。在处理过程中,std::cerr 应该包含有关异常原因的信息,但事实并非如此。
通过这种方式编写代码,开发人员向同事传达了“调试愉快”的愿望。这阻碍了理解到底是什么导致了失败。
该规则适用于标准例外。您可以使用自定义注释机制对自定义异常发出警告。
查看文档以了解有关此诊断规则的更多详细信息。
此诊断规则仅适用于C语言。
它的目的是检测使用 const 或 volatile 限定符的函数类型定义的情况。
根据 C23 标准(第 6.7.4.1 段第 10 点),使用这些类型会导致未定义的行为。
使 PVS-Studio 分析器生成警告的代码示例:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
查看文档以了解有关此诊断规则的更多详细信息。
C 语言的另一个诊断规则,可以在重构和调试时提供帮助。
此规则使分析器能够检测整数类型到枚举类型的隐式转换。
带有 PVS-Studio 警告的代码示例:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
此代码使用条件运算符 (?:) 在两个整型变量 posOne 和 posTwo 之间进行选择,从而产生隐式强制转换。
查看文档以了解有关此诊断规则的更多详细信息。
这是一个专注于安全性的新诊断规则,与 SAST 原则保持一致。
该规则是根据OWASP安全验证标准设计的。
它的目的是检测过时的加密函数的调用。它们的使用可能会导致严重的软件安全问题。
带有 PVS-Studio 警告的代码示例:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
根据 Microsoft 文档,CryptoImportKey 和 CryptoDestroyKey 函数已弃用。这些应该替换为下一代密码学的安全对应项(BCryptoImportKey 和 BCryptoDestroyKey)。
查看文档以了解有关此诊断规则的更多详细信息。
但这只是热身! C 和 C 团队计划涵盖各种软件开发标准的更多诊断规则。我们将特别关注 MISRA 标准。所以,等待消息吧:)
在新的 PVS-Studio 7.34 版本中,C# 团队专注于创建特定于 Unity 的诊断规则,但也没有忘记通用分析规则。
让我们从后者开始。
这个新的诊断规则旨在检测非 A 或 B 模式的错误使用。该问题源于开发者对操作优先级的混淆。
带有 PVS-Studio 警告的代码示例:
Orientation GetOrientation (bool b) { int posOne = 1; int posTwo = 2; return b ? posOne : posTwo; // V2022 }
在方法开始时,检查输入参数键是否为空字符串或 null。
但是条件表达式的逻辑有错误。 not 运算符的优先级高于 or 运算符。因此,否定不适用于表达式的右侧。另外,如果 key 设置为 null,则条件将为 true。
查看文档以了解有关此诊断规则的更多详细信息。
这是一系列新的 Unity 特定规则中的第一个诊断规则。
它的目的是检测 UnityEngine.Object(或从它继承的其他对象)与 System.WeakReference 的使用。
由于引擎本身隐式使用实例,弱引用的行为可能与预期不同。
带有 PVS-Studio 警告的代码示例:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
在示例中,我们可以看到对 GameObject 类的对象的弱引用。即使作者没有创建对此对象的强引用,垃圾收集器也无法清理它。
查看文档以了解有关此诊断规则的更多详细信息。
在 Unity 的另一个诊断规则中,分析器通过等待运算符搜索多次使用同一 UnityEngine.Awaitable 对象的位置。
出于优化目的,对象存储在对象池中。
在等待调用时,Awaitable 对象将返回到池中。之后,如果再次将await应用于同一个对象,我们会得到一个异常。在某些情况下,也可能出现死锁。
带有 PVS-Studio 警告的代码示例:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
在此代码中,我们遇到异常或死锁。让我解释一下原因。我们使用awaitable 的await 调用获取一个值。然后我们用这个值初始化结果变量。发生死锁是因为await 之前已在条件构造中应用于awaitable。
查看文档以了解有关此诊断规则的更多详细信息。
此诊断规则旨在检测与调用 UnityEngine.Object 类的 Destroy 或 DestroyImmediate 方法相关的异常。
该问题发生在使用 UnityEngine.Transform 类型的参数的情况下。这会导致方法调用期间出现错误。 Unity 中不允许从游戏对象中删除 Transform 组件。
带有 PVS-Studio 警告的代码示例:
Orientation GetOrientation (bool b) { int posOne = 1; int posTwo = 2; return b ? posOne : posTwo; // V2022 }
MonoBehaviour 基类的transform 属性返回Transform 类的一个实例,该实例作为参数传递给Destroy 方法。
以这种方式调用该方法时,Unity会给出错误信息,但组件本身不会被销毁。
查看文档以了解有关此诊断规则的更多详细信息。
此诊断规则针对不同范围的错误 - 性能问题。
如果您对静态分析如何帮助优化 Unity 项目感兴趣,我邀请您阅读这篇文章。
此规则的目的是帮助分析器检测频繁执行的方法中 Unity 对象的创建。
定期创建/销毁游戏对象不仅会增加CPU的负载,还会导致垃圾收集器调用频率增加。这会影响性能。
带有 PVS-Studio 警告的代码示例:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
在Update方法中,创建并销毁了一个游戏对象_instance。由于每次更新帧时都会执行 Update,因此建议尽可能避免其中的这些操作。
查看文档以了解有关此诊断规则的更多详细信息。
顺便说一句,其他 Unity 诊断尚未推出!准备好迎接我们团队的好消息吧:)
我们不得不告诉您 C# 分析器的一项重要增强功能 - 跟踪调用之间方法返回值的变化。它改变了什么?让我们来分解一下。
看看这个例子:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
Example() 方法检查 Foo() 的返回值是否为 null。然后在条件体中再次调用 Foo() 方法,并且其返回值被取消引用。
之前,分析器在这种情况下会生成警告,因为它没有考虑调用的上下文,只关注其声明的代码。分析器曾经暗示可以返回 null。
现在分析器知道 Foo() 在两种情况下返回相同的值,并且不会出现警告。
但是让我们看一个代码稍作修改的示例...
Orientation GetOrientation (bool b) { int posOne = 1; int posTwo = 2; return b ? posOne : posTwo; // V2022 }
从 Foo() 方法声明中我们可以知道,当 _condition == true 时,该方法返回非 null。
分析器将在第二次调用之前看到 _condition 字段发生变化,并做出假设:如果 Foo() 内部使用的字段发生变化,则 Foo() 的返回值也可能发生变化。
因此,潜在取消引用的警告将保留。
C# 分析器现在支持分析 .NET 9 项目!在此处详细了解 PVS-Studio 7.34 中的这些功能和其他新功能。
随着 PVS-Studio 7.34 的发布,Java 分析器现在有了污点分析机制!
该机制成为第一个诊断规则——搜索 SQL 注入的基础。 Java 分析器的未来更新将重点关注 SAST、OWASP Top-10 最常见潜在漏洞列表以及其他与污点相关的诊断规则。
现在,让我们从一些新的一般分析规则开始,因为它们也很有价值。
这个新的诊断规则突出显示了代码中未使用后缀运算值的区域。
问题在于,要么操作是多余的,或者更严重的是,操作混淆了,开发人员想要使用前缀一。
带有 PVS-Studio 警告的代码示例:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
运算符不会影响calculateSomething方法返回的值。
查看文档以了解有关此诊断规则的更多详细信息。
从这个诊断规则的名称可以看出,它检测到可能的溢出。
带有 PVS-Studio 警告的代码示例:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
给整型变量赋值超出了有效范围,会导致溢出。
变量显然会存储与开发人员尝试分配的值不同的值。
查看文档以了解有关此诊断规则的更多详细信息。
此诊断有助于识别同步问题。
带有 PVS-Studio 警告的代码示例:
Orientation GetOrientation (bool b) { int posOne = 1; int posTwo = 2; return b ? posOne : posTwo; // V2022 }
分析器发现wait、notify和notifyAll方法,因为它们可能在不同步的上下文中被调用。它们与发生同步的对象的监视器一起操作。也就是说,它们的调用仅在同步上下文中并且仅在发生同步的对象上才是正确的。
如果在不同步的上下文中或错误的对象上调用 wait、notify 或 notifyAll 方法,我们会收到 IllegalMonitorStateException 异常。
查看文档以了解有关此诊断规则的更多详细信息。
Java分析器的第一个与污点相关的诊断规则!更具体地说,分析器现在可以检测潜在的 SQL 注入。
SQL 注入是一个漏洞,允许攻击者将其代码注入 SQL 查询中。如果查询使用外部数据而没有正确验证它,则会面临数据库中存储信息的完整性和机密性的风险。
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
如果用户被证明是恶意的,并且参数的值大约如下:-“111'或1=1;删除表用户;选择'”,—您可以告别用户表。因此,检查外部数据很重要。
查看文档以了解有关此诊断规则的更多详细信息。
感谢您的阅读!
如果您有文章或问题的请求,请随时通过反馈表发送。最后但并非最不重要的一点是,我们很乐意在评论中听到您的想法:)
以上是PVS-Studio 4 中的新诊断规则的详细内容。更多信息请关注PHP中文网其他相关文章!