Challenge

C/C++ 提供了直接操作内存的强壮才能,但是运用不当也会招致许多问题,下面是 Google chromium 团队的一组统计数据:

“Around 70% of our high severity security bugs are memory unsafety problems (that is, mistakes with C/C++ pointers). Half of those are use-after-free bugs.”

Sanitizers 系列之 Sanitizers 概述

与内存相关的问题往往排查难度较大,耗时较多。网易云信的 IM、RTC 等 SDK 都是运用 C/C++ 来进行开发的,作为软件供应商,网易云信面临的应战更大:

  • 需求支撑更多的操作系统;
  • 需求支撑更多的开发框架

上述应战促进我们运用更强壮、更通用的 Sanitizer 东西来帮助工程师快速排查与定位内存问题,提高生产力,本系列文章共四篇,旨在向读者介绍网易云信的工程实践,本文为第一篇。

Sanitizers 简介

Sanitizers 是由 Google 研制团队提出的用于检测 C/C++ 程序常见内存过错的东西集,Google 工程师公开了它们的源代码和算法:

github.com/google/sani…

并在 LLVM clang 上完成,它们已经被用于多个工程中。比方 Chromium、Firefox 等闻名项目中。

下表汇总整理了 Sanitizers 的各个东西和它们的作用:

Sanitizers 系列之 Sanitizers 概述

从表格的内容能够看出,Sanitizers 除了能够检测内存过错外,还能够检测一些其它常见的过错。后面笔者将分章节介绍上述几种 Sanitizer 的用法与原理。

Sanitizers 的优势

当时市面上存在着多种用于检测内存过错的东西,在投入生产运用之前,能够从如下维度来评估:

Sanitizers 系列之 Sanitizers 概述

在后续介绍各种 Sanitizer 东西时,会从上述几个维度进行介绍。Sanitizer 并不是第一个被发明出来用于检测内存过错的东西,在它之前,同类的东西已经十分多了,Sanitizer 其实是在前人的成果上改善加创新而来,因而它在上述几个方面比起同类东西有着优势。

Sanitizers 具有如下优势:

  • 与 Compiler 集成,干流 IDE 都提供了不同程度的集成,因而运用起来相对简略;
  • 现在干流 OS 的 Compiler 都能够不同程度上支撑 Sanitizer,其通用性更强,因而关于需求跨平台的项目而言,它具有很大的优势;
  • 相比同类东西,可用性更强,成本更低;
  • 才能更强,能够检测的过错类型较多,确诊信息十分准确,能够帮助快速定位问题。

干流编译器对 Sanitizers 的支撑状况

现在干流编译器都在必定程度上支撑 Sanitizers,本节整理了 clang、GCC、MSVC 这三款干流编译器对 Sanitizers 的支撑状况。

  • LLVM clang

    Google 工程师开始在 LLVM clang上完成了 Sanitizers,LLVM clang 对各种 Sanitizer 支撑十分全面,详细能够拜见 LLVM clang 的官方文档:

Sanitizers 系列之 Sanitizers 概述

  • Apple clang

    需求注意的是,Apple clang 是依据 LLVM clang 但是不是完全照搬 LLVM clang,两者是存在区别的。现在 Apple clang 不支撑 lsan,支撑其它几种 Sanitizer,macOS 的 Instruments 东西提供了检测 Memory leakage 的才能。

  • MSVC

    现在 MSVC 仅支撑 asan,不支撑检测 use-after-return 类过错,从实践来看,MSVC 在敞开 asan 后,在一些特定状况下会呈现比较古怪的问题,用户能够考虑设计编译器版别。

    更多内容拜见:

    github.com/google/sani…

  • GCC

    从实践和 GCC 支撑的编译选项来看,GCC 不支撑 msan,支撑其它几种 Sanitizer。

    更多内容拜见:

    gcc.gnu.org/onlinedocs/…

What every programer should know about memory

在介绍正式的内容之前,我们一同回顾一下关于 Memory 的常识。

Virtual memory

当今 OS 普遍选用 Virtual memory 技术,下图形象地展现了 Virtual memory。

Sanitizers 系列之 Sanitizers 概述

上图源自:

en.wikipedia.org/wiki/File:P…

Process memory address space

下图展现进程的地址空间布局:

Sanitizers 系列之 Sanitizers 概述

上图源自:

en.wikipedia.org/wiki/File:P…

Memory error 分类

Memory error 的分类有多种,下表是依据 Sanitizer 东西的才能区分的一种分类方法:

Sanitizers 系列之 Sanitizers 概述

在后面的章节中,对每一类过错都会进行详细介绍,并提供详细的比如。

更多关于 Memory 的常识,拜见:

  • en.wikipedia.org/wiki/Memory…

  • en.wikipedia.org/wiki/Virtua…

  • people.freebsd.org/~lstewart/a…

C++ 言语标准对 Memory 的笼统

C++ 作为一门能够直接操作内存的言语,它的标准在言语层面临 Memory 进行笼统,概括的说,每个 C++ object 会占用一片内存区域,依据 C++ object 所在的内存位置对 object 的分类如下:

Sanitizers 系列之 Sanitizers 概述

上面表格中运用的“storage”术语其实是 C++ 言语标准运用的,读者能够拜见:

en.cppreference.com/w/cpp/langu…

这个术语所表达的其实是 object 所占用的内存。本系列后续的文章将会对heap objectstack objectglobal object的不同类型的内存过错进行介绍。

C++ 言语标准对object lifetime 进行了标准,概括地说,一个 C++object lifetime 如下:

Sanitizers 系列之 Sanitizers 概述

C++ 标准明确指出“access outside of object lifetime”是过错的 读者能够拜见:

en.cppreference.com/w/cpp/langu…

由于每个 C++ object 对应一片内存区域,这提示我们能够从 object lifetime 的角度来分析 Memory error,在这里能够提前告知读者,后面行将介绍的很多内存过错都能够归入“access outside of lifetime”领域。

后续将持续推出 Sanitizers 系列文章之 Address Sanitizer 用法篇、Address Sanitizer 原理篇、Leak Sanitizer 介绍等相关文章,请大家持续关注。

参考资料

  • Memory safety: www.chromium.org/Home/chromi…
  • Introduction to Memory Unsafety for VPs of Engineering: alexgaynor.net/2019/aug/12…
  • AddressSanitizerComparisonOfMemoryTools: github.com/google/sani…
  • en.cppreference.com/w/cpp/langu…