lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master ade6b59e 03/13: Fix defect introduced 2017022


From: Greg Chicares
Subject: [lmi-commits] [lmi] master ade6b59e 03/13: Fix defect introduced 20170221T0207Z: potential UB
Date: Fri, 10 Jun 2022 21:09:37 -0400 (EDT)

branch: master
commit ade6b59ed5a569dca23db348187506dc7543e44d
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    Fix defect introduced 20170221T0207Z: potential UB
    
    ASan found potential UB in commit d09d73d85a1cac of 20170221T0207Z. See:
      https://lists.nongnu.org/archive/html/lmi/2022-05/msg00032.html
    | fill_interval_gaps() in input_sequence.cpp can, in theory, dereference a
    | dangling "last" reference because it refers to the last element of the
    | "out" vector which may be reallocated after calling push_back() on it.
    
    Precluded UB by reserving enough capacity to prevent push_back() from
    invalidating iterators. Asserted some formerly tacit assumptions.
---
 input_sequence.cpp | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/input_sequence.cpp b/input_sequence.cpp
index 3f573bae..a940ff6e 100644
--- a/input_sequence.cpp
+++ b/input_sequence.cpp
@@ -29,10 +29,11 @@
 #include "assert_lmi.hpp"
 #include "contains.hpp"
 #include "input_sequence_parser.hpp"
+#include "oecumenic_enumerations.hpp"   // methuselah
 #include "ssize_lmi.hpp"
 #include "value_cast.hpp"
 
-#include <algorithm>                    // fill()
+#include <algorithm>                    // fill(), max()
 #include <sstream>
 #include <stdexcept>
 #include <type_traits>
@@ -404,6 +405,10 @@ void assert_not_insane_or_disordered
     ,int                               years_to_maturity
     )
 {
+    int const n_intervals = lmi::ssize(intervals);
+    LMI_ASSERT(0 <= n_intervals       && n_intervals       <= methuselah);
+    LMI_ASSERT(0 <= years_to_maturity && years_to_maturity <= methuselah);
+
     int prior_begin_duration = 0;
     for(auto const& i : intervals)
         {
@@ -523,6 +528,9 @@ void fill_interval_gaps
 
     LMI_ASSERT(out.empty());
 
+    // in.size() <= methuselah, so doubling it can't overflow
+    out.reserve(std::max(1, 2 * lmi::ssize(in)));
+
     ValueInterval default_interval;
     default_interval.value_is_keyword = keywords_only;
     if(keywords_only)
@@ -550,9 +558,13 @@ void fill_interval_gaps
             }
         else // Iff not first pass.
             {
-            auto const& last = out.back(); // Safe: 'out' cannot be empty.
+            // This reference to back() is valid because 'out' cannot
+            // be empty, and remains valid in the if-block below
+            // because push_back() cannot invalidate it.
+            auto const& last = out.back();
             if(last.end_duration != next.begin_duration)
                 {
+                LMI_ASSERT(out.size() < out.capacity());
                 out.push_back(default_interval);
                 out.back().begin_mode     = last.end_mode    ;
                 out.back().begin_duration = last.end_duration;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]