{"id":395984,"date":"2024-06-29T12:33:40","date_gmt":"2024-06-29T12:33:40","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=395984"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T12:33:40","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=395984","title":{"rendered":"<span>Checking the Code of DeepSpeech, or Why You Shouldn&#8217;t Write in namespace std<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">DeepSpeech is an open-source speech recognition engine developed by Mozilla. It&#8217;s pretty fast and ranks high, which makes its source code an interesting target for static analysis. In this article, I&#8217;ll show you some of the bugs found in DeepSpeech&#8217;s C++ code. <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/5ad\/5d0\/076\/5ad5d0076af2293cc7c41dc5db49f05b.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/5ad\/5d0\/076\/5ad5d0076af2293cc7c41dc5db49f05b.png\"\/><\/div>\n<p>  <\/p>\n<h2>Introduction<\/h2>\n<p>  We have already scanned a few projects based on machine learning before, so there was nothing new about <a href=\"https:\/\/github.com\/mozilla\/DeepSpeech\">DeepSpeech<\/a> to us in this respect. No wonder since the project is quite popular: as of this writing, it has 15k stars on GitHub.<br \/>  <a name=\"habracut\"><\/a><br \/>  As usual, the bugs discussed in this article have been found using the static code analyzer PVS-Studio.<\/p>\n<p>  DeepSpeech employs the TensorFlow library. I excluded the library&#8217;s code from analysis because we already made a <a href=\"https:\/\/www.viva64.com\/en\/b\/0497\/\">separate article<\/a> about it, but I left analysis enabled for all the other libraries used by DeepSpeech. Why? Because any bugs that sit in any of the libraries included into your project become bugs in your project. That&#8217;s why it makes sense to scan not only your own code but also any third-party code that you include. We gave a detailed argument for this approach in <a href=\"https:\/\/www.viva64.com\/en\/b\/0762\/\">our recent article<\/a>.<\/p>\n<p>  That&#8217;s all for the introduction \u2013 let&#8217;s move on to the bugs. By the way, if you are here to find out the answer to the question mentioned in the title (why you shouldn&#8217;t write in namespace std), you can skip straight over to the end of the article. There you&#8217;ll find an especially tasty example!<\/p>\n<h2>10 interesting warnings by PVS-Studio<\/h2>\n<p>  <b>Warning 1<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v773\/\">V773<\/a> The function was exited without releasing the &#8216;data&#8217; pointer. A memory leak is possible. edit-fst.h 311<\/p>\n<pre><code class=\"cpp\">\/\/ EditFstData method implementations: just the Read method. template &lt;typename A, typename WrappedFstT, typename MutableFstT> EditFstData&lt;A, WrappedFstT, MutableFstT> * EditFstData&lt;A, WrappedFstT, MutableFstT>::Read(std::istream &amp;strm,                                                const FstReadOptions &amp;opts) {   auto *data = new EditFstData&lt;A, WrappedFstT, MutableFstT>();   \/\/ next read in MutabelFstT machine that stores edits   FstReadOptions edits_opts(opts);    ....      std::unique_ptr&lt;MutableFstT> edits(MutableFstT::Read(strm, edits_opts));   if (!edits) return nullptr; \/\/ &lt;=    .... }<\/code><\/pre>\n<p>  This snippet is a classic example of a memory leak: the <i>Read<\/i> function calls &#8216;<i>return nullptr<\/i>&#8216; without having first freed the memory allocated earlier using the &#8216;<i>new EditFstData<\/i>&#8216; expression. When the function returns in a way like that (without calling <i>delete data<\/i>), only the pointer itself will be deleted, without calling the destructor of the object that it points at. Thus, the object will stay in memory and you won&#8217;t be able to delete or use it. <\/p>\n<p>  Besides the bug, this snippet also uses another poor practice: one function handles both smart and regular pointers at the same time. If, for example, <i>data<\/i> were a smart pointer too, no such error would have occurred: when necessary, smart pointers will automatically call the destructor of the allocated object upon leaving the scope.<\/p>\n<p>  <b>Warning 2<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v1062\/\">V1062<\/a> The &#8216;DfsState&#8217; class defines a custom &#8216;new&#8217; operator. The &#8216;delete&#8217; operator must also be defined. dfs-visit.h 62<\/p>\n<pre><code class=\"cpp\">\/\/ An FST state's DFS stack state. template &lt;class FST> struct DfsState { public:   ....   void *operator new(size_t size,                       MemoryPool&lt;DfsState&lt;FST>> *pool) {     return pool->Allocate();   }   .... }<\/code><\/pre>\n<p>  PVS-Studio never stops evolving and acquiring new diagnostics. The code above is a perfect example for showcasing one such new diagnostic, <a href=\"https:\/\/www.viva64.com\/en\/w\/v1062\/\">V1062<\/a>.<\/p>\n<p>  The rule behind it is simple: if you define your own &#8216;new&#8217; operator, you must also define your own &#8216;delete&#8217; operator. Likewise, if you define your own &#8216;delete&#8217; operator, you must also define your own &#8216;new&#8217;.<\/p>\n<p>  This rule was broken in this example: an object is created using a user-defined &#8216;new&#8217; operator but deleted using the standard &#8216;delete&#8217;. Let&#8217;s see what the <i>Allocate<\/i> function of the class <i>MemoryPool<\/i> does when it&#8217;s called by the user-defined &#8216;new&#8217;:<\/p>\n<pre><code class=\"cpp\">void *Allocate() {   if (free_list_ == nullptr) {     auto *link = static_cast&lt;Link *>(mem_arena_.Allocate(1));     link->next = nullptr;     return link;   } else {     auto *link = free_list_;     free_list_ = link->next;     return link;   } }<\/code><\/pre>\n<p>  This function creates an element and adds it to a linked list. Implementing such allocation in your own &#8216;new&#8217; makes sense. <\/p>\n<p>  But wait! Just a few lines later, you see the following function:<\/p>\n<pre><code class=\"cpp\">void Free(void *ptr) {   if (ptr) {     auto *link = static_cast&lt;Link *>(ptr);     link->next = free_list_;     free_list_ = link;   } }<\/code><\/pre>\n<p>  So, they already have ready-made functions both for allocation and deallocation. The programmer probably intended to write their own &#8216;delete&#8217; operator using this <i>Free()<\/i> function for deallocation.<\/p>\n<p>  The analyzer found at least three more errors of this type:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/V1062\/\">V1062<\/a> The &#8216;VectorState&#8217; class defines a custom &#8216;new&#8217; operator. The &#8216;delete&#8217; operator must also be defined. vector-fst.h 31<\/li>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/V1062\/\">V1062<\/a> The &#8216;CacheState&#8217; class defines a custom &#8216;new&#8217; operator. The &#8216;delete&#8217; operator must also be defined. cache.h 65<\/li>\n<\/ul>\n<p>  <b>Warning 3<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v703\/\">V703<\/a> It is odd that the &#8216;first_path&#8217; field in derived class &#8216;ShortestPathOptions&#8217; overwrites field in base class &#8216;ShortestDistanceOptions&#8217;. Check lines: shortest-path.h:35, shortest-distance.h:34. shortest-path.h 35<\/p>\n<pre><code class=\"cpp\">\/\/ Base class template &lt;class Arc, class Queue, class ArcFilter> struct ShortestDistanceOptions {   Queue *state_queue;    \/\/ Queue discipline used; owned by caller.   ArcFilter arc_filter;  \/\/ Arc filter (e.g., limit to only epsilon graph).   StateId source;        \/\/ If kNoStateId, use the FST's initial state.   float delta;           \/\/ Determines the degree of convergence required   bool first_path;       \/\/ For a semiring with the path property (o.w.                          \/\/ undefined), compute the shortest-distances along                          \/\/ along the first path to a final state found                          \/\/ by the algorithm. That path is the shortest-path                          \/\/ only if the FST has a unique final state (or all                          \/\/ the final states have the same final weight), the                          \/\/ queue discipline is shortest-first and all the                          \/\/ weights in the FST are between One() and Zero()                          \/\/ according to NaturalLess.    ShortestDistanceOptions(Queue *state_queue, ArcFilter arc_filter,                           StateId source = kNoStateId,                           float delta = kShortestDelta)       : state_queue(state_queue),         arc_filter(arc_filter),         source(source),         delta(delta),         first_path(false) {} }; \/\/ Derived class template &lt;class Arc, class Queue, class ArcFilter> struct ShortestPathOptions     : public ShortestDistanceOptions&lt;Arc, Queue, ArcFilter> {   using StateId = typename Arc::StateId;   using Weight = typename Arc::Weight;    int32 nshortest;    \/\/ Returns n-shortest paths.   bool unique;        \/\/ Only returns paths with distinct input strings.   bool has_distance;  \/\/ Distance vector already contains the                       \/\/ shortest distance from the initial state.   bool first_path;    \/\/ Single shortest path stops after finding the first                       \/\/ path to a final state; that path is the shortest path                       \/\/ only when:                       \/\/ (1) using the ShortestFirstQueue with all the weights                       \/\/ in the FST being between One() and Zero() according to                       \/\/ NaturalLess or when                       \/\/ (2) using the NaturalAStarQueue with an admissible                       \/\/ and consistent estimate.   Weight weight_threshold;  \/\/ Pruning weight threshold.   StateId state_threshold;  \/\/ Pruning state threshold.    ShortestPathOptions(Queue *queue, ArcFilter filter, int32 nshortest = 1,                       bool unique = false, bool has_distance = false,                       float delta = kShortestDelta, bool first_path = false,                       Weight weight_threshold = Weight::Zero(),                       StateId state_threshold = kNoStateId)       : ShortestDistanceOptions&lt;Arc, Queue, ArcFilter>(queue, filter,                                                        kNoStateId, delta),         nshortest(nshortest),         unique(unique),         has_distance(has_distance),         first_path(first_path),         weight_threshold(std::move(weight_threshold)),         state_threshold(state_threshold) {} };<\/code><\/pre>\n<p>  It would be a tough job to try to find a bug here on your own, wouldn&#8217;t it?<\/p>\n<p>  The problem here is that both the base and derived classes contain fields of the same name: <i>first_path<\/i>. Because of that, the derived class will have its own unique field overlapping the base class&#8217;s field. Errors like that may be a source of great confusion.<\/p>\n<p>  To better understand what I&#8217;m talking about, take a look at a small synthetic example from our documentation. Suppose we have the following code:<\/p>\n<pre><code class=\"cpp\">class U { public:   int x; };  class V : public U { public:   int x;  \/\/ &lt;= V703 here   int z; };<\/code><\/pre>\n<p>  Here, the name <i>x<\/i> is overlapped inside the derived class. The question is, what will the following code output?<\/p>\n<pre><code class=\"cpp\">int main() {   V vClass;   vClass.x = 1;   U *uClassPtr = &amp;vClass;   std::cout &lt;&lt; uClassPtr->x &lt;&lt; std::endl;   .... }<\/code><\/pre>\n<p>  If you believe it will output an undefined value, you are right. In this example, the value 1 will be written to the field of the derived class but the reading will be done from the base class&#8217;s field, which by the moment of outputting the value is still undefined.<\/p>\n<p>  Name overlapping in class hierarchy is a potential error, which you don&#8217;t want to have in your code \ud83d\ude42<\/p>\n<p>  <b>Warning 4<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v1004\/\">V1004<\/a> The &#8216;aiter&#8217; pointer was used unsafely after it was verified against nullptr. Check lines: 107, 119. visit.h 119<\/p>\n<pre><code class=\"cpp\">template &lt;....> void Visit(....) {   ....   \/\/ Deletes arc iterator if done.   auto *aiter = arc_iterator[state];   if ((aiter &amp;&amp; aiter->Done()) || !visit) {     Destroy(aiter, &amp;aiter_pool);     arc_iterator[state] = nullptr;     state_status[state] |= kArcIterDone;   }   \/\/ Dequeues state and marks black if done.   if (state_status[state] &amp; kArcIterDone) {     queue->Dequeue();     visitor->FinishState(state);     state_status[state] = kBlackState;     continue;   }   const auto &amp;arc = aiter->Value();       \/\/ &lt;=   .... }<\/code><\/pre>\n<p>  The <i>aiter<\/i> pointer is used after it has been checked for <i>nullptr<\/i>. The analyzer assumes that the presence of such a check indicates that the pointer may have the <i>nullptr<\/i> value during the check.<\/p>\n<p>  So, let&#8217;s track the <i>aiter<\/i> pointer assuming that it&#8217;s equal to null. It will first be checked in the &#8216;<i>if ((aiter &amp;&amp; aiter->Done()) || !visit)<\/i>&#8216; expression. This condition will evaluate to <i>false<\/i>, so we&#8217;ll skip the <i>then<\/i> branch of that <i>if<\/i> statement. And then, in the way of classic errors, the null pointer will get dereferenced: &#8216;<i>aiter->Value();<\/i>&#8216;. The result is undefined behavior.<\/p>\n<p>  <b>Warning 5<\/b><\/p>\n<p>  This snippet has triggered two warnings at once:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v595\/\">V595<\/a> The &#8216;istrm&#8217; pointer was utilized before it was verified against nullptr. Check lines: 60, 61. mapped-file.cc 60<\/li>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v595\/\">V595<\/a> The &#8216;istrm&#8217; pointer was utilized before it was verified against nullptr. Check lines: 39, 61. mapped-file.cc 39<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"cpp\">MappedFile *MappedFile::Map(std::istream *istrm, bool memorymap,                             const string &amp;source, size_t size) {   const auto spos = istrm->tellg();        \/\/ &lt;=   ....   istrm->seekg(pos + size, std::ios::beg); \/\/ &lt;=   if (istrm) {                             \/\/ &lt;=     VLOG(1) &lt;&lt; \"mmap'ed region of \" &lt;&lt; size             &lt;&lt; \" at offset \" &lt;&lt; pos             &lt;&lt; \" from \" &lt;&lt; source             &lt;&lt; \" to addr \" &lt;&lt; map;   return mmf.release();   }   .... }<\/code><\/pre>\n<p>  This bug is clearer than the previous one. The <i>istrm<\/i> pointer is first dereferenced (twice), and only then do the check and error logging take place. This obviously means that if a null pointer is passed to this function as <i>istrm<\/i>, undefined behavior (or a crash, which is more likely) will occur without any logging. Too bad\u2026 don&#8217;t let bugs like that into your code. <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/299\/d86\/22e\/299d8622eecc957c651b91d981d30856.png\" alt=\"image2.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/299\/d86\/22e\/299d8622eecc957c651b91d981d30856.png\"\/><\/div>\n<p>  <b>Warning 6<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v730\/\">V730<\/a> Not all members of a class are initialized inside the constructor. Consider inspecting: stones_written_. ersatz_progress.cc 14<\/p>\n<pre><code class=\"cpp\">ErsatzProgress::ErsatzProgress()   : current_(0)   , next_(std::numeric_limits&lt;uint64_t>::max())   , complete_(next_)   , out_(NULL) {}<\/code><\/pre>\n<p>  The warning says the constructor does not initialize all the fields of the <i>ErzatzProgress<\/i> structure. Let&#8217;s compare the constructor with the list of the structure&#8217;s fields:<\/p>\n<pre><code class=\"cpp\">class ErsatzProgress {   .... private:     void Milestone();      uint64_t current_, next_, complete_;     unsigned char stones_written_;     std::ostream *out_; };<\/code><\/pre>\n<p>  Indeed, as you can see, the constructor initializes all the fields except <i>stones_written_<\/i>.<\/p>\n<p>  <i>Note<\/i>: this snippet is not necessarily defective in itself. The real error will occur only when the program attempts to <i>use<\/i> the value of the uninitialized field. <\/p>\n<p>  That said, the <a href=\"https:\/\/www.viva64.com\/en\/w\/v730\/\">V730<\/a> diagnostic still helps debug cases of such unsafe use in a good time. After all, it&#8217;s just natural to wonder why the programmer should leave one of the class&#8217;s fields uninitialized while explicitly initializing all the rest.<\/p>\n<p>  My suspicion that the <i>stones_written_<\/i> field was left out by mistake proved right when I came across another constructor a few lines later:<\/p>\n<pre><code class=\"cpp\">ErsatzProgress::ErsatzProgress(uint64_t complete,                                std::ostream *to,                                const std::string &amp;message)   : current_(0)   , next_(complete \/ kWidth)   , complete_(complete)   , stones_written_(0)   , out_(to) {   .... }<\/code><\/pre>\n<p>  This constructor initializes all the fields, which proves the previous one was meant to do the same but the programmer overlooked one of the fields.<\/p>\n<p>  <b>Warning 7<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v780\/\">V780<\/a> The object &#8216;&amp; params&#8217; of a non-passive (non-PDS) type cannot be initialized using the memset function. binary_format.cc 261<\/p>\n<pre><code class=\"cpp\">\/* Not the best numbering system,    but it grew this way for historical reasons  * and I want to preserve existing binary files. *\/ typedef enum {   PROBING=0,   REST_PROBING=1,   TRIE=2,   QUANT_TRIE=3,   ARRAY_TRIE=4,   QUANT_ARRAY_TRIE=5 } ModelType;  ....  struct FixedWidthParameters {   unsigned char order;   float probing_multiplier;   \/\/ What type of model is this?   ModelType model_type;   \/\/ Does the end of the file    \/\/ have the actual strings in the vocabulary?   bool has_vocabulary;   unsigned int search_version; };  ....  \/\/ Parameters stored in the header of a binary file. struct Parameters {   FixedWidthParameters fixed;   std::vector&lt;uint64_t> counts; };  ....  void BinaryFormat::FinishFile(....) {   ....   \/\/ header and vocab share the same mmap.   Parameters params = Parameters();   memset(&amp;params, 0, sizeof(Parameters)); \/\/ &lt;=   .... }<\/code><\/pre>\n<p>  To understand this warning, let&#8217;s first figure out what a PDS type is. &#171;PDS&#187; stands for &#171;Passive Data Structure&#187;. Instead of &#171;PDS&#187;, you may sometimes see &#171;POD&#187; \u2013 &#171;Plain Old Data&#187;. Put simply, a PDS type is a data type that is characterized by strictly defined layout of fields and does not require access limitation and automatic management. Put even simpler, it&#8217;s a data type consisting only of built-in types.<\/p>\n<p>  The special feature of POD types is that you can change and process variables of these types using the primitive memory management functions (memset, memcpy, and so on). But you can&#8217;t say the same about &#171;non-PDS&#187; types: in their case, such low-level handling of values may lead to critical errors, such as memory leak, double deallocation of a resource, or undefined behavior.<\/p>\n<p>  As for the snippet above, the warning says you can&#8217;t work with a structure of type <i>Parameters<\/i> in the way it&#8217;s done there. If you look into the implementation of this structure, you&#8217;ll see that its second member is of type <i>std::vector<\/i>. This type heavily relies on automatic memory management and, in addition to its contents, stores additional, service variables. Setting such a field to zero using <i>memset<\/i> may break the class&#8217;s logic and is considered a serious error.<\/p>\n<p>  <b>Warning 8<\/b><\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v575\/\">V575<\/a> The potential null pointer is passed into &#8216;memcpy&#8217; function. Inspect the first argument. Check lines: 73, 68. modelstate.cc 73<\/p>\n<pre><code class=\"cpp\">Metadata* ModelState::decode_metadata(const DecoderState&amp; state,                              size_t num_results) {   ....   Metadata* ret = (Metadata*)malloc(sizeof(Metadata));   ....   memcpy(ret, &amp;metadata, sizeof(Metadata));   return ret; }<\/code><\/pre>\n<p>  This warning says that a null pointer is passed to the <i>memcpy<\/i> function. Indeed, if the <i>malloc<\/i> function fails to allocate storage, it will return <i>NULL<\/i>. This pointer will then be passed to the <i>memset<\/i> function, where it will be dereferenced \u2013 followed by an epic crash.<\/p>\n<p>  This may arouse indignation in you: if memory has run out or become fragmented to the point that <i>malloc<\/i> is not able to allocate storage, why should it matter what happens next? The program will crash anyway because it won&#8217;t be able to run normally under memory shortage conditions. <\/p>\n<p>  We&#8217;ve heard this opinion more than once, and we believe it&#8217;s wrong. I&#8217;d elaborate on this point, but this subject calls for a separate article \u2013 so much that we already posted one a few years ago \ud83d\ude42 If you want to know why you must always check pointers returned by functions like <i>malloc<\/i>, take a look at this post: <a href=\"https:\/\/www.viva64.com\/en\/b\/0558\/\">Why it is important to check what the malloc function returned<\/a>.<\/p>\n<p>  <b>Warning 9<\/b><\/p>\n<p>  This warning was issued for the same reasons as the previous one, only this one points at a somewhat different kind of error.<\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v769\/\">V769<\/a> The &#8216;middle_begin_&#8217; pointer in the &#8216;middle_begin_ + (counts.size() \u2014 2)&#8217; expression could be nullptr. In such case, resulting value will be senseless and it should not be used. Check lines: 553, 552. search_trie.cc 553<\/p>\n<pre><code class=\"cpp\">template &lt;class Quant, class Bhiksha> class TrieSearch { .... private:   ....   Middle *middle_begin_, *middle_end_;   .... };  template &lt;class Quant, class Bhiksha> uint8_t *TrieSearch&lt;Quant, Bhiksha>::SetupMemory(....) {   ....   middle_begin_     = static_cast&lt;Middle*>(malloc(sizeof(Middle) * (counts.size() - 2)));   middle_end_ = middle_begin_ + (counts.size() - 2);   .... }<\/code><\/pre>\n<p>  Like in the previous example, memory is allocated here using the <i>malloc<\/i> function. The pointer it returns is then used in an arithmetic expression without any prior check for <i>nullptr<\/i>. This expression will evaluate to some rubbish, meaningless value, which will be stored in the <i>middle_end_<\/i> field.<\/p>\n<p>  <b>Warning 10<\/b><\/p>\n<p>  Finally, we&#8217;ve reached what in my opinion is the most interesting case. This bug was found in the kenlm library included into DeepSpeech: <\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v1061\/\">V1061<\/a> Extending the &#8216;std&#8217; namespace may result in undefined behavior. sized_iterator.hh 210<\/p>\n<pre><code class=\"cpp\">\/\/ Dirty hack because g++ 4.6 at least wants \/\/ to do a bunch of copy operations. namespace std { inline void iter_swap(util::SizedIterator first,                       util::SizedIterator second) {   util::swap(*first, *second); } } \/\/ namespace std<\/code><\/pre>\n<p>  The hack, which is called &#171;dirty&#187; in the comment, is indeed a dirty one. You see, extending namespace <i>std<\/i> in a way like that may lead to undefined behavior. <\/p>\n<p>  Why? Because the contents of namespace <i>std<\/i> are determined solely by the Committee. That&#8217;s why the international C++ standard explicitly forbids extending <i>std<\/i> in a way like it&#8217;s done here. <\/p>\n<p>  C++03 is the latest standard supported by g++ 4.6. Here&#8217;s a quote from the <a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2013\/n3690.pdf\">C++03 final working draft<\/a> (see 17.6.4.2.1): &#171;The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified.&#187; This statement applies to all subsequent standards (C++11, C++14, C++17, and C++20). <\/p>\n<p>  Now, how can we fix the code above? The first question that naturally arises is, what are those &#171;unless otherwise specified&#187; cases? There are several situations when extending namespace <i>std<\/i> does not lead to undefined behavior. They are all listed on the <a href=\"https:\/\/www.viva64.com\/en\/w\/v1061\/\">V1061 diagnostic documentation page<\/a>, but we are now interested in one particular case: adding function template specializations.<\/p>\n<p>  Since namespace <i>std<\/i> already has a function called <i>iter_swap<\/i> (a template one, mind you), it&#8217;s just logical to assume that the programmer wanted to extend its functionality so that it could work with the <i>util::SizedIterator<\/i> type. But, unfortunately, instead of adding a <i>template function specialization<\/i>, they simply wrote an <i>ordinary overload<\/i>. What they should have written is the following:<\/p>\n<pre><code class=\"cpp\">namespace std { template &lt;> inline void iter_swap(util::SizedIterator first,                       util::SizedIterator second) {   util::swap(*first, *second); } } \/\/ namespace std<\/code><\/pre>\n<p>  Yet this code is not perfect either. The problem is that it will be correct only until C++20. Yes, starting with this version, the Standard defines template function specializations as causing undefined behavior too (see the <a href=\"https:\/\/isocpp.org\/files\/papers\/N4860.pdf\">C++20 final working draft<\/a>, 16.5.4.2.1). And since the snippet under analysis comes from a library, it will sooner or later be compiled with the <i>-std=C++20<\/i> flag. By the way, PVS-Studio distinguishes between the Standard&#8217;s versions and decides whether it should issue a warning depending on what version is used in the code. Just take a look for yourself: <a href=\"https:\/\/godbolt.org\/z\/ez3v6K\">example for C++17<\/a>, <a href=\"https:\/\/godbolt.org\/z\/4P8EoG\">example for C++20<\/a>. <\/p>\n<p>  Actually, there&#8217;s a much easier fix. You simply need to move the user definition of <i>iter_swap<\/i> to the same namespace in which the <i>SizedIterator<\/i> class is defined. You also need to add &#171;using std::iter_swap;&#187; before the calls to <i>iter_swap<\/i>. This is what you get (the definitions of the <i>SizedIterator<\/i> class and <i>util::swap()<\/i> function have been changed for simplicity):<\/p>\n<pre><code class=\"cpp\">namespace util {   class SizedIterator   {   public:     SizedIterator(int i) : m_data(i) {}      int&amp; operator*()     {       return m_data;     }   private:     int m_data;   };    ....    inline void iter_swap(SizedIterator first,                         SizedIterator second)   {     std::cout &lt;&lt; \"we are inside util::iter_swap\" &lt;&lt; std::endl;     swap(*first, *second);   } }   int main() {   double d1 = 1.1, d2 = 2.2;   double *pd1 = &amp;d1, *pd2 = &amp;d2;   util::SizedIterator si1(42), si2(43);    using std::iter_swap;    iter_swap(pd1, pd2);   iter_swap(si1, si2); \/\/ \"we are inside util::iter_swap\"    return 0; }<\/code><\/pre>\n<p>  The compiler will now automatically choose the appropriate overload of the <i>iter_swap<\/i> function based on argument-dependent lookup (ADL). For the <i>SizedIterator<\/i> class, it will call the version from <i>namespace util<\/i>, and for all other types, it will call the version from <i>namespace std<\/i>. <a href=\"https:\/\/godbolt.org\/z\/dqd97q\">Here&#8217;s<\/a> the proof. More than that, you don&#8217;t need to add any <i>using<\/i> statements inside the library functions: since their code is already inside <i>std<\/i>, the compiler will still be able to choose the appropriate overload.<\/p>\n<p>  And then \u2013 presto! \u2013 you get a normally working user-defined <i>iter_swap<\/i> function without any &#171;dirty hacks&#187; or other witchcraft:)<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/037\/1ab\/b41\/0371abb41d1f34e5aa65df8234d2ac1e.png\" alt=\"image3.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/037\/1ab\/b41\/0371abb41d1f34e5aa65df8234d2ac1e.png\"\/><\/div>\n<p>  <\/p>\n<h2>Conclusion<\/h2>\n<p>  That&#8217;s all for DeepSpeech. I hope you&#8217;ve liked the bugs discussed here and have learned something new. If you&#8217;ve read this far, I sincerely wish you clean and neat code. May bugs stay away from your projects!<\/p>\n<p>  If you write in C, C++, C#, or Java and if you are, as I am, interested in static analysis, don&#8217;t hesitate to try PVS-Studio on your own projects. You can download it <a href=\"https:\/\/viva64.com\/en\/pvs-studio-download\/\">here<\/a>.<\/p>\n<p>  <a href=\"https:\/\/viva64.com\/en\/pvs-studio-download\/?utm_source=habr&amp;utm_medium=banner&amp;utm_campaign=DeepSpeech\"><\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/42b\/757\/14b\/42b75714b45fa154c5497bdb32b2c568.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/42b\/757\/14b\/42b75714b45fa154c5497bdb32b2c568.png\"\/><\/div>\n<p><\/a><\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/524022\/\"> https:\/\/habr.com\/ru\/articles\/524022\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">DeepSpeech is an open-source speech recognition engine developed by Mozilla. It&#8217;s pretty fast and ranks high, which makes its source code an interesting target for static analysis. In this article, I&#8217;ll show you some of the bugs found in DeepSpeech&#8217;s C++ code. <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/5ad\/5d0\/076\/5ad5d0076af2293cc7c41dc5db49f05b.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/5ad\/5d0\/076\/5ad5d0076af2293cc7c41dc5db49f05b.png\"\/><\/div>\n<p>  <\/p>\n<h2>Introduction<\/h2>\n<p>  We have already scanned a few projects based on machine learning before, so there was nothing new about <a href=\"https:\/\/github.com\/mozilla\/DeepSpeech\">DeepSpeech<\/a> to us in this respect. No wonder since the project is quite popular: as of this writing, it has 15k stars on GitHub.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-395984","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/395984","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=395984"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/395984\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=395984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=395984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=395984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}