Repository: google/benchmark
File: src/benchmark_runner.cc (C++)

Code before:
    results.complexity_n += st.complexity_length_n();
    internal::Increment(&results.counters, st.counters);
  }
  manager->NotifyThreadComplete();
}

struct BenchTimeType {
  enum { ITERS, TIME } tag;
  union {
    int iters;
    double time;
  };
};

BenchTimeType ParseBenchMinTime(const std::string& value) {
  BenchTimeType ret;

  if (value.empty()) {
    ret.tag = BenchTimeType::TIME;
    ret.time = 0.0;
    return ret;
  }

  if (value.back() == 'x') {
    std::string num_iters_str = value.substr(0, value.length() - 1);
    int num_iters = std::atoi(num_iters_str.c_str());

    // std::atoi doesn't provide useful error messages, so we do some
    // sanity checks.
    // Also check that the iters is not negative.
    BM_CHECK(num_iters > 0 && !(num_iters == 0 && num_iters_str != "0"))
        << "Malformed iters value passed to --benchmark_min_time: `" << value
        << "`. Expected --benchmark_min_time=<integer>x.";

    ret.tag = BenchTimeType::ITERS;
    ret.iters = num_iters;
    return ret;
  }

  std::string min_time_str;
  if (value.back() != 's') {
    BM_VLOG(2) << "Value passed to --benchmark_min_time should have a suffix. "
                  "Eg., `30s` for 30-seconds.";
    min_time_str = value;
  } else {
    min_time_str = value.substr(0, value.length() - 1);
  }
  double min_time = std::atof(min_time_str.c_str());

  BM_CHECK(min_time > 0 &&
           !(min_time == 0 && (min_time_str != "0" || min_time_str != "0.0")))

Review comment (suggestion):
if we have `strtonum` we can get an error, but i'm not sure we do.  at least `strtol` provides some range protection (atoi does no such thing).

Code after:
    internal::ThreadManager::Result& results = manager->results;
    results.iterations += st.iterations();
    results.cpu_time_used += timer.cpu_time_used();
    results.real_time_used += timer.real_time_used();
    results.manual_time_used += timer.manual_time_used();
    results.complexity_n += st.complexity_length_n();
    internal::Increment(&results.counters, st.counters);
  }
  manager->NotifyThreadComplete();
}

double ComputeMinTime(const benchmark::internal::BenchmarkInstance& b,
                      const BenchTimeType& iters_or_time) {
  if (!IsZero(b.min_time())) return b.min_time();
  // If the flag was used to specify number of iters, then return the default
  // min_time.
  if (iters_or_time.tag == BenchTimeType::ITERS) return kDefaultMinTime;

  return iters_or_time.time;
}

IterationCount ComputeIters(const benchmark::internal::BenchmarkInstance& b,
                            const BenchTimeType& iters_or_time) {
  if (b.iterations() != 0) return b.iterations();

  // We've already concluded that this flag is currently used to pass
  // iters but do a check here again anyway.
  BM_CHECK(iters_or_time.tag == BenchTimeType::ITERS);
  return iters_or_time.iters;
}

}  // end namespace

BenchTimeType ParseBenchMinTime(const std::string& value) {
  BenchTimeType ret;

  if (value.empty()) {
    ret.tag = BenchTimeType::TIME;
    ret.time = 0.0;
    return ret;
  }

  if (value.back() == 'x') {
    const char* iters_str = value.c_str();
    char* p_end;
    // Reset errno before it's changed by strtol.
    errno = 0;
    IterationCount num_iters = std::strtol(iters_str, &p_end, 10);

    // After a valid parse, p_end should have been set to
    // point to the 'x' suffix.