Skip to content

Segfault when total = 0 #79

@jennybc

Description

@jennybc

It's easy to create a segfault if you create a progress bar with total = 0. Of course, I didn't mean to do this, it's just an edge case and I will rework things on my end so this doesn't happen.

In my actual usage, I create a progress bar and followed this recommendation:

It is good practice to call tick(0) at the beginning of the computation or download, which shows the progress bar immediately."

and that's where things go sideways if total = 0.

The main problem is that this makes ratio() return NaN. I think ratio() should return either 0 or 1 in the 0/0 case. But I'm not sure which.

double ratio() {
double ratio = current / total;
if (ratio < 0) ratio = 0;
if (ratio > 1) ratio = 1;
return ratio;
}


Contents of segfault.cpp, based on the example package in the tests:

#include <Rcpp.h>
#include <inst/include/RProgress.h>
#include <unistd.h>

// [[Rcpp::export]]
Rcpp::CharacterVector test_progress(Rcpp::CharacterVector formatSEXP =
                                      "[:bar] :percent ", double total = 100) {
  const char *format = formatSEXP[0];
  RProgress::RProgress pb(format, total);

  pb.tick(0);
  for (int i = 0; i < 100; i++) {
    usleep( (useconds_t) (2.0 / 100 * 1000000));
    pb.tick();
  }

  Rcpp::CharacterVector result(1);
  result[0] = "DONE";
  return result;
}

In R:

Rcpp::sourceCpp("segfault.cpp")

## nice demo :)
test_progress()

## this will segfault!
test_progress(total = 0)

Here's what I see in the debugger, which suggests the problem is total = 0 --> ratio() returns NaN --> ratio_now = complete_len = NaN --> i in a for loop initializes to nonsense.

> test_progress(total = 0)
Process 20422 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x000000010a0f1be7 sourceCpp_2.so`RProgress::RProgress::render(this=0x00007ffeefbfd9f8) at RProgress.h:181
   178 	    if (!bar) Rf_error("Progress bar: out of memory");
   179 	    for (int i = 0; i < complete_len; i++) { bar[i] = complete_char; }
   180 	    for (long int i = (long int) complete_len; i < bar_width; i++) {
-> 181 	      bar[i] = incomplete_char;
   182 	    }
   183 	    bar[bar_width] = '\0';
   184 	    replace_all(str, ":bar", bar);
Target 0: (R) stopped.
(lldb) frame variable i
(long) i = -9223372036854775808
(lldb) frame variable complete_len
(double) complete_len = NaN
(lldb) frame variable ratio_now
(double) ratio_now = NaN

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugan unexpected problem or unintended behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions